首页
社区
课程
招聘
[原创]Frida-Hook-Native层操作大全
发表于: 2024-3-7 21:15 17828

[原创]Frida-Hook-Native层操作大全

2024-3-7 21:15
17828

对于Native层的函数Hook,我们使用如下模板

file
可以发现,程序从EditText控件中获取到了用户的输入,然后调用了native层中的cmpstr函数进行比较。

file
程序在cmpstr中使用了strcmp函数,那么我们只需要拿到strcmp函数的传入参数就可以知道程序的正确输入了

首先我们使用Module.enumerateImports("libfrida0x8.so")查看导入表
file
可以发现strcmp来自于libc.so,那么我们就可以使用Module.findExportByName("libc.so","strcmp");来获取strcmp的地址了
file

获取了strcmp的地址就可以使用之前给的模板进行Hook了

但是我们需要注意的是strcmp可能不止调用一次,因此我们需要判断strcmp的第一个参数是否为0我们才进行操作,不然hook可能会一直循环输出
file
因此我们可以使用Memory.readUtf8String(args[0]);来获取我们的输入字符串,平且使用 if (input.includes("111"))来判断

file

首先还是给出hook的模板如下:

可以看到在onLeave中有一个参数retval,这个retval,就是我们hook上的程序的返回值,我们可以使用retval.replace(val)来修改返回值。

file
可以发现程序根据native层的check_flag 方法的返回值

file
只是简简单单的返回了一个1

首先使用Module.enumerateExports("liba0x9.so"),查看导出表,看看check_flag方法的偏移地址
file
然后就可以使用模板一把梭了

file

让我提供一个模板。

让我逐行解释。

要在 Frida 中调用一个本地函数,我们需要一个 NativePointer 对象。我们应该将要调用的本地函数的地址传递给 NativePointer 构造函数。接下来,我们将创建 NativeFunction 对象,它表示我们想要调用的实际本地函数。它在本地函数周围创建一个 JavaScript 包装器,允许我们从 Frida 调用该本地函数。

第一个参数应该是 NativePointer 对象,第二个参数是本地函数的返回类型,第三个参数是要传递给本地函数的参数的数据类型列表。现在我们可以像在 Java 空间中那样调用该方法了。

好的,我们明白了。让我们来看看例题。

file
发现就是在主函数中加载了stringFromJNI

file
没有关于flag的信息,但是有未被调用的flag函数,我们直接使用hook调用它输出log
file

file

首先我们先看来自x86指令集的frida使用模板

X86Writer的实例化:

**插入指令 **

刷新更改:

清理:

解除段只读权限
Memory.protect 。我们可以使用这个函数来修改内存区域的保护属性。Memory.protect 函数的语法如下:

那么如何使用进行覆写呢
对于x86系统而言我们首先需要查看官方文档中的使用方法
https://frida.re/docs/javascript-api/#x86writer

file
对与arm64系统而言,我们使用如下api
https://frida.re/docs/javascript-api/#arm64writer

file
接下来让我用一个用例程序来讲一下这个指令的用法,我们示范的内容为arm64架构

首先我们看到MainActivity函数内容
file
发现MainActivity就是在用户点击按钮后调用了getflag方法,但是正常点击getflag方法并不会返回flag值。

file
惊讶的发现MainActivity中什么都没有,显然这是不存在的。接下来我们到控制流窗口中查看。
file
查看控制流发现程序出现了永假条件跳转。导致导致ida识别不到输出flag的功能。那么我们可以把这个B.NE给Nop掉即可
首先我们需要计算B.NE的偏移地址
file
可以发现就是基地址增加15248,然后我们覆写为Nop就可以了

file

