跳过内容

MASTG-TECH-0044: 进程探索

在测试应用时,进程探索可以为测试人员提供对应用进程内存的深入了解。它可以通过运行时插桩来实现,并允许执行以下任务:

  • 检索内存映射和已加载的库。
  • 搜索特定数据的出现位置。
  • 在进行搜索后,获取内存映射中某个偏移量的位置。
  • 执行内存转储并离线检查或逆向工程二进制数据。
  • 在原生库运行时对其进行逆向工程。

正如您所见,这些被动任务有助于我们收集信息。此信息通常用于其他技术,例如方法钩取。

在以下章节中,您将使用 r2frida直接从应用运行时检索信息。请参阅r2frida 的官方安装说明。首先,打开一个 r2frida 会话到目标应用程序(例如,HelloWorld JNI APK),该应用程序应在您的 Android 手机上运行(通过 USB 连接)。使用以下命令

r2 frida://usb//sg.vantagepoint.helloworldjni

使用 r2 frida://? 查看所有选项。

进入 r2frida 会话后,所有命令都以 : 开头。例如,在 radare2 中,您将运行 i 来显示二进制信息,但在 r2frida 中,您将使用 :i

内存映射和检查

您可以通过运行 :dm 检索应用程序的内存映射。Android 中的输出可能非常长(例如,在 1500 到 2000 行之间),要缩小搜索范围并仅查看直接属于应用程序的内容,请按包名应用 grep (~) :dm~<package_name>

[0x00000000]> :dm~sg.vantagepoint.helloworldjni
0x000000009b2dc000 - 0x000000009b361000 rw- /dev/ashmem/dalvik-/data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.art (deleted)
0x000000009b361000 - 0x000000009b36e000 --- /dev/ashmem/dalvik-/data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.art (deleted)
0x000000009b36e000 - 0x000000009b371000 rw- /dev/ashmem/dalvik-/data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.art (deleted)
0x0000007d103be000 - 0x0000007d10686000 r-- /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.vdex
0x0000007d10dd0000 - 0x0000007d10dee000 r-- /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.odex
0x0000007d10dee000 - 0x0000007d10e2b000 r-x /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.odex
0x0000007d10e3a000 - 0x0000007d10e3b000 r-- /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.odex
0x0000007d10e3b000 - 0x0000007d10e3c000 rw- /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.odex
0x0000007d1c499000 - 0x0000007d1c49a000 r-x /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so
0x0000007d1c4a9000 - 0x0000007d1c4aa000 r-- /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so
0x0000007d1c4aa000 - 0x0000007d1c4ab000 rw- /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so
0x0000007d1c516000 - 0x0000007d1c54d000 r-- /data/app/sg.vantagepoint.helloworldjni-1/base.apk
0x0000007dbd23c000 - 0x0000007dbd247000 r-- /data/app/sg.vantagepoint.helloworldjni-1/base.apk
0x0000007dc05db000 - 0x0000007dc05dc000 r-- /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.art

当您搜索或探索应用程序内存时,您可以随时验证您在每个时刻的位置(当前偏移量所在的位置)在内存映射中。无需在此列表中记录和搜索内存地址,您可以简单地运行 :dm.。您将在以下“内存搜索”部分中找到一个示例。

如果您只对应用程序已加载的模块(二进制文件和库)感兴趣,则可以使用命令 :il 列出所有模块

[0x00000000]> :il
0x000000558b1fd000 app_process64
0x0000007dbc859000 libandroid_runtime.so
0x0000007dbf5d7000 libbinder.so
0x0000007dbff4d000 libcutils.so
0x0000007dbfd13000 libhwbinder.so
0x0000007dbea00000 liblog.so
0x0000007dbcf17000 libnativeloader.so
0x0000007dbf21c000 libutils.so
0x0000007dbde4b000 libc++.so
0x0000007dbe09b000 libc.so
...
0x0000007d10dd0000 base.odex
0x0000007d1c499000 libnative-lib.so
0x0000007d2354e000 frida-agent-64.so
0x0000007dc065d000 linux-vdso.so.1
0x0000007dc065f000 linker64

正如您可能期望的那样,您可以将库的地址与内存映射相关联:例如,应用程序的原生库位于 0x0000007d1c499000,优化后的 dex (base.odex) 位于 0x0000007d10dd0000

您还可以使用 objection 来显示相同的信息。

$ objection --gadget sg.vantagepoint.helloworldjni explore

sg.vantagepoint.helloworldjni on (google: 8.1.0) [usb] # memory list modules
Save the output by adding `--json modules.json` to this command

