安卓逆向10-ida,动态调试

###

动态调试的准备工作:

IDA动态调试:
配置:
#把本地文件推送进手机目录

将ida文件夹里面的dbgsrv下的android_server放入真机的/data/local/tmp/下
adb push android_x86_server(cpu型号要对应 模拟器是x86) /data/local/tmp/

 

 

 

 如果是64位,就选64位的,


#进入手机shell
adb shell
#真机要使用 su 命令 切换到root用户,模拟器不用
#进入手机tmp目录
cd /data/local/tmp/
#修改权限
chmod 777 android_server
#运行
./android_server
#在本地执行adb 做端口转发
adb forward tcp:23946 tcp:23946

 

要动态调试,要用真机调试,最好使用安卓6,7,安卓5会问题很多,

####

IDA动态调试

目的:找到自毁程序的内置密码

第一步,我们再开一个ida程序,不要关闭静态调试的那个窗口

这就是ida双开,

本地打开IDA,选中Go

然后连接到手机的服务,确保上面的配置,是正确的,服务是开启的,

 

 

第二步:

点击上面的连接真机,然后弹出下面的弹框,然后输入127.0.0.1,因为都是本地调试,所以就是输入这个本地ip就可以了,

 

 

第三步,

点击上面的,如果正常,就会弹出选择app的页面了,

这是把所有的进程都展示出来了,还可以搜索,

如果找不到这个app,那就重新打开一下app,

 

###

第四步,上面一步打开app可能有点慢,要等一等,

然后进行ctrl+s,进行搜索我们要调试的so文件,

 

 注意后面的权限,我们选择第一个有X权限的,就是有可执行权限,我们要调试这种的,

start就是内存地址,我们叫做基地址, 

##

第五步,

我们看到有很多个,怎么找到我们要调试的方法的那个地址??

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

 

 

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

 

 这个就是函数的偏移量,

000011A8

####

你要动态调试,你还是要先看懂了静态调试,才好去调试,

看看静态调试的c代码,

你逆向,不能从头看,你要有逻辑,不能从第一行看,你这样看不懂的,

可以从return看,

 

 上面我们已经分析过了,

v5就是我们输入的密码

v7就是真实密码,而v7是来自于v6,所以v6就是真正的密码,而v是一个常量

所以我们的目的就是调出来v6这个常量,

 

####

然后我们动态调试,怎么跳,

怎么加

用16进制的计算器,DC9E6000+000011A8  =DC9E71A8

然后使用快捷键 g  输入地址,DC9E71A8

然后就调到这里了,

 

 

第六步,上面的面板

是有很多的分支流程的,这就是条件语句,

 

F8是单步调试,这个就是不进入函数

F7单步调试,这个是要进入函数,

一般我们就是使用F8,因为F7进入之后太多了,调试难度大,

你要调试,你要先打断点,然后才可以单步调试,

选中然后进行右键,添加断点,就可以了,添加之后会标红的

 

 

然后让程序恢复执行

 

 

如果你点击了之后报错,一直报错,可能就是加入了反调试了,

#####

下面介绍一下反调试,

so反调试
IDA调试原理 是利用Linux系统 ptrace 来实现
当应用被调试时,应用内存里的TracerPid 字段就不为0

 

如果为什么会有反调试,

就是因为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()
演示有反调试检测的crackme 

###

反反调试
动态调试,找到检测TracerPid的代码,不执行此代码
方法:
此检查代码一般在.init_arra 和 JNI_OnLoad两处
在JNI_OnLoad函数出打断点调试,找到检测TracerPid的代码,不执行此代码
IDA调试反调试小经验 如何找到反调试代码:
结合IDA静态时的代码,观察程序逻辑
指令一般会整过执行完,直到函数末尾。

多次IDA中,如果指令在中途某个地方退出了,说明该处就是反调试指令。

 

####


如何在JNI_OnLoad函数打断点:
so文件在加载阶段会执行JNI_ONLoad,此后不再执行,要在so文件加载阶段才能给

