前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >安卓Frida Hook之Frida-Native-Hook

安卓Frida Hook之Frida-Native-Hook

作者头像
用户1423082
发布于 2024-12-31 12:24:04
发布于 2024-12-31 12:24:04
31100
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

实验环境

windows 10 vscode frida 16.2.1 jadx-gui

Frida相关api介绍

1.Process、Module、Memory基础

1.Process

Process 对象代表当前被Hook的进程,能获取进程的信息,枚举模块,枚举范围等

API

含义

Process.id

返回附加目标进程的 PID

Process.isDebuggerAttached()

检测当前是否对目标程序已经附加

Process.enumerateModules()

枚举当前加载的模块,返回模块对象的数组

Process.enumerateThreads()

枚举当前所有的线程,返回包含 id, state, context 等属性的对象数组

### 2.Module

Module 对象代表一个加载到进程的模块(例如,在 Windows 上的 DLL,或在 Linux/Android 上的 .so 文件),能查询模块的信息,如模块的基址、名称、导入/导出的函数等

API

含义

Module.load()

加载指定so文件,返回一个Module对象

enumerateImports()

枚举所有Import库函数,返回Module数组对象

enumerateExports()

枚举所有Export库函数,返回Module数组对象

enumerateSymbols()

枚举所有Symbol库函数,返回Module数组对象

Module.findExportByName(exportName)、Module.getExportByName(exportName)

寻找指定so中export库中的函数地址

Module.findBaseAddress(name)、Module.getBaseAddress(name)

返回so的基地址

3.Memory

Memory是一个工具对象,提供直接读取和修改进程内存的功能,能够读取特定地址的值、写入数据、分配内存等

方法

功能

Memory.copy()

复制内存

Memory.scan()

搜索内存中特定模式的数据

Memory.scanSync()

同上,但返回多个匹配的数据

Memory.alloc()

在目标进程的堆上申请指定大小的内存,返回一个NativePointer

Memory.writeByteArray()

将字节数组写入一个指定内存

Memory.readByteArray

读取内存

2.枚举导入导出表

  1. 导出表(Export Table):列出了库中可以被其他程序或库访问的所有公开函数和符号的名称。
  2. 导入表(Import Table):列出了库需要从其他库中调用的函数和符号的名称。

简而言之,导出表告诉其他程序:“这些是我提供的功能。”,而导入表则表示:“这些是我需要的功能。”。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest1(){
    Java.perform(function(){
        //打印导入表
        var imports = Module.enumerateImports("lib52pojie.so");
        for(var i =0; i < imports.length;i++){
            if(imports[i].name == "vip"){
                console.log(JSON.stringify(imports[i])); //通过JSON.stringify打印object数据
                console.log(imports[i].address);
            }
        }
        //打印导出表
        var exports = Module.enumerateExports("lib52pojie.so");
        for(var i =0; i < exports.length;i++){
            console.log(JSON.stringify(exports[i]));
        }
        
    })
}

3.Native函数的基础Hook打印

  1. 整数型、布尔值类型、char类型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest2(){
    Java.perform(function(){
        //根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so","Java_com_zj_wuaipojie_util_SecurityUtil_checkVip");
        console.log(helloAddr); 
        if(helloAddr != null){
	        //Interceptor.attach是Frida里的一个拦截器
            Interceptor.attach(helloAddr,{
	            //onEnter里可以打印和修改参数
                onEnter: function(args){  //args传入参数
                    console.log(args[0]);  //打印第一个参数的值
                    console.log(this.context.x1);  // 打印寄存器内容
                    console.log(args[1].toInt32()); //toInt32()转十进制
					console.log(args[2].readCString()); //读取字符串 char类型
					console.log(hexdump(args[2])); //内存dump

                },
                //onLeave里可以打印和修改返回值
                onLeave: function(retval){  //retval返回值
                    console.log(retval);
                    console.log("retval",retval.toInt32());
                }
            })
        }
    })
}
  1. 字符串类型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest2(){
    Java.perform(function(){
        //根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so","Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel");
        if(helloAddr != null){
            Interceptor.attach(helloAddr,{
                //onEnter里可以打印和修改参数
                onEnter: function(args){  //args传入参数
                    // 方法一
                    var jString = Java.cast(args[2], Java.use('java.lang.String'));
                    console.log("参数:", jString.toString());
                    // 方法二
                    var JNIEnv = Java.vm.getEnv();
                    var originalStrPtr = JNIEnv.getStringUtfChars(args[2], null).readCString();	
                    console.log("参数:", originalStrPtr);				
                },
                //onLeave里可以打印和修改返回值
                onLeave: function(retval){  //retval返回值
                    var returnedJString = Java.cast(retval, Java.use('java.lang.String'));
                    console.log("返回值:", returnedJString.toString());
                }
            })
        }
    })
}

