蒸米@阿里聚安全,然后再实践JNI

8 add breakpoint at JNI_OnLoad

安卓动态调节种种武器之孔雀翎
– Ida Pro

将ida的调节端口进行转发,这样pc端的ida才能一连手机。

0x01 孔雀翎

天底下的暗器共有三百六十余种,但里边最成功、最骇人听闻的就是孔雀翎。它选用简单,却威力无穷。据说,孔雀翎发动之时,暗器四射,有如孔雀开屏,辉煌灿烂,而就在敌人目眩神迷之际,便已心神不定。那武器的描述与Ida是多么的一般啊!所以说安卓动态调节多种武器中的孔雀翎非Ida莫属。因为Ida太有名了,相应的科目也是一切飞,但许多并不是安卓相关的情节,所以笔者决定将一些经典的安卓调试技巧总计归结一下。因为篇幅原因,小编并不可能确保本文可以覆盖到ida调试的方方面面,看官如有兴趣可以再持续深刻钻研学习。

 

于是大家查阅off_628c这一个地方对应的指针,发现对应的字符串是”wojiushidaan”。

 

7 jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

0x04 Ida双开定位

Ida双开定位的趣味是先用ida静态分析so文件,然后再开一个ida动态调试so文件。因为在动态调试中ida并不会对所有动态加载的so文件举行详尽的辨析,所以重重函数并无法辨别出来。比如静态分析中有不少的sub_XXXX函数:

图片 1

 

但动态调节中的ida是不曾那一个新闻的。

图片 2

 

之所以大家须求双开ida,然后经过ida静态分析的内容来稳定ida动态调节的函数。当然很多时候我们也急需动态调试的音讯来扶助了然静态分析的函数。

在上一节中,大家提到.init.array中有个sub_2378(),但当ida动态加载so后大家并无法在module中找到那个函数。这该怎么做呢?那时候我们就要通过静态分析的地方和so文件在内存中的基址来恒定目的函数。首先大家见到sub_2378()这几个函数在静态分析中的地址为.text:00002378。而在动态加载中那个so在内存中的基址为:4004F000。

图片 3

 

因此sub_2378()那个函数在内存中的确的地方应该为4004F000

  • 00002378
    =40051378。下边我们在动态调试窗口输入”g”,跳转到40051378那么些地点。然后发现全是乱码的节奏:

图片 4

 

不用担心,这是因为ida认为那里是数据段。那时候咱们如果按”P”或者选中部分数据按”c”,ida就会把那段数据当成汇编代码举办分析了:

图片 5

 

咱俩随后仍是可以够按”F5”,将汇编代码反编译为c语言。

图片 6

 

是或不是和静态分析中的sub_2378()长的大半?

图片 7

大家随后可以在这么些职位加入断点,再组成上一节提到的调剂技巧就能够对init.array中的函数举办动态调试了。

我们接下去继续分析自毁程序那道题,当大家在对init.array和JNI_OnLoad()进行调节的时候,发现先后在履行完dowrd_400552B4()后就挂掉了。

图片 8

 

于是大家在这边按”F7”进入函数看一下:

图片 9

 

原来是libc.so的phread_create()函数,算计是app本身开了一个新的线程举行反调试检测了。

诙谐的是在静态分析中大家并不精通dword_62B4那一个函数是做什么的,因为这么些函数的地方在.bss段还不曾被早先化:

图片 10

图片 11

 

不过当我们动态调试的时候,那么些地点的值已经修改为了phread_create()这一个函数的地方了。:

图片 12

图片 13

 

从而说自毁程序密码这些app会用pthread_create()开一个新的线程对app进行反调试检测。线程会运作sub_16A4()这么些函数。于是大家对这一个函数进行辨析,发现其间的始末有雅量的歪曲,看起来非凡进退维谷。那里我介绍个小trick:常见的反调试方法都会用fopen打开一些文本来检测自己的进度是不是被attach,比如说status这些文件中的tracerpid的值是还是不是为0,假设为0表明没有其余进程在调试这一个进程,即使不为0表明有程序在调节。所以大家得以一板一眼,在libc.so中的fopen()处下一个断点,然后我们在hex
view窗口中装置数据与R0的值同步:

