frida常用代码

JAVA

常用代码

普通函数hook

BASH

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
var use = Java.use("类名");
var use = Java.use("类名");
use.函数名.implementation = function (参数){
    return 函数名(参数);
}

//$init代表构造函数
use.$init.implementation = function (参数){
    return this.$init(参数);
}
//修改返回值
var use = Java.use("类名");
use.函数名.implementation = function (参数){
    var result = 1;
    return result;
}
      
//修改参数
    use.函数名.implementation = function(i, str){
    i = 1;
    str = 2;
    let ret = this.isGridInScreen(i, str);
    return ret;
};
//hook重载函数
use.函数名.overload("参数列表").implementation = function (A){
return this.函数名(A);
}

函数名或者类名加密函数

BASH

1
2
3
4
5
6
7
let use = Java.use("com.baidu.\u96C6\u5408");
    use["\u53D6\u9879\u76EE\u603B\u6570"].implementation = function () {
        console.log('\u53D6\u9879\u76EE\u603B\u6570 is called');
        let ret = this["\u53D6\u9879\u76EE\u603B\u6570"]();
        console.log('\u53D6\u9879\u76EE\u603B\u6570 ret value is ' + ret);
        return ret;
    };

frida 主动调用

静态函数

BASH

1
2
let use = Java.use("类名");
var ret = use.getString("参数");
非静态函数

BASH

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
//hook实例方法  实例方法需要获取到类的对象 才能调用
let use = Java.use("类名").$new();
var ret = use.getString("参数");

//或者在hook到某个函数时
 let ComposeMessageView = Java.use("com.android.messaging.ui.conversation.ComposeMessageView");
ComposeMessageView["sendMessageInternal"].implementation = function (z) {
    console.log('sendMessageInternal is called' + ', ' + 'z: ' + z);
    //this 就是当前类的对象
    this.getString();
    let ret = this.sendMessageInternal(z);
    console.log('sendMessageInternal ret value is ' + ret);
    return ret;
};

//在或者 在内存中搜索需要调用的类的对象
Java.choose("com.android.messaging.ui.conversation.ComposeMessageView",{
    onMatch: function (obj){
        console.log("内存中每找到一次就会调用一次");
        //实例方法的第三种种调用方式
        obj.getString();
    },
    onComplete:function (){
        console.log("内存中搜索完毕后执行")
    }
});

堆栈代码的打印 打印异常输出信息

BASH

1
2
var log = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
 console.log(log);

hookMethods

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function tuzihookMethods(){
    var utils = Java.use("com.tuzi");
    var methods = utils.class.getDeclaredMethods();
    for (let j = 0; j <methods.length ; j++) {
        let methodName = methods[j].getName();
        var overloadsArr = utils[methodName].overloads;
        for (let i = 0; i < overloadsArr.length; i++) {
            overloadsArr[i].implementation = function () {
                var params = "";
                for (let j = 0; j < arguments.length; j++) {
                    params += arguments[j] + " ";
                }
                console.log("utils.getCalc is called! params is: ", params);
                console.log(this);
                return this[methodName].apply(this, arguments);
            }
        }
    }
}

enumclass

BASH

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
37
38
39
40
41
42
function tuzienumclass(){
    Java.perform(function (){
        //枚举所有已加载的类
        // console.log(Java.enumerateLoadedClassesSync().join("\n"));
        // console.log(Java.enumerateLoadedClassesSync().length);
        //java反射
        Java.openClassFile("/data/local/tmp/out.dex").load();
        var wallet = Java.use("com.example.myapplication.MainActivity");
        var Methods = wallet.class.getDeclaredMethods();
        var Constructors = wallet.class.getDeclaredConstructors();
        var Fiedlds = wallet.class.getDeclaredFields();
        var Classes = wallet.class.getDeclaredClasses();
        for (let i = 0; i < Constructors.length; i++) {
            console.log("构造函数"+Constructors[i].getName());
        }
        for (let i = 0; i < Methods.length; i++) {
            console.log("函数"+Methods[i].getName());
        }
        for (let i = 0; i < Fiedlds.length; i++) {
            console.log("字段"+Fiedlds[i].getName());
        }
        for (let i = 0; i < Classes.length; i++) {
            console.log("内部类"+Classes[i].getName());
            var Wallet$InnerStructure = Classes[i].getDeclaredFields();
            var Wallet$InnerStructureMethods = Classes[i].getDeclaredMethods();
            var Wallet$InnerStructuregetConstructors = Classes[i].getDeclaredConstructors();

            for (let j = 0; j < Wallet$InnerStructure.length; j++) {
               console.log("内部类字段"+Wallet$InnerStructure[j].getName());
            }
            for (let j = 0; j < Wallet$InnerStructureMethods.length; j++) {
                console.log("内部类方法"+Wallet$InnerStructureMethods[j].getName());
            }
            for (let j = 0; j < Wallet$InnerStructuregetConstructors.length; j++) {
                console.log("内部类构造方法"+Wallet$InnerStructuregetConstructors[j].getName());
            }
        }

    });
}