4.Native函数的基础Hook修改

  1. 整数型修改
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest3(){
    Java.perform(function(){
        //根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so","func_four");
        console.log(helloAddr);
        if(helloAddr != null){
            Interceptor.attach(helloAddr,{
                onEnter: function(args){  //args参数
                    args[0] = ptr(1000); //第一个参数修改为整数 1000,先转为指针再赋值
                    console.log(args[0]);
                      
                },
                onLeave: function(retval){  //retval返回值
                    retval.replace(20000);  //返回值修改
                    console.log("retval",retval.toInt32());
                }
            })
        }
    })
}
  1. 字符串类型修改
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest2(){
    Java.perform(function(){
        //根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so","Java_com_zj_wuaipojie_util_SecurityUtil_vipLevel");
        if(helloAddr != null){
            Interceptor.attach(helloAddr,{
                //onEnter里可以打印和修改参数
                onEnter: function(args){  //args传入参数
                    var JNIEnv = Java.vm.getEnv();
                    var originalStrPtr = JNIEnv.getStringUtfChars(args[2], null).readCString();	
                    console.log("参数:", originalStrPtr);
                    var modifiedContent = "至尊";
                    var newJString = JNIEnv.newStringUtf(modifiedContent);
                    args[2] = newJString;				
                },
                //onLeave里可以打印和修改返回值
                onLeave: function(retval){  //retval返回值
                    var returnedJString = Java.cast(retval, Java.use('java.lang.String'));
                    console.log("返回值:", returnedJString.toString());
                    var JNIEnv = Java.vm.getEnv();
                    var modifiedContent = "无敌";
                    var newJString = JNIEnv.newStringUtf(modifiedContent);
                    retval.replace(newJString);
                }
            })
        }
    })
}

5.SO基址的获取方式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var moduleAddr1 = Process.findModuleByName("lib52pojie.so").base;  
var moduleAddr2 = Process.getModuleByName("lib52pojie.so").base;  
var moduleAddr3 = Module.findBaseAddress("lib52pojie.so");

6.Hook未导出函数与函数地址计算

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest6(){
    Java.perform(function(){
        //根据导出函数名打印基址
        var soAddr = Module.findBaseAddress("lib52pojie.so");
        console.log(soAddr);
        var funcaddr = soAddr.add(0x1071C);  
        console.log(funcaddr);
        if(funcaddr != null){
            Interceptor.attach(funcaddr,{
                onEnter: function(args){  //args参数
 
                },
                onLeave: function(retval){  //retval返回值
                    console.log(retval.toInt32());
                }
            })
        }
    })
}

函数地址计算

  1. 安卓里一般32 位的 so 中都是thumb指令,64 位的 so 中都是arm指令
  2. 通过IDA里的opcode bytes来判断,arm 指令为 4 个字节(options -> general -> Number of opcode bytes (non-graph) 输入4)
  3. thumb 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移 + 1 arm 指令,函数地址计算方式: so 基址 + 函数在 so 中的偏移 7.Hook_dlopen dlopen源码

android_dlopen_ext源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hook_dlopen() {
    var dlopen = Module.findExportByName(null, "dlopen");
    Interceptor.attach(dlopen, {
        onEnter: function (args) {
            var so_name = args[0].readCString();
            if (so_name.indexOf("lib52pojie.so") >= 0) this.call_hook = true;
        }, onLeave: function (retval) {
            if (this.call_hook) hookTest2();
        }
    });
    // 高版本Android系统使用android_dlopen_ext
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    Interceptor.attach(android_dlopen_ext, {
        onEnter: function (args) {
            var so_name = args[0].readCString();
            if (so_name.indexOf("lib52pojie.so") >= 0) this.call_hook = true;
        }, onLeave: function (retval) {
            if (this.call_hook) hookTest2();
        }
    });
}

8.借助IDA脚本实现一键式hook

通过MyIDAFrida直接生成,默认应该只适用于attach模式

粘贴到文件,之后也是通过的方式启动

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
frida -U wuaipojie -l .\idahook.js

