1. 安卓程序动态调试条件
安卓程序动态调试条件 ( 2个满足1个即可 ):
- 1. 在 AndroidMainfest.xml ---> application 标签下,设置或者添加属性 android:debuggable="true"
- 2. 系统默认模式,在 build.prop(boot.img),ro.debuggable=1
Android SDK 中有 android.os.debug 类提供了一个 isDebuggerConnected方法,用于判断 JDWP 调试器是否正在工作
2. Java层 的 反调试
示例:手动绕过百度加固 Debug.isDebuggerConnected 反调试的方法:
https://blog.csdn.net/QQ1084283172/article/details/78237571
**************************************************************************************************************
AndroidStudio调试smali 和 java 都是用的 jdwp 进行转发, IDA调试 so 用的是 tcp 转发
**************************************************************************************************************
JDWP 协议介绍
JDWP 是 Java Debug Wire Protocol 的缩写,它定义了调试器(debugger)和 被调试的 Java 虚拟机(target vm)之间的通信协议。JDWP 协议可以 远程 动态调试 Java 程序。
JVM 自带有对这个协议相应的支持,通过命令 java -agentlib:jdwp=help 可以查看help文档。
说明一下 debugger 和 target vm
- Target vm 中运行着我们想要调试的程序,它与一般运行的 Java 虚拟机没有什么区别,只是在启动时加载了 Agent JDWP 从而具备了调试功能。
- debugger 就是我们熟知的调试器,它向运行中的 target vm 发送命令来获取 target vm 运行时的状态和控制 Java 程序的执行。
- Debugger 和 target vm 分别在各自的进程中运行,他们之间的通信协议就是 JDWP。
JDWP 与其他许多协议不同,它仅仅定义了数据传输的格式,但并没有指定具体的传输方式。这就意味着一个 JDWP 的实现可以不需要做任何修改就正常工作在不同的传输方式上(在 JDWP 传输接口中会做详细介绍)。
JDWP 是语言无关的。理论上我们可以选用任意语言实现 JDWP。然而我们注意到,在 JDWP 的两端分别是 target vm 和 debugger。Target vm 端,JDWP 模块必须以 Agent library 的形式在 Java 虚拟机启动时加载,并且它必须通过 Java 虚拟机提供的 JVMTI 接口实现各种 debug 的功能,所以必须使用 C/C++ 语言编写。而 debugger 端就没有这样的限制,可以使用任意语言编写,只要遵守 JDWP 规范即可。JDI(Java Debug Interface)就包含了一个 Java 的 JDWP debugger 端的实现(JDI 将在该系列的下一篇文章中介绍),JDK 中调试工具 jdb 也是使用 JDI 完成其调试功能的。
JDWP agent 在调试中扮演的角色
使用 JDWP 远程调试 java 程序:https://www.jianshu.com/p/4b322505087f
使用 JDWP 进行远程调试:https://blog.csdn.net/renfufei/article/details/52756556
3. so层 的 反调试( JNI_OnLoad )
拿到一个 apk 分析步骤:首先先分析有没有加壳,如果没有加壳,使用 jadx-gui 打开自动反编译,并进行分析,如果有加壳,需要先脱壳,然后在进行分析。找到 入口点 或者 入口页面 进去查看分析。
IDA Pro 分析 so 库 JNI_OnLoad:https://www.bilibili.com/video/BV1UE411A7rW?p=69
AntiDebug 源码:https://github.com/weikaizhi/AntiDebug 。
github 下载完直接编译报错 ,所以使用 AndroidStudio 打开项目后需要做如下修改
- 在 antidebug.cpp 中添加 #include <pthread.h>
- AndroidManifest.xml 的 application 节点添加 android:debuggable=true
然后编译生成 apk,但是生成的 apk 是没有签名的,没法安装到手机或者模拟器上。
可以使用 AndroidStudio、apk上上签、AndroidKiller、安卓逆向助手等进行签名。这里使用 AndroidKiller 进行签名。。。
签名后就可以在手机或者模拟器上安装 apk 了。。。
源码中的反调试函数( 可以看到只检测了三个:状态、IsHookByXPosed、isBeDebug )
//反调试检测
MACRO_HIDE_SYMBOL void* AntiDebug::antiDebugCallback(void *arg)
{if(arg == NULL)return NULL;AntiDebug* pAntiDebug = (AntiDebug*)arg;while (true){try{bool bRet1 = pAntiDebug->readStatus();bool bRet2 = pAntiDebug->IsHookByXPosed();bool bRet3 = pAntiDebug->isBeDebug();if(bRet1 || bRet2 || bRet3){if(g_callbackRef != 0 && g_MethodCallback != 0){JNIEnv* env = GetEnv();if(env != NULL){env->CallVoidMethod(g_callbackRef, g_MethodCallback);}}}} catch (...){}sleep(1);}
}
当反调试被触发时,会出现一个弹窗,如图所示:
静态分析
下面使用 IDA Pro 进行 so 库的分析,解压 apk ,找到 so 文件
使用 IDA 打开,首先 Ctrl + s 搜索 段,看下 init_array 里面有没有函数,发现没什么有用的东东,继续在 Exports 里面搜索 java_ 和 jni,分析后发现 java_ 开头的静态注册函数也没有啥东东,所以分析 JNI_OnLoad 函数
源码中 JNI_OnLoad 函数
继续分析 sub_9C9C 这个函数。。。
方法 2:通过 IDA Pro 的 String 查看,看看有没有可疑的字符串。这种方法信息量比较多,还是推荐直接分析 JNI_OnLoad
源码中的反调试函数( 可以看到只检测了三个:状态、IsHookByXPosed、isBeDebug )
可以参看源码 和 so 理解反调试。。。。。
动态分析
参考:安卓逆向_17 --- 动态调试【 环境搭建、so库调试【动态普通、动态debug模式】、JNI_OnLoad调试分析、java_ 开头函数分析】:https://blog.csdn.net/freeking101/article/details/106701908
4. 示例
4.1 FindTracer.apk 过反调试 ( 动态调试 JNI_OnLoad )
反调试:https://www.bilibili.com/video/BV1UE411A7rW?p=70
FindTracer 破解反调试:https://www.jianshu.com/p/a2b3517d4815
安装 apk,然后打开 app,没有被调试时,显示 Everything fine 。
首先看下 Java 层,使用 jadx-gui 反编译 apk,看下 Java 代码,查看 入口点、入口页面
可以看到 FindTracer.getInstance().findTracer() 就是检测反调试的代码,双击 findTracer() 函数,进入查看函数
可以看到是 native 函数,所以需要从 so 库入手。。。
IDA 打开 so 后( init_array 执行时间比 JNI_OnLoad 早,所以先分析 init_array,再分析 java_ 或者 jni_onload):
- Ctrl + s ,找到 init_array,看下 init_array 里面有没有检测函数 ( 本例没有 )
- 搜索 java_ 和 jni_onload,进行分析
4.2 自毁程序密码.apk ( 动态调试 JNI_OnLoad )
APK文件下载链接: http://pan.baidu.com/s/1ntiKXg1 密码: 37xw
其中 AliCrackme_2.apk 是原安装包, signed.apk 是包含修改后so文件的安装包。
自毁程序密码(第二题)》分析( IDA 动态调试so ):https://www.pd521.com/thread-291-1-1.html
:https://www.bilibili.com/video/BV1UE411A7rW?p=71
安装 apk,然后打开 app 如图所示:
打开 app 后,直接出现如上图界面,这个就是 "入口页面"。首先还是从 Java 层开始,使用 jadx-gui 反编译 apk,看下 Java 代码,查看 入口点、入口页面。
入口页面代码:
可以看到如果 if 条件满足,则直接打开 ResultActivity 页面,通过查看 ResultActivity 页面的代码可知这个是成功后的页面
如果不满足,则弹出 "验证码校验失败",所以 if 里面的 securityCheck 函数就是检测反调试的。securityCheck 函数被 native 修饰,所以是在 so 里面实现的。同时 securityCheck 没有被 static 修饰。
使用 IDA 打开 crackme.so ---> Exports ---> 搜索 java_ 和 jni_onload ---> 分析C++ 函数
搜索 java_
securityCheck 函数只有一个 String 类型的参数,所以securityCheck对应的 java_ 开头的函数的第三个参数类型修改为 jstring
通过分析,没找到有用的东东,然后再 分析 jni_onload
搜索 jni_onload,发现也看不出什么有用的东东,
所以 动态调试 看下。(自毁程序密码:( IDA 动态调试so ):https://www.pd521.com/thread-291-1-1.html)
4.3 crackme ( 动态调试 JNI_OnLoad )
分析类似 4.2 ,导入 jni.h 识别函数
:https://www.bilibili.com/video/BV1UE411A7rW?p=72
5. init_array 下断
:https://www.bilibili.com/video/BV1UE411A7rW?p=74