Frida框架 -So-API(常用函数总结)

使用Frida框架来挂钩(hook)Android应用程序中的动态链接库(so)中的函数

// 定义一个函数hook_so
function hook_so(){
    // 找到libxiaojianbangA.so的基地址
    var soAddr = Module.findBaseAddress("libxiaojianbangA.so");
    // 获取bss段中某个函数的地址
    var bssFunc = soAddr.add(0x14018);
    // 读取bssFunc的真实函数地址
    var realFunc = bssFunc.readPointer();
    // 附加Interceptor到真实函数
    Interceptor.attach(realFunc, {
        onEnter: function(args){
            // 真实函数进入时,打印args[0]的十六进制dump
            console.log("realFunc args[0]: ", hexdump(args[0]));
        },
        onLeave: function(retval){
            // 真实函数退出时,无操作
        }
    });
    // 枚举进程中的所有模块
    var modules = Process.enumerateModules();
    // 遍历所有模块
    for(var i = 0; i < modules.length; i++){
        // 检查真实函数是否在当前模块的范围内
        if(realFunc > parseInt(modules[i].base) && realFunc < (parseInt(modules[i].base) + modules[i].size)){
            // 计算真实函数相对于当前模块基地址的偏移量
            var realFuncOffset = realFunc - parseInt(modules[i].base);
            // 打印当前模块的名称和真实函数的偏移量
            console.log("modules[i].name: ", modules[i].name, realFuncOffset.toString(16));
        }
    }
}
// 定义主函数main
function main(){
    // 调用hook_so()函数
    hook_so();
}
// 使用setImmediate来延迟执行main函数
setImmediate(main);

这段代码的作用是:

  1. 找到libxiaojianbangA.so库的基地址。
  2. 获取bss段中某个函数的地址,并读取其指向的真实函数地址。
  3. 使用Frida的Interceptor.attach方法,将钩子(hook)附加到真实函数上。
  4. 当真实函数被调用时,记录函数的输入参数(args[0]),并打印其十六进制dump。
  5. 枚举进程中的所有模块,并检查真实函数是否在某个模块的范围内。
  6. 如果真实函数在某个模块的范围内,计算它相对于该模块基地址的偏移量,并打印模块的名称和偏移量。
  7. 使用setImmediate来延迟执行main函数。
  8. 可以监控和分析Android应用程序中libxiaojianbangA.so库的真实函数的执行情况,这对于调试、分析和修改应用程序的行为非常有用。

hexToBytes用于将十六进制字符串转换为字节数组。


// 定义一个函数hexToBytes
function hexToBytes(str) {
    // 初始化位置变量pos为0
    var pos = 0;
    // 获取字符串的长度
    var len = str.length;
    // 检查字符串长度是否为偶数,因为十六进制字符串的长度必须是偶数
    if (len % 2 != 0) {
        // 如果不是偶数,返回null
        return null;
    }
    // 将字符串长度除以2,得到字节数组的长度
    len /= 2;
    // 创建一个新的数组hexA来存储字节值
    var hexA = new Array();
    // 遍历字节数组的长度
    for (var i = 0; i < len; i++) {
        // 获取当前字符串中2个字符的字符串
        var s = str.substr(pos, 2);
        // 将字符串转换为整数
        var v = parseInt(s, 16);
        // 将整数添加到hexA数组中
        hexA.push(v);
        // 增加pos的值,以便下次循环时读取下一个字符串
        pos += 2;
    }
    // 返回字节数组
    return hexA;
}

这段代码的作用是:

  1. 检查输入的十六进制字符串的长度是否为偶数,如果不是,则返回null。
  2. 如果字符串长度为偶数,则将其长度除以2,得到字节数组的长度。
  3. 创建一个新的数组hexA来存储字节值。
  4. 遍历字节数组的长度,每次从输入字符串中取出2个字符,并将其转换为整数。
  5. 将转换后的整数添加到hexA数组中。
  6. 返回字节数组hexA。 可以将十六进制表示的字符串转换为字节数组,这在处理二进制数据时非常有用。

stringToBytes用于将字符串转换为字节数组


// 定义一个函数stringToBytes
function stringToBytes(str) {
    // 创建一个空数组re来存储字节
    var re = [];
    // 遍历输入字符串的每一个字符
    for (var i = 0; i < str.length; i++) {
        // 获取当前字符的Unicode编码
        ch = str.charCodeAt(i);
        // 创建一个空数组st来存储当前字符的字节
        var st = [];
        // 进行循环,将字符的Unicode编码转换为字节
        do {
            // 获取当前字符的最高位
            st.push(ch & 0xFF);
            // 右移ch,获取下一位
            ch = ch >> 8;
        } while (ch);
        // 将转换后的字节数组re与st数组连接起来
        re = re.concat(st.reverse());
    }
    // 返回字节数组re
    return re;
}

