首页 > 代码库 > Android 逆向实战(一)

Android 逆向实战(一)

<style>p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; color: #000000 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Helvetica; color: #000000; min-height: 13.0px } span.s1 { }</style>

现在很多 apk 在开发中为了保证代码不被轻易逆向出来会对关键代码采用 ndk开发的方式。

什么是 Android NDK?

    Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。同时,Android NDK对于Android SDK只是个组件,它可以帮我们生成的JNI兼容的共享库可以在大于Android1.5平台的ARM CPU上运行,将生成的共享库拷贝到合适的程序工程路径的位置上,以保证它们自动的添加到你的apk包中。

 

  所以学会分析 .so 文件(加载流程、方式等)对安卓逆向来说是比较重要的。

  那so一般如何分析java层函数调用:

  通过System.loadLibrary找到该方法对应的so文件,使用ida载入后查找导出函数,native函数注册的两种形式:

  静态注册:java_xxx_xxx_xxx_类名_方法名(参数)

  动态注册:RegisterNatives

 

  Android 对 .so 文件加载时首先会查看  .init 或 .init_array 段是否存在,如果存在那么就先运行这段的内容,如果不存在的话那么就检查是否存在 JNI_Onload 存在则执行。

 

实际分析一个CrackMe.apk吧。

 

1)反编译 apk 文件得到 smali 代码

  分析后可以看到调用了 .so 文件里定义的 check 函数,然后这个 check 函数又和 button 的 OnClick 事件绑定,可以判断 check 则是判断用户输入 key 是否正确的函数。

2)用 IDA 对 libqtfreet.so 进行分析

  首先先看看有没有 JAVA_com_qtfreet_crackme001_check 这样类似的函数,如果存在的话就说明 .so 文件里面没有对 check 函数进行动态注册,JAVA_com_qtfreet_crackme001_check 就是 smali 里面调用的 check 函数原型,直接分析即可。

如果没有发现上面类似函数的话则说明 smali 调用的 check 函数进行了动态注册,此时需要找到注册的位置。

 

因为 .init 或者 .init_array 在 IDA 动态调试的时候是不会显示出来的,所以需要静态分析出这两段的偏移量然后动态调试的时候计算出绝对位置,然后在 make code(快捷键:c),这样才可以看到该段内的代码内容。

查看 .init_array 段的地址有两种办法:
1.可以使用 IDA 加载 .so 文件,新建 “Segments” 视图,这里会列出不同类型的代码段信息,如下图所示。

2.可以使用二进制工具 readelf 来查看 .so 文件的结构,在 OS X 上面可以使用 greadelf 代替。

 

3)可以看到这里两个都指示 .init_array 存在,并且偏移量为 0x20790,IDA 定位到该位置查看如图。

 

 .init_array 执行完之后就跳到 JNI_Onload 里面执行,IDA 跳到 JNI_Onload 之后 F5 查看伪代码。

看到高亮的 RegisterNatives,进去第三个参数 off_21458 位置查看保存的内容。

 

4)可以看到这里最后执行了一个 memcmp 所以可以确定 sub_8A64 开始是关键的判断代码,直接将 memcmp 的返回值修改即可成功破解 crackme。

Android 逆向实战(一)