JNI_OnLoad打断点
1).修改APP AndroidMenifest.xml文件, APP加上可调试权限,android:debuggable="true",

 

重新打包APP,

apktool.sh b ./AliCrackme_密码在so文件debug模式

签名,keytool -genkey -keystore my-release-key.keystore -alias my_alias -keyalg RSA -keysize 4096 -validity 10000

打包,jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore -signedjar AliCrackme_密码在so文件sign.apk AliCrackme_密码在so文件.apk my_alias

安装,

 

如果有签名校验,你还要过校验,这是一个复杂的事情,

 


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

 

 

让app停在这里,不要动,

然后把ida动态调试失败的页面关闭,不要保存

路径:file-close,

 

 然后重新来一遍上面的流程,

这个时候你是看不到so文件的,因为app现在是卡住的状态,

然后进入下一步


4).在debugger-DebuggerOptions

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

 

 

5).点击运行按钮


6).在设备里查看APP的进程ID
要adb shell先进入设备运行如下命令,过滤出该应用信息
ps | grep 应用包名

 

 

7). 使用JDB命令让APP 恢复运行
adb forward tcp:8700 jdwp:873(APP的PID)

adb forward tcp:8700 jdwp:29404
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

 

 

 


8).在so文件被加载时,IDA会停止住,使用ctrl+s 查看目标so文件是否加载

一开始肯定是搜不到的,因为还没有加载进来,

然后你点击ida右上角的运行按钮,一步一步的运行,这个时候要很小心,
若加载点选目标so文件,

 

 

找地址JNI_OnLoad

 

 

计算JNI_OnLoad的绝对地址,按G键跳转到JNI_OnLoad出设置断点,

 

打断点

 

 

 

恢复APP执行,

 

 会变成蓝色

 

###

找到反调试代码处,pthread_create(),
如何找到反调试代码处?(关键地方,可按f5,把汇编代码转成C语言辅助)
反复按F8单步执行,程序退出处(前面),既为反调试处

 

 如果按F8,继续往下走,说明没有问题,如果有地方不往下走了,往回走了,这个地方就有问题了,

 

 继续往下F8,就直接退出了,

下面我们就是把指令不执行,

####


如何让反调试代码不执行?
让该指令变为空指令,既 NOP,NOP指令的16进制是 00 00 00 00

 

 我们要做的就是把这个BLX R7,变成空,

记住反调试处的汇编指令,这个时候我们就要回到这个静态调试了,

同时以静态方式再打开一个IDA(也叫双开IDA 以动态和静态方式各打开一个IDA ),

打开so文件,在静态ida里查找到此汇编指令,鼠标选中后面寄存器,然后切换到Hex View,会显示该指令的16进制,

 

 然后copy下来,

37 FF 2F E1

去改so文件的二进制代码

然后又要重新打包so文件,上面的都要重新来一遍,

###

因为你已经找到反调试的地方,并且干掉了

所以就不需要从debugger模式运行了

我们直接运行app,直接调试我们的加密的方法那里,不需要调试JNI_OnLoad方法了,

1,启动ida动态 调试,

2,找到app,

3,找到so文件,直接进入

4,计算地址,跳转到加密方法那里

5,打断点

然后我手机输入密码,点击一下,才会触发这个方法,到这个so文件里面来

这一点要注意,你要去触发,

 

 

 到了这一步,发现了不往下走了,会有跳到下一个,

这个地方就有问题了,

 

 然后是出现了R1就是我们输入的密码1111,

说明R3就是真实的密码了,因为有一个比较,

这个时候可以点击R3查看,

还可以按F5,转成c代码,看看,

 

 这个时候,把鼠标放到v6,我们看到就密码已经出来了,

 

####

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

 

 

 

 

###

posted @ 2021-08-04 21:13  技术改变命运Andy  阅读(1121)  评论(1编辑  收藏  举报