使用kali
时间改成中国时区
dpkg-reconfigure tzdata
加入中文字体
apt upgrde
如果报错,解决方法: 下载最新key添加到keylist
wget -q -O - https://archive.kali.org/archive-key.asc | apt-key add
apt install xfonts-intl-chinese
apt install ttf-wqy-microhei
可以装一些好用的小工具;
htop
jnettop
安装py环境
pyenv
ipconfig查看ip
nano /etc/proxychains.conf
注释poxy—_dns
最后改成sock5 ip最后改成1,端口1080
将机器装入adb,且为了方便加入环境变量
wget https://dl.google.com/android/repository/platform-tools-latest-linux.zip
7z x platform-tools-latest-linux.zip
root@kali:~/Downloads# cat ~/.bashrc |grep export
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
root@kali:~/Downloads# cd platform-tools/
root@kali:~/Downloads/platform-tools# cd ..
export PATH="/root//Downloads/platform-tools:$PATH"
目前最新正确的Frida环境搭建方法:
wget https://github.com/frida/frida/releases/download/12.8.0/frida-server-12.8.0-android-arm64.xz
想要使用基于特定frida版本的objection,只需先安装好特定版本的frida和frida-tools(星球里搜“特定版本”有对应关系),再去objection的release里找那个日期之后一点点的版本。比如以frida 12.8.0版本举例:
pip install frida==12.8.0
pip install frida-tools==5.3.0
pip install objection==1.8.4
按照这个顺序,在装objection的时候,就会直接Requirement already satisfied,不会再去下载新的frida来安装了。
编写0530.js脚本
function main(){
Java.perform(function(){
console.log("Inside Frida Java Perform!")
})
}
setImmediate(main)
root@kali:~/Downloads/frida-agent-example/agent# frida -U -n com.android.providers.calendar -l 0530.js
____
/ _ | Frida 12.8.0 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Attaching...
Inside Frida Java Perform!
[Google Pixel XL::com.android.providers.calendar]->
apkmirror wifi adb
可以设置打开远程adb
QtScrcpy可以投屏
然后通过wifi的frida就可以通过
手机端启动server
./fridaserver -l 0.0.0.0:8888//0.0.0.0.0为任意ip
案例如下:
marlin:/data/local/tmp # ./fs1280arm64 -l 0.0.0.0:8888
手机端就可以查看与注入
frida-ps -H 手机ip:端口
案例如下:
root@kali:~/Desktop# frida-ps H 192.168.15.98:8888
PID Name
---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
905 (sd-pam)
596 ModemManager
562 NetworkManager
1109 Thunar
617 Xorg
559 accounts-daemon
2836 adb
1151 agent
616 agetty
1056 at-spi-bus-launcher
1075 at-spi2-registryd
1355 bash
3210 bash
3714 bash
3922 bash
4927 bash
3631 code
3673 code
注入就是:
frida H 192.168.15.98:8888 -f 包名 -l 脚本 --no-pause
-f为新开进程方式
objection是一个基于Frida开发的命令行工具,它可以很方便的Hook Java函数和类,并输出参数,调用栈,返回值
关于objection版本安装尽量选择frida版本时间稍后的版本
手机端启动frida-server
root@kali:~# objection -N -h 192.168.15.98 -p 8888 -g com.android.settings explore
Using networked device @`192.168.15.98:8888`
Agent injected and responds ok!
_ _ _ _
___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_| _| _| | . | |
|___|___| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.8.4
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
com.android.settings on (google: 8.1.0) [net] # frida
-------------------- -----------
Frida Version 12.8.0
Process Architecture arm64
Process Platform linux
Debugger Attached False
Script Runtime DUK
Script Filename /script1.js
Frida Heap Size 17.0 MiB
-------------------- -----------
com.android.settings on (google: 8.1.0) [net] # env
Name Path
---------------------- -----------------------------------------------------------
cacheDirectory /data/user_de/0/com.android.settings/cache
codeCacheDirectory /data/user_de/0/com.android.settings/code_cache
externalCacheDirectory /storage/emulated/0/Android/data/com.android.settings/cache
filesDirectory /data/user_de/0/com.android.settings/files
obbDir /storage/emulated/0/Android/obb/com.android.settings
packageCodePath /system/priv-app/SettingsGoogle/SettingsGoogle.apk
参考连接:
https://www.anquanke.com/post/id/197657
Frida只是提供了各种API供我们调用,在此基础之上可以实现具体的功能,比如禁用证书绑定之类的脚本,就是使用Frida的各种API来组合编写而成。于是有大佬将各种常见、常用的功能整合进一个工具,供我们直接在命令行中使用,这个工具便是objection。
objection功能强大,命令众多,而且不用写一行代码,便可实现诸如内存搜索、类和模块搜索、方法hook打印参数返回值调用栈等常用功能,是一个非常方便的,逆向必备、内存漫游神器。
首先介绍几个基本操作:
键入命令之后,回车执行;
help:不知道当前命令的效果是什么,在当前命令前加help比如,help env,回车之后会出现当前命令的解释信息;
按空格:不知道输入什么就按空格,会有提示出来,上下选择之后再按空格选中,又会有新的提示出来;
jobs:作业系统很好用,建议一定要掌握,可以同时运行多项(hook)作业;
我们以安卓内置应用“设置”为例,来示范一下基本的用法。
在手机上启动frida-server,并且点击启动“设置”图标,手机进入设置的界面,首先查看一下“设置”应用的包名。
提取内存信息
查看内存中加载的库
运行命令memory list modules
om.android.settings on (google: 8.1.0) [net] # memory list modules
Save the output by adding `--json modules.json` to this command
Name Base Size Path
----------------------------------------------- ------------ -------------------- --------------------------------------------------------------------
app_process64 0x5d907e9000 32768 (32.0 KiB) /system/bin/app_process64
libandroid_runtime.so 0x786e55a000 1990656 (1.9 MiB) /system/lib64/libandroid_runtime.so
libbinder.so 0x786c975000 557056 (544.0 KiB) /system/lib64/libbinder.so
libcutils.so 0x786c526000 81920 (80.0 KiB) /system/lib64/libcutils.so
libhwbinder.so 0x786f343000 163840 (160.0 KiB) /system/lib64/libhwbinder.so
liblog.so 0x786e4da000 102400 (100.0 KiB) /system/lib64/liblog.so
libnativeloader.so 0x786cfa2000 28672 (28.0 KiB) /system/lib64/libnativeloader.so
libutils.so 0x786bf5d000 131072 (128.0 KiB) /system/lib64/libutils.so
libwilhelm.so 0x786f203000 274432 (268.0 KiB) /system/lib64/libwilhelm.so
libc++.so 0x786c58a000 983040 (960.0 KiB) /system/lib64/libc++.so
libc.so 0x786ed5f000 892928 (872.0 KiB) /system/lib64/libc.so
libm.so 0x786eb42000 233472 (228.0 KiB) /system/lib64/libm.so
libdl.so 0x786deaf000 20480 (20.0 KiB) /system/lib64/libdl.so
libmemtrack.so 0x786c048000 282624 (276.0 KiB) /system/lib64/libmemtrack.so
libandroidfw.so 0x786dcc4000 339968 (332.0 KiB) /system/lib64/libandroidfw.so
libappfuse.so 0x786d12f000 57344 (56.0 KiB) /system/lib64/libappfuse.so
libbase.so 0x786cf2b000 73728 (72.0 KiB) /system/lib64/libbase.so
libcrypto.so 0x786d14f000 1155072 (1.1 MiB) /system/lib64/libcrypto.so
libnativehelper.so 0x786ddd2000 36864 (36.0 KiB) /system/lib64/libnativehelper.so
libdebuggerd_client.so 0x786c739000 28672 (28.0 KiB) /system/lib64/libdebuggerd_client.so
libui.so 0x786eb87000 147456 (144.0 KiB) /system/lib64/libui.so
libgraphicsenv.so 0x786ed1a000 16384 (16.0 KiB) /system/lib64/libgraphicsenv.so
libgui.so 0x786cc43000 622592 (608.0 KiB) /system/lib64/libgui.so
libsensor.so 0x786cb85000 94208 (92.0 KiB) /system/lib64/libsensor.so
libinput.so 0x786d00b000 184320 (180.0 KiB) /system/lib64/libinput.so
libcamera_client.so 0x786dd52000 327680 (320.0 KiB) /system/lib64/libcamera_client.so
libcamera_metadata.so 0x786f45a000 45056 (44.0 KiB) /system/lib64/libcamera_metadata.so
libskia.so 0x786d3cf000 8298496 (7.9 MiB) /system/lib64/libskia.so
libsqlite.so 0x786ca02000 1146880 (1.1 MiB) /system/lib64/libsqlite.so
libEGL.so 0x786e50e000 192512 (188.0 KiB) /system/lib64/libEGL.so
libGLESv1_CM.so
如果觉得信息太多,可以:
cat .objection/objection.log
查看库的导出函数
运行命令memory list exports libssl.so,效果如下
function _ZNSt3__16__treeINS_12__value_typeIN7android8String16ElEENS_19__map_value_compareIS3_S4_NS_4lessIS3_EELb1EEENS_9allocatorIS4_EEE25__emplace_unique_key_argsIS3_JRKNS_21piecewise_construct_tENS_5tupleIJRKS3_EEENSG_IJEEEEEENS_4pairINS_15__tree_iteratorIS4_PNS_11__tree_nodeIS4_PvEElEEbEERKT_DpOT0_ 0x786c9d44e8
function _ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvm 0x786c9add70
function _ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvm 0x786c9b6cc8
function _ZN7android6binder5ValueC2ERKS1_ 0x786c9d868c
variable _ZZ17internal_type_ptrIiEPKvvE6marker 0x786c9fc398
当结果太多,终端无法全部显示的时候,可以将结果导出到文件中,然后使用其他软件查看内容
# memory list exports libart.so --json /root/libart.json
Writing exports as json to /root/libart.json...
Wrote exports to: /root/libart.json
提取整个(或部分)内存
命令是memory dump all from_base。
搜索整个内存
命令是memory search --string --offsets-only
在堆上搜索实例
我们查看AOSP源码关于设置里显示系统设置的部分,发现存在着DisplaySettings类,可以在堆上搜索是否存在着该类的实例。首先在手机上点击进入“显示”设置,然后运行以下命令,并得到相应的实例地址:
# android heap search instances com.android.settings.DisplaySettings
Using exsiting matches for com.android.settings.DisplaySettings. Use --fresh flag for new instances.
Handle Class toString()
-------- ------------------------------------ -----------------------------------------
0x252a com.android.settings.DisplaySettings DisplaySettings{69d91ee #0 id=0x7f0a0231}
调用实例的方法
查看源码得知com.android.settings.DisplaySettings类有着getPreferenceScreenResId()方法(后文也会介绍在objection中直接打印类的所有方法的命令),这样就可以直接调用该实例的getPreferenceScreenResId()方法,用excute命令。
# android heap execute 0x2526 getPreferenceScreenResId
Handle 0x2526 is to class com.android.settings.DisplaySettings
Executing method: getPreferenceScreenResId()
2132082764
可见结果被直接打印了出来。
在实例上执行js代码
也可以在找到的实例上直接编写js脚本,输入android heap evaluate 0x2526命令后,会进入一个迷你编辑器环境,输入console.log(“evaluate result:”+clazz.getPreferenceScreenResId())这串脚本,按ESC退出编辑器,然后按回车,即会开始执行这串脚本,输出结果。
# android heap evaluate 0x2526
(The handle at `0x2526` will be available as the `clazz` variable.)
console.log("evaluate result:"+clazz.getPreferenceScreenResId())
JavaScript capture complete. Evaluating...
Handle 0x2526 is to class com.android.settings.DisplaySettings
evaluate result:2132082764
这个功能其实非常厉害,可以即时编写、出结果、即时调试自己的代码,不用再编写→注入→操作→看结果→再调整,而是直接出结果。
直接启动activity
直接上代码,想要进入显示设置,可以在任意界面直接运行以下代码进入显示设置:
可以使用android hooking list命令来查看当前可用的activities,然后使用上述命令进行调起。
com.android.settings on (google: 8.1.0) [net] # android hooking list activities
com.android.settings.ActivityPicker
com.android.settings.AirplaneModeVoiceActivity
com.android.settings.AllowBindAppWidgetActivity
com.android.settings.AppWidgetPickActivity
com.android.settings.BandMode
com.android.settings.ConfirmDeviceCredentialActivity
com.android.settings.CreateShortcut
com.android.settings.CredentialStorage
com.android.settings.CryptKeeper$FadeToBlack
om.android.settings on (google: 8.1.0) [net] # android intent launch_activity com.android.settings.wifi.WifiSettings
(agent) Starting activity com.android.settings.wifi.WifiSettings...
(agent) Activity successfully asked to start.
直接启动service
也可以先使用android hooking list services查看可供开启的服务,然后使用android intent launch_service com.android.settings.bluetooth.BluetoothPairingService命令来开启服务。
在学习Frida的时候,遇到的第一个问题就是,无法找到正确的类及子类,无法定位到实现功能的准确的方法,无法正确的构造参数、继而进入正确的重载,这时候可以使用Frida进行动态调试,来确定以上具体的名称和写法,最后写出正确的hook代码。
列出内存中所有的类
# android hooking list classes
sun.util.logging.LoggingSupport
sun.util.logging.LoggingSupport$1
sun.util.logging.LoggingSupport$2
sun.util.logging.PlatformLogger
sun.util.logging.PlatformLogger$1
sun.util.logging.PlatformLogger$JavaLoggerProxy
sun.util.logging.PlatformLogger$Level
sun.util.logging.PlatformLogger$LoggerProxy
void
Found 11885 classes
内存中搜索所有的类
在内存中所有已加载的类中搜索包含特定关键词的类。
# android hooking search classes display
[Landroid.hardware.display.WifiDisplay;
[Landroid.icu.impl.ICUCurrencyDisplayInfoProvider$ICUCurrencyDisplayInfo$CurrencySink$EntrypointTable;
[Landroid.icu.impl.LocaleDisplayNamesImpl$CapitalizationContextUsage;
[Landroid.icu.impl.LocaleDisplayNamesImpl$DataTableType;
[Landroid.icu.number.NumberFormatter$DecimalSeparatorDisplay;
[Landroid.icu.number.NumberFormatter$SignDisplay;
[Landroid.icu.text.DisplayContext$Type;
[Landroid.icu.text.DisplayContext;
[Landroid.icu.text.LocaleDisplayNames$DialectHandling;
[Landroid.view.Display$Mode;
[Landroid.view.Display;
android.app.Vr2dDisplayProperties
android.hardware.display.AmbientBrightnessDayStats
android.hardware.display.AmbientBrightnessDayStats$1
android.hardware.display.BrightnessChangeEvent
com.android.settings.wfd.WifiDisplaySettings$SummaryProvider
com.android.settings.wfd.WifiDisplaySettings$SummaryProvider$1
com.android.settingslib.display.BrightnessUtils
com.android.settingslib.display.DisplayDensityUtils
com.google.android.gles_jni.EGLDisplayImpl
javax.microedition.khronos.egl.EGLDisplay
Found 144 classes
内存中搜索所有的方法
在内存中所有已加载的类的方法中搜索包含特定关键词的方法,上文中可以发现,内存中已加载的类就已经高达11885个了,那么他们的方法一定是类的个数的数倍,整个过程会相当庞大和耗时.
android hooking search methods display
当搜索到了比较关心的类之后,就可以直接查看它有哪些方法,比如我们想要查看com.android.settings.DisplaySettings类有哪些方法:
# android hooking list class_methods com.android.settings.DisplaySettings
private static java.util.List com.android.settings.DisplaySettings.buildPreferenceControllers(android.content.Context,com.android.settingslib.core.lifecycle.Lifecycle)
protected int com.android.settings.DisplaySettings.getPreferenceScreenResId()
protected java.lang.String com.android.settings.DisplaySettings.getLogTag()
protected java.util.List com.android.settings.DisplaySettings.createPreferenceControllers(android.content.Context)
public int com.android.settings.DisplaySettings.getHelpResource()
public int com.android.settings.DisplaySettings.getMetricsCategory()
static java.util.List com.android.settings.DisplaySettings.access$000(android.content.Context,com.android.settingslib.core.lifecycle.Lifecycle)
Found 7 method(s)
列出的方法与源码相比对之后,发现是一模一样的。
直接生成hook代码
上文中在列出类的方法时,还直接把参数也提供了,也就是说我们可以直接动手写hook了,既然上述写hook的要素已经全部都有了,objection这个“自动化”工具,当然可以直接生成代码。
# android hooking generate simple com.android.settings.DisplaySettings
Java.perform(function() {
var clazz = Java.use('com.android.settings.DisplaySettings');
clazz.getHelpResource.implementation = function() {
//
return clazz.getHelpResource.apply(this, arguments);
}
});
Java.perform(function() {
var clazz = Java.use('com.android.settings.DisplaySettings');
clazz.getLogTag.implementation = function() {
//
return clazz.getLogTag.apply(this, arguments);
}
});
Java.perform(function() {
var clazz = Java.use('com.android.settings.DisplaySettings');
clazz.getPreferenceScreenResId.implementation = function() {
//
return clazz.getPreferenceScreenResId.apply(this, arguments);
}
});
上述操作均是基于在内存中直接枚举搜索,已经可以获取到大量有用的静态信息,以下几个方法,可以获取到执行时动态的信息,当然、同样地,不用写一行代码。
hook类的所有方法
我们以手机连接蓝牙耳机播放音乐为例为例,看看手机蓝牙接口的动态信息。首先我们将手机连接上我的蓝牙耳机——一加蓝牙耳机OnePlus Bullets Wireless 2,并可以正常播放音乐;然后我们按照上文的方法,搜索一下与蓝牙相关的类,搜到一个高度可疑的类:android.bluetooth.BluetoothDevice。运行以下命令,hook这个类:
# android hooking watch class android.bluetooth.BluetoothDevice
om.android.settings on (google: 8.1.0) [net] # android hooking search classes bluetooth
android.bluetooth.BluetoothA2dp
android.bluetooth.BluetoothA2dp$1
android.bluetooth.BluetoothA2dp$2
android.bluetooth.BluetoothAdapter
android.bluetooth.BluetoothAdapter$1
android.bluetooth.BluetoothDevice$1
android.bluetooth.BluetoothDevice$2
android.bluetooth.BluetoothHeadset
android.bluetooth.BluetoothHeadset$1
android.bluetooth.BluetoothHeadset$2
android.bluetooth.BluetoothHeadset$3
android.bluetooth.BluetoothManager
android.bluetooth.BluetoothProfile
android.bluetooth.BluetoothProfile$ServiceListener
android.bluetooth.IBluetooth
android.bluetooth.IBluetooth$Stub
android.bluetooth.IBluetooth$Stub$Proxy
android.bluetooth.IBluetoothA2dp
android.bluetooth.IBluetoothA2dp$Stub
android.bluetooth.IBluetoothA2dp$Stub$Proxy
android.bluetooth.IBluetoothGatt
android.bluetooth.IBluetoothGatt$Stub
android.bluetooth.IBluetoothHeadset
android.bluetooth.IBluetoothHeadset$Stub
android.bluetooth.IBluetoothHeadset$Stub$Proxy
android.bluetooth.IBluetoothManager
android.bluetooth.IBluetoothManager$Stub
android.bluetooth.IBluetoothManager$Stub$Proxy
android.bluetooth.IBluetoothManagerCallback
android.bluetooth.IBluetoothManagerCallback$Stub
android.bluetooth.IBluetoothProfileServiceConnection
android.bluetooth.IBluetoothProfileServiceConnection$Stub
android.bluetooth.IBluetoothStateChangeCallback
android.bluetooth.IBluetoothStateChangeCallback$Stub
com.android.settings.Settings$BluetoothSettingsActivity
com.android.settings on (google: 8.1.0) [net] # android hooking watch class android.bluetooth.BluetoothDevice
(agent) Hooking android.bluetooth.BluetoothDevice.-get0()
(agent) Hooking android.bluetooth.BluetoothDevice.-set0(android.bluetooth.IBluetooth)
(agent) Hooking android.bluetooth.BluetoothDevice.convertPinToBytes(java.lang.String)
(agent) Hooking android.bluetooth.BluetoothDevice.getService()
(agent) Hooking android.bluetooth.BluetoothDevice.cancelBondProcess()
(agent) Hooking android.bluetooth.BluetoothDevice.cancelPairingUserInput()
(agent) Hooking android.bluetooth.BluetoothDevice.connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback)
(agent) Hooking android.bluetooth.BluetoothDevice.connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int)
(agent) Hooking android.bluetooth.BluetoothDevice.connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int)
(agent) Hooking android.bluetooth.BluetoothDevice.connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler)
(agent) Hooking android.bluetooth.BluetoothDevice.connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, boolean, int, android.os.Handler)
(agent) Hooking android.bluetooth.BluetoothDevice.createBond()
(agent) Hooking android.bluetooth.BluetoothDevice.createBond(int)
(agent) Hooking android.bluetooth.BluetoothDevice.createBondOutOfBand(int, android.bluetooth.OobData)
(agent) Hooking android.bluetooth.BluetoothDevice.createInsecureL2capSocket(int)
(agent) Hooking android.bluetooth.BluetoothDevice.createInsecureRfcommSocket(int)
(agent) Hooking android.bluetooth.BluetoothDevice.createInsecureRfcommSocketToServiceRecord(java.util.UUID)
(agent) Hooking android.bluetooth.BluetoothDevice.createL2capSocket(int)
(agent) Hooking android.bluetooth.BluetoothDevice.createRfcommSocket(int)
(agent) Hooking android.bluetooth.BluetoothDevice.createRfcommSocketToServiceRecord(java.util.UUID)
(agent) Hooking android.bluetooth.BluetoothDevice.createScoSocket()
(agent) Hooking android.bluetooth.BluetoothDevice.describeContents()
(agent) Hooking android.bluetooth.BluetoothDevice.equals(java.lang.Object)
(agent) Hooking android.bluetooth.BluetoothDevice.fetchUuidsWithSdp()
(agent) Hooking android.bluetooth.BluetoothDevice.getAddress()
(agent) Hooking android.bluetooth.BluetoothDevice.getAlias()
(agent) Hooking android.bluetooth.BluetoothDevice.getAliasName()
(agent) Hooking android.bluetooth.BluetoothDevice.getBatteryLevel()
(agent) Hooking android.bluetooth.BluetoothDevice.getBluetoothClass()
(agent) Hooking android.bluetooth.BluetoothDevice.getBondState()
(agent) Hooking android.bluetooth.BluetoothDevice.getMessageAccessPermission()
(agent) Hooking android.bluetooth.BluetoothDevice.getName()
(agent) Hooking android.bluetooth.BluetoothDevice.getPhonebookAccessPermission()
(agent) Hooking android.bluetooth.BluetoothDevice.getSimAccessPermission()
(agent) Hooking android.bluetooth.BluetoothDevice.getType()
(agent) Hooking android.bluetooth.BluetoothDevice.getUuids()
(agent) Hooking android.bluetooth.BluetoothDevice.hashCode()
(agent) Hooking android.bluetooth.BluetoothDevice.isBluetoothDock()
(agent) Hooking android.bluetooth.BluetoothDevice.isBluetoothEnabled()
(agent) Hooking android.bluetooth.BluetoothDevice.isBondingInitiatedLocally()
(agent) Hooking android.bluetooth.BluetoothDevice.isConnected()
(agent) Hooking android.bluetooth.BluetoothDevice.isEncrypted()
(agent) Hooking android.bluetooth.BluetoothDevice.removeBond()
(agent) Hooking android.bluetooth.BluetoothDevice.sdpSearch(android.os.ParcelUuid)
(agent) Hooking android.bluetooth.BluetoothDevice.setAlias(java.lang.String)
(agent) Hooking android.bluetooth.BluetoothDevice.setDeviceOutOfBandData([B, [B)
(agent) Hooking android.bluetooth.BluetoothDevice.setMessageAccessPermission(int)
(agent) Hooking android.bluetooth.BluetoothDevice.setPairingConfirmation(boolean)
(agent) Hooking android.bluetooth.BluetoothDevice.setPasskey(int)
(agent) Hooking android.bluetooth.BluetoothDevice.setPhonebookAccessPermission(int)
(agent) Hooking android.bluetooth.BluetoothDevice.setPin([B)
(agent) Hooking android.bluetooth.BluetoothDevice.setRemoteOutOfBandData()
(agent) Hooking android.bluetooth.BluetoothDevice.setSimAccessPermission(int)
(agent) Hooking android.bluetooth.BluetoothDevice.toString()
(agent) Hooking android.bluetooth.BluetoothDevice.writeToParcel(android.os.Parcel, int)
(agent) Registering job pld7w7pk25n. Type: watch-class for: android.bluetooth.BluetoothDevice
com.android.settings on (google: 8.1.0) [net] # jobs list
Job ID Hooks Type
----------- ------- --------------------------------------------------
pld7w7pk25n 55 watch-class for: android.bluetooth.BluetoothDevice
com.android.settings on (google: 8.1.0) [net] #
使用jobs list命令可以看到objection为我们创建的Hooks数为57,也就是将android.bluetooth.BluetoothDevice类下的所有方法都hook了。
这时候我们在设置→声音→媒体播放到上进行操作,在蓝牙耳机与“此设备”之间切换时,会命中这些hook之后,此时objection就会将方法打印出来,会将类似这样的信息“吐”出来:
com.android.settings on (google: 9) [usb] # (agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getService()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.isConnected()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getService()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getAliasName()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getAlias()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getName()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.equals(java.lang.Object)
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getService()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.isConnected()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getService()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getAliasName()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getAlias()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.getName()
(agent) [h0u5g7uclo] Called android.bluetooth.BluetoothDevice.equals(java.lang.Object)
可以看到我们的切换操作,调用到了android.bluetooth.BluetoothDevice类中的多个方法。
hook方法的参数、返回值和调用栈
在这些方法中,我们对哪些方法感兴趣,就可以查看哪些个方法的参数、返回值和调用栈,比如想看getName()方法,则运行以下命令:
android hooking watch class_method android.bluetooth.BluetoothDevice.getName --dump-args --dump-return --dump-backtrace
注意最后加上的三个选项–dump-args --dump-return --dump-backtrace,为我们成功打印出来了我们想要看的信息,其实返回值Return Value就是getName()方法的返回值,我的蓝牙耳机的型号名字OnePlus Bullets Wireless 2;从调用栈可以反查如何一步一步调用到getName()这个方法的;虽然这个方法没有参数,大家可以再找个有参数的试一下。
hook方法的所有重载
objection的help中指出,在hook给出的单个方法的时候,会hook它的所有重载。
# help android hooking watch class_method
Command: android hooking watch class_method
Usage: android hooking watch class_method
(optional: --dump-args) (optional: --dump-backtrace)
(optional: --dump-return)
Hooks a specified class method and reports on invocations, together with
the number of arguments that method was called with. This command will
also hook all of the methods available overloads unless a specific
overload is specified.
If the --include-backtrace flag is provided, a full stack trace that
lead to the methods invocation will also be dumped. This would aid in
discovering who called the original method.
Examples:
android hooking watch class_method com.example.test.login
android hooking watch class_method com.example.test.helper.executeQuery
android hooking watch class_method com.example.test.helper.executeQuery "java.lang.String,java.lang.String"
android hooking watch class_method com.example.test.helper.executeQuery --dump-backtrace
android hooking watch class_method com.example.test.login --dump-args --dump-return
那我们可以用File类的构造器来试一下效果。
# android hooking watch class_method java.io.File.$init --dump-args
可以看到objection为我们hook了File构造器的所有重载,一共是6个。在设置界面随意进出几个子设置界面,可以看到命中很多次该方法的不同重载,每次参数的值也都不同,
插件使用,直接加载路径
com.android.settings on (google: 8.1.0) [net] # plugin load /root/Desktop/Wallbre
aker
就可以使用插件,查看查看各种变量及信息。
com.android.settings on (google: 8.1.0) [net] # plugin wallbreaker classdump --f
ullname android.bluetooth.BluetoothDevice
package android.bluetooth
class BluetoothDevice {
/* static fields */
static int ACCESS_ALLOWED; => 1
static int ACCESS_REJECTED; => 2
static int ACCESS_UNKNOWN; => 0
static java.lang.String ACTION_ACL_CONNECTED; => android.bluetooth.device.action.ACL_CONNECTED
static java.lang.String ACTION_ACL_DISCONNECTED; => android.bluetooth.device.action.ACL_DISCONNECTED
static java.lang.String ACTION_ACL_DISCONNECT_REQUESTED; => android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED
static java.lang.String ACTION_ALIAS_CHANGED; => android.bluetooth.device.action.ALIAS_CHANGED
static java.lang.String ACTION_BATTERY_LEVEL_CHANGED; => android.bluetooth.device.action.BATTERY_LEVEL_CHANGED
static java.lang.String ACTION_BOND_STATE_CHANGED; => android.bluetooth.device.action.BOND_STATE_CHANGED
static java.lang.String ACTION_CLASS_CHANGED; => android.bluetooth.device.action.CLASS_CHANGED
static java.lang.String ACTION_CONNECTION_ACCESS_CANCEL; => android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL
static java.lang.String ACTION_CONNECTION_ACCESS_REPLY; => android.bluetooth.device.action.CONNECTION_ACCESS_REPLY
static java.lang.String ACTION_CONNECTION_ACCESS_REQUEST; => android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST
static java.lang.String ACTION_DISAPPEARED; => android.bluetooth.device.action.DISAPPEARED
static java.lang.String ACTION_FOUND; => android.bluetooth.device.action.FOUND
static java.lang.String ACTION_MAS_INSTANCE; => android.bluetooth.device.action.MAS_INSTANCE
static java.lang.String ACTION_NAME_CHANGED; => android.bluetooth.device.action.NAME_CHANGED
static java.lang.String ACTION_NAME_FAILED; => android.bluetooth.device.action.NAME_FAILED
static java.lang.String ACTION_PAIRING_CANCEL; => android.bluetooth.device.action.PAIRING_CANCEL
static java.lang.String ACTION_PAIRING_REQUEST; => android.bluetooth.device.action.PAIRING_REQUEST
static java.lang.String ACTION_SDP_RECORD; => android.bluetooth.device.action.SDP_RECORD
static java.lang.String ACTION_UUID; => android.bluetooth.device.action.UUID
static int BATTERY_LEVEL_UNKNOWN; => -1
static int BOND_BONDED; => 12
static int BOND_BONDING; => 11
static int BOND_NONE; => 10
static int BOND_SUCCESS; => 0
static int CONNECTION_ACCESS_NO; => 2
static int CONNECTION_ACCESS_YES; => 1
static int CONNECTION_STATE_CONNECTED; => 1
static int CONNECTION_STATE_DISCONNECTED; => 0
static int CONNECTION_STATE_ENCRYPTED_BREDR; => 2
static int CONNECTION_STATE_ENCRYPTED_LE; => 4
static android.os.Parcelable$Creator CREATOR; => [0x2272]: android.bluetooth.BluetoothDevice$2@7a81e5
static boolean DBG; => false
static int DEVICE_TYPE_CLASSIC; => 1
static int DEVICE_TYPE_DUAL; => 3
static int DEVICE_TYPE_LE; => 2
static int DEVICE_TYPE_UNKNOWN; => 0
static int ERROR; => -2147483648
static java.lang.String EXTRA_ACCESS_REQUEST_TYPE; => android.bluetooth.device.extra.ACCESS_REQUEST_TYPE
static java.lang.String EXTRA_ALWAYS_ALLOWED; => android.bluetooth.device.extra.ALWAYS_ALLOWED
static java.lang.String EXTRA_BATTERY_LEVEL; => android.bluetooth.device.extra.BATTERY_LEVEL
static java.lang.String EXTRA_BOND_STATE; => android.bluetooth.device.extra.BOND_STATE
static java.lang.String EXTRA_CLASS; => android.bluetooth.device.extra.CLASS
static java.lang.String EXTRA_CLASS_NAME; => android.bluetooth.device.extra.CLASS_NAME
static java.lang.String EXTRA_CONNECTION_ACCESS_RESULT; => android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT
static java.lang.String EXTRA_DEVICE; => android.bluetooth.device.extra.DEVICE
static java.lang.String EXTRA_MAS_INSTANCE; => android.bluetooth.device.extra.MAS_INSTANCE
static java.lang.String EXTRA_NAME; => android.bluetooth.device.extra.NAME
static java.lang.String EXTRA_PACKAGE_NAME; => android.bluetooth.device.extra.PACKAGE_NAME
static java.lang.String EXTRA_PAIRING_KEY; => android.bluetooth.device.extra.PAIRING_KEY
static java.lang.String EXTRA_PAIRING_VARIANT; => android.bluetooth.device.extra.PAIRING_VARIANT
static java.lang.String EXTRA_PREVIOUS_BOND_STATE; => android.bluetooth.device.extra.PREVIOUS_BOND_STATE
static java.lang.String EXTRA_REASON; => android.bluetooth.device.extra.REASON
static java.lang.String EXTRA_RSSI; => android.bluetooth.device.extra.RSSI
static java.lang.String EXTRA_SDP_RECORD; => android.bluetooth.device.extra.SDP_RECORD
static java.lang.String EXTRA_SDP_SEARCH_STATUS; => android.bluetooth.device.extra.SDP_SEARCH_STATUS
static java.lang.String EXTRA_UUID; => android.bluetooth.device.extra.UUID
static int PAIRING_VARIANT_CONSENT; => 3
static int PAIRING_VARIANT_DISPLAY_PASSKEY; => 4
static int PAIRING_VARIANT_DISPLAY_PIN; => 5
static int PAIRING_VARIANT_OOB_CONSENT; => 6
static int PAIRING_VARIANT_PASSKEY; => 1
static int PAIRING_VARIANT_PASSKEY_CONFIRMATION; => 2
static int PAIRING_VARIANT_PIN; => 0
static int PAIRING_VARIANT_PIN_16_DIGITS; => 7
static int PHY_LE_1M; => 1
static int PHY_LE_1M_MASK; => 1
static int PHY_LE_2M; => 2
static int PHY_LE_2M_MASK; => 2
static int PHY_LE_CODED; => 3
static int PHY_LE_CODED_MASK; => 4
static int PHY_OPTION_NO_PREFERRED; => 0
static int PHY_OPTION_S2; => 1
static int PHY_OPTION_S8; => 2
static int REQUEST_TYPE_MESSAGE_ACCESS; => 3
static int REQUEST_TYPE_PHONEBOOK_ACCESS; => 2
static int REQUEST_TYPE_PROFILE_CONNECTION; => 1
static int REQUEST_TYPE_SIM_ACCESS; => 4
static java.lang.String TAG; => BluetoothDevice
static int TRANSPORT_AUTO; => 0
static int TRANSPORT_BREDR; => 1
static int TRANSPORT_LE; => 2
static int UNBOND_REASON_AUTH_CANCELED; => 3
static int UNBOND_REASON_AUTH_FAILED; => 1
static int UNBOND_REASON_AUTH_REJECTED; => 2
static int UNBOND_REASON_AUTH_TIMEOUT; => 6
static int UNBOND_REASON_DISCOVERY_IN_PROGRESS; => 5
static int UNBOND_REASON_REMOTE_AUTH_CANCELED; => 8
static int UNBOND_REASON_REMOTE_DEVICE_DOWN; => 4
static int UNBOND_REASON_REMOVED; => 9
static int UNBOND_REASON_REPEATED_ATTEMPTS; => 7
static android.bluetooth.IBluetoothManagerCallback mStateChangeCallback; => [0x2c1a]: android.bluetooth.BluetoothDevice$1@3db44ba
static android.bluetooth.IBluetooth sService; => null
/* instance fields */
java.lang.String mAddress;
/* constructor methods */
android.bluetooth.BluetoothDevice(java.lang.String);
/* static methods */
static android.bluetooth.IBluetooth -get0();
static android.bluetooth.IBluetooth -set0(android.bluetooth.IBluetooth);
static [B convertPinToBytes(java.lang.String);
static android.bluetooth.IBluetooth getService();
/* instance methods */
boolean cancelBondProcess();
boolean cancelPairingUserInput();
android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, boolean, int, android.os.Handler);
boolean createBond();
boolean createBond(int);
boolean createBondOutOfBand(int, android.bluetooth.OobData);
android.bluetooth.BluetoothSocket createInsecureL2capSocket(int);
android.bluetooth.BluetoothSocket createInsecureRfcommSocket(int);
android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID);
android.bluetooth.BluetoothSocket createL2capSocket(int);
android.bluetooth.BluetoothSocket createRfcommSocket(int);
android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID);
android.bluetooth.BluetoothSocket createScoSocket();
int describeContents();
boolean equals(java.lang.Object);
boolean fetchUuidsWithSdp();
java.lang.String getAddress();
java.lang.String getAlias();
java.lang.String getAliasName();
int getBatteryLevel();
android.bluetooth.BluetoothClass getBluetoothClass();
int getBondState();
int getMessageAccessPermission();
java.lang.String getName();
int getPhonebookAccessPermission();
int getSimAccessPermission();
int getType();
[Landroid.os.ParcelUuid; getUuids();
int hashCode();
boolean isBluetoothDock();
boolean isBluetoothEnabled();
boolean isBondingInitiatedLocally();
boolean isConnected();
boolean isEncrypted();
boolean removeBond();
boolean sdpSearch(android.os.ParcelUuid);
boolean setAlias(java.lang.String);
boolean setDeviceOutOfBandData(B[], B[]);
boolean setMessageAccessPermission(int);
boolean setPairingConfirmation(boolean);
boolean setPasskey(int);
boolean setPhonebookAccessPermission(int);
boolean setPin(B[]);
boolean setRemoteOutOfBandData();
boolean setSimAccessPermission(int);
java.lang.String toString();
void writeToParcel(android.os.Parcel, int);
}
安装测试软件,加载FRIDA-DEXDump插件,查看有该包有什么类
root@kali:~/Desktop# objection -N -h 192.168.1.10 -p 8888 -g com.cz.babySister explore
Using networked device @`192.168.1.10:8888`
Agent injected and responds ok!
_ _ _ _
___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_| _| _| | . | |
|___|___| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.8.4
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
com.cz.babySister on (google: 8.1.0) [net] # plugin
Unknown or ambiguous command: `plugin`. Try `help plugin`.
com.cz.babySister on (google: 8.1.0) [net] # plugin load /root/Desktop/FRIDA-DEX
Dump/frida_dexdump
Loaded plugin: dexdump
com.cz.babySister on (google: 8.1.0) [net] # android hooking search classes com.
cz.babySister
com.cz.babySister.activity.BaseActivity
com.cz.babySister.activity.LoginActivity
com.cz.babySister.activity.MainActivity
com.cz.babySister.activity.N
com.cz.babySister.activity.O
com.cz.babySister.activity.P
com.cz.babySister.activity.Q
com.cz.babySister.activity.RegisterActivity
com.cz.babySister.activity.S
com.cz.babySister.activity.T
com.cz.babySister.activity.WelcomeActivity
com.cz.babySister.activity.a
com.cz.babySister.activity.k
com.cz.babySister.activity.l
com.cz.babySister.activity.m
com.cz.babySister.activity.n
com.cz.babySister.activity.o
com.cz.babySister.activity.oa
com.cz.babySister.application.MyApplication
com.cz.babySister.application.a
com.cz.babySister.interfaces.CitySelectLiener
com.cz.babySister.interfaces.JiFenInterFaces
Found 22 classes
查看积分所在类的函数
com.cz.babySister on (google: 8.1.0) [net] # android hooking list class_methods
com.cz.babySister.interfaces.JiFenInterFaces
public abstract void com.cz.babySister.interfaces.JiFenInterFaces.getJiFen(float)
Found 1 method(s)
om.cz.babySister on (google: 8.1.0) [net] # plugin dexdump search
[DEXDump] Found: DexAddr=0x777f4ee01c, DexSize=0x636b10
[DEXDump] Found: DexAddr=0x777fbb8000, DexSize=0xba28
[DEXDump] Found: DexAddr=0x7781800000, DexSize=0xba28
[DEXDump] Found: DexAddr=0x7781dc4f85, DexSize=0x11c
[DEXDump] Found: DexAddr=0x7781f2abde, DexSize=0x11c
[DEXDump] Found: DexAddr=0x778212901c, DexSize=0x3339c
[DEXDump] Found: DexAddr=0x7782cb101c, DexSize=0xba28
[DEXDump] Found: DexAddr=0x778fddf080, DexSize=0x559638
[DEXDump] Found: DexAddr=0x781f5bd000, DexSize=0x580
[DEXDump] Found: DexAddr=0x781f691000, DexSize=0x1ec
com.cz.babySister on (google: 8.1.0) [net] # plugin dexdump dump
[DEXDump]: DexSize=0x636b10, DexMd5=231500141df1e99cee87d4efbc2913a2, SavePath=/root/Desktop/com.cz.babySister/0x777f4ee01c.dex
[DEXDump]: DexSize=0xba28, DexMd5=a2fa46881e6a15401a35e782d91a5c30, SavePath=/root/Desktop/com.cz.babySister/0x777fbb8000.dex
[DEXDump]: Skip duplicate dex 0x7781800000
[DEXDump]: DexSize=0x11c, DexMd5=f1771b68f5f9b168b79ff59ae2daabe4, SavePath=/root/Desktop/com.cz.babySister/0x7781dc4f85.dex
[DEXDump]: Skip duplicate dex 0x7781f2abde
[DEXDump]: DexSize=0x3339c, DexMd5=b4b87d2c326c2cbd92b15ca9d453a565, SavePath=/root/Desktop/com.cz.babySister/0x778212901c.dex
[DEXDump]: DexSize=0xba28, DexMd5=e5a76d0e8fc1e7b36ffa744bfa47a183, SavePath=/root/Desktop/com.cz.babySister/0x7782cb101c.dex
[Except] - Error: access violation accessing 0x778fe00000
at frida/runtime/core.js:144
at frida/runtime/message-dispatcher.js:15
at c (frida/runtime/message-dispatcher.js:25): {'addr': '0x778fddf080', 'size': 5609016}
[DEXDump]: DexSize=0x580, DexMd5=1dd45877a3cd479a9e54953d0b0b029c, SavePath=/root/Desktop/com.cz.babySister/0x781f5bd000.dex
[DEXDump]: DexSize=0x1ec, DexMd5=a5b3b0c4946613971682701397840f5f, SavePath=/root/Desktop/com.cz.babySister/0x781f691000.dex
就报存下来dump文件了。
源程序
package com.example.lesson4one;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
fun(50,80);
}
}
int fun(int x,int y){
Log.d("kanxue",String.valueOf((x+y)));
return x+y;
}
}
注入脚本
function main(){
Java.perform(function(){
Java.use("com.example.lesson4one.MainActivity").fun.implementation =function(arg1,arg2){
var result=this.fun(arg1,arg2)
console.log("arg1,arg2,result",arg1,arg2,result)
return result;
}
})
}
setImmediate(main)
root@kali:~/Downloads/frida-agent-example/agent# frida -U com.example.lesson4one -l lesson4-2.js
____
/ _ | Frida 12.8.0 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
[Google Pixel XL::com.example.lesson4one]-> arg1,arg2,result 50 80 130
arg1,arg2,result 50 80 130
arg1,arg2,result 50 80 130
arg1,arg2,result 50 80 130
arg1,arg2,result 50 80 130
[Google Pixel XL::com.example.lesson4one]-> arg1,arg2,result 50 80 130
修改脚本
var result=this.fun(100,200)
返回结果
rg1,arg2,result 50 80 300
arg1,arg2,result 50 80 300
arg1,arg2,result 50 80 300
arg1,arg2,result 50 80 300
以下一句话打印调用栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
如果在代码中加入
String fun(String x ){
total +=x ;
return x.toLowerCase();
}
int fun(int x ,int y){
Log.d("kanxue", String.valueOf((x+y)));
return x+y;
}
hook时如下会报错,提示重载
root@kali:~/Downloads/frida-agent-example/agent# frida -U com.example.lesson4one -l lesson4-2.js
Error: fun(): has more than one overload, use .overload() to choose from:
.overload('java.lang.String')
.overload('int', 'int')
at throwOverloadError (frida/node_modules/frida-java-bridge/lib/class-factory.js:1020)
at frida/node_modules/frida-java-bridge/lib/class-factory.js:707
at /lesson4-2.js:7
at frida/node_modules/frida-java-bridge/lib/vm.js:11
at E (frida/node_modules/frida-java-bridge/index.js:346)
at frida/node_modules/frida-java-bridge/index.js:298
at frida/node_modules/frida-java-bridge/lib/vm.js:11
at frida/node_modules/frida-java-bridge/index.js:278
at main (/lesson4-2.js:8)
需要按照提示加入
overload(‘int’, ‘int’)
function main(){
Java.perform(function(){
Java.use("com.example.lesson4one.MainActivity").fun.overload('int', 'int').implementation =function(arg1,arg2){
var result=this.fun(100,200)
console.log("arg1,arg2,result",arg1,arg2,result)
return result;
}
})
}
setImmediate(main)
此时就可以hook成功。
root@kali:~/Downloads/frida-agent-example/agent# frida -U com.example.lesson4one -l lesson4-2.js
____
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
java.lang.Throwable
at com.example.lesson4one.MainActivity.fun(Native Method)
at com.example.lesson4one.MainActivity.onCreate(MainActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6999)
at android.app.Activity.performCreate(Activity.java:6990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
arg1,arg2,result 50 80 300
如在android程序中
String secret(){
return total;
}
使用如下代码主动调用
静态函数可以直接调用
假如secret2是静态函数
Java.use("com.example.lesson4one.MainActivity").secret2()
动态函数要找到实例,然后再通过实例调用
function invoke(){
Java.perform(function(){
Java.choose("com.example.lesson4one.MainActivity",{
onMatch:function(instance){
console.log("found insttance ",instance);
console.log("invoke instance.secret ",instance.secret());
},onComplete:function(){console.log("search completed !")}
})
})
}
setTimeout(invoke,2000)
源码
Log.d("SimpleArray", "onCreate: SImpleArray");
char arr[][] = new char[4][]; // 创建一个4行的二维数组
arr[0] = new char[] { '春', '眠', '不', '觉', '晓' }; // 为每一行赋值
arr[1] = new char[] { '处', '处', '闻', '啼', '鸟' };
arr[2] = new char[] { '夜', '来', '风', '雨', '声' };
arr[3] = new char[] { '花', '落', '知', '多', '少' };
Log.d("SimpleArray", "-----横版-----");
for (int i = 0; i < 4; i++) { // 循环4行
//Log.d("SimpleArraysToString", Arrays.toString(arr[i]));
//Log.d("SimpleStringBytes", Arrays.toString (Arrays.toString (arr[i]).getBytes()));
for (int j = 0; j < 5; j++) { // 循环5列
Log.d("SimpleArray", Character.toString(arr[i][j])); // 输出数组中的元素
}
if (i % 2 == 0) {
Log.d("SimpleArray", ",");// 如果是一、三句,输出逗号
} else {
Log.d("SimpleArray", "。");// 如果是二、四句,输出句号
}
}
要对Character.toString用fridahook,观察值
function main(){
Java.perform(function(){
Java.use("java.lang.Character").toString.overload('char').implementation =function(x)
{
var result=this.toString(x)
console.log("x,result",x,result)
return result
}
})
}
setImmediate(main)
结果如下
root@kali:~/Downloads/frida-agent-example/agent# frida -U -f com.kanxue.lesson5 -l lesson5.js --no-pause
Spawned `com.kanxue.lesson5`. Resuming main thread!
[Google Pixel XL::com.kanxue.lesson5]-> x,result 春 春
x,result 眠 眠
x,result 不 不
x,result 觉 觉
x,result 晓 晓
x,result 处 处
x,result 处 处
x,result 闻 闻
再如要打印一整行,然后hook改变结果,改变如下代码生成的结果
Log.d("SimpleArraysToString", Arrays.toString(arr[i]));
脚本如下
function main(){
Java.perform(function(){
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x)
{
var result=this.toString(x);
console.log("x,result",x,result);
return result;
}
})
}
结果如下:
[Google Pixel XL::com.kanxue.lesson5]-> x,result [object Object] [春, 眠, 不, 觉, 晓]
x,result [object Object] [春, 眠, 不, 觉, 晓]
x,result [object Object] [处, 处, 闻, 啼, 鸟]
x,result [object Object] [处, 处, 闻, 啼, 鸟]
x,result [object Object] [夜, 来, 风, 雨, 声]
x,result [object Object] [夜, 来, 风, 雨, 声]
x,result [object Object] [花, 落, 知, 多, 少]
x,result [object Object] [花, 落, 知, 多, 少]
可以看到参数为[object Object] ,事实上知道他是Char C的数组。
可以使用JSON.stringfy(x)打印,或者使用roysue工具r0gson,如下
https://bbs.pediy.com/thread-259186.htm
脚本
function main(){
Java.perform(function(){
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use('com.r0ysue.gson.Gson');
//console.log(gson.$new().toJson(xxx));
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x)
{
var result=this.toString(x);
console.log("x,result",gson.$new().toJson(x),result);
return result;
}
})
}
setImmediate(main)
[Google Pixel XL::com.kanxue.lesson5]-> x,result ["春","眠","不","觉","晓"] [春, 眠, 不, 觉, 晓]
x,result ["处","处","闻","啼","鸟"] [处, 处, 闻, 啼, 鸟]
x,result ["夜","来","风","雨","声"] [夜, 来, 风, 雨, 声]
x,result ["花","落","知","多","少"] [花, 落, 知, 多, 少]
x,result ["春","眠","不","觉","晓"] [春, 眠, 不, 觉, 晓]
x,result ["处","处","闻","啼","鸟"] [处, 处, 闻, 啼, 鸟]
x,result ["夜","来","风","雨","声"] [夜, 来, 风, 雨, 声]
x,result ["花","落","知","多","少"] [花, 落, 知, 多, 少]
可以使用frida API Java.array构造
function main(){
Java.perform(function(){
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use('com.r0ysue.gson.Gson');
//console.log(gson.$new().toJson(xxx));
Java.use("java.util.Arrays").toString.overload('[C').implementation=function(x)
{
var charArray=Java.array('char',['一', '行', '白', '鹭', '上', '青', '天']);
var result=this.toString(charArray);
console.log("x,result",gson.$new().toJson(charArray),result);
return Java.use("java.lang.String").$new("我连安全在搞啥都不知道");
}
})
}
setImmediate(main)
结果如下:
root@kali:~/Downloads/frida-agent-example/agent# frida -U -f com.kanxue.lesson5 -l lesson5.js --no-pause
____
/ _ | Frida 12.8.0 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://www.frida.re/docs/home/
Spawned `com.kanxue.lesson5`. Resuming main thread!
[Google Pixel XL::com.kanxue.lesson5]-> x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
x,result ["一","行","白","鹭","上","青","天"] [一, 行, 白, 鹭, 上, 青, 天]
另外如果想hook以下代码,就是一个数组转为字符串,然后在getBytes打印。
Log.d("SimpleStringBytes", Arrays.toString (Arrays.toString (arr[i]).getBytes()));
frida脚本为:
Java.use("java.util.Arrays").toString.overload('[B').implementation=function(x)
{
var result=this.toString(x);
console.log("x,result",gson.$new().toJson(x),result);
return result;
}
首先定义一个父类Water,和子类Juice
代码如下:
package com.kanxue.lesson5;
import android.util.Log;
public class Water { // 水 类
public static String flow(Water W) { // 水 的方法
// SomeSentence
Log.d("2Object", "water flow: I`m flowing");
return "water flow: I`m flowing";
}
public String still(Water W) { // 水 的方法
// SomeSentence
Log.d("2Object", "water still: still water runs deep!");
return "water still: still water runs deep!";
}
}
package com.kanxue.lesson5;
import android.util.Log;
public class Juice extends Water { // 果汁 类 继承了水类
public String fillEnergy(){
Log.d("2Object", "Juice: i`m fillingEnergy!");
return "Juice: i`m fillingEnergy!";
}
public static void main() {
Water w1 = new Water();
flow(w1) ; //
Juice J = new Juice(); // 实例化果汁类对象
flow(J) ; // 调用水的方法 向上转型 J → W
Water w2 = new Juice();
((Juice) w2).fillEnergy();
}
}
脚本
function main(){
Java.perform(function(){
var Waterhandle=null;
Java.choose("com.kanxue.lesson5.Water",{
onMatch:function(instance){
console.log("found instance:",instance);
console.log("instance call still:",instance.still(instance));
Waterhandle=instance;
},onComplete:function(){console.log("search is completed!")}
})
})
}
setImmediate(main)
结果
root@kali:~/Downloads/frida-agent-example/agent# frida -U com.kanxue.lesson5 -l
found instance: com.kanxue.lesson5.Water@53ef60e
instance call still: water still: still water runs deep!
found instance: com.kanxue.lesson5.Water@79b382f
instance call still: water still: still water runs deep!
search is completed!
[Google Pixel XL::com.kanxue.lesson5]->
如果想强制转化子类为父类,在frida中可以如下操作
该操作是将子类Juice转化为water并且调用其的动态方法still
var JuiceHandle = null ;
Java.choose("com.kanxue.lesson5.Juice",{
onMatch:function(instance){
console.log("found instance :",instance);
console.log("filling energy,",instance.fillEnergy());
JuiceHandle= instance;
},onComplete:function(){"Search Completed!"}
})
var WaterHandle = Java.cast(JuiceHandle ,Java.use("com.kanxue.lesson5.Water"));
console.log("Water invoke still ", WaterHandle.still(WaterHandle));
结果
found instance : com.kanxue.lesson5.Juice@b8f6e3c
filling energy, Juice: i`m fillingEnergy!
found instance : com.kanxue.lesson5.Juice@e1067c5
filling energy, Juice: i`m fillingEnergy!
found instance : com.kanxue.lesson5.Juice@3f8651a
filling energy, Juice: i`m fillingEnergy!
found instance : com.kanxue.lesson5.Juice@bad284b
filling energy, Juice: i`m fillingEnergy!
Water invoke still water still: still water runs deep!
父类转子类是不行的
如下,代码,milk类实现了liquid接口
package com.kanxue.lesson5;
public interface liquid {
public String flow();
}
package com.kanxue.lesson5;
import android.util.Log;
public class milk implements liquid {
public String flow(){
Log.d("3interface", "flowing : interface ");
return "nihao";
};
public static void main() {
milk m = new milk();
m.flow();
}
}
我们可以用到Java.registerClass(spec),其可以根据接口创建一个类。
Java.registerClass(spec): create a new Java class and return a wrapper for it, where spec is an object containing:
name: String specifying the name of the class.
superClass: (optional) Super-class. Omit to inherit from java.lang.Object.
implements: (optional) Array of interfaces implemented by this class.
fields: (optional) Object specifying the name and type of each field to expose.
methods: (optional) Object specifying methods to implement.
实现了一个beer,beer类实现了接口liquid
function main(){
Java.perform(function(){
var beer = Java.registerClass({
name: 'com.kanxue.lesson5.beer',
implements: [Java.use('com.kanxue.lesson5.liquid')],
methods: {
flow: function(){
console.log("flow beer");
return "test good";
}
}
});
console.log("beer.flow",beer.$new().flow());
})
}
枚举相当于一个受限制的类。
在android代码中实现了枚举
package com.kanxue.lesson5;
import android.util.Log;
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
public static Signal color = Signal.RED;
public static void main() {
//Log.d("4enum", "enum "+ color.getClass().getName().toString());
Log.d("4enum", "enum "+ color);
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
frida脚本查找匹配枚举
Java.choose("com.kanxue.lesson5.Signal",{
onMatch:function(instance){
console.log("found instance",instance);
console.log("invoke getDeclaringClass",instance.getDeclaringClass());
},onComplete:function(){
{"Search Completed!"};
}
})
})
结果
found instance GREEN
invoke getDeclaringClass class com.kanxue.lesson5.Signal
found instance YELLOW
invoke getDeclaringClass class com.kanxue.lesson5.Signal
found instance RED
invoke getDeclaringClass class com.kanxue.lesson5.Signal
在源程序如下:
Map mapr0ysue = new HashMap<>(); // 创建Map集合对象
mapr0ysue.put("ISBN 978-7-5677-8742-1", "Android项目开发实战入门"); // 向Map集合中添加元素
mapr0ysue.put("ISBN 978-7-5677-8741-4", "C语言项目开发实战入门");
mapr0ysue.put("ISBN 978-7-5677-9097-1", "PHP项目开发实战入门");
mapr0ysue.put("ISBN 978-7-5677-8740-7", "Java项目开发实战入门");
//Log.d("5map", "key值toString"+mapr0ysue.toString());
Set set = mapr0ysue.keySet(); // 构建Map集合中所有key的Set集合
Iterator it = set.iterator(); // 创建Iterator迭代器
Log.d("5map", "key值:");
while (it.hasNext()) { // 遍历并输出Map集合中的key值
try {
Thread.sleep(2000);
Log.d("5map", it.next()+" ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
frida代码如下:
function hashmap888(){
Java.perform(function(){
Java.choose("java.util.HashMap",{
onMatch:function(instance){
if(instance.toString().indexOf("ISBN")!=-1)
{
console.log("found HashMap:",instance);
console.log("HashMap toString:",instance.toString());
}
},onComplete:function(){
console.log("Search Completed!");
}
})
})
}
setImmediate(hashmap888,2000)
结果:
found HashMap: {ISBN 978-7-5677-9097-1=PHP项目开发实战入门, ISBN 978-7-5677-8742-1=Android项目开发实战入门, ISBN 978-7-5677-8741-4=C语言项目开发实战入门, ISBN 978-7-5677-8740-7=Java项目开发实战入门}
HashMap toString: {ISBN 978-7-5677-9097-1=PHP项目开发实战入门, ISBN 978-7-5677-8742-1=Android项目开发实战入门, ISBN 978-7-5677-8741-4=C语言项目开发实战入门, ISBN 978-7-5677-8740-7=Java项目开发实战入门}
Search Completed!
如图找到判断LoginActivity.a(obj, obj).equals(obj2)调用错误代码处
public void onClick(View view) {
String obj = editText.getText().toString();
String obj2 = editText2.getText().toString();
if (TextUtils.isEmpty(obj) || TextUtils.isEmpty(obj2)) {
Toast.makeText(LoginActivity.this.mContext, "username or password is empty.", 1).show();
} else if (LoginActivity.a(obj, obj).equals(obj2)) {
LoginActivity.this.startActivity(new Intent(LoginActivity.this.mContext, FridaActivity1.class));
LoginActivity.this.finishActivity(0);
} else {
Toast.makeText(LoginActivity.this.mContext, "Login failed.", 1).show();
}
}
});
进行fridahook
function main(){
Java.perform(function(){
Java.use("com.example.androiddemo.Activity.LoginActivity").a.overload('java.lang.String', 'java.lang.String').implementation=function(x,y){
var result=this.a(x,y);
console.log("x,y,result:",x,y,result);
return result;
}
})
}
setImmediate(main)
随便输出aaaaa,结果如下:
[Google Pixel XL::com.example.androiddemo]-> x,y,result: aaaaaa aaaaaa 4dca528a2131b62a29686c0cf67a15926faef3cfc24becfc49f635a5bfec7519
所以后面这个result就是4dca528a2131b62a29686c0cf67a15926faef3cfc24becfc49f635a5bfec7519
使用adb 输入此段字符串
adb shell
input text 4dca528a2131b62a29686c0cf67a15926faef3cfc24becfc49f635a5bfec7519
可见进入界面,但是点击下一关,check failed
根据字符串Check Failed查找
附进有check success函数
public void CheckSuccess() {
}
根据代码找到第一关
ublic class FridaActivity1 extends BaseFridaActivity {
private static final char[] table = {'L', 'K', 'N', 'M', 'O', 'Q', 'P', 'R', 'S', 'A', 'T', 'B', 'C', 'E', 'D', 'F', 'G', 'H', 'I', 'J', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'o', 'd', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'e', 'f', 'g', 'h', 'j', 'i', 'k', 'l', 'm', 'n', 'y', 'z', '0', '1', '2', '3', '4', '6', '5', '7', '8', '9', '+', '/'};
@Override // com.example.androiddemo.Activity.BaseFridaActivity
public String getNextCheckTitle() {
return "当前第1关";
}
@Override // com.example.androiddemo.Activity.BaseFridaActivity
public void onCheck() {
try {
if (a(b("请输入密码:")).equals("R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=")) {
CheckSuccess();
startActivity(new Intent(this, FridaActivity2.class));
finishActivity(0);
return;
}
super.CheckFailed();
} catch (Exception e) {
e.printStackTrace();
}
}
所以根据代码可以,直接让a方法返回上述代码equal值。
脚本如下:
function main(){
Java.perform(function(){
Java.use("com.example.androiddemo.Activity.FridaActivity1").a.implementation=function(x){
var result="R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=";
console.log("result:",result);
return result;
}
})
}
setImmediate(main)
进入第二关
第二关关键代码如下,两者都为否才成功,所以就需要调用静动态函数即可
private static void setStatic_bool_var() {
static_bool_var = true;
}
private void setBool_var() {
this.bool_var = true;
}
@Override // com.example.androiddemo.Activity.BaseFridaActivity
public void onCheck() {
if (!static_bool_var || !this.bool_var) {
super.CheckFailed();
return;
}
CheckSuccess();
代码如下:
function second(){
Java.perform(function(){
//static
Java.use("com.example.androiddemo.Activity.FridaActivity2").setStatic_bool_var();
//dynamic
Java.choose("com.example.androiddemo.Activity.FridaActivity2",
{onMatch:function(instance){
console.log("found instance");
instance.setBool_var();
},onComplete:function(){console.log("search completed !")}
})
})
}
setImmediate(second)
如下注入进去。
第三关需要将3个变量都设置为真,才能进入下关。这三个为动静态方法和跟函数同名的变量
与函数同名变量开头前加下划线
public void onCheck() {
if (!static_bool_var || !this.bool_var || !this.same_name_bool_var) {
super.CheckFailed();
return;
}
function thrid(){
Java.perform(
function(){
Java.use("com.example.androiddemo.Activity.FridaActivity3").static_bool_var.value=true;
Java.choose("com.example.androiddemo.Activity.FridaActivity3",
{onMatch:function(instance){
console.log("found instance");
instance.bool_var.value=true;
instance._same_name_bool_var.value=true;
},onComplete:function(){console.log("search completed !")}
})
})
}
setImmediate(thrid)
第四关为内部类函数,全部要设置为true,才能进入下一关
public class FridaActivity4 extends BaseFridaActivity {
@Override // com.example.androiddemo.Activity.BaseFridaActivity
public String getNextCheckTitle() {
return "当前第4关";
}
private static class InnerClasses {
public static boolean check1() {
return false;
}
public static boolean check2() {
return false;
}
public static boolean check3() {
return false;
}
public static boolean check4() {
return false;
}
public static boolean check5() {
return false;
}
public static boolean check6() {
return false;
}
private InnerClasses() {
}
}
@Override // com.example.androiddemo.Activity.BaseFridaActivity
public void onCheck() {
if (!InnerClasses.check1() || !InnerClasses.check2() || !InnerClasses.check3() || !InnerClasses.check4() || !InnerClasses.check5() || !InnerClasses.check6()) {
super.CheckFailed();
return;
}
CheckSuccess();
startActivity(new Intent(this, FridaActivity5.class));
finishActivity(0);
}
}
frida代码如下:
function fourth(){
Java.perform(function(){
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check1.implementation=function(){
return true;
}
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check2.implementation=function(){
return true;
}
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check3.implementation=function(){
return true;
}
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check4.implementation=function(){
return true;
}
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check5.implementation=function(){
return true;
}
Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check6.implementation=function(){return true;}
}
)}
setImmediate(fourth)
如果函数太多可以使用枚举:
function forth2(){
Java.perform(function(){
var class_name = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses" ;
var InnerClass = Java.use(class_name);
var all_methods = InnerClass.class.getDeclaredMethods();
//console.log(all_methods);
for(var i = 0;i
第5个,看到关键函数如下,根据需要定位到getDynamicDexCheck的check为真跳转正误,getDynamicDexCheck返回值是一个DynamicDexCheck实例,实例有check方法。所以需要从定位到getDynamicDexCheck开始,而getDynamicDexCheck用到了DynamicDexCheck,DynamicDexCheck根据代码由com.example.androiddemo.Dynamic.DynamicCheck类实例化,又因为此类并没有导入加载,所以需要先换到com.example.androiddemo.Dynamic.DynamicCheck的clossloader然后去找cheeck。
首先需要定位到getDynamicDexCheck,没法直接跳转到,进行hook观察所在的类
public void onCheck() {
if (getDynamicDexCheck() == null) {
Toast.makeText(this, "onClick loaddex Failed!", 1).show();
} else if (getDynamicDexCheck().check()) {
CheckSuccess();
startActivity(new Intent(this, FridaActivity6.class));
finishActivity(0);
} else {
super.CheckFailed();
}
}
脚本如下:
function fifth()
{
Java.perform(function(){
Java.choose("com.example.androiddemo.Activity.FridaActivity5",{
onMatch:function(instance){
console.log("found instance getDynamicDexCheck:",instance.getDynamicDexCheck().$className);
},onComplete:function(){console.log("search completed !")}
})
})
}
setImmediate(fifth)
结果如下:
found instance getDynamicDexCheck: com.example.androiddemo.Dynamic.DynamicCheck
然后添加脚本去改变check的值
function fifth(){
Java.perform(function(){
Java.choose("com.example.androiddemo.Activity.FridaActivity5",{
onMatch:function(instance){
console.log("found instance getDynamicDexCheck :",instance.getDynamicDexCheck().$className);
},onComplete:function(){console.log("search complete!")}
})
Java.enumerateClassLoaders({
onMatch:function(loader){
try {
if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){
console.log("Succefully found loader!",loader);
Java.classFactory.loader = loader;
}
} catch (error) {
console.log("found error "+error)
}
},onComplete:function(){"enum completed!"}
})
Java.use("com.example.androiddemo.Dynamic.DynamicCheck").check.implementation = function(){return true};
})
}
setImmediate(fifth)
第六关
比较简单,脚本如下:
function sixth (){
Java.perform(function(){
Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class0").check.implementation = function (){return true };
Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class1").check.implementation = function (){return true };
Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class2").check.implementation = function (){return true };
})
}
也可以使用枚举:
function sixth2(){
Java.perform(function(){
Java.enumerateLoadedClasses({
onMatch:function(name,handle){
if(name.toString().indexOf("com.example.androiddemo.Activity.Frida6.Frida6")>=0){
console.log("name",name)
Java.use(name).check.implementation = function(){return true}
}
},onComplete(){}
})
})
}
关于单独打包.java文件,可以使用
root@kali:~/AndroidStudioProjects/lesson9/app/build/intermediates/javac/debug/cl
asses/com/kanxue/lesson9# /root/Android/Sdk/build-tools/30.0.3/d8 reverseA.class
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
root@kali:~/AndroidStudioProjects/lesson9/app/build/intermediates/javac/debug/classes/com/kanxue/lesson9# ls
BuildConfig.class classes.dex MainActivity.class reverseA.class
看雪视频