如何理解 Android NDK 库?

逆向工程 安卓 手臂
2021-06-17 21:12:07

所以我目前正在尝试了解 Android 应用程序如何解释从支持蓝牙的秤发送的数据。

理解 Java 代码相对容易。代码被混淆了,但我发现了蓝牙协议的工作原理。

但是,该应用程序使用 Android NDK 调用本机 (armeabi) 库,该库根据从秤(重量、阻抗...)发送的数据计算体脂百分比等数据:libBodyfat.so

我知道所有参数是什么以及 C 函数返回什么,但我不知道它们是如何做的(做了什么计算)。

显然,不可能像使用 Java 那样从 C 库创建可读代码。我发现了一些推荐用于 C 二进制文件(例如 IDA)的工具,但它们不适用于 ARM 二进制文件。

我该怎么做才能了解图书馆的运作方式?

2个回答

.so 文件的逆向工程并非易事。C 不像 java,你可以将 .class 文件转换成更易读的形式,比如 .smali。

您可以使用radare2检查.so 文件,但是要从r2 输出中获取任何内容,您需要一些有关处理器架构和正确操作码的基本知识。

你可以在这里开始你的教育:https : //azeria-labs.com/writing-arm-assembly-part-1/

或者您可以在下面找到一些基本说明:

假设你已经安装了radare2并且你已经解压了你的apk文件。

转到 apk 目录并列出lib目录abi docs

$树库
库/
├── arm64-v8a
│ └── libnative-lib.so
├── armeabi-v7a
│ └── libnative-lib.so
├── x86
│ └── libnative-lib.so
└── x86_64
    └── libnative-lib.so

4个目录,4个文件

选择您的平台(对于您的情况,它将是 armeabi-v7a 或 arm64-v8a)

用(-A选项运行aaa命令) 打开它

 r2 -A lib/armeabi-v7a/libnative-lib.so

列出函数或搜索特定函数名称

    [0x00006498]> afl
    [0x00006498]> afl ~JNI
    0x000064e4 9 256 -> 238 sym.Java_foo_com_bar_MainActivity_stringFromJNI
    0x000065f0 1 44 sym._JNIEnv::NewStringUTF_charconst
    0x00006724 1 28 sym.JNI_OnLoad
    //跳转到函数:
    $ [0x00006498]> s 0x00006724
    //打印指令
    $ [0x00006724]> pdf 
/ (fcn) sym.JNI_OnLoad 28
| sym.JNI_OnLoad();
| ; var int local_0h @ sp+0x0
| ; var int local_4h @ sp+0x4
| ; var int local_8h @ sp+0x8
| ; var int local_ch @ sp+0xc
| ; var int local_10h @ sp+0x10
| ; 来自 0x00000234 的未知外部参照 (aav.0x00000224 + 16)
| 0x00006724 85b0 sub sp, 0x14
| 0x00006726 0a46 移动 r2,r1
| 0x00006728 0346 移动 r3,r0
| 0x0000672a 0490 str r0,[sp + local_10h]
| 0x0000672c 0391 str r1,[sp + local_ch]
| 0x0000672e 0620 movs r0, 6 ; aav.0x00000006
| 0x00006730 .dword 0x0001f2c0 ;aav.0x0001f2c0
| 0x00006734 0290 str r0,[sp + local_8h]
| 0x00006736 0298 ldr r0,[sp + local_8h]
| 0x00006738 0192 str r2,[sp + local_4h]
| 0x0000673a 0093 str r3,[sp]
| 0x0000673c 05b0 添加 sp,0x14
\ 0x0000673e 7047 bx lr

现在您必须解释radare2 输出,为此您需要带有描述的操作码列表,可以在此处或(对于arm64)在此处找到

如您所见,没有简单的方法。

提示 您可以告诉radare2 在它们旁边写操作码描述。只需输入

e asm.describe=1

并且输出将更改为如下所示:

| 0x0000672e 0620 movs r0, 6 ; aav.0x00000006 ; 立即进入注册和更新标志
| 0x00006730 .dword 0x0001f2c0 ;aav.0x0001f2c0 ; 在半字的顶部写入 16 位值
| 0x00006734 0290 str r0,[sp + local_8h];将寄存器存储到内存中
| 0x00006736 0298 ldr r0,[sp + local_8h];从内存加载到寄存器
| 0x00006738 0192 str r2,[sp + local_4h];将寄存器存储到内存中
| 0x0000673a 0093 str r3, [sp]; 将寄存器存储到内存中

最后说明:

Arm 库有时会使用 Thumb 模式,这是另一个话题。您可以在azeria-labs 网站上找到有关拇指模式的一些信息

希望现在还不算太晚。我会尽力帮助你。我已经通过这个和那个对完全相同的库进行逆向工程。libBodyfat.so. 正如@TheKalin 回答的那样,您会.so在文件夹中找到几个文件。

我发现 x86-64 与其他版本相比最容易阅读。以下是我用来对库进行逆向工程的工具:

  1. 无 IDA它将很好地列出常量值。
  2. 料斗应用程序我用它来反汇编和反编译成类似 c 的语言。它还能够反汇编ARM。您可以尝试演示版,但它有时会关闭应用程序,您需要重新打开它。
  3. 十六进制浮点数 . 公式中使用了一些常数值,我用这个网站转换了这些值。
  4. 以及了解组装说明如何工作的网站。

我设法将一些函数(初始化和体脂百分比)转换为 javascript 函数

这里是。我还没有清理代码。如果有错误或需要改进的地方,请告诉我。

https://gist.github.com/mamadcloud/95c8fe8f5816286f2ad62c81f937e6b6

希望它有帮助。