-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
439 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,111 @@ | ||
function CallWX(jsapi_name, data) { | ||
let CallWX_asyncRequestCounter = 0; | ||
let Call_AppId = null; | ||
let AppId = null; | ||
|
||
function CallWX(appid, jsapi_name, data) { | ||
Call_AppId = appid; | ||
// CallWX_asyncRequestCounter = 0 | ||
Java.perform(function () { | ||
let I = 1; | ||
function dumpAllFieldValue(obj) { | ||
if (obj === null) { | ||
return; | ||
} | ||
var cls = obj.getClass(); | ||
while (cls !== null && !cls.equals(Java.use("java.lang.Object").class)) { | ||
var fields = cls.getDeclaredFields(); | ||
if (fields === null || fields.length === 0) { | ||
cls = cls.getSuperclass(); | ||
continue; | ||
} | ||
// if (!cls.equals(obj.getClass())) { | ||
// console.log("Dump super class " + cls.getName() + " fields:"); | ||
// } | ||
|
||
for (var i = 0; i < fields.length; i++) { | ||
var field = fields[i]; | ||
field.setAccessible(true); | ||
var name = field.getName(); | ||
var value = field.get(obj); | ||
var type = field.getType(); | ||
if (name === "C") { | ||
return value | ||
} | ||
// console.log(type + " " + name + "=" + value); | ||
} | ||
|
||
cls = cls.getSuperclass(); | ||
} | ||
} | ||
|
||
function getFieldValue(obj, fieldName) { | ||
var cls = obj.getClass(); | ||
var field = cls.getDeclaredField(fieldName); | ||
field.setAccessible(true); | ||
var name = field.getName(); | ||
var value = field.get(obj); | ||
// console.log("field: " + field + "\tname:" + name + "\tvalue:" + value); | ||
return value; | ||
} | ||
|
||
CallWX_asyncRequestCounter++; | ||
Java.choose('com.tencent.mm.appbrand.commonjni.AppBrandCommonBindingJni', { | ||
onMatch: function (instance) { | ||
// console.log(I, JSON.stringify(instance.mAppBrandDelegate)) | ||
instance.nativeInvokeHandler(jsapi_name, data, '{}', I++, true) | ||
// instance.nativeInvokeHandler('login', '{"requestInQueue":false}', '{}', I++, true) | ||
// CallWX_asyncRequestCounter++; | ||
// console.log(CallWX_asyncRequestCounter, instance.mNativeHandle.value, JSON.stringify(instance.mAppBrandDelegate)) | ||
try { | ||
let mAppBrandDelegate = getFieldValue(instance, 'mAppBrandDelegate') | ||
let g = getFieldValue(mAppBrandDelegate, 'g') | ||
dumpAllFieldValue(g) | ||
let C = dumpAllFieldValue(g) | ||
if (C.toString() !== '{__APP__=true}') { | ||
return; | ||
} | ||
} catch { | ||
return; | ||
} | ||
|
||
|
||
instance.nativeInvokeHandler(jsapi_name, data, '{}', CallWX_asyncRequestCounter, true) | ||
|
||
}, | ||
onComplete: function () { | ||
} | ||
}) | ||
}) | ||
// Call_AppId = null | ||
return `${Call_AppId}${CallWX_asyncRequestCounter}`; | ||
} | ||
|
||
function Main() { | ||
|
||
Java.perform(function () { | ||
Java.perform(function () { | ||
|
||
let AppBrandCommonBindingJni = Java.use("com.tencent.mm.appbrand.commonjni.AppBrandCommonBindingJni"); | ||
AppBrandCommonBindingJni["nativeInvokeHandler"].implementation = function (jsapi_name, data, str3, asyncRequestCounter, z15) { | ||
console.log(`[${asyncRequestCounter}] == \x1b[36m[requests]\x1b[0m: jsapi_name=${jsapi_name}, data=${data}, str3=${str3}, z15=${z15}`); | ||
return this["nativeInvokeHandler"](jsapi_name, data, str3, asyncRequestCounter, z15); | ||
}; | ||
let v = Java.use("com.tencent.mm.plugin.appbrand.v"); | ||
v["getAppId"].implementation = function () { | ||
AppId = this["getAppId"](); | ||
return AppId; | ||
}; | ||
|
||
let AppBrandJsBridgeBinding = Java.use('com.tencent.mm.appbrand.commonjni.AppBrandJsBridgeBinding'); | ||
AppBrandJsBridgeBinding['invokeCallbackHandler'].implementation = function (asyncRequestCounter, res) { | ||
console.log(`[${asyncRequestCounter}] == \x1b[32m[response]\x1b[0m: ${res}`) | ||
this['invokeCallbackHandler'](asyncRequestCounter, res) | ||
} | ||
let AppBrandCommonBindingJni = Java.use("com.tencent.mm.appbrand.commonjni.AppBrandCommonBindingJni"); | ||
AppBrandCommonBindingJni["nativeInvokeHandler"].implementation = function (jsapi_name, data, str3, asyncRequestCounter, z15) { | ||
CallWX_asyncRequestCounter = asyncRequestCounter; | ||
console.log(`[${AppId}] [${asyncRequestCounter}] == \x1b[36m[requests]\x1b[0m: jsapi_name=${jsapi_name}, data=${data}, str3=${str3}, z15=${z15}`); | ||
|
||
return this["nativeInvokeHandler"](jsapi_name, data, str3, asyncRequestCounter, z15); | ||
}; | ||
|
||
let AppBrandJsBridgeBinding = Java.use('com.tencent.mm.appbrand.commonjni.AppBrandJsBridgeBinding'); | ||
AppBrandJsBridgeBinding['invokeCallbackHandler'].implementation = function (asyncRequestCounter, res) { | ||
console.log(`[${AppId}] [${asyncRequestCounter}] == \x1b[32m[response]\x1b[0m: ${res}`) | ||
|
||
this['invokeCallbackHandler'](asyncRequestCounter, res) | ||
} | ||
) | ||
} | ||
|
||
setTimeout(Main, 500) | ||
} | ||
) | ||
|
||
|
||
rpc.exports = {call: CallWX} | ||
// frida -U -l Hook_WeChat_FaaS.js com.tencent.mm --no-pause | ||
|
||
// frida -U -l Hook_WeChat_FaaS.js com.tencent.mm --no-pause | ||
// CallWX('wx3c12cdd0ae8b1a7b', 'operateWXData', '{"data":{"api_name":"webapi_getuserinfo","data":{"lang":"en","version":"3.4.3"},"operate_directly":false,"with_credentials":true,"tid":1716198903418},"requestInQueue":true,"isImportant":true}') | ||
// CallWX('wx3c12cdd0ae8b1a7b', 'setStorageSync', '{"key":"sensors_mp_prepare_data","data":"[]","dataType":"Array","storageId":0}') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,46 @@ | ||
# Hook_WeChat_FaaS | ||
frida Hook 微信云函数脚本 | ||
|
||
![](https://raw.githubusercontent.com/FourTwooo/Hook_WeChat_FaaS/main/cesi.png) | ||
|
||
## 环境 | ||
|
||
开发测试环境. 理论来说 安卓APP应该是不限版本 通用的 | ||
|
||
- Android => 10 | ||
|
||
- frida => 14.2.18 | ||
|
||
- 微信安卓APP => 8.0.49 | ||
|
||
|
||
|
||
## 运行 | ||
|
||
|
||
在小程序界面时运行以下命令或使用进程ID去运行 | ||
``` | ||
frida -UF -l .\Hook_WeChat_FaaS.js com.tencent.mm --no-pause | ||
``` | ||
|
||
## 目前问题 | ||
|
||
主动调用那块 我是使用Java.choose 从内存中取的实例 但在内存中的实例有很多个 | ||
所以每次主动调用 都会触发好几次. 但其实只会成功一个 其他的不会成功 这个暂时没弄清楚为什么 | ||
|
||
如果要Hook多个小程序, 会存在问题. 我自己机型来看 打开多个小程序 进程ID是完全一样的 除了包名不一样 | ||
更别谈涉及微信多开这个问题 | ||
|
||
这些问题 在上班时间 我会逐步修复. 这个项目也是因为公司业务有需求 临时开发. 开源了有自己想法的可以自己二次开发 | ||
|
||
|
||
## 参考文章 | ||
|
||
- [看雪论坛 作者ID:Sharp_Wang](https://mp.weixin.qq.com/s/7yZzf4V-2fcn-jRwm4uO-w) | ||
|
||
## 支持 | ||
|
||
实际上并没有多少技术含量. 其实就是HOOK了 请求和响应的代码位置. 没有什么技术含量 | ||
|
||
开源不易, 可以的话支持以下 | ||
![](https://github.com/FourTwooo/Hook_WeChat_FaaS/blob/main/wx.jpg?raw=true) | ||
|
||
QQ交流群: 1021904342 | ||
# Hook_WeChat_FaaS | ||
frida Hook 微信云函数脚本 | ||
|
||
![](https://raw.githubusercontent.com/FourTwooo/Hook_WeChat_FaaS/main/cesi.png) | ||
|
||
## 环境 | ||
|
||
开发测试环境. 理论来说 安卓APP应该是不限版本 通用的 | ||
|
||
- Android => 10 | ||
|
||
- frida => 14.2.18 | ||
|
||
- 微信安卓APP => 8.0.49 | ||
|
||
|
||
|
||
## 运行 | ||
|
||
|
||
在小程序界面时运行以下命令或使用进程ID去运行 | ||
``` | ||
frida -UF -l .\Hook_WeChat_FaaS.js com.tencent.mm --no-pause | ||
``` | ||
|
||
## 目前问题 | ||
|
||
主动调用可能调用部分api会存在bug | ||
|
||
涉及微信多开的hook 暂时未适配 | ||
|
||
这个项目也是因为公司业务有需求 临时开发. 开源了有自己想法的可以自己二次开发 | ||
|
||
|
||
## 参考文章 | ||
|
||
- [看雪论坛 作者ID:Sharp_Wang](https://mp.weixin.qq.com/s/7yZzf4V-2fcn-jRwm4uO-w) | ||
|
||
## 支持 | ||
|
||
实际上并没有多少技术含量. 其实就是HOOK了 请求和响应的代码位置. 没有什么技术含量 | ||
|
||
开源不易, 可以的话支持以下 | ||
![](https://github.com/FourTwooo/Hook_WeChat_FaaS/blob/main/wx.jpg?raw=true) | ||
|
||
QQ交流群: 1021904342 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
let CallWX_asyncRequestCounter = 0; | ||
let Call_AppId = null; | ||
let AppId = null; | ||
|
||
function CallWX(appid, jsapi_name, data) { | ||
Call_AppId = appid; | ||
// CallWX_asyncRequestCounter = 0 | ||
Java.perform(function () { | ||
function dumpAllFieldValue(obj) { | ||
if (obj === null) { | ||
return; | ||
} | ||
var cls = obj.getClass(); | ||
while (cls !== null && !cls.equals(Java.use("java.lang.Object").class)) { | ||
var fields = cls.getDeclaredFields(); | ||
if (fields === null || fields.length === 0) { | ||
cls = cls.getSuperclass(); | ||
continue; | ||
} | ||
// if (!cls.equals(obj.getClass())) { | ||
// console.log("Dump super class " + cls.getName() + " fields:"); | ||
// } | ||
|
||
for (var i = 0; i < fields.length; i++) { | ||
var field = fields[i]; | ||
field.setAccessible(true); | ||
var name = field.getName(); | ||
var value = field.get(obj); | ||
var type = field.getType(); | ||
if (name === "C"){ | ||
return value | ||
} | ||
// console.log(type + " " + name + "=" + value); | ||
} | ||
|
||
cls = cls.getSuperclass(); | ||
} | ||
} | ||
|
||
function getFieldValue(obj, fieldName) { | ||
var cls = obj.getClass(); | ||
var field = cls.getDeclaredField(fieldName); | ||
field.setAccessible(true); | ||
var name = field.getName(); | ||
var value = field.get(obj); | ||
// console.log("field: " + field + "\tname:" + name + "\tvalue:" + value); | ||
return value; | ||
} | ||
|
||
CallWX_asyncRequestCounter++; | ||
Java.choose('com.tencent.mm.appbrand.commonjni.AppBrandCommonBindingJni', { | ||
onMatch: function (instance) { | ||
// CallWX_asyncRequestCounter++; | ||
// console.log(CallWX_asyncRequestCounter, instance.mNativeHandle.value, JSON.stringify(instance.mAppBrandDelegate)) | ||
try { | ||
let mAppBrandDelegate = getFieldValue(instance, 'mAppBrandDelegate') | ||
let g = getFieldValue(mAppBrandDelegate, 'g') | ||
dumpAllFieldValue(g) | ||
let C = dumpAllFieldValue(g) | ||
if (C.toString() !== '{__APP__=true}'){ | ||
return; | ||
} | ||
} catch { | ||
return; | ||
} | ||
|
||
|
||
instance.nativeInvokeHandler(jsapi_name, data, '{}', CallWX_asyncRequestCounter, true) | ||
|
||
}, | ||
onComplete: function () { | ||
} | ||
}) | ||
}) | ||
// Call_AppId = null | ||
return `${Call_AppId}${CallWX_asyncRequestCounter}`; | ||
} | ||
|
||
|
||
Java.perform(function () { | ||
|
||
let v = Java.use("com.tencent.mm.plugin.appbrand.v"); | ||
v["getAppId"].implementation = function () { | ||
if (Call_AppId === null) { | ||
AppId = this["getAppId"](); | ||
} else { | ||
AppId = Call_AppId; | ||
} | ||
// result = 'wx3c12cdd0ae8b1a7b'; | ||
// console.log(`v.getAppId result=${result}`); | ||
return AppId; | ||
}; | ||
|
||
// let o0 = Java.use("com.tencent.mm.plugin.appbrand.jsapi.auth.o0"); | ||
// o0["d"].implementation = function (rdVar) { | ||
// console.log(`o0.d is called: rdVar=${rdVar}`); | ||
// this["d"](rdVar); | ||
// }; | ||
|
||
// let AppBrandRuntime = Java.use("com.tencent.mm.plugin.appbrand.AppBrandRuntime"); | ||
// AppBrandRuntime["k0"].implementation = function (appBrandInitConfig) { | ||
// console.log(`AppBrandRuntime.k0 is called: appBrandInitConfig=${appBrandInitConfig}`); | ||
// this["k0"](appBrandInitConfig); | ||
// }; | ||
|
||
|
||
let AppBrandCommonBindingJni = Java.use("com.tencent.mm.appbrand.commonjni.AppBrandCommonBindingJni"); | ||
AppBrandCommonBindingJni["nativeInvokeHandler"].implementation = function (jsapi_name, data, str3, asyncRequestCounter, z15) { | ||
CallWX_asyncRequestCounter = asyncRequestCounter; | ||
// console.log(`[${AppId}] [${asyncRequestCounter}] == \x1b[36m[requests]\x1b[0m: jsapi_name=${jsapi_name}, data=${data}, str3=${str3}, z15=${z15}`); | ||
send(JSON.stringify({ | ||
type: 'requests', | ||
AppId: AppId, | ||
asyncRequestCounter: asyncRequestCounter, | ||
jsapi_name: jsapi_name, | ||
data: data, | ||
str3: str3, | ||
z15: z15 | ||
})) | ||
return this["nativeInvokeHandler"](jsapi_name, data, str3, asyncRequestCounter, z15); | ||
}; | ||
|
||
let AppBrandJsBridgeBinding = Java.use('com.tencent.mm.appbrand.commonjni.AppBrandJsBridgeBinding'); | ||
AppBrandJsBridgeBinding['invokeCallbackHandler'].implementation = function (asyncRequestCounter, res) { | ||
// console.log(`[${AppId}] [${asyncRequestCounter}] == \x1b[32m[response]\x1b[0m: ${res}`) | ||
send(JSON.stringify({ | ||
type: 'response', | ||
AppId: AppId, | ||
asyncRequestCounter: asyncRequestCounter, | ||
res: res | ||
})) | ||
this['invokeCallbackHandler'](asyncRequestCounter, res) | ||
} | ||
|
||
} | ||
) | ||
|
||
|
||
rpc.exports = {call: CallWX} | ||
// frida -U -l Hook_WeChat_FaaS.js com.tencent.mm --no-pause | ||
|
||
// CallWX('wx3c12cdd0ae8b1a7b', 'operateWXData', '{"data":{"api_name":"webapi_getuserinfo","data":{"lang":"en","version":"3.4.3"},"operate_directly":false,"with_credentials":true,"tid":1716198903418},"requestInQueue":true,"isImportant":true}') | ||
// CallWX('wx3c12cdd0ae8b1a7b', 'setStorageSync', '{"key":"sensors_mp_prepare_data","data":"[]","dataType":"Array","storageId":0}') |
Oops, something went wrong.