注入dex

BASH

1
2
3
4
5
6
7
8
9
10
11
function tuziopenDex(){
    Java.perform(function (){
        Java.openClassFile("/data/local/tmp/dexfile.dex").load();
        var use = Java.use("android.content.Intent");
        var dialog = Java.use("com.example.myapplication.dialog");
        use.$init.overload('android.content.Context', 'java.lang.Class').implementation = function (a,b){
            //console.log(a+b);
            dialog.showAlterDialog(a);
        }
});
}

启动activity

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
var ActivityThread = Java.use("android.app.ActivityThread");
       var application = ActivityThread.currentApplication();
       //获取context
       var context = application.getApplicationContext();
       console.log(context);
       var FridaActivity7 = Java.use("com.github.lastingyang.androiddemo.Activity.FridaActivity7");
       var Intent = Java.use("android.content.Intent");
       Java.scheduleOnMainThread(function() {
           var intent = Intent.$new(context, FridaActivity7.$new().getClass());
           intent.setFlags(0x10000000);
           console.log(intent);
           context.startActivity(intent);
       })

getContext

BASH

1
2
var current_application = Java.use('android.app.ActivityThread').currentApplication();
var context = current_application.getApplicationContext();

类型转换

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
function tuzicast(){
    Java.perform(function (){
        //JAVA.cast
       // 向上转型的,不能用toString直接得到结果,比如Map、List类型的打印会输出objcet
        var utils = Java.use("com.tuzi");
        utils.shufferMap2.implementation = function (map) {
            console.log("map: ", map);
            var result = Java.cast(map, Java.use("java.util.HashMap"));
            console.log("map: ", result);
            return this.shufferMap2(result);
        }
    });
}

构造数组

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function tuziArray(){
    Java.perform(function (){
        let Utils = Java.use("com.tuzi");
        var  strarr = Java.array(
            "Ljava.lang.String", //数组类型
            ["sjaldhja","sakhydo8iqw","sajwiqo","zutiaji"]
        );

        var bool = Java.use('java.lang.Boolean');
        var Integer = Java.use('java.lang.Integer');
        var  strarr1 = Java.array(
            "Ljava.lang.Object", //数组类型
            [Integer.$init(100),bool.$init(true),"sajwiqo","zutiaji"]
        );

     //   var retval = Utils.myPrint(["tuzi","Frida","lalla"]);
        var retval = Utils.myPrint(strarr1);
        console.log(retval)
    });
}

加载so

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function tuziloadlibrary(){
    Java.perform(function (){
        let SplshActivity = Java.use("com.hange.hangevip.SplshActivity");
        SplshActivity.onCreate.implementation = function(bundle){
            console.log('onCreate is called');
            let ret = this.onCreate(bundle);
            console.log('onCreate ret value is ' + ret);
            var system = Java.use("java.lang.System");
            system.loadLibrary("neonuijni_public");
            // var targetSo = Module.findBaseAddress('libneonuijni_public.so');
            //hook_suspected_function(targetSo);
            return ret;
        };
    })
}

常用的定位手段

定位弹窗

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function showStack(){
    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
}
var toast = Java.use("android.widget.Toast");
toast.show.implementation = function () {
    showStack();
    return this.show();
}

var Dialog = Java.use("android.app.Dialog");
    Dialog.setCancelable.implementation = function (bool){
    showStack();
    this.setCancelable(bool);
}

String的getBytes、isEmpty方法

