Android中Native ELF的反汇编与破解的一些经验

工具选择与使用

一般Android运行的HW有:

  • 32Bit的ARM
  • 64Bit的ARM64
  • X86
  • X64

对于Intel/AMD的X86/X64, 可选的工具比较多, 因为ELF运行的Host是Android, 使用静态反汇编工具Hopper Disassemble与IDA是比较好的选择.

对于32位ARM的ARM, IDA与Hopper Disassemble都可以完成, 但是对于ARM64就只有Hopper Disassemble了, 当然最新的IDA Pro也可以,但是一般难以获取得到.

剩下的方式就是用readelf + Android中的Toolchain中的objdump来完成. 

一般情况下, 多种工具需要一起结合使用.

如何快速定位

得到了我们需要反汇编与patch的ELF文件后, 将其拖入到Disassemble工具中, 就可以看到其Disassemble后的不同Section了, 例如Text, Code段. 那么要完成patch, 我们需要找到patch的位置. 对此, 个人总结有3种方式来帮助我们快速定位. 

根据字符串来快速定位

一般程序运行的时候会有log输出, 提示是何种错误, 例如对于在servicemanager中的add_service, 那么如果我们的service不在service list中,那么会提示权限不足”Permission Denied”, 那么这个字符串就是很好的切入点.

在IDA中我们直接使用Search中的Text即可找到.

编译带有符号的ELF来辅助定位

对于Android代码, 不同板子或者Android设备的ROM一般都是基于AOSP做的修改, 因此绝大地方的代码和AOSP的代码是一样的. 因此我们可以借助AOSP代码来帮助我们定位.

对此第一步是需要获取Android设备上面Android的版本, 这个在关于界面, 或者使用getprop, 或者在/system/build.prop中可以获取tag以及version. 

然后我们就可以根据这些信息去下载对应版本的AOSP, 然后选择对应的Arch编译, 编译后, 在out目录中会有一个带有symbol的可供调试用的ELF文件. 这个一般位于:

out/target/product/XXX/symbols/

然后我们可以将这里面的对应的ELF文件拖入到IDA Pro或者其他Disassemble工具中进行查看, 此时因为有Debug 信息, 反汇编的代码与变量等变得很容易被识别, 很容易让我们定位. 例如下面是对bluedroid stack的反汇编:


图片1

里面的变量我们可以都可以找到. 然后使用IDA的pseudo插件, 可以得到非常好的伪代码:


图片2

而且因为有symbols, 所以我们也就可以知道其位于哪个函数中. 这对我们对应者source code来看instructions, 然后对后面的写patching tool都很有帮助.

根据立即数来定位

有些代码中对某些变量或者参数有临界值判断, 这个临界值一般都是常量const, 或者是立即数. 这个时候, 使用这个立即数来查找也可以很快帮主我们定位. 例如前面图片2中的Line49中有一个立即数: 0xC7A. 

这个0xC7A的来源是0xC80-6, 和下面的BTM_BLE_CONN_INT_MAX是匹配的.然后根据ARM中的立即数的表示规则,会发现只能是0xC7A, 即不管任何的Toolchain编译下得到的arm-v7 的指令集中的这个立即数都是这个值.

  1. stack/include/btm_ble_api.h
  2. 131:#define BTM_BLE_CONN_INT_MAX            0x0C80
  3. 170:#ifndef BTM_BLE_CONN_INT_MAX_DEF
  4. 171:#define BTM_BLE_CONN_INT_MAX_DEF     40      /* recommended max: 50 ms = 56 * 1.25 */
  5. bta/include/bta_api.h
  6. 689:#define BTA_DM_BLE_CONN_INT_MAX          BTM_BLE_CONN_INT_MAX

 

因此我们也还可以使用立即数来查找:


如何结合源代码对ELF文件进行快速破解

对于servicemanager, mediaserver, surfaceflinger等等这些AOSP含有的service, AOSP中含有源代码, 而一般相同版本的Android,那么代码基本是绝大部分相同的. 

因此, 我们完全可以直接在代码中查找对应的立即数, 字符串等有用的信息, 找到对应的函数, 然后根据相关的代码块来得到对应的instructions. 然后用此在strip过的ELF中查找.

另外我们还可以根据代码的结构来查找, 例如如果含有switch case, 那么在IDA Pro中一般也会反汇编有jumptable. 而且使用IDA Pro的伪代码生成插件也可以得到类似的代码:


可以看到里面的case 12下面的Line97 98和source code中对应:


其中里面的case值为0x12:


如何patching变更

在以前的博客中写过使用010Editor加Instruction Converter来完成:Android中使用”hacker”方式解决ServiceManager的权限限制问题(1)

但是, 现在发现IDA Pro有个插件keypatch, 非常方便: https://github.com/keystone-engine/keypatch, 直接更改指令即可, 具体可以参考: 点击打开链接

如何替换patched后的文件

普通文件直接remount 分区,然后cp即可, 但是某些文件在正常模式无法替换. 可以参考:

 海思系类机顶盒STB的Hacker记录

制作patching tools

如果是特征值查找替换, 那么patching tools可以直接用C/C++等编写, 也可以使用现有的框架, 例如:AT4RE Patcher.

直接写的话, 也可以简单粗暴的直接fread, 然后memcpy, 然后替换, 然后fwrite即可.

另外patching tools如果使用AT4RE制作, 那么生成的exe可以在Linux下面借助Wine运行.

如果使用C/C++编写, 那么在Windows下面可以使用msys2来静态(-static)编译, 然后只需要拷贝一个msys2的dll即可到处运行, 也相当于只需要写一次即可在Linux与Windows下面运行.

如何让自己的Patching tools/破解机适应多个版本的Android

要完成这项任务,我们需要先查看和跟踪代码在不同版本Android中的变化,这个可以使用git来查看, 例如servicemanger:


我们可以看到从Android4.4.2到Android 4.4.4_r1几乎没有变化, 那么我们的patching tool就可以适配这些版本. 如果有变化的话, 我们需要更改patching tool中的特征匹配pattern. 由此来选择如何search & replace.

Leave a Reply

Your email address will not be published. Required fields are marked *