使用overloads
var overloads = SomeClass.someMethod.overloads;
for (var i in overloads) {
overloads[i].implementation = function() {
console.log("Hooked: ", arguments);
return this.overloads[i].apply(this, arguments);
};
}
** 使用overload**
SomeClass.someMethod.overload('int', 'java.lang.String').implementation = function(intArg, stringArg) {
console.log("Hooked: ", intArg, stringArg);
return this.someMethod.overload('int', 'java.lang.String').apply(this, arguments);
};
import frida
import subprocess
subprocess.getoutput("adb forward tcp:27042 tcp:27042")
subprocess.getoutput("adb forward tcp:27043 tcp:27043")
def get_target_pid(app_name):
rdev = frida.get_remote_device()
for process in rdev.enumerate_processes():
print(process.name)
if process.name == app_name:
return process.pid
front_app = rdev.get_frontmost_application()
print(front_app)
return None
# com.android.localtransport
# /data/local/tmp/fs64 -l 0.0.0.0:1234
# adb forward tcp:1234 tcp:1234
# frida -H 127.0.0.1:1234 package_name -l hook.js
# target_app_name = "Local News"
# target_app_name = "Translate"
target_pid = get_target_pid("")
adb shell pm path news.local.latest.newsbreak.free.app
spawn模式
frida -U -f com.android.localtransport -l hook.js
attach 附加模式
前台模式
frida -UF com.android.localtransport -l hook.js
指定名称
frida -U com.android.localtransport -l hook.js 指定名称
frida-trace -UF --runtime=v8 -j '*ud.*!*/isu' -j '*qe*!*/isu'
objection -g 包名 explore
常用的指令
Memory 指令
memory list modules //枚举当前进程模块
memory list exports [lib_name] //查看指定模块的导出函数
memory list exports libart.so --json /root/libart.json //将结果保存到json文件中
memory search --string --offsets-only //搜索内存
android heap 指令
//堆内存中搜索指定类的实例, 可以获取该类的实例id
search instances search instances com.xx.xx.class
//直接调用指定实例下的方法
android heap execute [ins_id] [func_name]
//自定义frida脚本, 执行实例的方法
android heap execute [ins_id]
android 指令
android root disable //尝试关闭app的root检测
android root simulate //尝试模拟root环境
android ui screenshot [image.png] //截图
android ui FLAG_SECURE false //设置FLAG_SECURE权限
内存漫游
android hooking list classes //列出内存中所有的类
//在内存中所有已加载的类中搜索包含特定关键词的类
android hooking search classes [search_name]
//在内存中所有已加载的方法中搜索包含特定关键词的方法
android hooking search methods [search_name]
//直接生成hook代码
android hooking generate simple [class_name]
hook 方式
/*
hook指定方法, 如果有重载会hook所有重载,如果有疑问可以看
--dump-args : 打印参数
--dump-backtrace : 打印调用栈
--dump-return : 打印返回值
*/
android hooking watch class_method com.xxx.xxx.methodName --dump-args --dump-backtrace --dump-return
//hook指定类, 会打印该类下的所有调用
android hooking watch class com.xxx.xxx
//设置返回值(只支持bool类型)
android hooking set return_value com.xxx.xxx.methodName false
Spawn 方式 Hook
objection -g packageName explore --startup-command '[obejection_command]'
activity 和 service 操作
android hooking list activities //枚举activity
android intent launch_activity [activity_class] //启动activity
android hooking list services //枚举services
android intent launch_service [services_class] //启动services
任务管理器
jobs list // 查看任务列表
jobs kill [task_id] // 关闭任务
关闭 app 的 ssl 校验
android sslpinning disable
监控系统剪贴板
// 获取Android剪贴板服务上的句柄并每5秒轮询一次用于数据。
// 如果发现新数据,与之前的调查不同,则该数据将被转储到屏幕上。
help android clipboard
执行命令行
help android shell_exec [command]
md5 hook
var md = Java.use('java.security.MessageDigest');
// md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
// // showStacks();
// console.log("======================================");
// console.log("算法名1:" + a);
// return this.getInstance(a, b);
// }
md.getInstance.overload('java.lang.String').implementation = function (a) {
// showStacks();
console.log("================start2======================");
console.log("算法名2:" + a);
console.log("================end2======================");
return this.getInstance(a);
}
md.digest.overload().implementation = function () {
//showStacks();
console.log("======================================");
var result = this.digest();
console.log("digest结果5:" + bytesToHex(result));
return result;
}
md.digest.overload('[B').implementation = function (a) {
showStacks();
console.log("=================start6=====================");
console.log("digest参数6:" + bytesToString(a));
var result = this.digest(a);
console.log("digest结果7:" + bytesToHex(result));
console.log("=================end6=====================");
return result;
}
// md.update.overload('[B').implementation = function (a) {
// //showStacks();
// console.log("======================================");
// console.log("update3:" + bytesToString(a))
// return this.update(a);
// }
// md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
// //showStacks();
// console.log("======================================");
// console.log("update4:" + bytesToString(a) + "|" + b + "|" + c);
// return this.update(a, b, c);
// }
var TreeMap = Java.use('java.util.TreeMap');
var Map = Java.use("java.util.Map");
TreeMap.put.implementation = function (key,value) {
if(key=="data"){
console.log(key,value);
}
var res = this.put(key,value);
return res;
}
var StringBuilder = Java.use("java.lang.StringBuilder");
StringBuilder.toString.implementation = function () {
var res = this.toString();
console.log(res);
return res;
}
var Base64Class = Java.use("android.util.Base64");
Base64Class.encodeToString.overload("[B", "int").implementation = function(a,b){
var resault = this.encodeToString(a,b);
console.log(">>> Base64 " + resault);
if(resault.length <= 20){
var stackAdd = threadinstance.currentThread().getStackTrace();
console.log("resault stackAdd is:" + Where(stack));
}
return rc;
}
var Builder = Java.use('okhttp3.OkHttpClient$Builder');
Builder.addInterceptor.implementation = function (inter) {
//console.log("实例化:");
console.log(JSON.stringify(inter) );
//console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
return this.addInterceptor(inter);
};
var a = Java.use("cn.shihuo.modulelib.startup.core.c.a");
a.intercept.implementation = function (chain) {
var req = chain.request();
var httpUrl = req.url().toString();
if( httpUrl.indexOf("https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_shoe/preload/single") != -1 ){
console.log('执行前',httpUrl);
}
var res = this.intercept(chain);
return res;
}
var a8 = Java.use('cn.shihuo.modulelib.utils.f1.a$a');
a8.intercept.implementation = function (chain) {
var request = chain.request();
var urlString = request.url().toString();
if(urlString.indexOf("https://sh-gateway.shihuo.cn/v4/services/sh-goodsapi/app_swoole_zone/getAttributes/v")!= -1){
console.log("拦截器8-->", urlString);
}
var response = chain.proceed(request);
return response;
//console.log("拦截器",this.b.value);
//var res = this.intercept(chain);
//console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
//return res;
};
function mapToString(map) {
var Map = Java.use('java.util.Map');
var Set = Java.use('java.util.Set');
var Iterator = Java.use('java.util.Iterator');
var result = "{";
var keySet = map.keySet();
var it = keySet.iterator();
while (it.hasNext()) {
var key = it.next();
var value = map.get(key);
result += "\"" + key.toString() + "\": \"" + value.toString() + "\", ";
}
// Remove trailing comma and space, if any
if (result.length > 1) {
result = result.substring(0, result.length - 2);
}
result += "}";
return result;
}
function mapToJson(map) {
if (map === null || typeof map.entrySet !== 'function') {
console.error('Invalid map object:', map);
return '{}';
}
var HashMap = Java.use('java.util.HashMap');
var Iterator = Java.use('java.util.Iterator');
var JSONObject = Java.use('org.json.JSONObject');
var json = JSONObject.$new();
var castedMap = Java.cast(map, HashMap);
var iterator = castedMap.entrySet().iterator();
while (iterator.hasNext()) {
var entry = iterator.next();
json.put(entry.getKey().toString(), entry.getValue().toString());
}
return json.toString();
};
function showStacks() {
var Exception = Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();
if (undefined == straces || null == straces) {
return;
}
console.log("============================= Stack strat=======================");
console.log("");
for (var i = 0; i < straces.length; i++) {
var str = " " + straces[i].toString();
console.log(str);
}
console.log("============================= Stack end=======================\r\n");
Exception.$dispose();
}
Java.choose('com.apm.insight.k.j', {
onMatch: function (instance) {
// 对于每一个找到的实例,调用其 sayHello 方法
console.log(111)
var res = instance.a();
console.log("aid:",res);
},
onComplete: function () {
console.log('Enumeration complete.');
}
});
请运行需要脱壳的APK
frida-dexdump -FU -d -o .
frida-trace -UF -j 'java.security.MessageDigest!digest'
{
/**
* Called synchronously when about to call MessageDigest.digest.
*
* @this {object} - The Java class or instance.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Java method arguments.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onEnter(log, args, state) {
//将byte[]转成String的方法
function bytesToString(arr) {
var str = '';
arr = new Uint8Array(arr);
for (var i in arr) {
str += String.fromCharCode(arr[i]);
}
return str;
}
if (args.length > 0 ) {
if (args.length == 1) {
log(`arg0:}`, bytesToString(args[0]));
}
}
log(`MessageDigest.digest(${args.map(JSON.stringify).join(', ')})`);
},
/**
* Called synchronously when about to return from MessageDigest.digest.
*
* See onEnter for details.
*
* @this {object} - The Java class or instance.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
function bytesToHex(arr) {
var str = '';
var k, j;
for (var i = 0; i < arr.length; i++) {
k = arr[i];
j = k;
if (k < 0) {
j = k + 256;
}
if (j < 16) {
str += "0";
}
str += j.toString(16);
}
return str;
}
if (retval !== undefined) {
var md5 = bytesToHex(retval);
log(`<= ${JSON.stringify(retval)},md5: ${md5} `);
}
}
}
overload 函数中来指定方法重载:
基本类型:
boolean: 布尔值,true 或 false
byte: 8位整数
char: 字符
short: 16位整数
int: 32位整数
long: 64位整数
float: 32位浮点数
double: 64位浮点数
对象类型:
java.lang.String: 字符串
java.lang.Object: 对象
java.lang.Integer: 整数对象
java.lang.Long: 长整数对象
java.lang.Boolean: 布尔对象
...以及其他任何 Java 类
数组类型:
[B: byte 数组
[C: char 数组
[D: double 数组
[F: float 数组
[I: int 数组
[J: long 数组
[S: short 数组
[Z: boolean 数组
[Ljava.lang.String;: 字符串数组
[Ljava.lang.Object;: 对象数组
function testDex(){
var ddex = Java.openClassFile("/data/local/tmp/Md5Util.dex");
Java.perform(function () {
ddex.load();
var Md5Util = Java.use("com.example.jnitest.Md5Util");
var res = Md5Util.reverseToSendA('V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003');
console.log("结果:",res);
});
}
javac -source 1.8 -target 1.8 Md5Util.java
mkdir -p com/example/jnitest
mv Md5Util.class com/example/jnitest/
jar cf Md5Util.jar com
/Users/admin/Library/Android/sdk/build-tools/30.0.3/dx --dex --output=Md5Util.dex Md5Util.jar
/Users/admin/Library/Android/sdk/build-tools/30.0.3/aapt dump badging /Users/admin/go/reverse/kanxue/课件资料/3月-Frida高级逆向/课时3/xman.apk | grep native-code
adb shell getprop ro.product.cpu.abi
https://blog.csdn.net/weixin_38927522/article/details/127120012
sudo xattr -rd com.apple.quarantine /Users/admin/go/reverse/tool/IDA\ Pro\ 7.0/ida64.app