Inlinehook PspCreateProcess
2015-05-16 21:01
543 查看
InineHook通过修改函数指令实现,此次以内核层的PspCreateProcess()为例。
本来是想写NtCreateProcess()的Inlinehook,但是想到PCHunter对于SSDT和ShadowSSDT的检测,就想试一下PCHunter对于更底层函数的检测功能,虽然最后还是被检测出来了 /桑心。通过查看wrk的源代码,NtCreateprocess() 紧接着调用了NtCreateProcessEx(),在NtCreateProcessEx()函数中又调用了
PspCreateProcess() ,于是这次打算Inlinehook掉PspCreateProcess()函数。
对于PspCreateProcess()的函数地址在ntoskrnl.exe中并未导出,所以对于PspCreateProcess()函数地址的获得采用匹配特征码的操作。
我们在Windbg中反汇编NtCreateProcess()函数
E8指令表示call 后面的c628e9ff表示的是一个相对偏移地址,是相对下一条指令地址的偏移,即我们图中的840ddea9
我们可以构建如下的特征码
现在就出现了另一个问题,就是搜索特征码的起始地址,我们应该从哪开始匹配特征码,最初我用的是从NtCreateProcess()函数的地址开始搜索,可能有人又会问那NtCreateProcess()函数的地址怎么获得,现在先跳过这个问题,我在以后的博客中会讲解SSDT 与 shadowSSDT结构。但是后来考虑到代码的复用性,我用对PE文件的Section的执行块进行搜索。如果对于PE文件结构不清楚,可以参考《加密与解密》中的”PE文件格式”章节
这里,我们得到了NtCreateProcess()函数中调用PspCreateProcess()函数的指令的地址,在我们这里就是840eadd4 。
得到PspCreateProcess()函数的绝对地址以后,就可以进行Inlinehook,将执行流程跳转到我们自己的函数中执行。
反汇编PspCreateProcess
我们接下来要做的就是将6878010000这5个字节换成我们自己构建的shellcode,跳转到我们自己的函数执行,大致代码如下
可以看到PspCreateProcess函数的前5个字节已经被我们Inlinehook,跳转到我们自己的函数NewPspCreateProcess() 函数了。
接下来重点就是对我们自己的函数NewPspCreateProcess()的实现。
函数声明如下
接下来就是完成FilterPspCreateProcess() 函数,对PspCreateProcess()函数进行一次过滤,通过查看wrk,找到PspCreateProcess()的函数原型
到此,我们的Inlinehook完成,当然还有恢复的工作,在我们的驱动卸载时对我们Inlinehook的修改代码的地方进行恢复就行了,将我们保存的原来的字节恢复就好了。
我这里只写了比较重要的地方,不太重要的地方的也没有过多的提及,比如关于关闭内核内存保护的问题,我在接下来的博客中会讲解到。
最后附上完整代码,编译环境采用的是VS2010+DDK7600
链接:http://pan.baidu.com/s/1gdfDsLP 密码:4y8m
本来是想写NtCreateProcess()的Inlinehook,但是想到PCHunter对于SSDT和ShadowSSDT的检测,就想试一下PCHunter对于更底层函数的检测功能,虽然最后还是被检测出来了 /桑心。通过查看wrk的源代码,NtCreateprocess() 紧接着调用了NtCreateProcessEx(),在NtCreateProcessEx()函数中又调用了
PspCreateProcess() ,于是这次打算Inlinehook掉PspCreateProcess()函数。
NTSTATUS NtCreateProcess( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in HANDLE ParentProcess, __in BOOLEAN InheritObjectTable, __in_opt HANDLE SectionHandle, __in_opt HANDLE DebugPort, __in_opt HANDLE ExceptionPort ) { //…… return NtCreateProcessEx (ProcessHandle, DesiredAccess, ObjectAttributes OPTIONAL, ParentProcess, Flags, SectionHandle, DebugPort, ExceptionPort, 0); } NTSTATUS NtCreateProcessEx( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in HANDLE ParentProcess, __in ULONG Flags, __in_opt HANDLE SectionHandle, __in_opt HANDLE DebugPort, __in_opt HANDLE ExceptionPort, __in ULONG JobMemberLevel ) { //摘自wrk调用PspCreateProcess()的代码 if (ARGUMENT_PRESENT (ParentProcess)) { Status = PspCreateProcess (ProcessHandle, DesiredAccess, ObjectAttributes, ParentProcess, Flags, SectionHandle, DebugPort, ExceptionPort, JobMemberLevel); } else { Status = STATUS_INVALID_PARAMETER; } return Status; }
对于PspCreateProcess()的函数地址在ntoskrnl.exe中并未导出,所以对于PspCreateProcess()函数地址的获得采用匹配特征码的操作。
//我们自己构建的特征码结构体 typedef struct _SIGNATURE_INFO{ UCHAR cSingature; int Offset; }SIGNATURE_INFO,*PSIGNATURE_INFO;
我们在Windbg中反汇编NtCreateProcess()函数
E8指令表示call 后面的c628e9ff表示的是一个相对偏移地址,是相对下一条指令地址的偏移,即我们图中的840ddea9
我们可以构建如下的特征码
SIGNATURE_INFO SignCode[5] = {{0xff,9},{0x55,5},{0x1c,4},{0x14,1},{0xE8,0}};
现在就出现了另一个问题,就是搜索特征码的起始地址,我们应该从哪开始匹配特征码,最初我用的是从NtCreateProcess()函数的地址开始搜索,可能有人又会问那NtCreateProcess()函数的地址怎么获得,现在先跳过这个问题,我在以后的博客中会讲解SSDT 与 shadowSSDT结构。但是后来考虑到代码的复用性,我用对PE文件的Section的执行块进行搜索。如果对于PE文件结构不清楚,可以参考《加密与解密》中的”PE文件格式”章节
//需包含<ntimage.h> ULONG SearchAddressForSign(ULONG uStartBase,ULONG uSearchLength,SIGNATURE_INFO SignatureInfo[5]) { /* uStartBase: 搜索开始的地址(PE文件的加载基地址) uSearchLength: 搜索的长度,一般采用SizeOfImage SignatureInfo: 构建的特征码数组 返回匹配特征码的地址 */ UCHAR *p; ULONG u_index1,u_index2; PIMAGE_DOS_HEADER pimage_dos_header; PIMAGE_NT_HEADERS pimage_nt_header; PIMAGE_SECTION_HEADER pimage_section_header; if(!MmIsAddressValid((PVOID)uStartBase)) { return 0; } pimage_dos_header = (PIMAGE_DOS_HEADER)uStartBase; pimage_nt_header = (PIMAGE_NT_HEADERS)((ULONG)uStartBase+pimage_dos_header->e_lfanew); pimage_section_header = (PIMAGE_SECTION_HEADER)((ULONG)pimage_nt_header+sizeof(IMAGE_NT_HEADERS)); for (u_index1 = 0;u_index1<pimage_nt_header->FileHeader.NumberOfSections;u_index1++) { //#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. //#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. //#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. //0x60000000 = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ if (pimage_section_header[u_index1].Characteristics&0x60000000) { //可读可执行的段 p = (UCHAR*)uStartBase + pimage_section_header[u_index1].VirtualAddress; for (u_index2 = 0;u_index2<pimage_section_header[u_index1].Misc.VirtualSize;u_index2++) { if (!MmIsAddressValid((p-SignatureInfo[0].Offset))|| !MmIsAddressValid((p-SignatureInfo[4].Offset))) { p++; continue; } __try{ if (*(p-SignatureInfo[0].Offset)==SignatureInfo[0].cSingature&& *(p-SignatureInfo[1].Offset)==SignatureInfo[1].cSingature&& *(p-SignatureInfo[2].Offset)==SignatureInfo[2].cSingature&& *(p-SignatureInfo[3].Offset)==SignatureInfo[3].cSingature&& *(p-SignatureInfo[4].Offset)==SignatureInfo[4].cSingature) { return (ULONG)p; } }__except(EXCEPTION_EXECUTE_HANDLER){ DbgPrint("Search error!\r\n"); } p++; } } } return 0; }
这里,我们得到了NtCreateProcess()函数中调用PspCreateProcess()函数的指令的地址,在我们这里就是840eadd4 。
//这里的g_PspCreateProcessAddress就是我们这条指令的地址 //840ddea4 e8 c628e9ff call nt!PspCreateProcess (83f7076f) //注意这里的*(LONG*)(g_PspCreateProcessAddress+1) 取出的c628e9ff是相对于下一条指令的偏移, //所以还需”+5”跳过我们自己的这条指令的5个字节,//就得到了PspCreateProcess()函数的绝对地址。 g_PspCreateProcessAddress = g_PspCreateProcessAddress + *(LONG*)(g_PspCreateProcessAddress + 1) + 5;
得到PspCreateProcess()函数的绝对地址以后,就可以进行Inlinehook,将执行流程跳转到我们自己的函数中执行。
反汇编PspCreateProcess
我们接下来要做的就是将6878010000这5个字节换成我们自己构建的shellcode,跳转到我们自己的函数执行,大致代码如下
ULONG jmp_offset; UCHAR jmp_code[5] = {0xE9}; //jmp指令 //保存原始函数的5个字节,便于恢复 RtlCopyMemory(Ori_Code,(PVOID)Destination,5); jmp_offset = Source - Destination-5; *(ULONG*)&jmp_code[1] = jmp_offset; //Destination就是g_PspCreateProcessAddress即PspCreateProcess()的函数地址 RtlCopyMemory((PVOID)Destination,jmp_code,5);
可以看到PspCreateProcess函数的前5个字节已经被我们Inlinehook,跳转到我们自己的函数NewPspCreateProcess() 函数了。
接下来重点就是对我们自己的函数NewPspCreateProcess()的实现。
函数声明如下
// __declspec(naked)用来告诉编译器函数代码的汇编语言为自己的所写,不需要编译器添加任何汇编代码 VOID __declspec(naked) NewPspCreateProcess();
VOID __declspec(naked) NewPspCreateProcess() { __asm { //处理栈 mov edi,edi push ebp mov ebp,esp pushad //保存我们各个寄存器的值 pushfd //保存标志寄存器的值 // 8411ae89 ff7528 push dword ptr [ebp+28h] // 8411ae8c ff7524 push dword ptr [ebp+24h] // 8411ae8f ff7520 push dword ptr [ebp+20h] // 8411ae92 ff7518 push dword ptr [ebp+18h] // 8411ae95 ff7510 push dword ptr [ebp+10h] // 8411ae98 ff750c push dword ptr [ebp+0Ch] // 8411ae9b ff7508 push dword ptr [ebp+8] // 8411ae9e 8b551c mov edx,dword ptr [ebp+1Ch] // 8411aea1 8b4d14 mov ecx,dword ptr [ebp+14h] // 8411aea4 e8c628e9ff call nt!PspCreateProcess (83fad76f) // PspCreateProcess函数的参数已经入栈 call FilterPspCreateProcess //调用我们想要进行操作的函数 popfd popad push 0x178 //执行被我们改写了的PspCreateProcess函数的前5个字节的指令 jmp g_JmpOrignPspCreateProcessAddr //跳转到原来的PspCreateProcess函数的第6个字节的地址开始继续执行 } }
接下来就是完成FilterPspCreateProcess() 函数,对PspCreateProcess()函数进行一次过滤,通过查看wrk,找到PspCreateProcess()的函数原型
NTSTATUS PspCreateProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, //ULONG IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ParentProcess OPTIONAL, IN ULONG Flags, IN HANDLE SectionHandle OPTIONAL, IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL, IN ULONG JobMemberLevel );
//我们仿照PspCreateProcess()函数声明构建过滤函数 ULONG_PTR FilterPspCreateProcess( OUT PHANDLE ProcessHandle, //0x8 IN ACCESS_MASK DesiredAccess,//0xc IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,//0x10 IN HANDLE ParentProcess OPTIONAL, //0x14 IN ULONG Flags, //0x18 IN HANDLE SectionHandle OPTIONAL, //0x1c IN HANDLE DebugPort OPTIONAL, //0x20 IN HANDLE ExceptionPort OPTIONAL, //0x24 IN ULONG JobMemberLevel //0x28 ) { //我这里什么都不做,只打印一句话,也可以进行一些过滤操作 DbgPrint("FilterPspCreateProcess\r\n"); return 1; }
到此,我们的Inlinehook完成,当然还有恢复的工作,在我们的驱动卸载时对我们Inlinehook的修改代码的地方进行恢复就行了,将我们保存的原来的字节恢复就好了。
我这里只写了比较重要的地方,不太重要的地方的也没有过多的提及,比如关于关闭内核内存保护的问题,我在接下来的博客中会讲解到。
最后附上完整代码,编译环境采用的是VS2010+DDK7600
链接:http://pan.baidu.com/s/1gdfDsLP 密码:4y8m
相关文章推荐
- inline hook未导出函数PspTerminateProcess
- APIHook CreateProcess
- inline hook未导出函数PspTerminateProcess
- inlinehook NtCreateFile
- 进程创建过程分析NtCreateProcess-NtCreateProcessEx-PspCreateProcess
- PspCreateProcessNotifyRoutine,PspCreateThreadNotifyRoutine,PspLoadImageNotifyRoutine表全部清空
- PspCreateProcess
- 小试X64 inline HOOK,hook explorer.exe--->CreateProcessInternalW监视进程创建
- 学HOOK学的 API 函数、、VirtualQuery、、VirtualProtect、、 WriteProcessMemory
- Android中的so挂钩(hook)之Inline hook
- python3.6执行pip3时 Unable to create process using '"'
- python2用pip进行安装时报错Fatal error in launcher: Unable to create process using '"'
- python3出现:Fatal error in launcher: Unable to create process using '"'(已解决)
- create process as system privilege
- 封装 fork wait execvp, 编写函数 process_create
- How to Create Modifiers Using the API QP_MODIFIERS_PUB.PROCESS_MODIFIERS
- delphi调试需要管理员权限程序报错“Unable to create process:请求的操作需要提升”
- NtOpenProcess被HOOK,跳回原函数地址后仍然无法看到进程
- Error:CreateProcess error=216, 该版本的 %1 与您运行的 Windows 版本不兼容。请查看计算机的系统信息,了解是否需要 x86 (32 位)或 x64 (64 位)
- 在Minifilter中使用PsSetCreateProcessNotifyRoutine之后监控到的一些进程信息