图片 14

 

那样的话,当函数在fopen处停住的时候大家就能阅览程序打开了怎么样文件。果不其然,程序打开了/proc/[pid]/status这一个文件。我们”F8”继续执行fopen函数,看看重临后的地点在哪。然后发现大家程序卡在了某个函数中间,PC上面都是数码,PC上面才是汇编。这该咋做吧?

图片 15

 

解决办法仍然ida双开,大家精通现在PC的地址为40050420,libcrackme.so文件的基址为4004F000。因而那段代码在so中的地点应该是:40050420

  • 4004F000 =
    1420。由此我们重临ida静态分析界面,就足以一定到大家实际是在sub_130C()那么些函数中。于是大家揣测这几个函数就是用来做反调试检测的。

图片 16

 

故而大家能够通过基址来定位sub_130C()那几个函数在内存中的地址:40050420

  • 130C = 4005030C。然后大家在4005030C这些地点处按”P”,
    ida就足以正确的鉴别整个函数了。

图片 17

 

故而说动态调试的时候可以帮大家询问到无数静态分析很难获得到的音信。那也就是ida双开的意义所在:静态接济动态定位函数地址,动态接济静态获取运行时音讯。

 

图片 18

0x09 Function Rewrite函数重写

偶尔我们想要将app中的某个函数的逻辑提取出来,用gcc重新编译一个可执行文件,比如大家想要写一个注册机,就须要把app生成key的逻辑提取出来。但是ida
”F5”过后的c语言直接编译平时会有好多错误,比如未定义的宏,未定义的扬言等。那是因为那几个宏都在ida的一个头文件里。里面定义了颇具ida自定义的宏和申明,比如说日常看看的BYTEn()宏:

图片 19

 

添加那些”defs.h”头文件后就可以正常的编译ida
”F5”后的c语言了。

其它大家还足以友善成立一个NDK项目,然后自己编排一个so或者elf利用dlopen()和dlsym()调用目的so中的函数。比如大家想要调用libdvm.so中的dvmGetCurrentJNIMethod()函数,大家就可以在大家的NDK项目中如此写:

图片 20

 

早晚要开拓ddms,否则调试端口是关门的,就不可以在先后刚初阶的中止了。我事先不知晓要开拓ddms才能用jdb,还以为android系统或者sdk出标题了,重装好两遍。汗。

小编:蒸米@阿里聚安全

图片 21

0x10 小结

或者这句话,写了这么多依然不可以保险本文可以覆盖到ida调试的成套,因为ida实在是太博大精深了。看官如有兴趣能够三番五次深刻钻研学习。别的小说中兼有关乎的代码和工具都得以在自身的github下载到,地址是:https://github.com/zhengmin1989/TheSevenWeapons

 

那会儿大家启动ida并attach那些app的长河。

0x06 Patch so文件

在上文中,大家经过分析稳定到sub_130C()那么些函数有很大可能是用来做反调试检测的,并且作者开了一个新的线程,并且用了一个while来不断推行sub_130C()那一个函数,所以说咱俩每一遍手动的修改TracerPid实在是不现实。

图片 22

 

既是大家何不把sub_130C()这些函数给nop掉吧?为了防备nop出错,我们先在”F5”界面拔取具有代码,然后用”Copy
to assembly”功效,就可以把c语言代码注释到汇编代码里。

图片 23

图片 24

 

在此处大家看出要是想要注释掉sub_130C()函数,只需求注释掉000016B8以此职位上的代码即可,如果我们想要注释掉dword_62B0(3)这几个函数,大家则须求注释掉000016BC-000016C4那多个岗位上的代码。接下来大家选中000016B8这一行,然后再点击HexView。HexView会帮大家机关定位到000016B8以此地点。

图片 25

 

因为ARM是未曾单独的NOP指令的。于是大家利用movs
r0,r0作为NOP。对应的机器码为”00 00 A0 E1”。所以大家把”13 FF FF
EB”那段内容改动为”00 00 A0 E1”。

