前言

 不得不说自从有了IDE之后,很多原本很基本的开发命令开发步骤似乎被人们慢慢淡忘了,特别是Android开发,先是eclipse+adt作为Android开发的IDE,到现在的Android Studio2.3.3的功能可谓是如此得强大,编译速度越来越快。然而很多基础的东西却被这强大的IDE悄悄地替我们完成了,比如apk的编译,打包,签名。而开发者需要做的仅仅是在GUI界面点击编译,打包按钮即可。其实这些步骤都可以用最基本的jdk,sdk tools工具完成的,通过jdk,sdk,…提供的一些命令工具在加个编辑器即可进行android开发。IDE给我们带来方便的同时也让我们对一些基本的知识有所淡忘。

 回想自己,发现自己有点过于依赖于IDE,过于依赖于网络,对于一些知识从来都不刻意去记,以至于写个java测试文件都想着下载eclipse;以至于在面试的时候出现这个问题我明明知道怎么解答但需要给我一台可以上网的电脑或手机的尴尬场景。或许是因为我有一段时间没接触这一块了的原因,对于命令,api之类的知识从来都不记,对于设计模式,算法之类的我想靠的就是理解了。而计算机技术层出不穷,发展迅速,这个命令,那个工具,这种语言等等,在现在的这个快速发展的社会,逆水行舟,不进则退,唯有不断地学习才能让自己更好地适应社会。

准备

android反编译常用到的工具如下:

解压过apk的人都知道,直接解压得到的布局文件是乱码,除了图片外,其他的文件基本不能使用。而通过apktool解压后的结果大家可以试着去对比一下。

apktool工具下载后,它是一个jar文件,需要编写一个.bat文件取名叫apktool.bat,下面是它的内容(注意由于apktool版本不同,将apktool_v2.2.4.jar之类的自己改成apktool.jar),同时apktool.jar和apktool.bat需要放在同一目录。之后使用apktool就到该目录下在命令行中执行apktool命令即可或是将apktool所在的路径添加到path环境变量中,之后在任意目录即可直接输入apktool命令即可。

@echo off
if "%PATH_BASE%" == "" set PATH_BASE=%PATH%
set PATH=%CD%;%PATH_BASE%;
java -jar -Duser.language=en "%~dp0\apktool.jar" %*

apktool反编译命令:apktool d apkname.apk

反编译修改manifest文件 反编译修改界面_apk

apktool打包命令:apktool b 目录 -o apkname.apk

反编译修改manifest文件 反编译修改界面_反编译_02

dex2jar工具使用比较简单,解压dex2jar.zip后可以看到有很多.bat文件,其中有个dex2jar.bat(类似,可以自己改名)的文件,命令行到该界面下并将解压得到的classes.dex文件放到该目录下,执行dex2jar classes.dex命令即可。

反编译修改manifest文件 反编译修改界面_apktool_03

使用JD-GUI工具打开刚才用dex2jar得到的.jar文件,即可查看反编译得到的apk源码。

反编译修改manifest文件 反编译修改界面_反编译_04

代码演示

修改apk的启动页,我们的思路是编写一个自己的启动页(Activity),然后修改apk的AndroidManifest.xml文件中LAUNCHER Activity为我们的启动页,最后在重新打包得到apk即可。

  1. 编写闪屏页;
  2. 修改AndroidManifest.xml文件;
  3. 重新打包。

一、得到apk(目标apk)

可以去市场上找一个apk用来反编译测试,不过为了方便直接编写一个简单的测试apk,如只是用一个Activity显示official app的字符串~

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.lt.demo.official.MainActivity">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="official app" app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

编写好代码之后我们需要将项目打包得到apk文件,打包方式有两种,可以借助IDE,也可以使用命令进行打包。

1、使用Android Studio(Build->Generate Signed Apk)

反编译修改manifest文件 反编译修改界面_反编译修改manifest文件_05