这段代码的作用是:

  1. 创建一个空数组re来存储字节。
  2. 遍历输入字符串的每一个字符。
  3. 获取当前字符的Unicode编码。
  4. 创建一个空数组st来存储当前字符的字节。
  5. 进行循环,将字符的Unicode编码转换为字节。
  6. 将转换后的字节数组rest数组连接起来。
  7. 返回字节数组re。 可以将字符串转换为字节数组,这在处理文本和二进制数据时非常有用

枚举导入导出表

使用Frida框架来枚举和打印`libxiaojianbang.so`库的导入(imports)
和导出(exports)信息。

// 定义一个函数hookTest1
function hookTest1(){
    // 使用Module.enumerateImports来枚举libxiaojianbang.so库的导入信息
    var imports = Module.enumerateImports("libxiaojianbang.so");
    // 遍历导入信息数组
    for(var i = 0; i < imports.length; i++){
        // 检查当前导入项的名称是否为"strncat"
        if(imports[i].name == "strncat"){
            // 如果找到,打印导入项的JSON表示
            console.log(JSON.stringify(imports[i]));
            // 打印导入项的地址
            console.log(imports[i].address);
            // 找到后跳出循环
            break;
        }
    }
    // 使用Module.enumerateExports来枚举libxiaojianbang.so库的导出信息
    var exports = Module.enumerateExports("libxiaojianbang.so");
    // 遍历导出信息数组
    for(var i = 0; i < exports.length; i++){
        // 打印导出项的JSON表示
        console.log(JSON.stringify(exports[i]));
    }
}

这段代码的作用是:
1. 枚举`libxiaojianbang.so`库的导入信息,并存储在`imports`数组中。
2. 遍历`imports`数组,查找名称是否为"strncat"的导入项。
3. 如果找到,打印该导入项的JSON表示和地址,并跳出循环。
4. 枚举`libxiaojianbang.so`库的导出信息,并存储在`exports`数组中。
5. 遍历`exports`数组,打印每个导出项的JSON表示。
通过这种方式,这段代码可以获取和分析`libxiaojianbang.so`库的导入和导出信息,

Hook导出函数

这段JavaScript代码使用Frida框架来查找并挂钩(hook)`libxiaojianbang.so`库中名
为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数。

// 定义一个函数hookTest2
function hookTest2(){
    // 使用Module.findExportByName来查找libxiaojianbang.so库中名为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数
    var helloAddr = Module.findExportByName("libxiaojianbang.so", "Java_com_xiaojianbang_app_NativeHelper_add");
    // 打印导出函数的地址
    console.log(helloAddr);
    // 如果找到地址,则附加Interceptor
    if(helloAddr != null){
        Interceptor.attach(helloAddr,{
            onEnter: function(args){
                // 函数进入时,打印args中的所有参数
                console.log(args[0]);
                console.log(args[1]);
                console.log(args[2]);
                console.log(this.context.x2);
                console.log(args[3]);
                console.log(args[4].toInt32());
            },
            onLeave: function(retval){
                // 函数退出时,打印返回值
                console.log(retval);
                // 打印返回值的整数表示
                console.log("retval", retval.toInt32());
            }
        });
    }
}
这段代码的作用是:
1. 查找`libxiaojianbang.so`库中名为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数。
2. 如果找到,打印该函数的地址。
3. 如果找到地址,使用Frida的`Interceptor.attach`方法,将钩子(hook)附加到该函数上。
4. 当函数被调用时,记录函数的输入参数,并打印它们的值。
5. 当函数退出时,打印返回值及其整数表示。

修改函数参数返回值

这段JavaScript代码使用Frida框架来查找并挂钩(hook)`libxiaojianbang.so`库中名
为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数,并在函数进入和离开时修改其参数
和返回值。