PLAINTEXT

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    var str = Java.use("java.lang.String");
    str.getBytes.overload().implementation = function () {
        showStack();
        var result = this.getBytes();
        var newStr = str.$new(result);
        console.log("str.getBytes result: ", newStr);
        return result;
    }
    str.getBytes.overload('java.lang.String').implementation = function (a) {
        showStack();
        var result = this.getBytes(a);
        var newStr = str.$new(result, a);
        console.log("str.getBytes result: ", newStr);
        return result;
    }

    str.split.overload('java.lang.String').implementation = function (s){
        var ret = this.split(s);
        console.log(ret);
        return ret;
    }
    str.split.overload('java.lang.String', 'int').implementation = function (s,i){
        var ret = this.split(s,i);
        console.log(ret);
        return ret;
    }
    var StringBuffer = Java.use("java.lang.StringBuffer");


    str.getBytes.overload().implementation = function () {
        //    showStack();
        var result = this.getBytes();
        var newStr = str.$new(result);
        console.log("str.getBytes result: ", newStr);
        return result;
    }
    str.getBytes.overload('java.lang.String').implementation = function (a) {
//        showStack();
        console.log("str.getBytes crete: ", a);
        var result = this.getBytes(a);
        var newStr = str.$new(result, a);
        console.log("str.getBytes result: ", newStr);
        return result;
    }

    StringBuffer.toString.implementation = function () {
        var result = this.toString.apply(this, arguments);
        console.log(result);
        var result = this.toString();
        console.log(result);
        return result;
    }


    str.valueOf.overload('int').implementation = function (c){
        var ret = this.valueOf(c);
        console.log(ret);
        return ret;
    }

    str.valueOf.overload('char').implementation = function (){
        var ret = this.valueOf();
        console.log(ret);
        return ret;
    }

getContext

BASH

1
2
var current_application = Java.use('android.app.ActivityThread').currentApplication();
var context = current_application.getApplicationContext();

hookJSON

BASH

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
var jSONObject = Java.use("org.json.JSONObject");
 jSONObject.getString.implementation = function (a) {
     console.log("jSONObject.getString: ", a);
     var result = this.getString(a);
     console.log("jSONObject.getString result: ", result);
     return result;
 }
 jSONObject.optString.overload('java.lang.String').implementation = function (a) {
     console.log("jSONObject.optString: ", a);
     var result = this.optString(a);
     console.log("jSONObject.optString result: ", result);
     return result;
 }
 jSONObject.$init.overload('java.lang.String').implementation = function (s){

     console.log(s);
     var result = this.$init(s);
     console.log("jSONObject.$init result: ", result);
     return result;
 }
 var JSONArray = Java.use("org.json.JSONArray");
 JSONArray.getJSONObject.overload('int').implementation = function (i){
     console.log("JSONArray.getJSONObject: ",i);
     var reslut = this.getJSONObject(i);
     console.log("JSONArray.getJSONObject: ",reslut);
     return reslut;
 }

hook加固的app

BASH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Java.perform(function () {
    var application = Java.use('android.app.Application');
    application.attach.overload('android.content.Context').implementation = function (context) {
        var result = this.attach(context);
        var classloader = context.getClassLoader();
        Java.classFactory.loader = classloader;
        var activation = Java.classFactory.use('com.baidu.input.activation');
        console.log("activation:" + activation);
        activation.aaa.implementation = function (z) {
            console.log('aaa is called' + ', ' + 'z: ' + z);
            let ret = this.aaa(z);
            console.log('aaa ret value is ' + ret);
            return ret;
        };
    }
})

java层的各种好用工具

r0trace 肉丝大佬

BASH

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
var isLite = false;
var ByPassTracerPid = function () {
    var fgetsPtr = Module.findExportByName("libc.so", "fgets");
    var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);
    Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) {
        var retval = fgets(buffer, size, fp);
        var bufstr = Memory.readUtf8String(buffer);
        if (bufstr.indexOf("TracerPid:") > -1) {
            Memory.writeUtf8String(buffer, "TracerPid:\t0");
            console.log("tracerpid replaced: " + Memory.readUtf8String(buffer));
        }
        return retval;
    }, 'pointer', ['pointer', 'int', 'pointer']));
};
setImmediate(ByPassTracerPid);

