hook未导出native api的好办法

本文介绍了一种避免硬编码SSDT服务号的方法,通过映射ntdll.dll并直接从DLL检索所需函数位置,确保了驱动程序在不同操作系统版本间的兼容性。
昨天写的那个 hook ssdt的驱动,用的是硬编码的办法,这样在不同的系统中由于NtShutdownSystem的服务号都不相同,所以在不同的操作系统上代码都要做修改,这个比较不爽.今天听老大PJF说有避免硬编码的方法,google了下,发现下面的文章,代码稍微改了改,用在我的驱动中,果然好使.文章贴在下面: ------------------------------------------------------------------------------------------- from http://www.rootkit.com Hardcoding the positions seems a poor solution, since it means after a new service pack, the rootkit may no longer work and become discovered. As I have found the code on this site extremely helpful, I think it is only fair that I return the favour ;-) I have implemented the method described in previous posts, whereby I have mapped a view of ntdll.dll into the process space of whoever loads the driver initially, and then retrieve the required function positions directly from the dll. This was relatively simple to do, and only requires knowledge of the pe file format, and a few undocumented apis. Using the function pasted below, when hooking you simply do as follows: RtlInitUnicodeString(&dllName, L"//Device//HarddiskVolume1//Windows//System32//ntdll.dll"); functionAddress = GetDllFunctionAddress(functionName, &dllName); position = *((WORD*)(functionAddress+1));      g_OriginalZwCreateProcessEx = (ZWCREATEPROCESSEX)(KeServiceDescriptorTable.ServiceTableBase[position]); and here's the function GetDllFunctionAddress: DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)  {     HANDLE hThread, hSection, hFile, hMod;     SECTION_IMAGE_INFORMATION sii;     IMAGE_DOS_HEADER* dosheader;     IMAGE_OPTIONAL_HEADER* opthdr;     IMAGE_EXPORT_DIRECTORY* pExportTable;     DWORD* arrayOfFunctionAddresses;     DWORD* arrayOfFunctionNames;     WORD* arrayOfFunctionOrdinals;     DWORD functionOrdinal;     DWORD Base, x, functionAddress;     char* functionName;     STRING ntFunctionName, ntFunctionNameSearch;     PVOID BaseAddress = NULL;     SIZE_T size=0;     OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};     IO_STATUS_BLOCK iosb;     //_asm int 3;     ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);     oa.ObjectName = 0;     ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);          ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);           ZwClose(hFile);          hMod = BaseAddress;          dosheader = (IMAGE_DOS_HEADER *)hMod;          opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);     pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);     // now we can get the exported functions, but note we convert from RVA to address     arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);     arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);     arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);     Base = pExportTable->Base;     RtlInitString(&ntFunctionNameSearch, lpFunctionName);     for(x = 0; x < pExportTable->NumberOfFunctions; x++)     {         functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);         RtlInitString(&ntFunctionName, functionName);         functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; // always need to add base, -1 as array counts from 0         // this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...         // oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!         functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);         if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)          {             ZwClose(hSection);             return functionAddress;         }     }     ZwClose(hSection);     return 0; }
<think> 首先,用户的问题是关于Frida进行原生Hook的使用方法和示例。系统级指令要求我使用中文回答、正确使用LaTeX格式(但数学表达式可能不适用这里)、生成相关问题、在引用末尾添加引用标识,并确保回答结构清晰。 回顾用户的查询:用户提供了几个引用,但这些引用似乎是之前的上下文或示例,并不是用户真正的需求。引用[1]到[3]是关于Frida hook的尝试、教程和Java函数hook的方法。用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 然后用户明确表示:“我想查找Frida进行原生Hook的相关信息,可能包括使用方法、教程、示例等 请问Frida进行原生Hook的使用方法和示例”。 所以,我需要专注于用户当前的问题:Frida进行原生Hook的使用方法和示例。原生Hook指的是hook原生代码,比如C/C++库,而不是Java代码。Frida支持hook原生函数,尤其是在Android或iOS上。 关键点: - 用户想要原生Hook的使用方法和示例。 - 我需要参考提供的引用,但它们是辅助性的。引用[2]提到hook Native函数,引用[3]涉及到发送消息,这可能是原生hook的一部分。 - 我的回答应该结构清晰,逐步解决问题。 - 生成相关问题作为结尾。 - 在引用末尾添加引用标识。 结构化回答: 1. **介绍**:简要解释什么是原生Hook和使用Frida。 2. **使用方法**:概述步骤,如设置环境、编写脚本等。 3. **示例**:提供一个简单的原生Hook示例代码。 4. **引用**:如果需要,引用相关部分。 5. **相关问题**:生成2-3个相关问题。 内容来源: - 从引用[2]:提到了hook RegisterNative函数和通过USB连接。 - 从引用[3]:提到了发送消息和读取内存,可能是原生hook的示例。 - 我自己的知识:Frida可以通过JavaScript或Python脚本hook原生函数。例如,在Android上hook一个C函数。 示例脚本: - 引用[3]中有一个代码片段:`send("mono_image_open_from_data_with_name("+Memory.readCString(args[5])+","+Memory.readCString(args[0])+")");` 这看起来像是hook一个原生函数后发送消息。 - 我可以基于这个构建一个简单的示例。 步骤: 1. 安装Frida和相关工具。 2. 编写JavaScript脚本来hook原生函数。 3. 运行脚本连接到设备。 回答结构: - 开头:回应查询。 - 主体: - 什么是原生Hook。 - 使用方法:包括环境设置、脚本编写。 - 示例:给出代码和解释。 - 结尾:添加相关问题。 引用标识:在引用参考的部分末尾添加[^1]、[^2]等。例如,如果提到引用[2]的内容,就加[^2]。 生成相关问题: - 例如:1. Frida原生Hook的常见问题?2. 如何调试原生Hook?3. Frida在iOS上的原生Hook方法? 确保中文回答。 </think> ### Frida进行原生Hook的使用方法和示例 原生Hook是指使用Frida框架拦截和修改原生代码(如C/C++库或系统调用)的执行过程。这在Android、iOS等平台上常用于分析或修改底层函数的行为。以下是详细的使用方法和一个实际示例,基于Frida的JavaScript API实现。我会逐步解释过程,确保内容真实可靠。 #### 1. **原生Hook的基本使用方法** 要使用Frida进行原生Hook,需遵循这些步骤: - **环境准备**:安装Frida工具链(如Frida CLI、Frida-server),确保设备(如Android手机)已连接并开启开发者模式。引用[2]提到通过USB连接设备的方法:使用`frida.get_usb_device()`或指定设备ID连接[^2]。 - **编写脚本**:使用JavaScript编写Hook脚本,定义目标函数、拦截点(如函数入口/出口)和自定义逻辑。 - **注入脚本**:将脚本注入到目标进程,启动Hook。 - **调试与分析**:捕获函数参数、返回值或修改行为,通过Frida的`send()`函数输出结果。 关键API: - `Interceptor.attach()`:用于附加到原生函数地址。 - `Memory.readCString()`:读取内存中的字符串(常用于参数获取)。 - `send()`:发送消息到Frida控制台。 #### 2. **原生Hook示例:Hook一个Android原生函数** 假设我们要Hook Android中的一个原生C函数`libnative.so`中的`open_file(const char* path)`。以下是完整示例脚本(JavaScript),演示如何拦截函数调用、读取参数并修改返回值。 ```javascript // 加载Frida的Interceptor和Memory模块 Interceptor.attach(Module.findExportByName("libnative.so", "open_file"), { onEnter: function(args) { // args[0]是函数的第一个参数(path字符串) var filePath = Memory.readCString(args[0]); console.log("[Hook] 函数open_file被调用,文件路径: " + filePath); // 发送消息到Frida控制台 send("open_file参数: " + filePath); }, onLeave: function(retval) { // 修改返回值,例如强制返回错误码-1 console.log("[Hook] 修改返回值为-1"); retval.replace(-1); } }); ``` **示例解释**: - **目标函数**:`open_file`在`libnative.so`库中,我们通过`Module.findExportByName`定位其地址。 - **onEnter**:在函数执行前触发,读取参数`args[0]`(文件路径字符串),并输出到控制台。 - **onLeave**:在函数执行后触发,修改返回值`retval`为-1(模拟错误)。 - **输出**:使用`send()`发送消息,引用[3]中类似地展示了如何构造消息字符串[^3]。 **运行步骤**: 1. 在PC上启动Frida CLI:`frida -U -f com.example.app --no-pause` - `-U` 表示USB设备连接(如引用[2]所述[^2])。 - `-f com.example.app` 指定目标应用包名。 2. 加载脚本:在Frida CLI中输入`%load script.js`(script.js是上述脚本文件)。 3. 观察输出:当应用调用`open_file`时,控制台显示Hook消息和修改后的行为。 #### 3. **注意事项** - **地址定位**:如果函数地址知,使用`Module.enumerateExports()`列出所有导出函数。 - **错误处理**:添加`try-catch`块防止脚本崩溃。 - **性能影响**:Hook频繁调用的函数可能降低应用性能,建议在测试环境中使用。 - **跨平台**:该方法同样适用于iOS原生库。引用[1]提到通过Hook打开分析空间[^1]。 通过这个方法,您可以监控或修改任何原生函数,如加密算法、系统调用等。实际使用时,需根据目标函数签名调整参数索引(如`args[0]`对应第一个参数)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值