图片 26

 

大家再回”F5”界面,就会意识sub_130C()函数已经远非了。

图片 27

 

最终大家点击”Edit->Plugins->modifyfile”,然后就足以保留新的so文件了。我们将以此so文件覆盖原apk中的so文件,然后再重复签名。

图片 28

 

本次我们先运行程序,再用ida加载,app并从未闪退,表明咱们patch成功了。于是大家先在”Java_com_yaotong_crackme_MainActivity_securityCheck”处下断点。然后在app随便输入一个密码,点击app上的”输入密码”按钮。

图片 29

 

次第就会半涂而废在”Java_com_yaotong_crackme_MainActivity_securityCheck”处。大家先按”P”再按”F5”,就可以观察反汇编的c语言了。而这边的unk_4005228C就是保留了密码字符串指针的指针。

图片 30

 

因为是指针的指针,所以大家先双击进入这么些地点。

图片 31

 

接下来在这一个地址上按三下”D”,将那里的数额格式从字符转化为指针情势。

图片 32

 

下一场大家再双击进入那个地方,就可以见到最终的flag了。答案是”aiyou,bucuoo”。

图片 33

 

那道题里我们只是选拔了很粗略的patch
so技巧,在实战中大家不但可以NOP,大家还是能改变规则判断语句,比如将”BNE”变为”
BEQ”。我们竟然可以修改跳转地址,比如直接让程序B到某个地点去执行,那样的话就不必要种种的NOP很多语句了。要注意的是,ARM中的跳转指令是基于相对地址总括的,所以你要根据当前命令地址和目标地址来测算出相对跳转的值。

比如说00001BCC: BEQ
loc_1C28对应的汇编代码为”15 00 00 0A”。

图片 34

图片 35

 

0x0A代表BEQ,”15 00
00”代表跳转的周旋地址,因为在arm中pc的值是现阶段下令的下两条(下一条的下一条)指令的地址,所以我们须求将0x15再添加2。随后就足以测算出最后跳转到的地方:
(0x15 + 0x2)*4 + 0x1BCC = 0x1C28。Ida反汇编后的结果也申明了结果是BEQ
loc_1C28。

接下去大家想修改汇编代码为00001BCC:
BNE loc_1C2C。只要求将”0A”变成”1A”,将”15”变成”16”即可。

图片 36

图片 37

 

0x0A代表BEQ,”15 00
00”代表跳转的相持地址,因为在arm中pc的值是方今下令的下两条(下一条的下一条)指令的地方,所以大家要求将0x15再拉长2。随后就足以测算出最后跳转到的地址:
(0x15 + 0x2)*4 + 0x1BCC = 0x1C28。Ida反汇编后的结果也证实了结果是BEQ
loc_1C28。

接下去大家想修改汇编代码为00001BCC:
BNE loc_1C2C。只须求将”0A”变成”1A”,将”15”变成”16”即可。

 

因为经过有点麻烦,我录制了一个调试JNI_OnLoad()的视频在自我的github,有趣味的同班可以去下载阅览。因为关乎到此外的技巧,大家将会在随后的”ida双开定位”章节中延续助教怎样调试.init_array中的函数。

0x08 在内存中dump Dex文件

在现在的移动安全条件中,程序加壳已经改成日常便饭了,如果不会脱壳简直没法在破解界混的韵律。ZJDroid作为一种万能脱壳器是不行好用的,然则当小编公开公布这几个类型后就面临了种种加壳器的针对性,比如说抢占ZJDroid的播放接收器让ZJDroid不能接受命令等。大家也会在”安卓动态调节多种武器之多情环

  • Customized
    DVM”那篇文章中牵线另一种架构的万能脱壳器。但工具就是工具,当大家发表的时候也许也会境遇近乎ZJDroid那样的指向。所以说手动脱壳那项技能依然需求学习的。在这一节中大家会介绍一下最大旨的内存dump流程。在随后的篇章中我们会介绍更多的技艺。

那里大家拿alictf2014中的apk300看作例子来介绍一下ida脱简单壳的为主流程。
首先大家用调试JNI_OnLoad的技术将先后在运转前挂起:

 