// 定义一个函数hookTest3
function hookTest3(){
    // 使用Module.findExportByName来查找libxiaojianbang.so库中名为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数
    var helloAddr = Module.findExportByName("libxiaojianbang.so", "Java_com_xiaojianbang_app_NativeHelper_add");
    // 打印导出函数的地址
    console.log(helloAddr);
    // 如果找到地址,则附加Interceptor
    if(helloAddr != null){
        Interceptor.attach(helloAddr,{
            onEnter: function(args){
                // 函数进入时,尝试修改args中的参数
                args[2] = ptr(1000); // 使用ptr()函数创建一个指针,指向值为1000的内存地址
                // 打印修改后的第二个参数的整数表示
                console.log(args[2].toInt32());
                // 打印第三个参数
                console.log(args[3]);
                // 打印第四个参数
                console.log(args[4]);
            },
            onLeave: function(retval){
                // 函数退出时,修改返回值
                retval.replace(20000); // 将返回值替换为20000
                // 打印修改后的返回值的整数表示
                console.log("retval", retval.toInt32());
            }
        });
    }
}

1. 查找`libxiaojianbang.so`库中名为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数。
2. 如果找到,打印该函数的地址。
3. 如果找到地址,使用Frida的`Interceptor.attach`方法,将钩子(hook)附加到该函数上。
4. 当函数被调用时,尝试修改函数的第二个参数为指向值为1000的内存地址的指针,并打印修改后的参数和
第三个参数。
5. 当函数退出时,修改返回值为20000,并打印修改后的返回值。
通过这种方式,这段代码可以监控和分析`libxiaojianbang.so`库中名为"Java_com_xiaojianbang_app_NativeHelper_add"的导出函数的执行情况,并且可以修改函数的参数和返回值,这对于调试、分析和修改应用程序的行为非常有用。

Hook未导出函数

使用Frida框架来挂钩(hook)`libxiaojianbang.so`库中计算出的某个函数。
// 定义一个函数hookTest4
function hookTest4(){
    // 使用Module.findBaseAddress来找到libxiaojianbang.so库的基地址
    var soAddr = Module.findBaseAddress("libxiaojianbang.so");
    // 打印基地址
    console.log(soAddr);
    // 计算要挂钩的函数的地址,这里使用了thumb指令集的偏移量
    var funcAddr = soAddr.add(0x23F4);
    // 打印函数地址
    console.log(funcAddr);
    // 如果找到地址,则附加Interceptor
    if(funcAddr != null){
        Interceptor.attach(funcAddr,{
            onEnter: function(args){
                // 函数进入时,无操作
            },
            onLeave: function(retval){
                // 函数退出时,打印返回值的十六进制dump
                console.log(hexdump(retval));
            }
        });
    }
}

1. 找到`libxiaojianbang.so`库的基地址。
2. 计算要挂钩的函数的地址,这里使用了thumb指令集的偏移量。
3. 打印该函数的地址。
4. 如果找到地址,使用Frida的`Interceptor.attach`方法,将钩子(hook)附加到该函数上。
5. 当函数被调用时,无操作。
6. 当函数退出时,打印返回值的十六进制dump。

获取指针参数返回值

frida框架来挂钩(hook)`libxiaojianbang.so`库中计算出的某个函数,并在函数退出时修改其返回
的内存数据。

// 定义一个函数hookTest5
function hookTest5(){
    // 使用Module.findBaseAddress来找到libxiaojianbang.so库的基地址
    var soAddr = Module.findBaseAddress("libxiaojianbang.so");
    // 打印基地址
    console.log(soAddr);
    // 计算要挂钩的函数的地址,这里使用了thumb指令集的偏移量
    var sub_208C = soAddr.add(0x208C);
    // 打印函数地址
    console.log(sub_208C);
    // 如果找到地址,则附加Interceptor
    if(sub_208C != null){
        Interceptor.attach(sub_208C,{
            onEnter: function(args){
                // 函数进入时,保存args中的第二个参数
                this.args1 = args[1];
            },
            onLeave: function(retval){
                // 函数退出时,修改内存数据
                // 将十六进制字符串转换为字节数组
                var newData = hexToBytes("0123456789abcdef0123456789abcdef");
                // 写入修改后的数据到内存中
                ptr(this.args1).writeByteArray(newData);
                // 打印返回地址的十六进制dump
                console.log(hexdump(this.args1));
            }
        });
    }
}

这段代码的作用是:
1. 找到`libxiaojianbang.so`库的基地址。
2. 计算要挂钩的函数的地址,这里使用了thumb指令集的偏移量。
3. 打印该函数的地址。
4. 如果找到地址,使用Frida的`Interceptor.attach`方法,将钩子(hook)附加到该函数上。
5. 当函数被调用时,记录函数的输入参数(args中的第二个参数)。
6. 当函数退出时,修改内存中`this.args1`地址的数据,将其替换为预定义的十六进制字节数组。
7. 打印修改后的内存地址的十六进制dump。
通过这种方式,这段代码可以监控和分析`libxiaojianbang.so`库中某个函数的执行情况,
并在函数返回时修改其返回的内存数据,这对于调试、分析和修改应用程序的行为非常有用。

