安卓逆向-IDA动态调试 | 自毁程序的反调试

IDA动态调试

配置:
 #把本地文件推送进手机目录(我的nexus是64位的)
 #注意注意!!!!这里不是Frida的server是ida自带的server!!
 adb push android_x86_server(cpu型号要对应 模拟器是x86) /data/local/tmp/
 #进入手机shell
 adb shell
 #真机要使用 su 命令 切换到root用户,模拟器不用
 #进入手机tmp目录
 cd /data/local/tmp/
 #修改权限
 chmod 777 android_server
 #运行
 ./android_server
 #在本地执行adb 做端口转发
 adb forward tcp:23946 tcp:23946

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

等待加载
ctrl + s 找到要调试的so文件 选择用X字样(可执行的)

在这里插入图片描述

按键盘G键, 输入绝对地址,跳转到要调试的函数处
如何计算要调试函数的绝对地址:
绝对地址 = so文件的基地址 + 该函数的偏移量
so文件的基地址在哪儿找:
快捷键 ctrl + s 找到目标so文件 Start 那一项就是 基地址

在这里插入图片描述

函数的偏移量在哪儿找:
以静态方式打开so文件,函数列表里

在这里插入图片描述

得到函数的绝对地址,按g进行跳转

在这里插入图片描述

跳转到目标函数后,在此处设置断点(快捷键F2 或 fn+F2 或右键)

在这里插入图片描述

断点设置好后,点击左上角三角形运行,等待APP运行到此断点处,就会停止,此时即可调试

F7单步调试,要进入函数
F8单步调试,不进入函数(一般情况用这个)
so反调试
IDA调试原理 是利用Linux系统 ptrace 来实现
当应用被调试时,应用内存里的TracerPid 字段就不为0
 进入设备查看ptrace字段:
 //进入设备
 adb shell
 //获得APP的进程ID
 ps | grep 包名

在这里插入图片描述
在这里插入图片描述

 //打印该APP里内存状态信息
 cat /proc/pid(进程ID)/status
TracerPid为0代表没有被调试,不为0代表在被调试。
反调试,既检测TracerPid是否被占用

在这里插入图片描述

so文件反调试的手段就是:
新建一个线程 不停的检测TracerPid这个字段是否不为0, 不为0,就立即退出程序。
 //linux中创建进程的函数
 pthread_create()
反反调试
动态调试,找到检测TracerPid的代码,不执行此代码
方法:
根据so文件的加载顺序,此检查代码一般在.init_arra 和 JNI_OnLoad两处
在JNI_OnLoad函数出打断点调试,找到检测TracerPid的代码,不执行此代码
如何在JNI_OnLoad函数打断点:
so文件在加载阶段会执行JNI_ONLoad,此后不再执行,要在so文件加载阶段才能给JNI_OnLoad打断点
  1. 修改APP AndroidMenifest.xml文件, APP加上可调试权限,android:debuggable=“true”,重新打包APP,签名,安装
    在这里插入图片描述

  2. 检查flags中是否有应许debug项
    adb shell dumpsys package com.yaotong.crackme
    在这里插入图片描述

  3. 以调试模式启动APP APP此时会挂住

 adb shell am start -D -n 包名/.类名
 adb shell am start -D -n com.yaotong.crackme/.MainActivity

在这里插入图片描述
在这里插入图片描述

  1. DebuggerOptions里勾选 Suspend on thread start/exit | Suspend on library load/unload,因为JNI_OnLoad函数是lib刚加载时就会执行,必须要在lib载入时就让程序停下来,才能调试JNI_OnLoad

在这里插入图片描述

  1. 点击运行按钮

在这里插入图片描述

  1. 在设备里查看APP的进程ID
    要adb shell先进入设备运行如下命令,过滤出该应用信息
ps | grep 应用包名(可以是一部分,用来过滤)
ps | grep cra

在这里插入图片描述

  1. 使用JDB命令让APP 恢复运行
 adb forward tcp:8700 jdwp:27556(APP的PID)
 jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
  1. 在so文件被加载时,IDA会停止住,使用ctrl+s 查看目标so文件是否加载,没有的话点击绿色运行,然后继续查看是否被加载。找到后进行的JNI_OnLoad的绝对内存位置计算,按g进行位置跳转。按一下绿色开始然后F8单步调试(pthread_create也是关键字眼)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  1. 用UltraEdit打开so文件,把上面37 FF 2F E1的汇编指令数值改成00 00 00 00,重新打包签名然后安装,解决反调试的问题

在这里插入图片描述


解决反调试的问题之后继续在securityCheck打断点,再点击左上角绿色运行让程序执行

在这里插入图片描述

然后因为这里是通过APP输入密码后才触发,所以输入密码,成功断上

在这里插入图片描述

在这里插入图片描述

上面按F5也能知道是运行到那

在这里插入图片描述
在这里插入图片描述

成功!

在这里插入图片描述


动态调试libcrackme拿到密码:

  1. 分析出密码判断的函数是哪一个
  2. IDA静态分析此函数,理清脉络(变量重命名会有帮助,一些语句判断)
  3. IDA动态调试,在此函数处下断点调试
  4. 单步调试,观察指令执行流程
  5. 密码不对时,指令会跨越执行,不再顺序执行
  6. 动态调试时,在关键指令处按F5,把指令转成c代码辅助分析
  7. 动态调试时鼠标移动到寄存器上,会显示该寄存器里的值
  8. 动态调试时,把指令转换成C代码,把鼠标移动到C代码的变量上,会显示该变量的值

猜你喜欢

转载自blog.csdn.net/m0_50685012/article/details/114658675