(function(){
    let Color = {RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", "Green": "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01"};
    let LightColor = {RESET: "\x1b[39;49;00m", Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", "Green": "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"};    
    var colorPrefix = '\x1b[3', colorSuffix = 'm'
    for (let c in Color){
        if (c  == "RESET") continue;
        console[c] = function(message){
            console.log(colorPrefix + Color[c] + colorSuffix + message + Color.RESET);
        }
        console["Light" + c] = function(message){
            console.log(colorPrefix + LightColor[c] + colorSuffix + message + Color.RESET);
        }
    }
})();
function uniqBy(array, key) {
    var seen = {};
    return array.filter(function (item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    });
}
function hasOwnProperty(obj, name) {
    try {
        return obj.hasOwnProperty(name) || name in obj;
    } catch (e) {
        return obj.hasOwnProperty(name);
    }
}
function getHandle(object) {
    if (hasOwnProperty(object, '$handle')) {
        if (object.$handle != undefined) {
            return object.$handle;
        }
    }
    if (hasOwnProperty(object, '$h')) {
        if (object.$h != undefined) {
            return object.$h;
        }
    }
    return null;
}
//查看域值
function inspectObject(obj, input) {
    var isInstance = false;
    var obj_class = null;
    if (getHandle(obj) === null) {
        obj_class = obj.class;
    } else {
        var Class = Java.use("java.lang.Class");
        obj_class = Java.cast(obj.getClass(), Class);
        isInstance = true;
    }
    input = input.concat("Inspecting Fields: => ", isInstance, " => ", obj_class.toString());
    input = input.concat("\r\n")
    var fields = obj_class.getDeclaredFields();
    for (var i in fields) {
        if (isInstance || Boolean(fields[i].toString().indexOf("static ") >= 0)) {
            // output = output.concat("\t\t static static static " + fields[i].toString());
            var className = obj_class.toString().trim().split(" ")[1];
            // console.Red("className is => ",className);
            var fieldName = fields[i].toString().split(className.concat(".")).pop();
            var fieldType = fields[i].toString().split(" ").slice(-2)[0];
            var fieldValue = undefined;
            if (!(obj[fieldName] === undefined))
                fieldValue = obj[fieldName].value;
            input = input.concat(fieldType + " \t" + fieldName + " => ", fieldValue + " => ", JSON.stringify(fieldValue));
            input = input.concat("\r\n")
        }
    }
    return input;
}

// trace单个类的所有静态和实例方法包括构造方法 trace a specific Java Method
function traceMethod(targetClassMethod) {
    var delim = targetClassMethod.lastIndexOf(".");
    if (delim === -1) return;
    var targetClass = targetClassMethod.slice(0, delim)
    var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length)
    var hook = Java.use(targetClass);
    var overloadCount = hook[targetMethod].overloads.length;
    console.Red("Tracing Method : " + targetClassMethod + " [" + overloadCount + " overload(s)]");
    for (var i = 0; i < overloadCount; i++) {
        hook[targetMethod].overloads[i].implementation = function () {
            //初始化输出
            var output = "";
            //画个横线
            for (var p = 0; p < 100; p++) {
                output = output.concat("==");
            }
            //域值
            if (!isLite) { output = inspectObject(this, output); }
            //进入函数
            output = output.concat("\n*** entered " + targetClassMethod);
            output = output.concat("\r\n")
            // if (arguments.length) console.Black();
            //参数
            var retval = this[targetMethod].apply(this, arguments);
            if (!isLite) {
                for (var j = 0; j < arguments.length; j++) {
                    output = output.concat("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j]));
                    output = output.concat("\r\n")
                }
                //调用栈
                output = output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
                //返回值
                output = output.concat("\nretval: " + retval + " => " + JSON.stringify(retval));
            }
            // inspectObject(this)
            //离开函数
            output = output.concat("\n*** exiting " + targetClassMethod);
            //最终输出
            // console.Black(output);
            var r = parseInt((Math.random() * 7).toFixed(0));
            var i = r;
            var printOutput = null;
            switch (i) {
                case 1:
                    printOutput = console.Red;
                    break;
                case 2:
                    printOutput = console.Yellow;
                    break;
                case 3:
                    printOutput = console.Green;
                    break;
                case 4:
                    printOutput = console.Cyan;
                    break;
                case 5:
                    printOutput = console.Blue;
                    break;
                case 6:
                    printOutput = console.Gray;
                    break;
                default:
                    printOutput = console.Purple;
            }
            printOutput(output);
            return retval;
        }
    }
}

function traceClass(targetClass) {
    //Java.use是新建一个对象哈,大家还记得么?
    var hook = Java.use(targetClass);
    //利用反射的方式,拿到当前类的所有方法
    var methods = hook.class.getDeclaredMethods();    
    //建完对象之后记得将对象释放掉哈
    hook.$dispose;
    //将方法名保存到数组中
    var parsedMethods = [];
    var output = "";    
    output = output.concat("\tSpec: => \r\n")
    methods.forEach(function (method) {
        output = output.concat(method.toString())
        output = output.concat("\r\n")
        parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]);
    });
    //去掉一些重复的值
    var Targets = uniqBy(parsedMethods, JSON.stringify);
    // targets = [];
    var constructors = hook.class.getDeclaredConstructors();
    if (constructors.length > 0) {
        constructors.forEach(function (constructor) {
            output = output.concat("Tracing ", constructor.toString())
            output = output.concat("\r\n")
        })
        Targets = Targets.concat("$init")
    }
    //对数组中所有的方法进行hook,
    Targets.forEach(function (targetMethod) {
        traceMethod(targetClass + "." + targetMethod);
    });
    //画个横线
    for (var p = 0; p < 100; p++) {
        output = output.concat("+");
    }
    console.Green(output);
}
function hook(white, black, target = null) {
    console.Red("start")
    if (!(target === null)) {
        console.LightGreen("Begin enumerateClassLoaders ...")
        Java.enumerateClassLoaders({
            onMatch: function (loader) {
                try {
                    if (loader.findClass(target)) {
                        console.Red("Successfully found loader")
                        console.Blue(loader);
                        Java.classFactory.loader = loader;
                        console.Red("Switch Classloader Successfully ! ")
                    }
                }
                catch (error) {
                    console.Red(" continuing :" + error)
                }
            },
            onComplete: function () {
                console.Red("EnumerateClassloader END")
            }
        })
    }
    console.Red("Begin Search Class...")
    var targetClasses = new Array();
    Java.enumerateLoadedClasses({
        onMatch: function (className) {
            if (className.toString().toLowerCase().indexOf(white.toLowerCase()) >= 0 &&
               (black == null || black == '' || className.toString().toLowerCase().indexOf(black.toLowerCase()) < 0)) {
                console.Black("Found Class => " + className)
                targetClasses.push(className);
                traceClass(className);
            }
        }, onComplete: function () {
            console.Black("Search Class Completed!")
        }
    })
    var output = "On Total Tracing :"+String(targetClasses.length)+" classes :\r\n";
    targetClasses.forEach(function(target){
        output = output.concat(target);
        output = output.concat("\r\n")        
    })
    console.Green(output+"Start Tracing ...")
}
function main() {
    Java.perform(function () {
        console.Purple("r0tracer begin ... !")
        //0. 增加精简模式,就是以彩虹色只显示进出函数。默认是关闭的,注释此行打开精简模式。
        //isLite = true;
        /*
        //以下三种模式,取消注释某一行以开启
        */
        //A. 简易trace单个函数
        traceClass("javax.crypto.Cipher")
        //B. 黑白名单trace多个函数,第一个参数是白名单(包含关键字),第二个参数是黑名单(不包含的关键字)
        // hook("javax.crypto.Cipher", "$");
        //C. 报某个类找不到时,将某个类名填写到第三个参数,比如找不到com.roysue.check类。(前两个参数依旧是黑白名单)
        // hook("com.roysue.check"," ","com.roysue.check");        
    })
}
/*
//setImmediate是立即执行函数,setTimeout是等待毫秒后延迟执行函数
//二者在attach模式下没有区别
//在spawn模式下,hook系统API时如javax.crypto.Cipher建议使用setImmediate立即执行,不需要延时
//在spawn模式下,hook应用自己的函数或含壳时,建议使用setTimeout并给出适当的延时(500~5000)
*/
setImmediate(main)
//
// setTimeout(main, 2000);