内存读写

使用Frida框架来读取和写入`libxiaojianbang.so`库中特定地址的字符串和字节数据。

// 定义一个函数hookTest7
function hookTest7(){
    // 使用Module.findBaseAddress来找到libxiaojianbang.so库的基地址
    var soAddr = Module.findBaseAddress("libxiaojianbang.so");
    // 打印基地址
    console.log(soAddr);
    // 如果找到了基地址
    if(soAddr != null){
        // 读取指定地址的字符串
        console.log(soAddr.add(0x2C00).readCString());
        // 打印指定地址的十六进制dump
        console.log(hexdump(soAddr.add(0x2C00)));
        // 读取指定地址的字节数组
        var strByte = soAddr.add(0x2C00).readByteArray(16); 
        console.log(strByte);
        // 写入内存
        soAddr.add(0x2C00).writeByteArray(stringToBytes("xiaojianbang")); 
        // 读取指定地址的字符串
        console.log(hexdump(soAddr.add(0x2C00)));  
        // 使用旧API读取指定地址的字节数组
        var bytes = Memory.readByteArray(soAddr.add(0x2C00), 16); 
        console.log(bytes);
    }
}

这段代码的作用是:
1. 找到`libxiaojianbang.so`库的基地址。
2. 打印基地址。
3. 如果找到了基地址,执行以下操作:
   - 读取基地址+0x2C00处的字符串,并打印。
   - 读取基地址+0x2C00处的16字节数据,并打印其十六进制dump。
   - 读取基地址+0x2C00处的16字节数据,并打印。
   - 写入基地址+0x2C00处一个字符串"xiaojianbang"对应的字节数组。
   - 再次读取基地址+0x2C00处的16字节数据,并打印其十六进制dump。
   - 使用旧API读取基地址+0x2C00处的16字节数据,并打印。
通过这种方式,这段代码可以读取和写入`libxiaojianbang.so`库中特定地址的字符串和字节数据,

Hook dlopen


// 定义 hookTest6 函数,这是主要的入口点。
function hookTest6() {
    // 使用 Frida 的 Module.findExportByName 方法查找当前进程的 'dlopen' 函数的地址。
    // 'dlopen' 函数用于加载动态链接库(.so文件)。
    var dlopen = Module.findExportByName(null, "dlopen");
    // 打印 'dlopen' 函数的地址,用于调试。
    console.log(dlopen);
    // 判断 'dlopen' 是否存在。
    if (dlopen != null) {
        // 如果存在,使用 Frida 的 Interceptor.attach 方法挂钩到 'dlopen' 函数。
        Interceptor.attach(dlopen, {
            // 在 'dlopen' 函数调用前执行的代码。
            onEnter: function (args) {
                // 读取 'dlopen' 函数的第一个参数,即要加载的库的名称。
                var soName = args[0].readCString();
                // 打印库名,用于调试。
                console.log(soName);
                // 检查库名是否包含 "libxiaojianbang.so"。
                if (soName.indexOf("libxiaojianbang.so") != -1) {
                    // 如果包含,则设置 this.hook 为 true,表示后续需要执行额外操作。
                    this.hook = true;
                }
            },
            // 在 'dlopen' 函数调用后执行的代码。
            onLeave: function (retval) {
                // 检查之前是否设置了 this.hook。
                if (this.hook) {
                    // 如果是,调用 hookTest5 函数。
                    hookTest5();
                }
            }
        });
    }
    // 重复上述过程,但针对 Android 特有的 'android_dlopen_ext' 函数。
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    // 打印 'android_dlopen_ext' 函数的地址,用于调试。
    console.log(android_dlopen_ext);
    // 判断 'android_dlopen_ext' 是否存在。
    if (android_dlopen_ext != null) {
        // 如果存在,使用 Frida 的 Interceptor.attach 方法挂钩到 'android_dlopen_ext' 函数。
        Interceptor.attach(android_dlopen_ext, {
            // 在 'android_dlopen_ext' 函数调用前执行的代码。
            onEnter: function (args) {
                // 读取 'android_dlopen_ext' 函数的第一个参数,即要加载的库的名称。
                var soName = args[0].readCString();
                // 打印库名,用于调试。
                console.log(soName);
                // 检查库名是否包含 "libxiaojianbang.so"。
                if (soName.indexOf("libxiaojianbang.so") != -1) {
                    // 如果包含,则设置 this.hook 为 true,表示后续需要执行额外操作。
                    this.hook = true;
                }
            },
            // 在 'android_dlopen_ext' 函数调用后执行的代码。
            onLeave: function (retval) {
                // 检查之前是否设置了 this.hook。
                if (this.hook) {
                    // 如果是,调用 hookTest5 函数。
                    hookTest5();
                }
            }
        });
    }
}

