开发环境为 Visual Studio Code
- 
新建目录 frida-demo
 
- 
在目录中创建 package.json,内容如下,依赖不指定版本,均为最新
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  | 
{
  "name": "frida-demo",
  "version": "1.0.0",
  "description": "Example Frida agent written in TypeScript",
  "private": true,
  "main": "index.ts",
  "scripts": {
    "prepare": "npm run build",
    "build": "frida-compile.cmd index.ts -o _agent.js -c",
    "watch": "frida-compile.cmd index.ts -o _agent.js -w"
  },
  "devDependencies": {
    "@types/frida-gum": "*",
    "@types/node": "*",
    "frida-compile": "*"
  }
}
  | 
 
 
 
- 
在目录中创建 tsconfig.json,内容如下
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  | 
{
  "compilerOptions": {
    "target": "esnext",
    "lib": ["esnext"],
    "allowJs": true,
    "noEmit": true,
    "strict": true,
    "esModuleInterop": true
  }
}
  | 
 
 
 
- 
新建一个 TypeScript 文件,例如 index.ts
 
- 
初始化项目
 
- 
启动 watch 功能监控文件更改,自动编译
在 vs code 中打开 package.json, 点击”调试“,选择 watch 即可。这样每次修改保存 index.ts 后,都会自动进行编译。
 


启动 app,执行命令获取到当前登录页面的 Activity 名
1
2
  | 
# adb shell dumpsys window | grep mCurrentFocus
mCurrentFocus=Window{1f38bfa u0 com.example.androiddemo/com.example.androiddemo.Activity.LoginActivity}
  | 
 
 
使用 jadx 打开 apk,找到 LoginActivity,可以看到登录逻辑如下

我们 hook 这里的函数 a,修改返回值为 1,这样我们用户名任意输入,密码输入 1 即可正常登录。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  | 
function hookSign() {
    Java.perform(function () {
        var LoginActivity = Java.use("com.example.androiddemo.Activity.LoginActivity");
        LoginActivity.a.overload('java.lang.String', 'java.lang.String').implementation = function (str1: any, str2: any) {
            var result = this.a(str1, str2);
            console.log("str1, str2, result is =>", str1, str2, result);
            return "1";
        }
    });
}
  | 
 
 
 
在 jadx 中拿到字符串,hook 函数,修改返回值即可。
1
2
3
4
5
6
7
8
9
  | 
function frida1() {
    Java.perform(function () {
        var FridaActivity1 = Java.use("com.example.androiddemo.Activity.FridaActivity1");
        FridaActivity1.a.implementation = function (x: any) {
            console.log("com.example.androiddemo.Activity.FridaActivity1.a");
            return "R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=";
        }
    })
}
  | 
 
 
 
直接修改变量的值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  | 
function frida2_1() {
    Java.perform(function () {
        var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2");
        FridaActivity2.static_bool_var.value = true;
        Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
            onMatch: function (ins) {
                console.log("ins found =>", ins);
                ins.bool_var.value = true;
            }, onComplete: function () {
                console.log("Search completed!");
            }
        })
    })
}
  | 
 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  | 
function frida2_2() {
    Java.perform(function () {
        Java.use("com.example.androiddemo.Activity.FridaActivity2").setStatic_bool_var();
        Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
            onMatch: function (ins) {
                console.log("ins found =>", ins);
                ins.setBool_var();
            }, onComplete: function () {
                console.log("Search completed!");
            }
        })
    })
}
  | 
 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  | 
function frida2_3() {
    Java.perform(function () {
        Java.use("com.example.androiddemo.Activity.FridaActivity2").$init.implementation = function () {
            console.log("Frida2 hook init function");
            this.$init();
            // this.setBool_var();
            // this.setStatic_bool_var();
            this.bool_var.value = true;
            this.static_bool_var.value = true;
        }
    })
}
  | 
 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | 
function frida3() {
    Java.perform(function () {
        Java.use("com.example.androiddemo.Activity.FridaActivity3").$init.implementation = function () {
            console.log("Frida3 hook init function");
            this.$init();
            this.static_bool_var.value = true;
            this.bool_var.value = true;
            this._same_name_bool_var.value = true;
        }
    })
}
  | 
 
 
 
内部类使用 $ 连接
 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
27
28
  | 
function frida4_1() {
    Java.perform(function () {
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check1.implementation = function () {
            console.log("InnerClasses.check1 called!");
            return true;
        }
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check2.implementation = function () {
            console.log("InnerClasses.check2 called!");
            return true;
        }
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check3.implementation = function () {
            console.log("InnerClasses.check3 called!");
            return true;
        }
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check4.implementation = function () {
            console.log("InnerClasses.check4 called!");
            return true;
        }
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check5.implementation = function () {
            console.log("InnerClasses.check5 called!");
            return true;
        }
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check6.implementation = function () {
            console.log("InnerClasses.check6 called!");
            return true;
        }
    })
}
  | 
 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  | 
function frida4_2() {
    Java.perform(function () {
        var class_name = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses";
        var all_methods = Java.use(class_name).class.getDeclaredMethods();
        for (var i = 0; i < all_methods.length; i++) {
            var method = all_methods[i];
            var methodStr = method.toString();
            var substring = methodStr.substr(methodStr.indexOf(class_name) + class_name.length + 1);
            var funcname = substring.substr(0, substring.indexOf("("));
            Java.use(class_name)[funcname].implementation = function () {
                return true;
            }
        }
    })
}
  | 
 
 
 
 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
27
28
29
30
31
32
33
34
35
36
  | 
function frida5() {
    // Java.perform(function () {
    //     var groups = Java.enumerateMethods("*!check");
    //     console.log(JSON.stringify(groups, null, 2));
    // })
    var getDynamicDexCheckClassName = "";
    Java.choose("com.example.androiddemo.Activity.FridaActivity5", {
        onMatch: function (instance) {
            getDynamicDexCheckClassName = instance.getDynamicDexCheck().$className;
        }, onComplete: function () {
        }
    });
    console.log("className is =>", getDynamicDexCheckClassName);
    Java.enumerateClassLoaders({
        onMatch: function (loader) {
            try {
                if (loader.findClass(getDynamicDexCheckClassName)) {
                    console.log("Successfully found loader");
                    //Java.classFactory.loader 属性为只读,需要进入源码,删除只读属性
                    Java.classFactory.loader = loader;
                    console.log("Switch Classloader Successfully ! ")
                }
            } catch (error) {
                console.warn("continuing =>", error)
            }
        }, onComplete: function () {
            console.log("EnumerateClassloader END")
        }
    })
    Java.use(getDynamicDexCheckClassName).check.implementation = function () {
        return true;
    }
}
  | 
 
 
 
1
2
3
4
5
6
7
  | 
function frida6_1() {
    Java.perform(() => {
        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; };
    })
}
  | 
 
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  | 
function frida6_2() {
    Java.perform(() => {
        Java.enumerateLoadedClasses({
            onMatch: function (classname) {
                if (classname.toString().indexOf("com.example.androiddemo.Activity.Frida6.Frida6Class") >= 0) {
                    console.log("Found Class => ", classname);
                    Java.use(classname).check.implementation = function () { return true; }
                }
            }, onComplete: function () {
                console.log("Search Class Completed!");
            }
        })
    })
}
  |