// 玄之又玄,众妙之门
// Frida的崩溃有时候真的是玄学,大项目一崩溃根本不知道是哪里出的问题,这也是小而专的项目也有一丝机会的原因
// Frida自身即会经常崩溃,建议多更换Frida(客/服要配套)版本/安卓版本,我自己常用的组合是两部手机,Frida12.8.0全家桶+安卓8.1.0,和Frida14.2.2全家桶+安卓10 

dump证书

BASH

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
function dump(){
    let path = "/data/data/com.feigua.yingshi/tuzi.p12"
    Java.perform(function () {
        var KeyStore = Java.use("java.security.KeyStore");
        var str = Java.use("java.lang.String");
        KeyStore.load.overload("java.io.InputStream", "[C").implementation = function (input, pwdStr) {
            if (input) {
                console.log("pwdStr: ", str.$new(pwdStr));
                var file = Java.use("java.io.File").$new(path);
                var output = Java.use("java.io.FileOutputStream").$new(file);
                var r, myArr = [];
                for (var i = 0; i < 1024; i++) {
                    myArr[i] = 0;
                }
                var buffer = Java.array("byte", myArr);
                while((r = input.read(buffer)) > 0) {
                    output.write(buffer, 0, r);
                }
                console.log("save");
                output.close();
            }
            return this.load(input, pwdStr);
        }
    
    });
}

