Hook 通杀

Hook 普通方法和修改函数参数返回值

fradaserver 是手机端的,

  1. android低版本 frida 尽量低版本
  2. fridaserver版本要与frida库版本一致
  3. 不同平台用不同fridaserver
  4. 不要和xposed装一起,新疆模拟器,刷机

设备要求:

​ root

调试

下载frida-server push到手机中 (注意查看手机是86的还是64的)

adb push .\frida-server-12.8.14-android-x86 /data/local/tmp/fsx86

image-20200319214805400

之后cd到tmp目录下

先给fsx86 赋权 chmod 777 fsx86

之后执行即可。 ./fsx86

执行后有一个报错,这里是版本出现的问题,会有一些小bug ,不影响使用,最好还是在真机中调试

WARNING: linker: ./fsx86: unused DT entry: type 0x6ffffef5 arg 0x1c24

插入一个学习

image-20200320103048870

Hook 构造方法

​ 绕过一些验证

​ 构造方法

money.$init.implementation = function(){}

Hook 重载方法

image-20200320105658343

Hook 重载方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function hooktest2() {
//Error: test(): has more than one overload, use .overload(<signature>)
var utils = Java.use("com.xiaojianbang.app.Utils");
utils.test.overload('int').implementation = function (a) {
a = 888;
var retval = this.test();
console.log(a, retval);
return retval;
};
utils.test.overload().implementation = function () {
var retval = this.test();
console.log(retval);
return retval;
};
utils.test.overload('com.xiaojianbang.app.Money').implementation = function (a) {
var retval = this.test(a);
console.log(retval);
return retval;
}
}

Hook 所有重载方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function hookTest3() {
// hook 方法的所有重载
var utils = Java.use("com.xiaojianbang.app.Utils");
console.log(utils.test.overloads.length);
for (var i = 0; i < utils.test.overloads.length; i++) {
utils.test.overloads[i].implementation = function () {
// console.log(JSON.stringify(arguments));

if (arguments.length == 0) {
return "调用没有参数的";
} else if (arguments.length == 1){
if (JSON.stringify(arguments).indexOf("Money") != -1){
return "调用了Money参数的";
}else{
return "调用了Int 类型的";
}
}

arguments[0] = 1000;
// console.log(arguments.length);
// apply 改变所属
return this.test.apply(this, arguments);
}
}
}

Hook 构造参数与对象实例化

image-20200321172539738

image-20200321173626852