主动调用JNI函数

这个函数用于劫持特定的 C 函数,
并在其执行过程中修改返回值。此函数特别针对 Android 应用中使用的 JNI (Java Native Interface) 
函数进行挂钩。这里的代码用 Frida 框架实现,它广泛用于动态分析和逆向工程。

// 定义 hookTest8 函数,用于挂钩并修改 JNI 函数的返回值。
function hookTest8() {
    // 使用 Frida 的 Module.findExportByName 方法找到特定动态库中导出的函数地址。
    // 这里的 "libxiaojianbang.so" 是库名,
    //"Java_com_xiaojianbang_app_NativeHelper_helloFromC" 是函数名。
    var funcAddr = Module.findExportByName("libxiaojianbang.so", "Java_com_xiaojianbang_app_NativeHelper_helloFromC");
    // 打印找到的函数地址,用于调试。
    console.log(funcAddr);
    // 检查函数地址是否有效。
    if (funcAddr != null) {
        // 如果地址有效,使用 Frida 的 Interceptor.attach 方法挂钩到该函数。
        Interceptor.attach(funcAddr, {
            // 在函数调用前执行的代码块,此处未进行任何操作。
            onEnter: function(args) {
            },
            // 在函数调用后执行的代码块。
            onLeave: function(retval) {
                // 尝试获取当前的 JNI 环境,这是与 Java 交互的接口。
                var env = Java.vm.tryGetEnv();
                // 使用 JNI 环境的 newStringUtf 方法创建一个新的 Java 字符串 "bbs.125.la"。
                var jstr = env.newStringUtf("bbs.125.la");
                // 使用 retval.replace 方法替换原始函数的返回值为新创建的 Java 字符串。
                retval.replace(jstr);
                // 使用 getStringUtfChars 方法将 Java 字符串转换为 C 字符串。
                var cstr = env.getStringUtfChars(jstr, null);
                // 打印 C 字符串的内容,用于验证转换是否成功。
                console.log(cstr.readCString());
                // 使用 hexdump 函数打印 C 字符串的内存布局,便于调试和分析内存内容。
                console.log(hexdump(cstr));
            }
        });
    }
}

这段代码主要在于监控和修改由 JNI 调用的 C 函数的行为。在 `onLeave` 钩子中,
通过 JNI 接口主动操作 Java 字符串和 C 字符串的转换,并修改了函数的返回值。

Hook libart 来Hook jni相关函数

函数主要用于监视和记录在 Android ART 运行时中由 `libart.so` 库导出的 `NewStringUTF` 函数的调用。
这里使用了 Frida 框架来实现函数挂钩和监控。

// 定义 hookTest10 函数,用于监控 ART 运行时中的 NewStringUTF 函数调用。
function hookTest10() {
    // 使用 Frida 的 Module.enumerateSymbols 方法列举指定库中的所有符号(函数、变量等)。
    var artSym = Module.enumerateSymbols("libart.so");
    // 定义一个变量用于存储 NewStringUTF 函数的地址。
    var NewStringUTFAddr = null;
    // 遍历找到的符号列表。
    for (var i = 0; i < artSym.length; i++) {
        // 检查符号名是否包含 "NewStringUTF",但不包含 "CheckJNI"。
        if (artSym[i].name.indexOf("CheckJNI") == -1 && artSym[i].name.indexOf("NewStringUTF") != -1) {
            // 打印找到的 NewStringUTF 函数的相关信息,用于调试和确认。
            console.log(JSON.stringify(artSym[i]));
            // 存储 NewStringUTF 函数的地址。
            NewStringUTFAddr = artSym[i].address;
        }
    }
    // 检查 NewStringUTF 函数地址是否有效。
    if (NewStringUTFAddr != null) {
        // 如果地址有效,使用 Frida 的 Interceptor.attach 方法挂钩到该函数。
        Interceptor.attach(NewStringUTFAddr, {
            // 在函数调用前执行的代码块。
            onEnter: function (args) {
                // 读取函数的第一个参数,即要转换的 C 字符串。
                console.log(args[1].readCString());
            },
            // 在函数调用后执行的代码块,此处未进行任何操作。
            onLeave: function (retval) {
            }
        });
    }
}

