前言
由于本人使用的是Mac来做开发,并且最近要做逆向相关,苦于网上多数教程都是Win的,没办法只有到处搜集资料和自己踩坑,摸着石头过河。这里分享一下Mac来做的整个过程。目标,IDA动态调试,dump dex脱壳。
脱壳的话,目前两种方法,一种动态调试,一种xposed,当前为动态调试学习
环境:
macOS 10.14.1
root过后的手机 htc 4.4.2
IDA 7.0 附送地址
IDA mac 高版本崩溃解决适配
mprop 设置手机所有应用为可调试 下载地址
精简方案
1、 copy 启动 Android server
- 上传IDA调试服务器地址:IDAPro70\dbgsrv\android_server
- cmd进入到该目录下: IDAPro70\dbgsrv
- 导入IDA调试服务器:adb push android_server /data/local/tmp
- adb shell 以su启动(手机要求root)
- cd到/data/local/tmp下:chmod 777 android_server
- ./android_server(如果失败重启手机)
2、 root手机使用mprop设置ro.debuggable为1
adb push xxx/mprop /data/local/tmp/mprop
adb shell su
chmod 755 /data/local/tmp/mprop
data/local/tmp/mprop
setprop ro.debuggable 1
/data/local/tmp/mprop -r3、 转发ida端口 开启adb应用调试
adb forward tcp:23946 tcp:23946
adb shell am start -D -n 包名/包名对应启动Activity4、 ida attach到应用进程 打断点
打开IDA设置好process options 地址127.0.0.1 端口23946
Ida -》debugger -》attach process
选择对应应用进程
选择libdvm.so
找到dvmDexFileOpenPartial 计算偏移量
下断点5、 jdb连接应用
连接jdb(两种方式)
1、通过ddms(如果占用8700 ps查看 kill杀掉 重来)
2、命令
adb shell ps | xxx 找到对应app的进程号
adb forward tcp:8700 jdwp:进程号
jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost6 IDA开启调试
启动ida F9 开始进行调试
大致原理
通过IDA的动态调试系统库libdvm.so的dvmDexFileOpenPartial方法,来寻找内存中的dex段地址,然后进行dump,最终达到脱壳的目的。
(4.4前后的不同java虚拟机类型,所以这里用的是4.4.2的手机,系统库为libdvm,如果是之后的便是libart,调试方法为openMemory)
详细过程
看似原理很简单,但是会遇到许多的问题和坑,每个都能卡你半天,所以这里分享给大家一些细节东西,望君莫要重蹈覆辙。
1、 copy 启动 Android server
- 上传IDA调试服务器地址:IDAPro70\dbgsrv\android_server
- cmd进入到该目录下: IDAPro70\dbgsrv
- 导入IDA调试服务器:adb push android_server /data/local/tmp
- adb shell 以su启动(手机要求root)
- cd到/data/local/tmp下:chmod 777 android_server
- ./android_server(如果失败重启手机)
这里启动之后 可以看到IDA Android 32-bit remote debug server(ST) v1.22. Hex-Rays (c) 2004-2017
注意:这里32-bit的话,你打开IDA就用32位的打开 不然就是64位的
2、 root手机使用mprop设置ro.debuggable为1
adb push xxx/mprop /data/local/tmp/mprop
adb shell su
chmod 755 /data/local/tmp/mprop
data/local/tmp/mprop
setprop ro.debuggable 1
/data/local/tmp/mprop -r
使用getprop ro.debuggable 就可以查看是否修改成功
有时候遇到
android_server Address already in use
可以杀掉进程重来
进入adb shell
ps | grep android_server
kill -s 9 进程号
重新启动android_server
注意:手机每次重启都要重复此操作,都要重新设置debuggable为1,有时候手机会无意重启,注意。
3、 转发ida端口 开启adb应用调试
adb forward tcp:23946 tcp:23946
adb shell am start -D -n 包名/包名对应启动Activity
这里转发了之后可以使用lsof -i:23946
来查看如果有Listen则说明转发成功
接着调用adb 调试命令 填好对应包名和启动的Activity注入调试
这里提供一下 查询启动页的方法
adb shell dumpsys activity top 启动app之后查看现在的Activity信息可以拿到包名
然后
adb shell dumpsys package 包名
就可以查询一下有action MAIN的Activity,一般类似为SplashActivity
注入调试,手机上就有等待调试的弹框了。
4、 ida attach到应用进程 打断点
打开IDA设置好process options 地址127.0.0.1 端口23946
Ida -》debugger -》attach process
选择对应应用进程
选择libdvm.so
找到dvmDexFileOpenPartial 计算偏移量
下断点
这里我们使用的是32位的IDA打开,一般要开两个,一个为了静态分析so(也就是找到libdvm.so的对应的dexFileOpen函数地址,后面要做寻找断点用);另外一个是拿来调试用的。
首先,需要获取libdvm.so,一般是在手机的/system/lib/ 下面
adb pull /system/lib/libdvm.so /users/jafir/desktop/
直接pull到电脑上来,然后IDA打开
0004BB10
这个地址就是dexFileOpen函数在libdvm.so中的偏移地址,后面我们打断点的时候,需要在整个内存中去寻找到真正的dexFileOpen的地址。
原理就是 找到libdvm.so在内存中的首地址,然后加上这里的偏移地址,就可以得到libdvm.so中的dexFileOpen的地址。
好,这就是静态分析获取地址。
然后,再打开一个,File->New Instance,选择 GO
Debugger->Attach->Remote ArmLinux/Android
接下来就ctrl+s找到libdvm.so然后查看,它在内存中的首地址,计算偏移量
计算一下偏移量 4152D000+ 0004BB10 = 41578b10,按G,进行地址跳转
打上断点
ok
5、 jdb连接应用
连接jdb(两种方式)
1、通过ddms(如果占用8700 ps查看 kill杀掉 重来)
2、命令
(-- adb shell ps | xxx 找到对应app的进程号
-- adb forward tcp:8700 jdwp:进程号)
jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost
最简单的打开ddms,它是在你Android sdk/tools下面的monitor
然后jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost
(base) Jafir:~ jafir$ jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...
>
如果打开DDMS报8700被占用了,lsof -i :端口号
查看,然后kill -s 9 进程号
杀掉,重来
(base) Jafir:~ jafir$ lsof -i:8700
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
monitor 31587 jafir 121u IPv6 0x8c41b253ec7cd357 0t0 TCP localhost:8700 (LISTEN)
(base) Jafir:~ jafir$ kill -s 9 31587
如果不用ddms,也可以用命令,来连接jdb
adb shell ps | xxx包名 找到对应app的进程号
adb forward tcp:8700 jdwp:进程号
jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost
6 IDA开启调试
启动ida F9 开始进行调试
点击绿色启动按钮,就可以了,这时候按道理,手机的debug等待框也消失了,进入调试状态。
ddms的灯变成绿色,然后断点断在了libc上头,就成功了
之后便是一路F9,回车。F9,回车
直到我们的断点处。
注意断点,向下执行,不要超过BL,过了PUSH就可以了
到断点处,如果成功的话,就可以从General registers里面看到变量值。
static main(void){
auto fp, dex_addr,end_addr;
//打开或创建一个文件
fp = fopen("/users/jafir/desktop/dump.dex", "wb");
end_addr = r0+r1;
for ( dex_addr = r0; dex_addr < end_addr; end_addr ++ ){
//按字节将其dump到本地文件中
fputc(Byte(dex_addr), fp);
}
}
File->Script Command可以创建脚本命令
过一会就可以看到桌面上dump.dex文件了。
后面还会遇到很多坑:
命令相关分享
进程相关:
ps A 查看所有
ps a 显示同一终端下的所有程序
lsof -i:xxx 查看端口进程信息
kill -9 xxxx 杀死某个进程逆向相关命令:
cat 查看
cat /proc/xxxpid/maps 查看xxx进程的lib库文件(一般需要root才能查看)
echo touch 写内容到文件中
echo 内容 >> 文件路径 (如果有文件就追加 没有就创建)
echo 内容 >文件路径 (如果有文件就清空写入 没有就创建)
adb shell dumpsys activity top
adb shell dumpsys package [packagename]
adb shell dumpsys meminfo xxxx com.cctv4g.cctvmobiletv
adb shell dumpsys dainfo xxx
adb shell screencap -p xxx路径
adb install -t xxx 以测试包的类型安装查看当前的activity:
1、adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
2、adb shell dumpsys activity | grep -i run查看权限的命令:
ls -alf 查看文件及其权限
ls -a 可以查看包含隐藏文件
ls 查看查看keystore的信息摘要 sha1
keytool -list -keystore keystore
jadx-gui:
jadx-gui xxx.jar/xxxx.dex/xxx.apk
配置好环境变量Dx:
dx --dex --output=HelloWorld.dex HelloWorld.class
把class文件编译成dex执行dex文件
1、生成dex文件(可以直接从apk中解压出来,也可以从jar利用dx命令生成)
2、然后adb push xxx.dex xxx到手机中去
3、adb shell
4、dalvikvm -cp xxx.dex com.jafir.signprotect.Main(主类)
后记
本人也是刚入手,小白一个,摸索着石头过河,请教过很多大神,但是不管怎么说还是要自己动手,踩坑,尝试,无数次尝试。
这里只进行到dump dex,其实后面还有很多的操作,比如什么指令抽取的要还原啊,还要过滤反调试等的。
我只是用了自己的没有反调试的apk来过了一遍手,而后在想要脱壳的时候,却遇到了更多的问题,总之,初来乍到,还要继续学习和探索,有志同道合者,希望相互交流。