java层hook对应

  1. 通过java层修改
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义一个名为hookTest1的函数
function hookTest1(){
	let SecurityUtil = Java.use("com.zj.wuaipojie.util.SecurityUtil");
    SecurityUtil["checkVip"].implementation = function () {
        console.log(`SecurityUtil.checkVip is called`);
        let result = this["checkVip"]();
        console.log(`SecurityUtil.checkVip result=${result}`);
        return true;
    };
}
  1. 通过hook java层
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function hookTest2(){
    Java.perform(function(){
        //根据导出函数名打印地址
        var helloAddr = Module.findExportByName("lib52pojie.so","Java_com_zj_wuaipojie_util_SecurityUtil_checkVip");
        console.log(helloAddr); 
        if(helloAddr != null){
	        //Interceptor.attach是Frida里的一个拦截器
            Interceptor.attach(helloAddr,{
	            //onEnter里可以打印和修改参数
                onEnter: function(args){  //args传入参数
                    // console.log(args[0]);  //打印第一个参数的值
                    // console.log(this.context.x1);  // 打印寄存器内容
                    // console.log(args[1].toInt32()); //toInt32()转十进制
					// console.log(args[2].readCString()); //读取字符串 char类型
					// console.log(hexdump(args[2])); //内存dump

                },
                //onLeave里可以打印和修改返回值
                onLeave: function(retval){  //retval返回值
                    console.log(retval);
                    // console.log("retval",retval.toInt32());
                    retval.replace(1);
                }
            })
        }
    })
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
攻防|记一次攻防演练实战总结
https://hunter.qianxin.com/ https://fofa.info/ https://quake.360.cn/
亿人安全
2022/12/22
1.7K0
攻防|记一次攻防演练实战总结
攻防演练-某集团红队检测
链接:https://github.com/EdgeSecurityTeam/EHole
hyyrent
2022/12/26
7750
攻防演练-某集团红队检测
攻防 | 记一次打穿xx公司域控
https://www.freebuf.com/articles/web/373114.html
亿人安全
2023/08/10
4350
攻防 | 记一次打穿xx公司域控
从 Github 泄露到拨入 V*N 拿到域控
大家好,这里是 渗透攻击红队 的第 60 篇文章,本公众号会记录一些红队攻击的案例,不定时更新
渗透攻击红队
2021/07/14
9150
从DNSBeacon到域控
首先,在资产某处发现存在SQL注入,数据库类型是SQLServer,并且当前用户为sa管理用户。
谢公子
2022/01/20
1.8K0
从DNSBeacon到域控
从cve到幸运域控
前言 这次渗透测试是从一个CVE开始的,从阿三外网的Jboss打点到内网然后到域控,手法很简单常规,主要还是要扩展一下思路吧哈哈哈!
黑白天安全
2021/02/26
1.2K0
从cve到幸运域控
从外网SiteServer前端漏洞getshell,到远程加载shellcode绕过杀软360全家桶杀入内网域控
windows 2016 web:192.168.2.29 - www.moonlab.com(外网)、10.10.1.131(内网)
渗透攻击红队
2020/11/25
5K0
从外网SiteServer前端漏洞getshell,到远程加载shellcode绕过杀软360全家桶杀入内网域控
域控被突破的几种途径v2
写在前面:前面一篇公众号主要是一些突破域控的思路,许多师傅建议我放一些相关技术文章链接方便大家学习,于是就有了第二版。同时也感谢各位师傅的一些思路,本文增加了WSUS、SCCM服务器到域控的途径和域控运维人员密码管理不当造成域控突破的途径。另外希望大家看相关攻击路径的时候,也可以想想为什么域控运维人员要这样配置,这可以帮助大家更好的理解漏洞。
JDArmy
2022/06/06
1.4K0
红队技巧-域渗透的协议利用
哈希传递(pth)攻击是指攻击者可以通过捕获密码的hash值(对应着密码的值),然后简单地将其传递来进行身份验证,以此来横向访问其他网络系统,攻击者无须通过解密hash值来获取明文密码,因为对于每个Session hash值都是固定的,除非密码被修改了(需要刷新缓存才能生效),所以pth可以利用身份验证协议来进行攻击,攻击者通常通过抓取系统的活动内存和其他技术来获取哈希。
Gamma实验室
2021/07/01
1.6K0
攻防|记一次攻防案例总结
由于传播、利用本公众号亿人安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号亿人安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
亿人安全
2023/12/25
7490
攻防|记一次攻防案例总结
浅谈攻防演练
国家级攻防演练从2016年开始,已经走过了6个年头,它是由公安部组织的,这个网络安全攻防演练集结了国家顶级的攻防力量,以不限制手段、路径,进行获取权限并攻陷指定靶机为目的实战攻防演练。
小道安全
2022/04/28
2.7K0
浅谈攻防演练
漫谈攻击链:从WebShell到域控的奇妙之旅
做渗透测试时遇到的域环境经常就是要么太复杂我们搞不定,要么太简单进去就拿到域控没啥意思,这些显然都无法满足我们实践已掌握知识的刚需。同时为了给我们道格安全技术小组的小伙伴们搭建线下实战环境,笔者索性自己搭建了一套完整的域环境,通过实战时遇到的一些坑来配备合适的漏洞,让域渗透不再神秘,也大大增加我们对知识的理解程度,下面我将为大家揭露从web到域控的奇妙旅程!文末有相关下载链接。
FB客服
2018/07/30
1.2K0
漫谈攻击链:从WebShell到域控的奇妙之旅
sql注入到获得域控-下
内网中的机器: 1.在域中,分为高权限(域控)、低权限(域成员) 2.域控的密码和用户能够登陆所有加入域的机器。 3.不在域中:互相有联系,但是是平级。
kam1
2022/03/08
1.1K0
sql注入到获得域控-下
从外网Thinkphp3日志泄露到杀入内网域控 - 红队攻击之域内靶机渗透实战演练
由上图可知,目标开放了80端口,其中用的是phpstudy搭建的网站,用ip打开发现是一个403:
渗透攻击红队
2020/11/25
9.1K0
从外网Thinkphp3日志泄露到杀入内网域控 - 红队攻击之域内靶机渗透实战演练
一次Shiro反序列化引起的域控沦陷
本文内容是笔者一次从0到1的实战记录,通过一次完整的外网到内网到拿下域控的过程,来为大家带来渗透的一些思路。
谢公子
2022/01/20
1K0
一次Shiro反序列化引起的域控沦陷
AD域不靠谱了吗;LDAP验证如何保证应用安全 | FB甲方群话题讨论
1. 某集团企业生产网(私有云或机房数据中心)、办公网终端均使用同一个AD域,那么其生产服务器是否需要脱域或其它方式整改?
FB客服
2024/04/26
7490
AD域不靠谱了吗;LDAP验证如何保证应用安全 | FB甲方群话题讨论
攻防|记一次平平无奇有手就行的幸运域控
最近在学习内网渗透,很想找个机会练练手。正好团队接到红队评估的项目,于是便有了此文,没什么技术含量,师傅们轻点喷。
亿人安全
2023/02/28
2K0
攻防|记一次平平无奇有手就行的幸运域控
[干货] - 红队渗透小技巧
有一段时间没有写文章了,也不知写什么,毕竟从攻击方换成防守方,乙方换到甲方,还有些许不适应。。。但还是决定把自己接触渗透所积累的东西也拿出分享,不管糟粕,还是大伙觉得我分享的有用(那阿鑫自然是很开心),希望能帮到还在学习路上的朋友,文章若有错误,请及时联系我指出,我也不想误导才学习的朋友。此外,本文为口嗨文,基本在说思路,没有实操。
drunk_kk
2021/07/23
1.5K0
[干货] - 红队渗透小技巧
记一次由sql注入到拿下域控的渗透测试实战演练(上)
4.通过在目标服务器上安装并使用nmap完成信息收集,为接下来横向移动以及拿下域控提供基础
FB客服
2021/03/09
1K0
记一次由sql注入到拿下域控的渗透测试实战演练(上)
记一次C/S架构客户端配置文件泄露导致的内网沦陷
注:由于目标单位所用的web系统以及服务器都是比较老的机子,所以可能没有很高的技术含量,不足之处还望批评指正。
F12sec
2022/09/29
1.7K0
记一次C/S架构客户端配置文件泄露导致的内网沦陷
相关推荐
攻防|记一次攻防演练实战总结
更多 >
LV.4
腾讯安全工程师
目录
  • 实验环境
  • Frida相关api介绍
    • 1.Process、Module、Memory基础
      • 1.Process
      • 3.Memory
    • 2.枚举导入导出表
    • 3.Native函数的基础Hook打印
    • 4.Native函数的基础Hook修改
    • 5.SO基址的获取方式
    • 6.Hook未导出函数与函数地址计算
    • 8.借助IDA脚本实现一键式hook
  • java层hook对应
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档