简介
objection是一个基于Frida的动态的移动测试工具包,可以帮助我们来进行应用程序安全评估。
主要由以下三个组件组成
1.Frida-Gadget,以嵌入式模式运行应用,通过objection自己的api方法去调用frda执行我们想要的命令
2.objeciton本身是由python编写的可以通过python实现一个交互式shell进行命令的加载和使用,以此来调用objection
3.objection进行hook时会通过TypeScript独立生成一个agent.js文件,这样可以在使用中可以去直接调用所有的功能
首先挂一张图
下载 # 推荐兼容下载也可自行选择 pip3 install frida==5.3.0 pip3 install frida==12.8.0 pip3 install objection==1.8.4 # 下载最新版本 pip3 install --upgrade objection
# 测试环境 Mac OS 12.3 Kali 2022 Nexus 6P MUMU模拟器
基础命令 查看环境任务 jobs 用于查看和管理当前Hook所执行的任务,可以同时运行多项hook作业。
com.android.settings on (google: 6.0.1) [usb] # jobs list Job ID Hooks Type ----------- ----- ------------------------------------ 5tk3e403t35 4 watch-method for: java.io.File.$init
Frida命令 查看Frida相关信息
常用命令 列出内存中的所有类 android hooking list classes
内存中所有已加载的类中搜索包含关键词的类 android hooking search classes eg: android hooking search classes display
com.android.settings on (google: 6.0.1) [usb] # android hooking search classes display [Landroid.icu.text.DisplayContext$Type; [Landroid.icu.text.DisplayContext; [Landroid.view.Display$ColorTransform; [Landroid.view.Display$Mode; android.hardware.display.DisplayManager android.hardware.display.DisplayManager$DisplayListener android.hardware.display.DisplayManagerGlobal android.hardware.display.DisplayManagerGlobal$DisplayListenerDelegate android.hardware.display.DisplayManagerGlobal$DisplayManagerCallback android.hardware.display.IDisplayManager android.hardware.display.IDisplayManager$Stub android.hardware.display.IDisplayManager$Stub$Proxy android.hardware.display.IDisplayManagerCallback android.hardware.display.IDisplayManagerCallback$Stub android.icu.impl.CurrencyData$CurrencyDisplayInfo android.icu.impl.CurrencyData$CurrencyDisplayInfoProvider android.icu.impl.ICUCurrencyDisplayInfoProvider android.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo android.icu.text.CurrencyDisplayNames android.icu.text.DisplayContext android.icu.text.DisplayContext$Type android.media.RemoteDisplay android.opengl.EGLDisplay android.util.DisplayMetrics android.view.Choreographer$FrameDisplayEventReceiver android.view.Display android.view.Display$ColorTransform android.view.Display$ColorTransform$1 android.view.Display$Mode android.view.Display$Mode$1 android.view.DisplayAdjustments android.view.DisplayEventReceiver android.view.DisplayInfo android.view.DisplayInfo$1 android.view.DisplayListCanvas android.view.SurfaceControl$PhysicalDisplayInfo com.android.settings.DisplaySettings com.android.settings.wfd.WifiDisplaySettings com.google.android.gles_jni.EGLDisplayImpl javax.microedition.khronos.egl.EGLDisplay Found 40 classes
内存中搜索所有包含关键词key的方法 android hooking search methods <keys> eg:android hooking search methods dispaly
列出类的所有方法 android hooking list class_methods android hooking list class_methods <class> android hooking list class_methods android.hardware disapaly.DisplayManager
列出进程中所有的activity android hooking list activities
列出进程中所有的service android hook list services
列出进程中所有的广播接收器 android hooking list receivers
列出进程中所有的内容提供者 android hooking list providers
对指定的方法进行hook android hooking watch class_method <method_Name> android hooking watch class java.io.File com.android.settings on (google: 6.0.1) [usb] # jobs list Job ID Hooks Type ----------- ----- ----------------------------- nenk6ks64jg 64 watch-class for: java.io.File
android hooking watch class_method java.io.File.$init --dump-args --dump-backtrace --dump-return --dump-args //打印函数的参数 --dump-backtrace //调用栈 --dump-return //返回值
com.android.settings on (google: 6.0.1) [usb] # android hooking watch class_method java.io.File.$init --dump-args --dump-backtrace --dump-return (agent) Attempting to watch class java.io.File and method $init. (agent) Hooking java.io.File.$init(java.io.File, java.lang.String) (agent) Hooking java.io.File.$init(java.lang.String) (agent) Hooking java.io.File.$init(java.lang.String, java.lang.String) (agent) Hooking java.io.File.$init(java.net.URI) (agent) Registering job 5tk3e403t35. Type: watch-method for: java.io.File.$init
虽然只确定了Hook构造,但是默认会Hook对应方法的所有重载。同时,在输出的最后一行显示Registering job 5tk3e403t35 ,表示这个Hook被作为一个任务被添加。
com.android.settings on (google: 6.0.1) [usb] # jobs list Job ID Hooks Type ----------- ----- ------------------------------------ 5tk3e403t35 4 watch-method for: java.io.File.$init
在“设置”应用中的任意位置进行点击时,会发现java.ioFile.File(java.io.lang.String)这一个函数被调用了。在Backtrace之后打印的调用栈中,我们可以清楚的看到这个构造函数的调用来源
(agent) [5tk3e403t35] Called java.io.File.File(java.lang.String) (agent) [5tk3e403t35] Backtrace: java.io.File.<init>(Native Method) android.content.res.XResources.isFirstLoad(XResources.java:115) de.robv.android.xposed.XposedInit.cloneToXResources(XposedInit.java:396) de.robv.android.xposed.XposedInit.access$100(XposedInit.java:63) de.robv.android.xposed.XposedInit$9.afterHookedMethod(XposedInit.java:326) de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:374) android.app.ResourcesManager.getTopLevelResources(<Xposed>) android.app.ActivityThread.getTopLevelResources(ActivityThread.java:1701) android.app.ApplicationPackageManager.getResourcesForApplication(ApplicationPackageManager.java:1032) de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method) de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:360) android.app.ApplicationPackageManager.getResourcesForApplication(<Xposed>) android.app.ApplicationPackageManager.getText(ApplicationPackageManager.java:1286) android.content.pm.ComponentInfo.loadLabel(ComponentInfo.java:85) com.android.settings.DreamBackend.getActiveDreamName(DreamBackend.java:136) com.android.settings.DreamSettings.getSummaryTextWithDreamName(DreamSettings.java:261) com.android.settings.DisplaySettings.updateScreenSaverSummary(DisplaySettings.java:425) com.android.settings.DisplaySettings.updateState(DisplaySettings.java:381) com.android.settings.DisplaySettings.onResume(DisplaySettings.java:362) android.app.Fragment.performResume(Fragment.java:2263) android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1008) android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148) android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1130) android.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1963) android.app.FragmentController.dispatchResume(FragmentController.java:174) android.app.Activity.performResume(Activity.java:6348) android.app.ActivityThread.performResumeActivity(ActivityThread.java:3092) android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3134) android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2481) android.app.ActivityThread.-wrap11(ActivityThread.java) android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) android.os.Handler.dispatchMessage(Handler.java:102) android.os.Looper.loop(Looper.java:148) android.app.ActivityThread.main(ActivityThread.java:5417) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) de.robv.android.xposed.XposedBridge.main(XposedBridge.java:107) (agent) [5tk3e403t35] Arguments java.io.File.File(/data/app/com.google.android.deskclock-1/base.apk) (agent) [5tk3e403t35] Return Value: (none)
测试结束后,可以根据作业的ID来删除作业,取消对这些函数的Hook,最终执行结果如下
com.android.settings on (google: 6.0.1) [usb] # jobs list Job ID Hooks Type ----------- ----- ------------------------------------ 5tk3e403t35 4 watch-method for: java.io.File.$init com.android.settings on (google: 6.0.1) [usb] # jobs kill 5tk3e403t35 com.android.settings on (google: 6.0.1) [usb] # jobs list Job ID Hooks Type ------ ----- ----
主动调用 android heap search instances <classname>
android heap search instances java.io.File Class instance enumeration complete for java.io.File Handle Class toString() -------- ------------ --------------------------------------------------------------------------------------- 0x200d26 java.io.File /data/app/com.google.android.gms-1/base.apk 0x200d2a java.io.File /data/user/0/com.android.settings/shared_prefs 0x200d2e java.io.File /data/user/0/com.android.settings/shared_prefs/com.android.settings_preferences.xml 0x200d32 java.io.File /data/user/0/com.android.settings/shared_prefs/com.android.settings_preferences.xml.bak 0x100d36 java.io.File /data/app/com.google.android.deskclock-1/base.apk 0x100d3a java.io.File /data/misc/keychain/cacerts-added 0x100d3e java.io.File /data/misc/keychain/cacerts-removed 0x100d42 java.io.File /system/etc/security/cacerts 0x100d46 java.io.File /data 0x100d4a java.io.File /data 0x100d4e java.io.File /system 0x100d52 java.io.File /storage 0x100d56 java.io.File /oem 0x100d5a java.io.File /vendor 0x100d5e java.io.File /cache 0x100d62 java.io.File /data/secure 0x100d66 java.io.File /vendor/lib64 0x100d6a java.io.File /system/lib64 0x100d6e java.io.File 0x100d72 java.io.File /data/app/mobi.acpm.inspeckage-1/base.apk 0x100d76 java.io.File /vendor/lib64 0x100d7a java.io.File /system/lib64 0x100d7e java.io.File 0x100d82 java.io.File 0x100d86 java.io.File /data/data/mobi.acpm.sslunpinning/shared_prefs/UnpinningPrefs.xml 0x100d8a java.io.File /vendor/lib64 0x100d8e java.io.File /system/lib64 0x100d92 java.io.File 0x100d96 java.io.File /data/app/mobi.acpm.sslunpinning-1/base.apk 0x100d9a java.io.File /data/data/mobi.acpm.inspeckage/shared_prefs/InspeckagePrefs.xml 0x100d9e java.io.File /vendor/lib64 0x100da2 java.io.File /system/lib64 0x100da6 java.io.File 0x100daa java.io.File /data/app/just.trust.me-1/base.apk 0x100dae java.io.File /data/dalvik-cache 0x100db2 java.io.File /vendor/lib64 0x100db6 java.io.File /system/lib64 0x100dba java.io.File 0x100dbe java.io.File /system/framework/XposedBridge.jar 0x100dc2 java.io.File /data/misc/user/0 0x100dc6 java.io.File /data/misc/user/0/cacerts-added 0x100dca java.io.File /data/misc/user/0/cacerts-removed 0x100dce java.io.File /data/user/0/com.android.settings/shared_prefs/home_prefs.xml.bak 0x100dd2 java.io.File /data/user/0/com.android.settings/shared_prefs/home_prefs.xml 0x100dd6 java.io.File /data/user/0/com.android.settings/shared_prefs/development.xml.bak 0x100dda java.io.File /data/user/0/com.android.settings/shared_prefs/development.xml 0x100dde java.io.File /data/user/0/com.android.settings/files 0x100de2 java.io.File /data/user/0/com.android.settings/shared_prefs 0x100de6 java.io.File /data/user/0/com.android.settings/cache 0x100dea java.io.File /data/user/0/com.android.settings/databases 0x100dee java.io.File /data/user/0/com.android.settings 0x100df2 java.io.File / 0x100df6 java.io.File /data/data/com.android.settings/cache 0x100dfa java.io.File /vendor/lib64 0x100dfe java.io.File /system/lib64 0x100e02 java.io.File lib/arm64-v8a 0x100e06 java.io.File /system/priv-app/Settings/Settings.apk 0x100e0a java.io.File /system/priv-app/Settings/lib/arm64 0x100e0e java.io.File /system/priv-app/Settings/Settings.apk!/lib/arm64-v8a 0x100e12 java.io.File 0x100e16 java.io.File /system/priv-app/Settings/Settings.apk
调用实例方法 android heap execute <Handle> <methodname>
com.android.settings on (google: 6.0.1) [usb] # android heap execute 0x200d2e getPath Handle 0x200d2e is to class java.io.File Executing method: getPath() /data/user/0/com.android.settings/shared_prefs/com.android.settings_preferences.xml
使用execute执行带参数时会报错
com.android.settings on (google: 6.0.1) [usb] # android heap execute 0x200d2e setExecutable True Handle 0x200d2e is to class java.io.File Executing method: setExecutable() A Frida agent exception has occurred. Error: setExecutable(): argument count of 0 does not match any of: .overload('boolean') .overload('boolean', 'boolean') at throwOverloadError (frida/node_modules/frida-java-bridge/lib/class-factory.js:1020) at n (frida/node_modules/frida-java-bridge/lib/class-factory.js:667) at /script1.js:9147 at /script1.js:9435 at frida/node_modules/frida-java-bridge/lib/vm.js:11 at frida/node_modules/frida-java-bridge/index.js:279 at /script1.js:9439 at /script1.js:3011 at /script1.js:9440
执行带参数函数 android heap evaluate <Handle>
执行之后会进入一个迷你的编辑器环境,之后输入我们想要执行的脚本内容,编辑完成后按回车键,即会开始执行这行脚本并输出结果。我们来使用File类的canWrite()函数和setWrite()函数进行测试,具体内容如下
console.log('File is canWrite? =>' ,clazz.canWrite()) clazz.setWritable(false) console.log('File is canWrite? =>' , clazz.canWrite())
com.android.settings on (google: 6.0.1) [usb] # android heap evaluate 0x200d2e (The handle at `0x200d2e` will be available as the `clazz` variable.) console.log('File is canWrite? =>' ,clazz.canWrite()) clazz.setWritable(false) console.log('File is canWrite? =>' , clazz.canWrite()) JavaScript capture complete. Evaluating... Handle 0x200d2e is to class java.io.File File is canWrite? => true File is canWrite? => false
查看内存中的so库
查看so库的导出(export)函数
memory list exports libssl.so
将结果保存到json文件中
memory list exports libart.so --json /root/libart.json
关闭SSLPINNING android sslpinning disable
objection远程连接 frida 启动
objection远程链接
objection -N -h 192.168.31.52 -p 8888 -g com.xxx.xxx explore
Obejction Wallbreaker插件 下载 git clone https://github.com/hluwa/Wallbreaker ~/.objection/plugins/Wallbreaker
使用 objection: objection -g com.app.name explore -P ~/.objection/plugins
搜索类 plugin wallbreaker classsearch <pattern> //根据给的 pattern 对所有类名进行匹配,列出匹配到的所有类名。
搜索对象 plugin wallbreaker objectsearch <classname> //根据类名搜索内存中已经被创建的实例,列出 handle 和 toString() 的结果。
Classdump plugin wallbreaker classdump <classname> [--fullname] 输出类的结构, 若加了 --fullname 参数,打印的数据中类名会带着完整的包名。
ObjectDump plugin wallbreaker objectdump <handle> [--fullname] 在 ClassDump 的基础上,输出指定对象中的每个字段的数据。