主要用于监控 ART 运行时中的 `NewStringUTF` 函数调用,并在函数调用前打印要转换的 C 字符串。
这对于了解应用程序在 JNI 层和 ART 运行时之间的交互非常有用。
通过 Frida 框架,可以方便地进行动态分析和调试。

so层主动调用任意函数

这个函数主要用于在 Android 应用中通过 Frida 和 JNI 接口直接调用一个指定的本地函数。
这种方法通常用于测试、调试或修改本地库中的特定功能。

// 定义 hookTest11 函数,用于在 Java 层执行环境中调用指定的本地函数。
function hookTest11() {
    // 使用 Java.perform 方法确保在正确的线程和执行环境中执行以下代码。
    Java.perform(function() {
        // 使用 Module.findBaseAddress 加上偏移量来定位 libxiaojianbang.so 中的特定函数地址。
        var funcAddr = Module.findBaseAddress("libxiaojianbang.so").add(0x23F4);
        // 使用 Frida 的 NativeFunction 类型来声明一个新的函数指针,指定该函数的返回类型和参数类型。
        var func = new NativeFunction(funcAddr, "pointer", ['pointer', 'pointer']);
        // 尝试获取当前的 JNI 环境,用于与 Java 层交互。
        var env = Java.vm.tryGetEnv();
        // 打印环境变量的信息,用于调试。
        console.log("env: ", JSON.stringify(env));
        // 检查是否成功获取到 JNI 环境。
        if (env != null) {
            // 使用 JNI 环境的 newStringUtf 方法创建一个新的 Java 字符串。
            var jstr = env.newStringUtf("xiaojianbang is very good!!!");
            // 调用之前声明的本地函数,传递 JNI 环境和 Java 字符串作为参数。
            var cstr = func(env, jstr);
            // 读取并打印从本地函数返回的 C 字符串。
            console.log(cstr.readCString());
            // 使用 hexdump 函数打印 C 字符串的内存布局,便于调试和分析内存内容。
            console.log(hexdump(cstr));
        }
    });
}

这段代码的关键在于它演示了如何在 Android 应用中结合使用 Frida 和 JNI 接口来直接调用内存中的
本地函数。通过这种方式,可以实现对本地代码的深入分析和调试。
此外,通过直接与 JNI 环境交互,可以更灵活地处理和修改应用程序的行为。

frida API 写文件

这个函数主要用于在 Android 设备上打开并写入文件,使用的是 JavaScript 的 `File` 对象,
这在用于测试、记录数据或进行文件操作时非常有用。

// 定义 hookTest12 函数,用于在 Android 设备的 sdcard 上创建并写入文件。
function hookTest12() {
    // 创建一个新的 File 对象,指定文件路径为 "/sdcard/xiaojianbang.txt",并设置模式为 "w"(写入模式)。
    var ios = new File("/sdcard/xiaojianbang.txt", "w");
    // 使用 File 对象的 write 方法写入字符串 "xiaojianbang is very good!!!\\n" 到文件中。
    ios.write("xiaojianbang is very good!!!\\n");
    // 调用 flush 方法确保所有数据都被写入到文件系统。
    ios.flush();
    // 完成文件操作后,调用 close 方法关闭文件。
    ios.close();
}

这段代码通过简单的 API 调用演示了如何在 Android 设备上进行文件写入操作。
这种操作可以用于保存日志、数据输出或其他需要持久化到设备存储的信息。在进行文件操作时,
需要确保应用有相应的权限来访问存储设备。
在 Android 平台上,通常需要在应用的 manifest 文件中声明对 `WRITE_EXTERNAL_STORAGE` 权限的需求,
以允许写入到外部存储。

Hook libc 写文件

这个函数主要用于在 Android 设备上使用 `libc.so` 中的 `fopen`、`fputs` 和 `fclose` 函数来打开、
写入和关闭文件。通过 Frida 框架,

