对安卓root软件Kingroot
的Root原理的简单逆向分析。
1.背景知识
A.获取设备上正在运行的app信息
1、Android5.0以下——
((ActivityManager.RunningAppProcessInfo)((ActivityManager)paramContext.getSystemService("activity")).getRunningAppProcesses().get(0)).processName;
2、Android5.0——
((ActivityManager.RunningTaskInfo)((ActivityManager)paramContext.getSystemService("activity")).getRunningTasks(1).get(0)).topActivity;
3、Android5.1及以上——Android限制了此功能的使用,只有申请了permission.REAL_GET_TASKS
权限的系统应用才能使用此功能。此种情况下可参考此处,选择其他方式(如AccessibilityService
)进行获取。
B.通过Thread,Looper和Handler实现线程通信
其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler。最终消息由looper交由Handler处理,即Handler的dispatchmessage方法会被调用,这是Handler就进入处理消息的阶段。图解Looper , Handler , Message 这三者关系。
如下述代码示例——
MainActivity.java
public class MainActivity extends Activity {
public static final String TAG = "Main Acticity";
Button btn = null;
Button btn2 = null;
Handler handler = null;
MyHandlerThread mHandlerThread = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button);
btn2 = (Button)findViewById(R.id.button2);
Log.d("MainActivity.myLooper()", Looper.myLooper().toString());
Log.d("MainActivity.MainLooper", Looper.getMainLooper().toString());
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mHandlerThread = new MyHandlerThread("onStartHandlerThread");
Log.d(TAG, "创建myHandlerThread对象");
mHandlerThread.start();
Log.d(TAG, "start一个Thread");
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mHandlerThread.mHandler != null){
Message msg = new Message();
msg.what = 1;
mHandlerThread.mHandler.sendMessage(msg);
}
}
});
}
MyHandlerThread.java
public class MyHandlerThread extends Thread {
public static final String TAG = "MyHT";
public Handler mHandler = null;
@Override
public void run() {
Log.d(TAG, "进入Thread的run");
Looper.prepare();
Looper.prepare();
mHandler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg){
Log.d(TAG, "获得了message");
super.handleMessage(msg);
}
};
Looper.loop();
}
Android中的Thread, Looper和Handler机制(附带HandlerThread与AsyncTask)
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
C.APP正版验证机制
从方法上分类可分为:文件完整性校验、签名校验、混合校验(二者都有);从校验代码所处层面进行分类可分为:Java层校验、So层校验和混合校验(如在Java层获取APP签名信息,在So层进行校验)。
在破解APP正版验证机制时,可从以下步骤入手——
- 解压APK,删除原签名,重打包,若安装后提示版本错误,则为签名验证机制,若能正常运行,则不包含签名验证机制;
- 修改APK中的代码后重打包,若安装后提示版本错误,而且程序中不包含签名验证机制或签名验证机制已被破解,则为DEX校验;
- 在判断出有以上校验机制后,断开网络连接,以判断校验机制是本地的还是服务器端的。
2.逆向分析
该APP并未加壳,可直接分析其代码。
A.找入手点
一般Android APP逆向有以下快速定位到分析点的方式。
- 根据运行过程中的日志信息,或界面上的关键字符串,在代码中搜索定位。
- 根据资源文件(如
string.xml
)中的关键字符串进行搜索定位。 - 根据抓到的关键数据包,在代码中搜索定位。
- 根据APP包名和类名进行可疑类的定位和分析(如寻找包名目录下类名中带
ROOT
的关键类)。效率较低不推荐。 - 直接在手机上运行到关键界面,然后获取界面信息(具体的Activity名字),就可以快速定位到关键代码。
B.具体分析
最开始分析的时候,定位到关键代码后,由于不是很熟悉Handler
、message
、Looper
的具体操作(但是代码中采用了较多相关操作),所以分析起来比较吃力。于是去了解了相关的基础知识,再进行分析,看起来就轻松很多。另外,也不能一味的静态分析,在静态分析获取到关键类/方法后,可通过动态调试辅助分析(如获取参数等)。
由于动态调试需求,添加了android:debuggable=”true”,重打包了应用程序,但运行时触发了报错。解决这个问题的2种方法:(1)自定义Android系统;(2)破掉apk中的签名/apk完整性验证机制。
(1)破掉apk正版验证机制
通过关键词verificaion
、Signatures
、kill
、check
等入手,先静态分析定位可能的关键代码位置,然后尝试动态调试辅助思考如何改变返回参数。
注意程序中可能存在的迷惑性方法,比如在分析过程中发现在2个smali类中都发现了checkSignatures
方法,但只有方法的定义,在JAVA层中并没有对此方法的调用,当然有可能是在so层调用,但是在apk的so文件中也没有看到相关调用方法,所以对此方法的改变并没有办法破解掉正版验证机制。
首先判断出该APK的正版校验机制是本地的签名校验,接下来就需要找出关键验证函数(通过关键词缩小范围),实现破解。