FridaHook(二)——Native层函数

By ruanruan,2022.04.19

0x00 前言

so文件当中的函数,分为导出函数和未导出函数两种,导出函数打开IDA后能够在导出表中找到的函数就是导出函数,未导出函数则在导出表中寻找不到,一般来说静态编写的native函数都能在导出表中寻找到,而动态加载的则无法在导出表中发现

下面是学习用Frida hook Native层的导出函数和未导出函数的记录。

demo下载链接:https://pan.baidu.com/s/1ZCIeJXzeTpQ8uJ9Ew5nnGQ
提取码:z94i

0x01 Hook导出函数

1、apk相关信息

关键代码:

FridaHook(二)——Native层函数_第1张图片

用IDA分析,查找函数

FridaHook(二)——Native层函数_第2张图片

点击按钮,实现1+2=3的功能

FridaHook(二)——Native层函数_第3张图片

2、js代码

修改输出值3为指定值。

Java.perform(function(){ 
	//下面这一句代码是指定要Hook的so文件名和要Hook的函数名,函数名即IDA导出表中显示的函数名
    var nativePointer = Module.findExportByName("libfridaso.so", "Java_com_example_fridaso_FridaSoDefine_FridaSo"); 
    send("native: " + nativePointer); 
    Interceptor.attach(nativePointer, { 
        onEnter: function(args){ 
        	//进入该函数前要执行的代码,第三个参数才是传入的参数
            send(args[0]); 
            send(args[1]); 
            send(args[2].toInt32()); 
            send(args[3].toInt32()); 
            //send(args[4].toInt32()); 
        }, 
        onLeave: function(retval){ 
            send(retval.toInt32()); 
            retval.replace(10000);//将输出值替换为10000
            send(retval.toInt32());
        } 
    });
});

retval对象只在 onLeave函数作用域范围内有效。

3、frida hook

一般顺序为:

手机运行frida

在这里插入图片描述

转发端口

adb forward tcp:27043 tcp:2703

手机运行app

查看pid,执行hook脚本

frida-ps -U

在这里插入图片描述

frida -U -l fridaso.js 22467

点击按钮。

命令行和app都能看到被篡改的结果为10000,而不是3。

FridaHook(二)——Native层函数_第4张图片

FridaHook(二)——Native层函数_第5张图片

也可以先点击按钮,再执行hook脚本。

4、踩坑

遇到的问题:

(1)python代码不能根据包名指定进程

FridaHook(二)——Native层函数_第6张图片

(2)不能通过pid查找进程

FridaHook(二)——Native层函数_第7张图片

(3)找不到基地址

FridaHook(二)——Native层函数_第8张图片

解决:

后两个问题在确定js脚本没有问题,更换模拟器为测试机后,可以成功hook

第一个问题在之后需注意,使用python脚本进行hook时不能指定pid,在调用进程时按照包名查找不一定成功,最好还是用js脚本指定相应pid进行hook。

0x02 Hook未导出函数

1、apk相关信息

页面功能:

点击按钮显示3

FridaHook(二)——Native层函数_第9张图片

MainActivity:

FridaHook(二)——Native层函数_第10张图片

进一步查看

FridaHook(二)——Native层函数_第11张图片

在Ghidra查看该函数

FridaHook(二)——Native层函数_第12张图片

2、查看函数地址
(1)通过IDA查看地址

FridaHook(二)——Native层函数_第13张图片

脚本1.1:

Java.perform(function(){ 
    var soAddr = Module.findBaseAddress("libfridaso.so"); 
    send('soAddr: ' + soAddr); 
    var MD5FinalAddr = soAddr.add(0x0770+1); 
    //1768为函数偏移量 
    send('MD5FinalAddr: ' + MD5FinalAddr); 
    Interceptor.attach(MD5FinalAddr, { 
        onEnter: function(args){
            send(args[0]); 
            send(args[1]);
        }, 
        onLeave: function(retval){ 
            send(retval); 
        } 
    }); 
});
(2)通过Ghidra查看地址(X86_64)

FridaHook(二)——Native层函数_第14张图片

脚本1.2:

