介绍

Frida是一款功能强大的动态分析工具,可以使用它的API来编写各种自定义的脚本和插件。而Objection是基于Frida API开发的一个工具,它将常见的Frida脚本和插件整合到一起,并提供了一个命令行接口,使用户可以方便地使用这些功能,而无需编写复杂的脚本。

Objection的目标是使移动应用程序的安全评估更加简单和高效。它提供了许多常见的功能,如反调试、禁用证书绑定、绕过安全检查、修改应用程序的行为等等。这些功能都是通过调用Frida的API来实现的,但是Objection将它们封装成易于使用的命令行接口,从而降低了使用门槛,并提高了效率。

GitHub: https://github.com/sensepost/objection

安装说明

安装

pip3 install objection

参数说明

   objection
Usage: objection [OPTIONS] COMMAND [ARGS]...

选项:
  -N,--network 使用网络连接而不是USB进行连接。[默认值:False]
  -h,--host TEXT 使用的主机地址。[默认值:127.0.0.1]
  -p,--port INTEGER 连接使用的端口号。[默认值:27042]
  -ah,--api-host TEXT API服务器绑定的主机地址。[默认值:127.0.0.1]
  -ap,--api-port INTEGER API服务器绑定的端口号。[默认值:8888]
  -g,--gadget TEXT 要连接的Frida Gadget/进程的名称。[默认值:Gadget]
  -S,--serial TEXT 要连接的设备序列号。
  -d,--debug 启用调试模式并输出详细信息。(包括堆栈跟踪中的代理源映射)
  --help 显示此帮助消息并退出。

命令:
  api 在无头模式下启动Objection API服务器。
  device-type 获取附加设备的信息。
  explore 启动Objection exploration REPL。
  patchapk 使用frida-gadget.so修补APK。
  patchipa 使用FridaGadget dylib修补IPA。
  run 运行单个Objection命令。
  signapk 使用Objection密钥对APK进行zipalign和签名。
  version 打印当前版本并退出。

启动objection

sieve为目标,注入目标中

默认是连接USB,如果有多个USB,就需要用-S指定

Objection 在启动时会自动注入Frida Agent到目标应用程序中

objection -S emulator-5554 -g com.mwr.example.sieve explore

启动后,不知道输入什么命令,可以按tab,他会帮你提示,支持tab键自动补齐,也可以通过help 命令来查看对应命令的说明,如help android

image-20230316111654152

启动activity/service

获取activity列表

android hooking list activities

启动activity

android intent launch_activity com.mwr.example.sieve.PWList

获取service列表

android hooking list services

启动service

android intent launch_service com.mwr.example.sieve.CryptoService

内存操作

内存搜索

memory search "abcde" --string

内存查看

# memory dump <base address> <size to dump> <local destination>
memory dump from_base 0xf7778765 200 main

搜索类

列出所有加载的类

android hooking list classes

搜索类

# android hooking search classes 关键词
android hooking search classes sieve

搜索方法

列出指定类的方法

# android hooking list class_methods 类名
android hooking list class_methods com.mwr.example.sieve.MainLoginActivity

搜索方法

# android hooking search methods 关键词
android hooking search methods com.mwr.example.sieve.MainLoginActivity

主动执行方法

先尝试找到该类的实例(和Java.choose类似)

android heap search instances com.mwr.example.sieve.MainLoginActivity

# res
Class instance enumeration complete for com.mwr.example.sieve.MainLoginActivity
 Hashcode  Class                                    toString()
---------  ---------------------------------------  -----------------------------------------------
135299310  com.mwr.example.sieve.MainLoginActivity  com.mwr.example.sieve.MainLoginActivity@81080ee

尝试调用这个实例的com.mwr.example.sieve.MainLoginActivity.loginSuccessful()方法

android heap execute 135299310 loginSuccessful

# res
Handle 135299310 is to class
        com.mwr.example.sieve.MainLoginActivity
Executing method: loginSuccessful()

也可以直接hook这个实例,去编写js脚本;默认实例是clazz

android heap evaluate 135299310

# res
(The hashcode at `135299310` will be available as the `clazz` variable.)
console.log(clazz);
console.log(clazz.loginSuccessful());
JavaScript capture complete. Evaluating...
Handle 135299310 is to class
        com.mwr.example.sieve.MainLoginActivity
com.mwr.example.sieve.MainLoginActivity@81080ee
undefined

生成hook代码

# android hooking generate simple 类名
android hooking generate simple com.mwr.example.sieve.MainLoginActivity