Name                                             Base          Size                  Path
-----------------------------------------------  ------------  --------------------  --------------------------------------------------------------------
app_process64                                    0x558b1fd000  32768 (32.0 KiB)      /system/bin/app_process64
libandroid_runtime.so                            0x7dbc859000  1982464 (1.9 MiB)     /system/lib64/libandroid_runtime.so
libbinder.so                                     0x7dbf5d7000  557056 (544.0 KiB)    /system/lib64/libbinder.so
libcutils.so                                     0x7dbff4d000  77824 (76.0 KiB)      /system/lib64/libcutils.so
libhwbinder.so                                   0x7dbfd13000  163840 (160.0 KiB)    /system/lib64/libhwbinder.so
base.odex                                        0x7d10dd0000  442368 (432.0 KiB)    /data/app/sg.vantagepoint.helloworldjni-1/oat/arm64/base.odex
libnative-lib.so                                 0x7d1c499000  73728 (72.0 KiB)      /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so

您甚至可以直接在 Android 文件系统中查看该二进制文件的大小和路径。

内存搜索是一种非常有用的技术,用于测试应用程序内存中可能存在的敏感数据。

请参阅 r2frida 的搜索命令帮助 (:/?) 以了解有关搜索命令的信息并获取选项列表。以下仅显示了其中的一部分

[0x00000000]> :/?
 /      search
 /j     search json
 /w     search wide
 /wj    search wide json
 /x     search hex
 /xj    search hex json
...

您可以通过使用搜索设置 :e~search 来调整您的搜索。例如,:e search.quiet=true; 将仅打印结果并隐藏搜索进度

[0x00000000]> :e~search
e search.in=perm:r--
e search.quiet=false

现在,我们将继续使用默认设置并专注于字符串搜索。此应用程序实际上非常简单,它从其原生库加载字符串“Hello from C++”并将其显示给我们。您可以先搜索“Hello”并查看 r2frida 发现了什么

[0x00000000]> :/ Hello
Searching 5 bytes: 48 65 6c 6c 6f
...
hits: 11
0x13125398 hit0_0 HelloWorldJNI
0x13126b90 hit0_1 Hello World!
0x1312e220 hit0_2 Hello from C++
0x70654ec5 hit0_3 Hello
0x7d1c499560 hit0_4 Hello from C++
0x7d1c4a9560 hit0_5 Hello from C++
0x7d1c51cef9 hit0_6 HelloWorldJNI
0x7d30ba11bc hit0_7 Hello World!
0x7d39cd796b hit0_8 Hello.java
0x7d39d2024d hit0_9 Hello;
0x7d3aa4d274 hit0_10 Hello

现在您想知道这些地址实际上在哪里。您可以通过运行 :dm. 命令来获取所有与 glob hit0_* 匹配的 @@ 命中

[0x00000000]> :dm.@@ hit0_*
0x0000000013100000 - 0x0000000013140000 rw- /dev/ashmem/dalvik-main space (region space) (deleted)
0x0000000013100000 - 0x0000000013140000 rw- /dev/ashmem/dalvik-main space (region space) (deleted)
0x0000000013100000 - 0x0000000013140000 rw- /dev/ashmem/dalvik-main space (region space) (deleted)
0x00000000703c2000 - 0x00000000709b5000 rw- /data/dalvik-cache/arm64/system@[email protected]
0x0000007d1c499000 - 0x0000007d1c49a000 r-x /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so
0x0000007d1c4a9000 - 0x0000007d1c4aa000 r-- /data/app/sg.vantagepoint.helloworldjni-1/lib/arm64/libnative-lib.so
0x0000007d1c516000 - 0x0000007d1c54d000 r-- /data/app/sg.vantagepoint.helloworldjni-1/base.apk
0x0000007d30a00000 - 0x0000007d30c00000 rw-
0x0000007d396bc000 - 0x0000007d3a998000 r-- /system/framework/arm64/boot-framework.vdex
0x0000007d396bc000 - 0x0000007d3a998000 r-- /system/framework/arm64/boot-framework.vdex
0x0000007d3a998000 - 0x0000007d3aa9c000 r-- /system/framework/arm64/boot-ext.vdex

此外,您可以搜索字符串的宽字符版本 (:/w) 的出现位置,并再次检查它们的内存区域

[0x00000000]> :/w Hello
Searching 10 bytes: 48 00 65 00 6c 00 6c 00 6f 00
hits: 6
0x13102acc hit1_0 480065006c006c006f00
0x13102b9c hit1_1 480065006c006c006f00
0x7d30a53aa0 hit1_2 480065006c006c006f00
0x7d30a872b0 hit1_3 480065006c006c006f00
0x7d30bb9568 hit1_4 480065006c006c006f00
0x7d30bb9a68 hit1_5 480065006c006c006f00