Interceptor.attach(targetAddress, {
    onEnter: function (args) {
        console.log('Entering ' + functionName);
        // Modify or log arguments if needed
    },
    onLeave: function (retval) {
        console.log('Leaving ' + functionName);
        // Modify or log return value if needed
    }
});
Interceptor.attach(targetAddress, {
    onEnter: function (args) {
        console.log('Entering ' + functionName);
        // Modify or log arguments if needed
    },
    onLeave: function (retval) {
        console.log('Leaving ' + functionName);
        // Modify or log return value if needed
    }
});
function hook(){
 
    var targetAddress = Module.findExportByName("libc.so","strcmp");
    console.log("Strcmp Address: ",targetAddress.toString(16));
 
    Interceptor.attach(targetAddress,{
        onEnter:function (args){
             
        },onLeave:function(retval){
 
        }
    })
    console.log("success!");
}
 
 
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(main);
function hook(){
 
    var targetAddress = Module.findExportByName("libc.so","strcmp");
    console.log("Strcmp Address: ",targetAddress.toString(16));
 
    Interceptor.attach(targetAddress,{
        onEnter:function (args){
             
        },onLeave:function(retval){
 
        }
    })
    console.log("success!");
}
 
 
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(main);
function hook(){
 
    var targetAddress = Module.findExportByName("libc.so","strcmp");
    console.log("Strcmp Address: ",targetAddress.toString(16));
 
    Interceptor.attach(targetAddress,{
        onEnter:function (args){
            var input = Memory.readUtf8String(args[0]);
            if (input.includes("111")){
                console.log(Memory.readUtf8String(args[1]));
            }
 
        },onLeave:function(retval){
 
        }
    })
    console.log("success!");
}
 
 
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(main);
function hook(){
 
    var targetAddress = Module.findExportByName("libc.so","strcmp");
    console.log("Strcmp Address: ",targetAddress.toString(16));
 
    Interceptor.attach(targetAddress,{
        onEnter:function (args){
            var input = Memory.readUtf8String(args[0]);
            if (input.includes("111")){
                console.log(Memory.readUtf8String(args[1]));
            }
 
        },onLeave:function(retval){
 
        }
    })
    console.log("success!");
}
 
 
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(main);
Interceptor.attach(functionaddr, {
    onEnter: function (args) {
 
    },
    onLeave: function (retval) {
 
    }
});
Interceptor.attach(functionaddr, {
    onEnter: function (args) {
 
    },
    onLeave: function (retval) {
 
    }
});
function hook(){
    var check_flag = Module.enumerateExports("liba0x9.so")[0]["address"];
    console.log("Func address = ",check_flag);
    Interceptor.attach(check_flag,{
        onEnter:function (args){
 
        },onLeave:function (retval){
            console.log("Origin retval : ",retval);
            retval.replace(1337);
        }
    })
}
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(hook);
function hook(){
    var check_flag = Module.enumerateExports("liba0x9.so")[0]["address"];
    console.log("Func address = ",check_flag);
    Interceptor.attach(check_flag,{
        onEnter:function (args){
 
        },onLeave:function (retval){
            console.log("Origin retval : ",retval);
            retval.replace(1337);
        }
    })
}
function main(){
    Java.perform(function (){
        hook();
    })
}
setImmediate(hook);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 18
支持
分享
最新回复 (13)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-3-8 11:17
1
雪    币: 1030
活跃值: (202)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
写的真多啊
2024-4-25 00:54
0
雪    币: 47
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qig
4
刚开始学这个工具的我,跟完了全部题目,感觉这些题目难度刚刚好,可以快速熟悉API,不过有一些写法在最新Frida版本编译不了,提示找不到方法.比如Module.enumerateImports("libfrida0x8.so"),readUtf8String方法等等. 不知道是不是Frida版本不同的原因.  还有从0xA题目开始,Android9里面运行不了apk,一运行就崩溃. 换到了Android13做. native的题目,我发现可以直接hook 那个 native api,不用管so文件,直接就能hook出来.
  
2024-5-17 18:50
0
雪    币: 1460
活跃值: (1921)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
qig 刚开始学这个工具的我,跟完了全部题目,感觉这些题目难度刚刚好,可以快速熟悉API,不过有一些写法在最新Frida版本编译不了,提示找不到方法.比如Module.enumerateImports(&qu ...
尽量避免模拟器
2024-5-27 09:41
0
雪    币: 218
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
Shangwendada 尽量避免模拟器
我用的实机,frida14.1.18版本的,这些函数也用不了
2024-6-4 16:32
0
雪    币: 1460
活跃值: (1921)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
7
F1nGY3 我用的实机,frida14.1.18版本的,这些函数也用不了[em_5]
现在都到16.2.5啦怎么还在用14
2024-6-5 10:18
0
雪    币: 250
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
大佬例题可以分享一下吗
2024-6-27 22:32
0
雪    币: 234
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
感谢大佬分享
2024-6-30 09:29
0
雪    币: 1460
活跃值: (1921)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
10
北袅 大佬例题可以分享一下吗
上一篇帖子给出了
2024-7-3 00:58
0
雪    币: 4741
活跃值: (1745)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
0x8这个,不知道为啥我替换了返回值,还是没有出flag
var input = ""
   Interceptor.attach(targetAddress,{
        onEnter:function(args){
            //console.log("args ");
            input = Memory.readUtf8String(args[0]);
            //console.log(Memory.readUtf8String(args[0]));
            if(input.includes("111")){
                console.log("---"+Memory.readUtf8String(args[0]));
                console.log("---"+Memory.readUtf8String(args[1]));
            }
        },onLeave:function(retval){
            if(input.includes("111")){
                console.log("retval is:"+retval);
                //retval = 1;
                
                retval.replace(1)
                console.log("after retval is:"+retval);
            }
            //retval = 1;
        }
   })
}
2024-7-11 15:06
0
雪    币: 1460
活跃值: (1921)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
12
passself 0x8这个,不知道为啥我替换了返回值,还是没有出flag var input = "" Interceptor.attach(targetAddress,{ ...
在logcat中查看
2024-7-12 18:44
0
雪    币: 250
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
佬你IDApro啥版本
2024-11-10 13:47
0
雪    币: 1460
活跃值: (1921)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
14
北袅 佬你IDApro啥版本
7.7
2024-11-10 18:43
0
游客
登录 | 注册 方可回帖
返回
//