// 定义 hookTest13 函数,用于在 Android 设备上使用 libc.so 中的文件操作函数进行文件写入。
function hookTest13() {
    // 使用 Module.findExportByName 方法查找 libc.so 中的 fopen、fputs 和 fclose 函数的地址。
    var addr_fopen = Module.findExportByName("libc.so", "fopen");
    var addr_fputs = Module.findExportByName("libc.so", "fputs");
    var addr_fclose = Module.findExportByName("libc.so", "fclose");
    // 打印找到的函数地址,用于调试。
    console.log("addr_fopen:", addr_fopen, "addr_fputs:", addr_fputs, "addr_fclose:", addr_fclose);
    // 使用 NativeFunction 类型声明这些函数的函数指针,指定返回类型和参数类型。
    var fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);
    var fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);
    var fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);
    // 使用 Memory.allocUtf8String 方法分配存储文件路径和打开模式的内存空间。
    var filename = Memory.allocUtf8String("/sdcard/xiaojianbang.txt");
    var open_mode = Memory.allocUtf8String("w");
    // 调用 fopen 函数打开指定路径的文件,并传递文件路径和打开模式作为参数。
    var file = fopen(filename, open_mode);
    // 打印 fopen 返回的文件指针,用于调试。
    console.log("fopen:", file);
    // 使用 Memory.allocUtf8String 方法分配存储要写入文件的内容的内存空间。
    var buffer = Memory.allocUtf8String("bbs.125.la\\n");
    // 调用 fputs 函数将内容写入文件,并传递内容和文件指针作为参数。
    var retval = fputs(buffer, file);
    // 打印 fputs 函数的返回值,用于确认写入是否成功。
    console.log("fputs:", retval);
    // 调用 fclose 函数关闭文件,并传递文件指针作为参数。
    fclose(file);
}

这段代码展示了如何使用 Frida 在运行时劫持 `libc.so` 中的文件操作函数,以实现文件写入操作。
通过调用 `fopen` 打开文件、`fputs` 写入内容和 `fclose` 关闭文件,
可以在 Android 设备上进行文件操作。确保在使用时拥有合适的权限以及对文件系统的访问权限。

inlineHook与寄存器Hook

该函数使用 Frida 框架在 Android 设备上拦截共享库中特定函数的调用。
此函数专注于在函数调用期间操作寄存器,以动态修改行为或结果。

// 定义 hookTest14 函数,用于劫持指定动态库中的函数。
function hookTest14() {
    // 使用 Module.findBaseAddress 查找 "libxiaojianbang.so" 动态库的基地址。
    var soAddr = Module.findBaseAddress("libxiaojianbang.so");
    // 打印基地址,用于调试。
    console.log(soAddr);
    // 计算函数 "sub_2894" 的地址,根据平台差异可能需要调整地址计算方式(比如 THUMB 模式需要加1)。
    var sub_2894 = soAddr.add(0x2894); 
    // 打印计算得到的函数地址,用于调试。
    console.log(sub_2894);
    // 检查 "sub_2894" 地址是否有效。
    if(sub_2894 != null) {
        // 使用 Interceptor.attach 方法挂钩到 "sub_2894" 函数。
        Interceptor.attach(sub_2894, {
            // 当函数进入时执行的代码块。
            onEnter: function() {
                // 打印进入函数时第一个参数 x0 的值。
                console.log(this.context.x0.toInt32());
                // 修改 x0 寄存器的值。
                this.context.x0 = 0x1000;
                // 打印修改后 x0 寄存器的值。
                console.log(this.context.x0.toInt32());
            },
            // 当函数离开时执行的代码块。
            onLeave: function() {
            }
        });
    }
    // 重复上述步骤,但针对另一个函数 "sub_2858"。
    var sub_2858 = soAddr.add(0x2858);
    // 打印 "sub_2858" 的地址。
    console.log(sub_2858);
    // 检查 "sub_2858" 地址是否有效。
    if(sub_2858 != null) {
        // 挂钩到 "sub_2858" 函数。
        Interceptor.attach(sub_2858, {
            // 当函数进入时执行的代码块。
            onEnter: function() {
                // 打印进入函数时第二个参数 x1 的值。
                console.log(this.context.x1);
                // 修改 x1 寄存器的值为指定地址。
                this.context.x1 = soAddr.add(0x2C35);
                // 打印修改后 x1 寄存器的值。
                console.log(this.context.x1);
            },
            // 当函数离开时执行的代码块。
            onLeave: function() {
            }
        });
    }
}