生成的框架代码如下,我们只需要根据要hook的逻辑进行修改即可,其中arguments就是传入的参数。

Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.sendFailed.implementation = function() {

        //

        return clazz.sendFailed.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.loginSuccessful.implementation = function() {

        //

        return clazz.loginSuccessful.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onCreateOptionsMenu.implementation = function() {

        //

        return clazz.onCreateOptionsMenu.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.loginFailed.implementation = function() {

        //

        return clazz.loginFailed.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onOptionsItemSelected.implementation = function() {

        //

        return clazz.onOptionsItemSelected.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.checkKeyResult.implementation = function() {

        //

        return clazz.checkKeyResult.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.login.implementation = function() {

        //

        return clazz.login.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.connected.implementation = function() {

        //

        return clazz.connected.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.firstLaunchResult.implementation = function() {

        //

        return clazz.firstLaunchResult.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.welcomeUser.implementation = function() {

        //

        return clazz.welcomeUser.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.setPinResult.implementation = function() {

        //

        return clazz.setPinResult.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.unbind.implementation = function() {

        //

        return clazz.unbind.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.openSettings.implementation = function() {

        //

        return clazz.openSettings.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.initaliseActivity.implementation = function() {

        //

        return clazz.initaliseActivity.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.setPin.implementation = function() {

        //

        return clazz.setPin.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onResume.implementation = function() {

        //

        return clazz.onResume.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onBackPressed.implementation = function() {

        //

        return clazz.onBackPressed.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onStart.implementation = function() {

        //

        return clazz.onStart.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onActivityResult.implementation = function() {

        //

        return clazz.onActivityResult.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onCreate.implementation = function() {

        //

        return clazz.onCreate.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.onPause.implementation = function() {

        //

        return clazz.onPause.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.setKeyResult.implementation = function() {

        //

        return clazz.setKeyResult.apply(this, arguments);
    }
});


Java.perform(function() {
    var clazz = Java.use('com.mwr.example.sieve.MainLoginActivity');
    clazz.checkPinResult.implementation = function() {

        //

        return clazz.checkPinResult.apply(this, arguments);
    }
});

监听类和方法

hook类中所有的方法

# android hooking watch class 类名
android hooking watch class com.mwr.example.sieve.MainLoginActivity

# res
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.checkKeyResult(boolean)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.checkPinResult(boolean)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.connected()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.firstLaunchResult(int)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.login(android.view.View)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onActivityResult(int, int, android.content.Intent)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onBackPressed()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onCreate(android.os.Bundle)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onCreateOptionsMenu(android.view.Menu)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onOptionsItemSelected(android.view.MenuItem)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onPause()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onResume()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.onStart()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.sendFailed()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.setKeyResult(boolean)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.setPinResult(boolean)
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.initaliseActivity()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.loginFailed()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.loginSuccessful()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.openSettings()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.setPin()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.unbind()
(agent) Hooking com.mwr.example.sieve.MainLoginActivity.welcomeUser()
(agent) Registering job 963225. Type: watch-class for: com.mwr.example.sieve.MainLoginActivity

hook后,输入jobs list可以查看该类下的方法都被hook

job list

# res

Job ID  Hooks  Type
------  -----  --------------------------------------------------------
963225     23  watch-class for: com.mwr.example.sieve.MainLoginActivity

正常操作app,当hook的方法被调用时,会自动将这些方法输出。

image-20230316133930166

hook对应方法的参数、返回值和调用栈

# android hooking watch class_method <方法名> --dump-args --dump-return  --dump-backtrace
android hooking watch class_method com.mwr.example.sieve.MainLoginActivity.login --dump-args --dump-return  --dump-backtrace

当这个方法被调用时,会输出相关的信息

com.mwr.example.sieve on (Xiaomi: 6.0.1) [usb] # (agent) [880894] Called com.mwr.example.sieve.MainLoginActivity.login(android.view.View)
(agent) [880894] Backtrace:
    com.mwr.example.sieve.MainLoginActivity.login(Native Method)
        java.lang.reflect.Method.invoke(Native Method)
    android.view.View$DeclaredOnClickListener.onClick(View.java:4453)
    android.view.View.performClick(View.java:5204)
    android.view.View$PerformClick.run(View.java:21153)
    android.os.Handler.handleCallback(Handler.java:739)
    android.os.Handler.dispatchMessage(Handler.java:95)
    android.os.Looper.loop(Looper.java:148)
    android.app.ActivityThread.main(ActivityThread.java:5647)
    java.lang.reflect.Method.invoke(Native Method)
    com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)

(agent) [880894] Arguments com.mwr.example.sieve.MainLoginActivity.login(android.widget.Button{8efa50c VFED..C.. ...P.... 0,879-1872,1004 #7f080010 app:id/mainlogin_button_login})
(agent) [880894] Return Value: (none)

其他技巧

其他命令

查看命令的帮助

objection explore --hel

# 如同步执行命令
objection -g com.xxx.xxx -S emulator-5554 explore --startup-command 'android hooking search classes sieve'

显示当前应用程序环境的目录信息。

env

导入js脚本(需要结合frida使用,不然会有找不到pid的问题,参考issue

import <js脚本路径>

关闭root检测

android root disable

绕过ssl pinning检测

android sslpinning disable

设置proxy代理(不是很好用)

android proxy set 172.20.10.2 8080

获取当前的activity

android hooking get current_activity

截图并保存到本地

android ui screenshot ./1.png

结合frida

部分情况,比如存在root检测这种,需要在app启动时进行hook,但是直接用objection提供的-s或者-S参数又不能生效,或者有各种问题,因此可以直接结合frida来进行,也很方便好用。

# 绕过root检测
frida -D emulator-5554 -l root_detection_bypass.js -f owasp.mstg.uncrackable1

# 获取pid
frida-ps -D emulator-5554 -a

# objection attach
objection -g 4093 -S emulator-5554 explore
Copyright © d4m1ts 2023 all right reserved,powered by Gitbook该文章修订时间: 2023-03-19 19:44:35

results matching ""

    No results matching ""