Java.perform(function(){ 
    var soAddr = Module.findBaseAddress("libfridaso.so"); 
    send('soAddr: ' + soAddr); 
    var MD5FinalAddr = soAddr.add(0x05cf+1); 
    //1768为函数偏移量 
    send('MD5FinalAddr: ' + MD5FinalAddr); 
    Interceptor.attach(MD5FinalAddr, { 
        onEnter: function(args){
            send(args[0]); 
            send(args[1]); 
            send(args[2].toInt32()); 
            send(args[3].toInt32()); 
        }, 
        onLeave: function(retval){ 
            send("result: "+retval.toInt32()); 
        } 
    }); 
});
(3)最终版
  • 通过已导出的hook方法获得地址值

    FridaHook(二)——Native层函数_第15张图片

    得到偏移地址为0x7966b8d5dc

  • 通过Ghidra查看地址(arm64)

    FridaHook(二)——Native层函数_第16张图片

Java.perform(function(){ 
    var soAddr = Module.findBaseAddress("libfridaso.so"); 
    send('soAddr: ' + soAddr); 
    var MD5FinalAddr = soAddr.add(0x05db+1); 
    //1768为函数偏移量 
    send('MD5FinalAddr: ' + MD5FinalAddr); 
    Interceptor.attach(MD5FinalAddr, { 
        onEnter: function(args){
        	send("111");
            send(args[0]); 
            send(args[1]); 
            send(args[2].toInt32()); 
            send(args[3].toInt32()); 
        }, 
        onLeave: function(retval){ 
            send("result: "+retval.toInt32()); 
        } 
    }); 
});

hook结果:

FridaHook(二)——Native层函数_第17张图片

3、修改返回值

找到正确的偏移地址,再修改返回值就很简单了

(1)hook.js
Java.perform(function(){ 
    var soAddr = Module.findBaseAddress("libfridaso.so"); 
    send('soAddr: ' + soAddr); 
    var MD5FinalAddr = soAddr.add(0x05db+1); 
    //1768为函数偏移量 
    send('MD5FinalAddr: ' + MD5FinalAddr); 
    Interceptor.attach(MD5FinalAddr, { 
        onEnter: function(args){
            send(args[0]); 
            send(args[1]); 
            send(args[2].toInt32()); 
            send(args[3].toInt32()); 
        }, 
        onLeave: function(retval){ 
            send("result1: "+retval.toInt32()); 
            retval.replace(2022);
            send("result2: "+retval.toInt32());
        } 
    }); 
});
(2)运行结果

FridaHook(二)——Native层函数_第18张图片

(3)APP显示

FridaHook(二)——Native层函数_第19张图片

4、踩坑记录
(1)环境相关
A、测试机安装同电脑版本的magiskfrida报错

在这里插入图片描述

解决:搜索引擎搜不到相关报错,但从错误来看 会比较底层。最终通过安装高版本的magiskfrida解决

B、很多报错能通过修改时间解决,但是在使用NTP时间服务器来修改时间但不准确

原因是刷机时的时区设置问题,修改时区即可解决

(2)脚本相关
A、如何正确查看偏移地址问题

要根据所用测试机、模拟器的系统架构(arm64、X86…),来选择对应的so文件,再用Ghidra分析查看函数地址。

直接运行frida命令查看只会返回基地址和偏移量地址,进不了Interceptor接口

FridaHook(二)——Native层函数_第20张图片

如果地址错误就会一直报错:拦截器找不到该地址的函数,说明是找的偏移地址错了。

FridaHook(二)——Native层函数_第21张图片

B、frida命令参数–no-pause

进程直接执行

对比是否使用–no-pause参数,在这个场景对参数地址的运行结果影响不大

使用参数运行:

FridaHook(二)——Native层函数_第22张图片

不用参数运行:

FridaHook(二)——Native层函数_第23张图片

(3)小技巧
  • 遇到问题看官方文档:https://frida.re/docs/gadget/
  • 在cmd调试hook脚本时会更快发现问题
  • frida-ps -U查看app进程时可以加个a来查看当前正在运行的进程软件:frida-ps -Ua

0x03 总结

Hook导出函数主要是根据so文件中函数名来确定被Hook的函数,较为简单。而Hook 未导出函数是根据函数偏移量来确定被Hook的函数,但是一定要注意在使用工具反编译时要选对架构。也可以用Hook 未导出函数的方法来Hook导出函数。

你可能感兴趣的:(安全)