adb shell am start -D -n com.ali.tg.testapp/.MainActivity

 

![enter image description
here][59]

然后在libdvm.so中的dvmDexFileOpenPartial函数上下一个断点:

图片 38

 

然后大家点击继续运行,程序就会在dvmDexFileOpenPartial()那一个函数处暂停,R0寄存器指向的地址就是dex文件在内存中的地址,R1寄存器就是dex文件的轻重缓急:

图片 39

图片 40

 

然后大家就足以应用ida的script
command去dump内存中的dex文件了。

图片 41

图片 42

图片 43

Dump完dex文件后,我们就可以用baksmali来反编译那些dex文件了。

图片 44

 

因为经过有点麻烦,我录制了一个dump
dex文件的摄像在我的github,有趣味的同学可以去下载观看。

理所当然那只是最简单易行脱壳方法,很多高级壳会动态修改dex的结构体,比如将codeoffset指向内存中的其余地方,这样的话你dump出来的dex文件其实是不完整的,因为代码段保存在了内存中的别样任务。但您不用操心,大家会在紧接着的篇章中介绍一种卓殊不难的缓解方案,敬请期待。

 

我们知道so文件在被加载的时候会率先执行.init_array中的函数,然后再举行JNI_OnLoad()函数。JNI_Onload()函数因为有标志表所以万分不难找到,但是.init_array里的函数要求自己去找一下。首先打开view
->Open
subviews->Segments。然后点击.init.array就足以看到.init_array中的函数了。

0x07 Kill调试技巧

该技能是Q伊芙r
在《MSC的伪解题报告》中涉嫌的。利用kill大家得以让程序挂起,然后用ida挂载上来,获取实惠的新闻,然后可以再用kill将先后复苏运行。大家仍然拿自毁程序密码这么些应用举例,具体实施格局如下:

 

1
首先用ps获取运行的app的pid。

图片 45

 

2 然后用kill -19 [pid]
就足以将这一个app挂起了。

图片 46

 

3 随后大家用ida
attach上这一个app。因为整个进程都挂起了,所以本次ida挂载后app并从未闪退。然后就足以在内存中找到答案了。

图片 47

 

4
若是想要恢复生机app的运转,须求将ida退出,然后再使用kill -18
[pid]即可。

图片 48

 

打开程序后,界面是那样的:

0x03 调试.init_array和JNI_OnLoad

我们知晓so文件在被加载的时候会首先执行.init_array中的函数,然后再举办JNI_OnLoad()函数。JNI_Onload()函数因为有记号表所以卓殊简单找到,不过.init_array里的函数要求协调去找一下。首先打开view
->Open
subviews->Segments。然后点击.init.array就足以看到.init_array中的函数了。

图片 49

图片 50

图片 51

 

但貌似当大家采纳ida举办attach的时候,.init_array和JNI_Onload()早已经推行完成了,根本来不急调试。那时候大家可以行使jdb这些工具来解决,那几个工具是安装完jdk未来自带的,可以在jdk的bin目录下找到。在此处大家选取阿里移动安全挑衅赛2014的第二题作为例子讲解一下什么调节JNI_OnLoad()。

 

开拓程序后,界面是那样的:

图片 52

 

咱俩的目的就是获得到密码。使用ida反编译一下so文件会看到大家输入后的密码会和off_628c那么些指针指向的字符串举办相比。

图片 53

 

于是乎大家查阅off_628c这几个地方对应的指针,发现对应的字符串是”wojiushidaan”。

图片 54

图片 55

 

于是乎我们把那些密码输入一下,发现密码错误。看样子so文件在加载的时候对密码字符串进行了动态修改。既然动态修改了那我们用ida动态调试一下好了,大家开拓程序,然后再用ida
attach一下,发现先后直接闪退了,ida那边也远非其他有用新闻。原来那就是自毁程序的意味啊。既然如此大家动态调试一下JNI_OnLoad()来看一下顺序究竟做了怎么吧。步骤如下:

 

1 ddms