2、使用命令打包(apktool b 目录 -o appname.apk

注意:

  1. 使用apktool打包的apk没有进行签名,还需要签名,否则apk无法安装;
  2. 签名需要签名文件(.keystore),可以用Android Studio GUI生成,也可以使用命令生成;
  3. Android 7.0后天就了v2 Full Signature签名机制,在Android Studio高版本进行打包的时候不要使用v2,否则本次项目演示会失败。

反编译修改manifest文件 反编译修改界面_apktool_06

签名命令(jarsigner )(可以输入jarsigner回车查看该命令参数说明):

jarsigner -verbose -sigalg SHA1withRS
A -digestalg SHA1 -keystore lt.keystore -storepass 123456 official.apk lt.key
store

反编译修改manifest文件 反编译修改界面_apktool_07

二、编写自己的启动页(用于更改目标apk的启动页)

MainActivity.java

package com.lt.demo.official;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;

public class FlashActivity extends AppCompatActivity {

    private Handler mHandler = new Handler(Looper.getMainLooper());

    private Runnable mCallback = new Runnable() {
        @Override
        public void run() {
            startActivity(new Intent(FlashActivity.this,MainActivity.class));
            finish();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flash);
        mHandler.postDelayed(mCallback,3000);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacks(mCallback);
    }
}

注意包名要与目标apk的包名一致。

由于apktool反编译得到的类文件为smail格式,所以,我们要在目标apk中添加我们自己的Activity,就需要得到Activity对应的smail文件,由于smail语法我们不会,但可以通过Android Studio工具得到FlashActivity对应得smail,步骤为:

  1. 新建一个项目;
  2. 项目添加FlashActivity(包括layout文件);
  3. 使用as打包得到apk;
  4. 通过apktool反编译这个apk,在smail文件夹下取出对应的smail文件,这里为FlashActivity.smaliFlashActivity$1.smali,FlashActivity$1.smali为FlashActivity中的内部类。

得到了我们启动页的smail后,将其添加到目标文件中。

三、植入目标apk

1、将得到的两个smail添加到反编译目标apk得到的文件夹中的smail目录对应的目录中,如

反编译修改manifest文件 反编译修改界面_反编译修改manifest文件_08

2、修改目标apk的AndroidManifest.xml文件

反编译修改manifest文件 反编译修改界面_反编译修改manifest文件_09

3、添加layout,将FlashActivity.java对应的activity_flash.xml(反编译后的)添加到目标apk反编译得到的文件夹中。

反编译修改manifest文件 反编译修改界面_反编译_10

4、添加资源文件对应的ID

R.java反编译对应的是好多的smail文件

反编译修改manifest文件 反编译修改界面_android_11

打开R$layout.smail,在最后一行中添加activity_flash.xml的ID

反编译修改manifest文件 反编译修改界面_反编译_12

这里注意ID不要重复了,通常设置为最后一个ID+1比较好。

5、修改FlashActivity.smail对应的ID(需要和R$layout.smail中的activity_flash ID一致)

反编译修改manifest文件 反编译修改界面_反编译修改manifest文件_13

四、重新打包apk,完成启动页的修改。

接下来只需要重新打包签名目标apk即完成了启动页的修改,打包和签名命令在前面的内容中提到过了,ok,到这里就完成了apk启动页的修改了,总体来说比较简单,关键是我们不明白smail语法,其实仅仅是通过偷梁换柱的方式替换了apk的启动页而已。

二次打包后得到的apk安装后打开崩溃的错误有可能是用的Android Studio版本比较高,在打包的时候使用了v2 Full APK Signature 签名机制,得到apk体积会变小。

APK signature scheme v2:

 APK signature scheme v2是Android 7.0引入的新的应用签名机制,系统默认会根据以前的签名机制(V1 Jar signature)和APK signature scheme v2进行签名,APK signature scheme v2签名可能会导致一些问题。这里就导致了程序崩溃的问题,当遇到这种问题的时候,我们的解决方案是采用v1签名机制即可。

反编译修改manifest文件 反编译修改界面_apktool_14