r0capture

BASH

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
(function(){

"use strict";
rpc.exports = {
  setssllib: function (name) {
    console.log("setSSLLib => " + name);
    libname = name;
    initializeGlobals();
    return;
  }
};

var addresses = {};
var SSL_get_fd = null;
var SSL_get_session = null;
var SSL_SESSION_get_id = null;
var getpeername = null;
var getsockname = null;
var ntohs = null;
var ntohl = null;
var SSLstackwrite = null;
var SSLstackread = null;

var libname = "*libssl*";

function initMessage(){
  var message={};
  message["jsname"]="r0capture";
  return message;
}

function uuid(len, radix) {
  var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  var uuid = [], i;
  radix = radix || chars.length;

  if (len) {
    // Compact form
    for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
  } else {
    // rfc4122, version 4 form
    var r;

    // rfc4122 requires these characters
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
    uuid[14] = '4';

    // Fill in random data. At i==19 set the high bits of clock sequence as
    // per rfc4122, sec. 4.1.5
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | Math.random() * 16;
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  return uuid.join('');
}
function return_zero(args) {
  return 0;
}
function initializeGlobals() {
  var resolver = new ApiResolver("module");
  var exps = [
    [Process.platform == "darwin" ? "*libboringssl*" : "*libssl*", ["SSL_read", "SSL_write", "SSL_get_fd", "SSL_get_session", "SSL_SESSION_get_id"]], // for ios and Android
    [Process.platform == "darwin" ? "*libsystem*" : "*libc*", ["getpeername", "getsockname", "ntohs", "ntohl"]]
  ];
  // console.logs(exps)
  for (var i = 0; i < exps.length; i++) {
    var lib = exps[i][0];
    var names = exps[i][1];
    for (var j = 0; j < names.length; j++) {
      var name = names[j];
      // console.logs("exports:" + lib + "!" + name)
      var matches = resolver.enumerateMatchesSync("exports:" + lib + "!" + name);
      if (matches.length == 0) {
        if (name == "SSL_get_fd") {
          addresses["SSL_get_fd"] = 0;
          continue;
        }
        throw "Could not find " + lib + "!" + name;
      }
      else if (matches.length != 1) {
        // Sometimes Frida returns duplicates.
        var address = 0;
        var s = "";
        var duplicates_only = true;
        for (var k = 0; k < matches.length; k++) {
          if (s.length != 0) {
            s += ", ";
          }
          s += matches[k].name + "@" + matches[k].address;
          if (address == 0) {
            address = matches[k].address;
          }
          else if (!address.equals(matches[k].address)) {
            duplicates_only = false;
          }
        }
        if (!duplicates_only) {
          throw "More than one match found for " + lib + "!" + name + ": " + s;
        }
      }
      addresses[name] = matches[0].address;
    }
  }
  if (addresses["SSL_get_fd"] == 0) {
    SSL_get_fd = return_zero;
  } else {
    SSL_get_fd = new NativeFunction(addresses["SSL_get_fd"], "int", ["pointer"]);
  }
  SSL_get_session = new NativeFunction(addresses["SSL_get_session"], "pointer", ["pointer"]);
  SSL_SESSION_get_id = new NativeFunction(addresses["SSL_SESSION_get_id"], "pointer", ["pointer", "pointer"]);
  getpeername = new NativeFunction(addresses["getpeername"], "int", ["int", "pointer", "pointer"]);
  getsockname = new NativeFunction(addresses["getsockname"], "int", ["int", "pointer", "pointer"]);
  ntohs = new NativeFunction(addresses["ntohs"], "uint16", ["uint16"]);
  ntohl = new NativeFunction(addresses["ntohl"], "uint32", ["uint32"]);
}
initializeGlobals();

function ipToNumber(ip) {
  var num = 0;
  if (ip == "") {
    return num;
  }
  var aNum = ip.spli
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Frida JS 是一种用于在 Android 和 iOS 设备上注入代码的工具。它使用 JavaScript 语法来编写代码,使得开发人员可以通过动态注入代码来修改和扩展应用程序的行为。 Frida JS 提供了一套用于在注入的代码与目标应用程序进行交互的 API。它允许开发人员在应用程序运行的任何时候监视和修改函数的参数和返回值、访问和修改目标应用程序的内存、调用应用程序的函数,并与其它已经存在的类和对象进行交互。 在 Frida JS ,可以使用常见的 JavaScript 语法来编写代码,比如声明变量、使用条件语句和循环语句、定义函数等。此外,Frida JS 还提供了一些特殊的 API 供开发人员使用。例如,可以使用 `Java.use()` 方法来动态地获取目标应用程序的类,并对其进行操作;还可以使用 `Interceptor` 对象来拦截函数的调用,并修改其行为。 Frida JS 还支持与 Java、Objective-C 等其它语言进行互操作。开发人员可以在 Frida JS 调用 Java 和 Objective-C 的函数,并传递参数和获取返回值。这使得开发人员可以利用 Frida JS 强大的注入功能与现有的库和框架进行交互。 总之,Frida JS 是一种高效的工具,它使用 JavaScript 语法来编写代码,并提供了丰富的 API 供开发人员进行应用程序的动态修改和扩展。通过注入代码,开发人员可以实现诸如修改函数行为、监视和修改内存、与现有框架进行交互等功能。 ### 回答2: Frida JS是一种基于JavaScript的动态代码注入和脱壳工具,主要用于在运行时分析、修改和控制Android和iOS应用程序。它具有以下几个特点。 首先,Frida JS支持通过JavaScript脚本进行代码注入,无需重新编译或重新打包应用程序。这使得分析和修改应用程序变得非常方便快捷。 其次,Frida JS提供了一组强大的API,可以访问应用程序的内部结构和函数,以实现各种功能。它可以帮助我们查找敏感信息、拦截网络请求、修改函数逻辑、绕过安全检测等等。 另外,Frida JS还支持与Java和Objective-C代码的交互,可以直接调用Java和Objective-C的方法,从而打破了JavaScript的限制,使得我们可以更加灵活地操作应用程序。 此外,Frida JS具有良好的可扩展性和兼容性,可以在不同的平台上使用,包括Android、iOS和Windows等系统。它还提供了丰富的工具和插件,用于帮助分析和调试应用程序。 总结起来,Frida JS是一种强大的动态代码注入和脱壳工具,基于JavaScript语言,具有方便快捷、强大灵活、可扩展兼容等特点,能够帮助我们分析和修改应用程序,是移动应用安全研究和渗透测试工作常用的工具之一。 ### 回答3: Frida JS是一种基于JavaScript的脚本语言,用于在移动设备或操作系统上进行动态的代码注入和调试。它是Frida工具的核心部分,能够帮助开发者进行安卓应用程序的逆向工程以及测试工作。 Frida JS的语法基本上与常见的JavaScript语法相似,但有一些特定的语法和函数用于与Frida API进行交互,从而实现代码注入和追踪目标应用程序的功能。 在Frida JS,可以使用Frida提供的方法来加载目标应用程序,例如通过进程名称、PID或软件包名来定位应用程序,并可以使用attach方法来附加进程,或者使用spawn方法来启动一个新的进程。一旦与目标应用程序连接,可以使用Frida JS的函数来监视、截获和修改应用程序的运行时行为。 为了实现对目标应用程序的代码注入,Frida JS提供了一些特定的函数,如Interceptor、Memory、Module等。Interceptor用于在运行时截获和修改函数调用,Memory用于读写内存数据,Module用于定位并导入外部函数库。 Frida JS还提供了一些工具函数来帮助开发者调试目标应用程序,如console.log、send和recv等函数。通过这些函数,可以在代码执行时输出调试信息,并与Frida主机应用程序进行通信。 总结来说,Frida JS是一种专门为Frida工具设计的脚本语言,用于实现在移动设备或操作系统上进行代码注入和调试的功能。它有类似于JavaScript的语法,但也有特定的函数和工具来与Frida API进行交互。Frida JS为开发者提供了一种灵活和强大的工具来逆向工程、测试和调试应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值