肯定要打开ddms,否则调试端口是倒闭的,就无法在程序刚先河的中断了。我此前不明白要打开ddms才能用jdb,还以为android系统或者sdk出标题了,重装好两遍。汗。

 

2 adb push androidserver
/data/local/tmp/

 

adb shell
su
chmod 777 /data/local/tmp/androidserver
/data/local/tmp/androidserver

那边我们把ida的androidserver
push到手机上,并以root身份实施。

 

3 adb forward tcp:23946
tcp:23946

将ida的调节端口举行转向,那样pc端的ida才能延续手机。

 

4 adb shell am start -D
-n com.yaotong.crackme/.MainActivity

此地大家以debug情势启动程序。程序会油但是生waiting
for debugger的调剂界面。

图片 56

 

5 ida attach target
app

此时大家启动ida并attach这一个app的经过。

 

6 suspend on libary
loading

俺们在debugger setup里勾选
suspend on library load。然后点击继续。

图片 57

 

7 jdb -connect
com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

用jdb将app復苏执行。

 

8 add breakpoint at
JNI_OnLoad

继而程序会在加载libcrackme.so这一个so文件的时候停住。那时候ida会产出找不到文件的唤醒,不用管她,点收回即可。随后就能在modules中见到libcrackme.so那么些so文件了,我们点进去,然后在JNI_OnLoad处下个断点,然后点击执行,程序就进去了JNI_OnLoad()那几个函数。

PS:有时候你精通在一个函数中却无力回天F5,那时候你须要先按一下”p”键,程序会将那段代码作为函数分析,然后再按一下”F5”,你就可以看到反汇编的函数了。

因为经过有点麻烦,我录制了一个调剂JNI_OnLoad()的视频在自我的github,有趣味的同室可以去下载阅览。因为关乎到其余的技能,我们将会在随之的”ida双开定位”章节中继续讲师怎么样调试.init_array中的函数。

 

那里大家以debug方式启动程序。程序会出现waiting for debugger的调剂界面。

0x02 还原JNI函数方法名

在android调试中,你会不时来看那连串型的函数:

图片 58

 

首先是一个指针加上一个数字,比如v3+676。然后将以此地址作为一个主意指针进行艺术调用,并且第二个参数就是指针自己,比如(v3+676)(v3…)。那实在就是大家在JNI里不时应用的JNIEnv方法。因为Ida并不会自动的对这么些措施进行辨别,所以当大家对so文件进行调节的时候平时会看到却搞不清楚那几个函数究竟在干什么,因为这么些函数实在是太肤浅了。解决办法卓殊不难,只要求对JNIEnv指针做一个类型转换即可。比如说上边提到v3指针,大家选中后按一下”y”键,然后将项目申明为”JNIEnv*”。

图片 59

 

继而IDA就会活动检索对应的格局并且出示出来了:

图片 60

 

是否一念之差分明了过多?别的有人(
貌似是看雪论坛上的)还总计了装有JNIEnv方法对应的数字,地址以及艺术申明:

图片 61

有趣味的校友可以去自己的github下载。

 

adb shell
su
chmod 777 /data/local/tmp/androidserver
/data/local/tmp/androidserver

0x05 Ida动态修改内存多少和寄存器数值

咱俩后续分析自毁程序密码这些app,大家发现该程序会用fopen
()打开/proc/[pid]/status这几个文件,随后会用fgets()和strstr()来获得,于是大家在strstr()处下个断点,然后让hex
view的数额与R0同步。每一次点击继续,大家都会看到strstr传入的参数。当传入的参数变为TracerPid:XXXX的时候大家停一下。因为在健康状态下,TracerPid的值应该是0。不过当被调剂的时候就会化为调试器的pid。

图片 62

图片 63

 

为了防备程序意识我们在调节,在此间大家要求把值改回0。大家在hex
view的2这里点击右键,然后采取edit。随后大家输入30和00,再点击”apply
changes”。就足以把TracerPid改为0了。然后就可以bypass这两回的反调试的检测。

图片 64

 