1
2
3
4
5
6
7
8
9
10
11
function hooktest2() {
//Error: test(): has more than one overload, use .overload(<signature>)
var utils = Java.use("com.xiaojianbang.app.Utils");
var money = Java.use("com.xiaojianbang.app.Money");

utils.test.overload('int').implementation = function (a) {
a = 888;
var retval = this.test(money.$new("日元", 1000000)); // 对象实例化
console.log(a, retval);
return retval;
};

hook 实例化

image-20200321174929718

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function hookTest5() {
Java.perform(function () {
//静态字段的修改
var money = Java.use("com.xiaojianbang.app.Money");
//send(JSON.stringify(money.flag));
money.flag.value = "ceshi";
console.log('log', money.flag.value);
// 非静态字段的修改
Java.choose("com.xiaojianbang.app.Money", {
onMatch: function (obj) {
obj._name.value = "ouyuan"; // 字段与函数名相同, 前面加下划线
obj.num.value = 15254131;
},
onComplete: function () {

},
});
});
}

获取所有的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function hookTest7() {
Java.perform(function () {
Java.enumerateLoadedClasses({
onMatch:function (name,handle) {
if (name.indexOf("com.xiaojianbang.app") != -1){
console.log(name);
var clazz = Java.use(name);
var methods = clazz.class.getDeclaredMethods();
console.log(methods)
for (var i = 0 ; i< methods.length;i++){
console.log(methods[i]);
}
}
},
onComplete:function () {

},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
var classes = Java.enumerateLoadedClassesSync();
for (var i = 0 ; i < classes.length ; i++){
if (classes[i].indexOf("com.xiaojianbang.app") != -1){
console.log(classes[i]);
var clazz = Java.use(classes[i]);
var methods = clazz.class.getDeclaredMethods();
for (var j = 0 ;j < methods.length ;j++){
console.log(methods[j]);
}
}


}

Hook 回笼重造

image-20200324171350015

xposed 框架替换了很多文件,如果要从xposed转frida 需要刷机

修改debuggable 参考:https://www.bodkin.ren/index.php/archives/533/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Go0s]: ~/Security/_Tools/Android/mprop/armeabi-v7a ✗ master*
➜ adb push mprop /data/local/tmp
mprop: 1 file pushed. 1.6 MB/s (17712 bytes in 0.011s)
[Go0s]: ~
➜ adb shell
shell@hammerhead:/ $ cat default.prop | grep debug
ro.debuggable=0
shell@hammerhead:/ $ getprop ro.debuggable
0
shell@hammerhead:/ $ cd /data/local/tmp
shell@hammerhead:/data/local/tmp $ su
root@hammerhead:/data/local/tmp # ./mprop ro.debuggable 1
properties map area: b6f7a000-b6f9a000
00000000 08 8d 00 00 19 01 00 00 50 52 4f 50 ab d0 6e fc ........PROP??n?
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
……
root@hammerhead:/ # cat default.prop | grep debug
ro.debuggable=0
root@hammerhead:/ # getprop ro.debuggable
1

版本太高导致的问题,问题不会大

image-20200324192712444

配置代码提示

i @types/frida-gum```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26



hook步骤

1. 进入手机终端 启动 fsx86
2. 端口转发
3. 使用命令开始hook吧 `frida -U 包名 -l hook代码`

### 逻辑分析

要hook getCalc 方法,定位到函数声明

![image-20200324201846328](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324201846328.png)

定位到getCalc 方法有两个参数 a,b

![image-20200324201919870](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324201919870.png)

### Hook普通方法

接下来根据这个函数开始hook

​ `var utils = Java.use("com.xiaojianbang.app.Utils");` 定位函数

​ 重写方法 implementation

var utils = Java.use(“com.xiaojianbang.app.Utils”);
utils.getCalc.implementation = function (a,b) { // implementation 是重写方法, js中不需要函数类型
// 先打印一下a,b 参数和返回的参数
var retval = this.getCalc(a,b);

console.log(a,b,retval);
return retval;

}

1
2
3
4
5
6

​ 点击普通方法,即可在frida中看到获取的参数

![image-20200324202244461](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324202244461.png)

之后修改a ,b 参数

var utils = Java.use(“com.xiaojianbang.app.Utils”);
utils.getCalc.implementation = function (a,b) { // implementation 是重写方法, js中不需要函数类型
a = 123;
b = 345;

var retval = this.getCalc(a,b);

console.log(a,b,retval);
return retval;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

![image-20200324203353529](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324203353529.png)



### Hook 重载方法和重载方法的Hook

重载方法和一般普通方法区别不大

![image-20200324205305292](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324205305292.png)

当使用之前的方法 去hook重载方法

![image-20200324205229878](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324205229878.png)

需要使用overload 去指定参数
utils.test.overload('int').implementation = function (a, b) { // implementation 是重写方法, js中不需要函数类型
1
2
3
4

最后hook所有的重载方法

只要符合返回值,可以随意改的,即使调用其他的重载函数也是可以执行

utils.test.overload(‘int’).implementation = function (a) { // implementation 是重写方法, js中不需要函数类型
a = 888888888;
var retval = this.test(a);
console.log(a, retval);
return retval;
};
utils.test.overload().implementation = function () {
var retval = this.test();
console.log(“无参:”,retval);
return retval;
};
utils.test.overload(“com.xiaojianbang.app.Money”).implementation = function (a) {
var retval = this.test(a);
console.log(a,retval);
return retval;
};

1
2

Hook所有重载函数

for (var i = 0 ;i < utils.test.overloads.length;i++){ // 通过for 循环去获取每一个
utils.test.overloads[i].implementation = function () {
console.log(arguments); // arguments 是一个数组
}
}

1
2

通过apply 可以避免每次返回需要改变返回参数的问题

this.test.apply(this,arguments) // apply 是改变函数所属

1
2
3
4

> 在frida 中,在同位置下多个钩子 最后一个会生效,因为他的代码会覆盖之前的代码。

返回hook每个重载函数 参数长度

function hookTest3() {
// hook方法的所有重载
var utils = Java.use(“com.xiaojianbang.app.Utils”);
console.log(utils.test.overloads.length)
// 之后遍历参数
for (var i = 0 ;i < utils.test.overloads.length;i++){
utils.test.overloads[i].implementation = function () {
//console.log(arguments);

        return this.test.apply(this,arguments) // apply 是改变函数所属
    }
}

}

1
2
3
4
5
6

返回结果

![](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324213234513.png)

如果需要修改其中的某个重载函数 则需要在这里做一个判断

if (arguments.length == 0){
return “xiaojianbang”;
}

1
2
3
4



hook 完整代码

function hookTest3() {
// hook方法的所有重载
var utils = Java.use(“com.xiaojianbang.app.Utils”);
console.log(utils.test.overloads.length)
// 之后遍历参数
for (var i = 0 ;i < utils.test.overloads.length;i++){
utils.test.overloads[i].implementation = function () {
//console.log(arguments);
if (arguments.length == 0){
return “xiaojianbang”;
}else if (arguments.length == 1){
if (JSON.stringify(arguments).indexOf(“Money”) != -1 ){
return “调用了Money参数”;
} else{
return “ 调用了int参数的”;
}
}
return this.test.apply(this,arguments) // apply 是改变函数所属
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12

## Hook 构造函数与对象实例化

这里的`Money` 是我们的构造函数 函数与类型一致

![image-20200324215249350](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324215249350.png)

也需要指明

![image-20200324215639928](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324215639928.png)

构造函数和重载只是多了个 $init

function hookTest4() {
var money = Java.use(“com.xiaojianbang.app.Money”);
// 函数名与方法名一致
money.$init.overload(‘java.lang.String’,’int’).implementation = function (str,num) {
console.log(str,num);
this.$init(str,num);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

在上一节重载函数,我们调用了money ,但是当我们要修改其中的值时 需要调用money的包

![image-20200324220110549](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324220110549.png)

在函数开始位置添加

![image-20200324220151168](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324220151168.png)

这就完成了一个实例化

![image-20200324220241983](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324220241983.png)

## 修改类的字段

先尝试hook一下静态资源

var money = Java.use(“com.xiaojianbang.app.Money”);
//send(money.flag)
console.log(JSON.stringify(money.flag.value));

1
2
3
4

> 多个对象就会有多个字段,所以要修改 必须找到对应的字段

修改字段

// 静态字段
var money = Java.use(“com.xiaojianbang.app.Money”);
//send(money.flag)
money.flag.value = “xiaojianbang”;

console.log(JSON.stringify(money.flag.value));

1
2
3
4
5
6

hook 修改非静态字段

> 正常的每次修改都会new一个对象,所以看不到返回的值

![image-20200324222948009](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324222948009.png)

Java.choose(“com.xiaojianbang.app.Money”, {
onMatch: function (obj) { // 每次遍历对象都会调用一次onMatch
// 修改对象参数,如果修改单个 价格判断即可
obj._name.value = “ouyuan”; // 这块注意字段名与函数名是否相同
obj.num.value = 15000000;
},
onComplete: function () {

}

}); // cakkbacks指的是对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

> 这块注意 当字段名与函数名相同 要加`_`来区分

## hook 内部类和匿名类

当hook 类下的类 hook方法

可以通过jeb smail 去看

![image-20200324230631123](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324230631123.png)

money 只是一个父类,匿名类是getInfo 这里实现了一次, 匿名类一般都是$1 这种形式

![image-20200324231541211](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200324231541211.png)

## 枚举所有的类和所有的方法

Java.enumerateLoadedClasses() //枚举类 只能加载 已经被加载的类

1
2

java反射获取方法

var methods = clazz.class.getDeclaredMethods();

1
2

获取所有的类

Java.enumerateLoadedClasses({
onMatch:function (name,handle) { // 代码都是写在这里的
if (name.indexOf(“com.xiaojianbang.app”) != -1){
console.log(name)
}
},
onComplete:function () { // 这里只会使用一次

}

})

1
2

获取类下的方法

Java.enumerateLoadedClasses({
onMatch:function (name,handle) { // 代码都是写在这里的
if (name.indexOf(“com.xiaojianbang.app”) != -1){
console.log(name) // 类和地址 打印好多系统类,这里就要做个过滤
// 遍历类下的所有的方法 java 反射 有个getDeclaredMethods
var clazz = Java.use(name);
console.log(clazz);
var methods = clazz.class.getDeclaredMethods(); // 得到的是一个对象,这里要通过class转
//console.log(methods); // 直接打印输出较乱 做一个整理

            if (var i = 0; i < methods[i].length;i++){
                console.log(methods[i]);
            }
            console.log()



        }
    },
    onComplete:function () { // 这里只会使用一次

    }
})
1
2

异步方式获取类和类的方法

var classes = Java.enumerateLoadedClassesSync();
for (var i = 0; i < classes.length; i++) {
if (classes[i].indexOf(“com.xiaojianbang.app”) != -1) {
console.log(classes[i]);
var clazz = Java.use(classes[i]);
var methods = clazz.class.getDeclaredMethods();
for (var j = 0; j < methods.length; j++) {
console.log(methods[j]);
}
}
}

1
2
3
4

## hook类的所有方法

首先确定hook那个类, 比如md5,之后通过java反射 获取类下的方法

var md5 = Java.use(“com.xiaojianbang.app.MD5”);
var methods= md5.class.getDeclaredMethods();

1
2

之后通过循环返回打印

function hookTest8() {
Java.perform(function () {
var md5 = Java.use(“com.xiaojianbang.app.MD5”);
var methods = md5.class.getDeclaredMethods();
for (var i = 0; i < methods.length; i++) {
var methodName = methods[i].getName();
console.log(methodName);
for (var k = 0; k < md5[methodName].overloads.length; k++) {
md5[methodName].overloads[k].implementation = function () {
for (var j = 0; j < arguments.length; j++) {
console.log(arguments[j]);
}
return this[methodName].apply(this, arguments) // 不知道返回的对象
}
}

    }
})

}

1
2
3
4
5
6
7
8
9
10
11
12

## 动态加载dex

遇到问题: 在调用函数后,有些dex 是通过动态加载调用的,反编译并不会反编译到所有的dex

一般可以通过DexClassLoader动态加载,或者通过so层 或者内存中去加载

这里通过DexClassLoader去加载,文件放在apk的目录中

![image-20200325214341078](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200325214341078.png)

当直接调用就会报错

function hookTest9() {
Java.perform(function () {
var dynamic = Java.use(“com.xiaojianbang.app.Dynamic”);
console.log(dynamic);
})
}

1
2
3
4
5
6

![image-20200325214906826](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200325214906826.png)

这里就要找到对应的classloader

> 注意:这个api是要在7版本以上使用,用android5 可能会报错

function hookTest9(){
Java.perform(function(){

    Java.enumerateClassLoaders({
        onMatch: function(loader){
            try {
                if(loader.loadClass("com.xiaojianbang.app.Dynamic")){
                    Java.classFactory.loader = loader;
                    var Dynamic = Java.use("com.xiaojianbang.app.Dynamic");
                    console.log(Dynamic);
                    Dynamic.sayHello.implementation = function(){
                        return "xiaojianbang";
                    }
                }
            } catch (error) {

            }
        }
        ,
        onComplete: function(){

        }
    });
});

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

![image-20200326091943750](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200326091943750.png)



> Java.classFactory.loader = loader; 这里的loader 可能会报错 不影响正确性



## Java 里特殊类型的遍历与修改

Hook map 或者修改其中的某些值



![image-20200329001310423](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200329001310423.png)

![image-20200329001325832](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200329001325832.png)

这块可以使用show(java的代码) 去hook

可以将show方法 直接copy过去,但是要注意里面的函数要遵守js的语法

这块要使用迭代器去获取map

不要调用伪代码的方法,而是去自写
function hookTest10(){
Java.perform(function () {
var ShufferMap = Java.use(“com.xiaojianbang.app.ShufferMap”)
console.log(ShufferMap);
ShufferMap.show.implementation = function (map) {
console.log(JSON.stringify(map));

        var key = map.keySet();
        var it = key.iterator();
        var result = "";
        while (it.hasNext()) {
            var keystr = it.next();
            var valuestr = map.get(keystr);
            result += valuestr;
        }
    console.log(result);
    return result;

    }
})

}

1
2

之后是java 特殊类型的修改

function hookTest10(){
Java.perform(function () {
var ShufferMap = Java.use(“com.xiaojianbang.app.ShufferMap”)
console.log(ShufferMap);
ShufferMap.show.implementation = function (map) {
console.log(JSON.stringify(map));
// 2 修改特殊方法
map.put(“pass”,”zygx8”);
map.put(“xxxx”,”www.zygx8.com");
var retval = this.show(map);
console.log(retval);
return retval;

    }
})

}

1
2
3
4
5
6

## Java 层主动调用函数

只有当函数被触发才会被执行,那么当我们需要解密一个比较复杂的算法,是可以通过主动调用函数去获取的

静态主动调用

调用rsa方法
function hookTest11() {
Java.perform(function () {
var rsa = Java.use(“com.xiaojianbang.app.RSA”);
var str = Java.use(“java.lang.String”);
var base64 = Java.use(“android.util.Base64”);
var bytes = str.$new(“xioajianbang”).getBytes();
console.log(bytes);
var retval = rsa.encrypt(bytes);
console.log(retval);
var result = base64.encodeToString(retval,0);
console.log(result);
})
}

1
2

非静态方法的主动调用 调用getinfo

Java.use(“com.xiaojianbang.Money”).$new(“欧元”,3000000).getInfo();

1
2
3
4
5
6
7
8
9
10



## Java 打印函数堆栈

之前使用Log.d 来打印信息

![image-20200330115446399](D:\Blog\ST0new.github.io\source\_posts\逆向\XposedFridaHook系列\Hook开始.assets\image-20200330115446399.png)

推荐: 使用`Log.getStack.TrachString(new Throwable())` 或``Log.getStack.TrachString(new exception())``

function hookTest12() {
// 写一个函数堆栈
function showStacks(){
console.log(Java.use(“android.util.Log”).getStackTraceString(Java.use(“java.lang.Exception”).$new()));
//console.log(Java.use(“android.util.Log”).getStackTraceString(Java.use(“java.lang.Exception”).$new()));
}
Java.perform(function () {
//Java.cast();
//Java.openClassFile();
var MessageDigest = Java.use(“java.security.MessageDigest”);
MessageDigest.digest.overload().implementation = function () {
showStacks();
return this.digest();

    }
})

}
```

相关文章
评论
分享
  • Hook jni 主动调用

    Hook jni 主动调用要对hellofromc 进行主动调用,修改返回值,但是这里不能直接通过replace去修改返回值,而是要通过newstringutf 去修改返回值。 1234567891011121314151617181...

    Hook jni 主动调用
  • jni函数hook

    jni函数hook(计算 地址方式)12345678910111213141516171819202122232425262728293031323334353637function hookTest9() { Jav...

    jni函数hook
  • Hook 计算非导出函数地址

    hook 读写内存数据对string字符串,可能是加密的,可以通过直接hook 加载的内存数据来读取解密状态的字符串 123456789读取内存字符串数据function hookTest7() { var soAdd...

    Hook 计算非导出函数地址
  • Hook dlopen

    hook dlopen在刚开始hook 我们必须使得app加载so 才能hook, 我们可以hookdlopen 获取到so在那加载,在高版本中有一些so会走android_dlopen_ext 1234567891011121314...

    Hook dlopen
  • Hook 获取指针参数的返回值

    Hook 获取指针参数的返回值在c语言中,一般都会以指针传递返回的值 ,没有return 或者return为true hook sub_750 打印参数和输出 12345678910111213141516171819functio...

    Hook 获取指针参数的返回值
  • Hook 导出函数和修改函数参数返回值

    Hook 导出函数123456789101112131415161718192021222324252627282930// hook 导出函数function hookTest1() { var addAddr =...

    Hook 导出函数和修改函数参数返回值
  • Hook so 导入导出表

    hook so 导入导出表启动frida打开两个cmd 窗口 12345第一个cmd窗口adb shellsucd /data/local/tmp./fx // 这个是frida-server-12.8.14-android-x86...

    Hook so 导入导出表
  • 最右登录协议分析

    Hey, password is required here. 184ec4c94e65a4b619ea732bd39a29aaf452514072ddb6dff084e29ad47fa9af...

    最右登录协议分析
  • 攻防世界-RememberOther

    RememberOther附件下载https://adworld.xctf.org.cn/media/task/attachments/476d9022bb0449c09c0b1e24f0686b66.zip 分析先安装 然后看看逻辑...

    攻防世界-RememberOther
  • 攻防世界-Ph0en1x-100

    Ph0en1x-100附件下载https://adworld.xctf.org.cn/media/task/attachments/f6adc401d0eb472892a4ac4481f76a85.apk 分析上手第一步还是看app逻...

    攻防世界-Ph0en1x-100
Please check the comment setting in config.yml of hexo-theme-Annie!