这个函数展示了如何在特定函数内拦截并操作寄存器,提供了对内部计算的实时洞察和控制。
它特别适用于本地应用程序的调试、测试和逆向工程任务。
主要包括地址计算、拦截执行和动态修改寄存器值。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Frida-server-15.2.2-android-x86是一款适用于安卓x86架构的Frida服务器的版本。Frida是一种开源的动态插桩框架,可用于安卓设备上的应用程序逆向工程和安全性评估。 Frida-server是Frida框架中的一部分,用于在安卓设备上与Frida客户端通信。Frida-server是在设备上运行的服务,可以与Frida客户端(通常是运行在PC上的Frida工具)进行通信,并接收来自客户端的指令。 Frida-server-15.2.2-android-x86适用于安卓x86架构的设备。x86是一种PC上常见的处理器架构,而不是常用于移动设备的ARM架构。因此,如果你的安卓设备是基于x86架构的,那么你可以使用这个版本的Frida-server在设备上运行Frida服务。 通过在设备上运行Frida-server,你可以利用Frida的强大功能来分析、修改和控制应用程序。Frida允许你动态地插入JavaScript代码到应用程序中,以实时地跟踪和修改应用程序的行为。你可以使用Frida进行代码注入、函数钩子、网络流量捕获、数据修改等操作,以便进行应用程序逆向工程、漏洞挖掘、安全性评估等任务。 总而言之,Frida-server-15.2.2-android-x86是一种适用于安卓x86架构设备的Frida服务器版本,通过在设备上运行Frida-server,你可以利用Frida框架的功能对应用程序进行逆向工程和安全性评估。 ### 回答2: frida-server-15.2.2-android-x86是一款用于Android x86架构的Frida服务器。Frida是一种强大的开源工具,用于分析、修改和调试软件。它可以通过脚本语言来进行动态注入和操作,支持多种平台和架构。 通过使用frida-server-15.2.2-android-x86,我们可以在Android x86设备上安装和运行Frida服务器。安装frida-server时我们需要将其推送到设备上,并在设备上运行它。运行成功后,我们可以通过Frida客户端连接到该设备上的Frida服务器,并使用Frida的功能进行应用程序的分析、修改和调试。 Frida-server-15.2.2-android-x86版本适用于Android x86架构的设备。在使用时,我们首先需要确保设备已经以root权限运行,并且具备adb工具的连接。然后,我们可以通过命令行将frida-server-15.2.2-android-x86安装到设备上。在设备上运行frida-server时,它会监听指定的端口,并等待Frida客户端的连接。 通过与Frida服务器建立连接,我们可以使用JavaScript或Python等脚本语言来进行动态插桩、API Hook、函数跟踪等操作。Frida提供了强大的API,使得应用程序的分析和修改变得更加简单高效。使用Frida,我们可以实时监测应用程序的行为,获取关键信息,进行漏洞分析,甚至可以修改应用程序的逻辑和数据。 总之,frida-server-15.2.2-android-x86是一款用于Android x86平台的Frida服务器,它提供了强大的功能和API,用于动态分析、修改和调试应用程序。通过与Frida客户端的连接,我们可以通过脚本语言来操作和控制应用程序,使得应用程序的分析和修改变得更加高效和可靠。 ### 回答3: Frida-Server是一款功能强大的开源工具,用于在Android设备上进行动态代码注入和调试。frida-server-15.2.2-android-x86指的是适用于Android x86架构的Frida-Server版本15.2.2。 Frida-Server能够以服务的形式运行在目标Android设备上,通过与Frida桌面端或其他脚本进行通信,来实现对目标应用程序的动态分析和操作。它提供了一套JavaScript API,允许我们在运行时通过修改和执行目标应用程序中的代码来实现功能扩展,如函数拦截、数据修改等。 在具体使用时,首先需要在目标Android设备上安装Frida-Server,这个版本适用于x86架构的设备。其次,需要将Frida-Server与Frida桌面端或其他脚本工具配合使用,以实现与目标应用程序的通信。我们可以通过Frida提供的命令行工具或编写脚本的方式来进行代码注入和调试。 Frida-Server-15.2.2-android-x86版本对于使用x86架构的Android设备来说是必需的,因为它能够确保Frida-Server能在这样的设备上正确运行。使用适合设备架构的版本,可以保证性能和稳定性,并且避免兼容性问题。 总而言之,Frida-Server-15.2.2-android-x86是一款用于在Android x86架构设备上进行动态代码注入和调试的工具,通过与Frida桌面端或其他脚本进行通信来实现相关功能。它可以帮助安全研究人员、开发人员等对Android应用程序进行潜在威胁分析、性能优化以及功能增强等工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值