me.jsonet.jshook
me.jsonet.jshook copied to clipboard
用js实现hook 支持java层和native层
关于
xposed是一个模块框架,可以在不接触任何apk的情况下更改系统和应用程序的行为。这意味着模块可以在不同版本甚至rom上工作而无需任何更改。
jshook是对app注入rhino/frida,xposed模块开发需要一定的java语法基础,技术门槛高,而jshook注入的rhino/frida只需要会简短的js,即可用手机快速实现hook,并且hook支持java层和native层。
兼容
- Xposed api 82
- Android 5 - 12
如何使用
如何启用脚本
启用脚本前请确认选择的应用已开启hook服务选项,如果是lsposed非全局作用域在激活时除了勾选系统还需勾选对应脚本生效的应用,每次更改脚本内容都需要重启一下被hook的app。
如何选择注入框架
如果你对xposed的hook方法比较熟,推荐rhino,使用js调用xposed框架的api,且兼容性高;而frida属于另一个hook框架,需要对frida有一定的了解,上手较难,且不支持部分机型和app。
脚本说明
通用
日志打印:
common.log('...');
console.log('...');
消息提示:
common.toast('...');
弹窗提示:
common.dialog('...');
获取Context:
common.getcontext();
mod菜单:
| modmenu | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| title | String | 标题 | N |
| item | Array | 菜单项 | Y |
| title | String | 标题 | N |
| change | Function | 回调 | N |
示例:
common.modmenu('test mod', [
{
'id': '1',
'type': 'category',
'title': 'category title'
},
{
'id': '2',
'type': 'switch',
'title': 'switch1 title',
'enable': true
},
{
'id': '3',
'type': 'switch',
'title': 'switch2 title'
},
{
'id': '4',
'type': 'webview',
'data': '<font color="red"><b>text</b></font>',
//or
//'url': 'http://xxxxx.com'
},
{
'id': '5',
'type': 'button',
'title': 'button title'
},
{
'id': '6',
'type': 'input',
'title': 'input title',
'val': 'default value'
},
{
'type': 'collapse',
'title': 'collapse title',
'item': [
{
'id': '7',
'type': 'switch',
'title': 'switch title'
}
],
'enable': true
},
{
'id': '8',
'type': 'slider',
'title': 'slider title',
'val': 88,
'min': 1,
'max': 100
},
{
'id': '9',
'type': 'checkbox',
'title': 'checkbox title',
'enable': true
},
{
'type': 'checkboxs',
'item': [
{
'id': '10',
'type': 'checkbox',
'title': '1 title'
},
{
'id': '11',
'type': 'checkbox',
'title': '2 title'
},
{
'id': '12',
'type': 'checkbox',
'title': '33333333 title'
}
]
},
{
'id': '13',
'type': 'radio',
'title': 'radio title',
'item': ['test', 'test2', 'test3']
}
], function (data) {
common.toast(JSON.stringify(data));
});
带tab选项卡的示例:
common.modmenu('test mod', [
{
'type': 'tab',
'title': 'tab1 title',
'item': [
{
'id': '1',
'type': 'switch',
'title': 'switch1 title'
}
],
'enable': true
},
{
'type': 'tab',
'title': 'tab2 title',
'item': [
{
'id': '2',
'type': 'switch',
'title': 'switch2 title'
}
]
}
], function (data) {
common.toast(JSON.stringify(data));
});
注意:使用mod菜单需要让jshook保持运行状态且授权悬浮窗权限,关闭jshook会导致菜单关闭,不影响hook服务
rhino
获取LoadPackageParam
| getlpparam | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| 无 | |||
示例:
common.getlpparam();
获取类实例
| findClass | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | String | 类名 | Y |
| classLoader | ClassLoader | 类加载器 | Y |
示例:
common.findClass('com.test.test', classLoader);
hook构造函数
| hookAllConstructors | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| beforeHookedMethod | Function | 构造函数执行前 | N |
| afterHookedMethod | Function | 构造函数执行后 | N |
| replaceHookedMethod | Function | 替换构造函数执行过程 | N |
示例:
common.hookAllConstructors('com.test.test', function (param) {
//构造函数执行前
//打印构造函数接收到的第一个参数
common.log(param.args[0]);
//修改这个参数的值
param.args[0] = 'fuck';
}, function (param) {
//构造函数执行后
//...
});
hook指定参数的构造函数
| hookConstructor | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| paramTypes | Object[] | 参数类型 | Y |
| beforeHookedMethod | Function | 构造函数执行前 | N |
| afterHookedMethod | Function | 构造函数执行后 | N |
| replaceHookedMethod | Function | 替换构造函数执行过程 | N |
示例:
common.hookConstructor('com.test.test', ['java.lang.String', 'int'], function (param) {
//...
}, function (param) {
//...
});
hook类方法
| hookAllMethods | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| beforeHookedMethod | Function | 函数执行前 | N |
| afterHookedMethod | Function | 函数执行后 | N |
| replaceHookedMethod | Function | 替换函数执行过程 | N |
示例:
common.hookAllMethods('com.test.test', 'methodname', function (param) {
//...
}, function (param) {
//...
}, function (param) {
//调用原方法返回
return common.thisMethod(param);
});
hook指定的类方法
| hookByMethod | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| method | Method | 方法对象 | Y |
| beforeHookedMethod | Function | 函数执行前 | N |
| afterHookedMethod | Function | 函数执行后 | N |
| replaceHookedMethod | Function | 替换函数执行过程 | N |
示例:
common.hookByMethod(method, function (param) {
//...
//修改返回值
param.setResult('fuck');
}, function (param) {
//...
//获取类方法的返回值并打印
common.log(param.getResult());
});
hook指定参数的类方法
| hookMethod | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | String | 类名 | Y |
| paramTypes | Object[] | 参数类型 | Y |
| beforeHookedMethod | Function | 函数执行前 | N |
| afterHookedMethod | Function | 函数执行后 | N |
| replaceHookedMethod | Function | 替换函数执行过程 | N |
示例:
common.hookMethod('com.test.test', 'methodname', ['java.lang.String', 'int'], function (param) {
//...
//修改返回值
param.setResult('fuck');
}, function (param) {
//...
//获取类方法的返回值并打印
common.log(param.getResult());
});
修改静态变量值
| setStaticObjectField | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| fieldName | String | 变量名 | Y |
| fieldValue | Object | 变量值 | Y |
示例:
common.setStaticObjectField('com.test.test', '变量名', '变量值');
修改动态变量值
| setObjectField | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类名或者当前实例 | Y |
| fieldName | String | 变量名 | Y |
| fieldValue | Object | 变量值 | Y |
示例:
common.setObjectField('com.test.test', '变量名', '变量值');
//或者
//param.thisObject 在hook回调方法中获取
common.setObjectField(param.thisObject, '变量名', '变量值');
获取静态变量值
| getStaticObjectField | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| fieldName | String | 变量名 | Y |
示例:
common.getStaticObjectField('com.test.test', '变量名');
获取动态变量值
| getObjectField | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类名或者当前实例 | Y |
| fieldName | String | 变量名 | Y |
示例:
common.getObjectField('com.test.test', '变量名');
主动调用动态方法
| callMethod | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类名或者当前实例 | Y |
| methodMame | String | 方法名 | Y |
| paramTypes | Object[] | 参数值 | N |
示例:
common.callMethod('com.test.test', 'methodname', ['a', 1]);
主动调用静态方法
| callStaticMethod | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| className | Object | 类实例或类名 | Y |
| methodMame | String | 方法名 | Y |
| paramTypes | Object[] | 参数值 | N |
示例:
common.callStaticMethod('com.test.test', 'methodname', ['a', 1]);
replaceHookedMethod中调用原方法
| thisMethod | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| param | Object | 参数 | Y |
示例:
//param在replaceHookedMethod中获取
common.thisMethod(param);
frida
fridamod
curl
| curl | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| url | String | 地址 | Y |
| method | String | 请求类型 | N |
| header | Array | 头部信息 | N |
| data | Object | 提交数据 | N |
| callback | Function | 回调 | N |
示例:
common.curl('https://xxxxx.com', 'post', ['token: sssss'], {data: '111'}, function (data) {
common.log(data);
});
shell
| shell | |||
| 参数 | 参数类型 | 参数说明 | 是否必填 |
| content | String | 内容 | Y |
示例:
common.shell('curl https://xxxxx.com', function (data) {
common.log(data);
});