但以此顺序检测TracerPid的次数分外频仍,大家要不断的修改TracerPid的值才行,那种格局其实有些治标不治本,所以大家会在下一节介绍patch
so文件的方法来缓解这几个题材。

别的在ida动态调试进度中,除了内存中的数据足以修改,寄存器的数额也是可以动态修改的。比如说程序执行到CMP
R6,
#0。本来R6的值是0,经过比较后,程序会跳转到4082A3FC那么些地址。

图片 65

 

不过只要大家在PC执行到4082A1F8这条语句的时候,将R6的值动态修改为0。程序就不会开展跳转了。

图片 66

图片 67

 

您居然足以修改PC寄存器的值来决定程序跳转到任何想要跳转到的任务,几乎和ROP的原理一样。但记得要小心栈平衡等题材。

图片 68

 

图片 69

0x00 序

乘势移动安全尤为火,种种调节工具也都习以为常,但因为环境和须要的差距,并没有工具是全能的。别的工具是死的,人是活的,若是能搞懂工具的原理再组成上我的阅历,你也能够创制出属于自己的调剂武器。因此,作者将会在这一多重文章中分享部分融洽常常用或原创的调试工具以及手段,希望能对境内移动安全的钻研起到部分催化剂的功效。

 

目录如下:

安卓动态调试八种武器之长生剑 –
Smali
Instrumentation

安卓动态调试八种武器之孔雀翎 –
Ida Pro

安卓动态调试七种武器之离别钩 –
Hooking

安卓动态调试多样武器之碧玉刀-
Customized DVM

安卓动态调节各类武器之多情环-
Customized Kernel

安卓动态调节三种武器之霸王枪 –
Anti Anti-debugging

安卓动态调节三种武器之拳头

  • Tricks & Summary

 

图片 70

0x11 参考小说

  1. MSC解题报告
    http://bbs.pediy.com/showthread.php?t=197235
  2. 伪·MSC解题报告http://bbs.pediy.com/showthread.php?p=1349632

 

作者:蒸米@阿里聚安全,越多Android技术文章,请访问阿里聚康宁博客

6 suspend on libary loading

图片 71

图片 72

 

图片 73

3 adb forward tcp:23946 tcp:23946

用jdb将app恢复生机执行。

5 ida attach target app

图片 74

大家的目标就是获取到密码。使用ida反编译一下so文件会看到我们输入后的密码会和off_628c那些指针指向的字符串进行相比较。

但貌似当大家选取ida举办attach的时候,.init_array和JNI_Onload()早已经施行完毕了,根本来不急调试。那时候大家得以拔取jdb那么些工具来缓解,这一个工具是安装完jdk将来自带的,可以在jdk的bin目录下找到。在此间我们应用阿里活动安全挑战赛2014的第二题作为例子讲解一下哪些调节JNI_OnLoad()。

于是乎大家把这么些密码输入一下,发现密码错误。看样子so文件在加载的时候对密码字符串实行了动态修改。既然动态修改了那我们用ida动态调节一下好了,大家开辟程序,然后再用ida
attach一下,发现先后直接闪退了,ida那边也从不其余有用信息。原来那就是自毁程序的意趣啊。既然如此大家动态调节一下JNI_OnLoad()来看一下程序究竟做了怎么吗。步骤如下:

1 ddms

俺们在debugger setup里勾选 suspend on library load。然后点击继续。

PS:有时候你显然在一个函数中却一筹莫展F5,那时候你必要先按一下”p”键,程序会将那段代码作为函数分析,然后再按一下”F5”,你就可以见到反汇编的函数了。

4 adb shell am start -D -n com.yaotong.crackme/.MainActivity

那里大家把ida的androidserver push到手机上,并以root身份实施。

图片 75

随之程序会在加载libcrackme.so那个so文件的时候停住。那时候ida会油可是生找不到文件的唤起,不用管她,点收回即可。随后就能在modules中看看libcrackme.so这一个so文件了,我们点进去,然后在JNI_OnLoad处下个断点,然后点击执行,程序就进入了JNI_OnLoad()那一个函数。

2 adb push androidserver /data/local/tmp/

相关文章