[0x00000000]> :dm.@@ hit1_*
0x0000000013100000 - 0x0000000013140000 rw- /dev/ashmem/dalvik-main space (region space) (deleted)
0x0000000013100000 - 0x0000000013140000 rw- /dev/ashmem/dalvik-main space (region space) (deleted)
0x0000007d30a00000 - 0x0000007d30c00000 rw-
0x0000007d30a00000 - 0x0000007d30c00000 rw-
0x0000007d30a00000 - 0x0000007d30c00000 rw-
0x0000007d30a00000 - 0x0000007d30c00000 rw-

它们与之前的字符串之一位于相同的 rw- 区域 (0x0000007d30a00000)。请注意,搜索字符串的宽字符版本有时是找到它们的唯一方法,您将在以下部分中看到。

内存搜索非常有用,可以快速了解某些数据是否位于主应用程序二进制文件中、共享库中或另一个区域中。您也可以使用它来测试应用程序关于数据在内存中如何保存的行为。例如,您可以分析执行登录的应用程序并搜索用户密码的出现位置。此外,您可以在登录完成后检查是否仍然可以在内存中找到密码,以验证此敏感数据是否在使用后从内存中擦除。

内存转储

您可以使用 objection Fridump转储应用程序的进程内存。为了在非 root 设备上利用这些工具,必须使用 frida-gadget.so 重新打包 Android 应用程序并重新签名。可以在非 root 设备上的动态分析中找到此过程的详细说明。要在 root 设备上使用这些工具,只需安装并运行 frida-server。

注意:使用这些工具时,您可能会遇到几个内存访问冲突错误,通常可以忽略这些错误。这些工具会注入 Frida 代理,并尝试转储应用程序的所有映射内存,而不管访问权限(读取/写入/执行)如何。因此,当注入的 Frida 代理尝试读取不可读取的区域时,它将返回相应的内存访问冲突错误。有关更多详细信息,请参阅上一节“内存映射和检查”。

使用 objection 可以通过使用命令 memory dump all 转储设备上运行的进程的所有内存。

$ objection --gadget sg.vantagepoint.helloworldjni explore

sg.vantagepoint.helloworldjni on (google: 8.1.0) [usb] # memory dump all /Users/foo/memory_Android/memory

Will dump 719 rw- images, totalling 1.6 GiB
Dumping 1002.8 MiB from base: 0x14140000  [------------------------------------]    0%  00:11:03(session detach message) process-terminated
Dumping 8.0 MiB from base: 0x7fc753e000  [####################################]  100%
Memory dumped to file: /Users/foo/memory_Android/memory

在这种情况下,出现了一个错误,这可能是由于我们已经预料到的内存访问冲突引起的。只要我们能够在文件系统中看到提取的转储,就可以安全地忽略此错误。如果您有任何问题,第一步是在运行 objection 时启用调试标志 -d,如果这没有帮助,请在objection 的 GitHub 中提交问题。

接下来,我们能够使用 radare2 找到“Hello from C++”字符串

$ r2 /Users/foo/memory_Android/memory
[0x00000000]> izz~Hello from
1136 0x00065270 0x00065270  14  15 () ascii Hello from C++

或者,您可以使用 Fridump。这次,我们将输入一个字符串,看看是否可以在内存转储中找到它。为此,请打开 MASTG 黑客游乐场(Java)应用程序,导航到“OMTG_DATAST_002_LOGGING”并在密码字段中输入“owasp-mstg”。接下来,运行 Fridump

python3 fridump.py -U sg.vp.owasp_mobile.omtg_android -s

Current Directory: /Users/foo/git/fridump
Output directory is set to: /Users/foo/git/fridump/dump
Starting Memory dump...
Oops, memory access violation!-------------------------------] 0.28% Complete
Progress: [##################################################] 99.58% Complete
Running strings on all files:
Progress: [##################################################] 100.0% Complete

Finished!

提示:如果您想查看更多详细信息,例如引发内存访问冲突的区域,请通过包含标志 -v 来启用详细模式。

这将需要一段时间才能完成,您将在转储文件夹中获得一系列 *.data 文件。当您添加 -s 标志时,所有字符串都会从转储的原始内存文件中提取并添加到文件 strings.txt 中,该文件也存储在转储目录中。

ls dump/
dump/1007943680_dump.data dump/357826560_dump.data  dump/630456320_dump.data ... strings.txt

最后,在转储目录中搜索输入字符串

$ grep -nri owasp-mstg dump/
Binary file dump//316669952_dump.data matches
Binary file dump//strings.txt matches

可以在其中一个转储文件以及处理过的字符串文件中找到“owasp-mstg”字符串。