Inlinehook PspCreateProcess
InineHook通过修改函数指令实现,此次以内核层的PspCreateProcess()为例。
本来是想写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,
);
} 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[] = {{0xff,},{0x55,},{0x1c,},{0x14,},{0xE8,}};
现在就出现了另一个问题,就是搜索特征码的起始地址,我们应该从哪开始匹配特征码,最初我用的是从NtCreateProcess()函数的地址开始搜索,可能有人又会问那NtCreateProcess()函数的地址怎么获得,现在先跳过这个问题,我在以后的博客中会讲解SSDT 与 shadowSSDT结构。但是后来考虑到代码的复用性,我用对PE文件的Section的执行块进行搜索。如果对于PE文件结构不清楚,可以参考《加密与解密》中的”PE文件格式”章节
//需包含<ntimage.h>
ULONG SearchAddressForSign(ULONG uStartBase,ULONG uSearchLength,SIGNATURE_INFO SignatureInfo[])
{
/*
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 ; } 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 = ;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 = ;u_index2<pimage_section_header[u_index1].Misc.VirtualSize;u_index2++)
{
if (!MmIsAddressValid((p-SignatureInfo[].Offset))||
!MmIsAddressValid((p-SignatureInfo[].Offset)))
{
p++;
continue;
}
__try{
if (*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature&&
*(p-SignatureInfo[].Offset)==SignatureInfo[].cSingature)
{
return (ULONG)p;
} }__except(EXCEPTION_EXECUTE_HANDLER){
DbgPrint("Search error!\r\n");
}
p++;
}
}
} return ;
}
这里,我们得到了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 + ) + ;
得到PspCreateProcess()函数的绝对地址以后,就可以进行Inlinehook,将执行流程跳转到我们自己的函数中执行。
反汇编PspCreateProcess
我们接下来要做的就是将6878010000这5个字节换成我们自己构建的shellcode,跳转到我们自己的函数执行,大致代码如下
ULONG jmp_offset;
UCHAR jmp_code[] = {0xE9}; //jmp指令
//保存原始函数的5个字节,便于恢复
RtlCopyMemory(Ori_Code,(PVOID)Destination,);
jmp_offset = Source - Destination-;
*(ULONG*)&jmp_code[] = jmp_offset;
//Destination就是g_PspCreateProcessAddress即PspCreateProcess()的函数地址
RtlCopyMemory((PVOID)Destination,jmp_code,);
可以看到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 ;
}
到此,我们的Inlinehook完成,当然还有恢复的工作,在我们的驱动卸载时对我们Inlinehook的修改代码的地方进行恢复就行了,将我们保存的原来的字节恢复就好了。
我这里只写了比较重要的地方,不太重要的地方的也没有过多的提及,比如关于关闭内核内存保护的问题,我在接下来的博客中会讲解到。
最后附上完整代码,编译环境采用的是VS2010+DDK7600
链接:http://pan.baidu.com/s/1gdfDsLP 密码:4y8m
Inlinehook PspCreateProcess的更多相关文章
- C# inline-hook / api-hook
我查阅了一下相关C#方面的资料,却没有发现有提供过关于api-hook方面的资 料包括应用库由此本人编写一套inline-hook的库用于支持x64.x86上的基于在 clr的公共语言,如: c#.c ...
- 检测API函数的InlineHook
BOOL GetProcHookStatus(LPCSTR lpModuleName, LPCSTR lpProcName) { HMODULE hModule = GetModuleHandleA( ...
- InlineHook
前言 IATHOOK局限性较大,当我们想HOOK一个普通函数,并不是API,或者IAT表里并没有这个API函数(有可能他自己LoadLibrary,自己加载的),那我们根本就从导入表中找不到这个函数, ...
- Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook
Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...
- x64 InlineHook 黑魔法
目录 x64 InlineHook 黑魔法 为什么不能用X86 的HOOK方式? 原理:jmp + rip 进行寻址6字节方式跳转 手动InlineHook 临时地址x(找一块空内存) 计算偏移 源地 ...
- 驱动开发:内核层InlineHook挂钩函数
在上一章<驱动开发:内核LDE64引擎计算汇编长度>中,LyShark教大家如何通过LDE64引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的InlineHook函 ...
- Win32API起始处的mov edi, edi与用户空间InlineHook
在x86平台上,无论是在调试器中跟到系统DLL中时,还是反汇编某个系统DLL时,经常会发现很多API的第一条汇编指令都是mov edi, edi.根据经验来讲,C函数的汇编形式,应该是首先push e ...
- 64位系统InlineHook
APIHook64Class.h #ifndef APIHOOK64CLASS_H_ #define APIHOOK64CLASS_H_ #include <Windows.h> clas ...
- 64位下的InlineHook
目录 x64下手工HOOK的方法 一丶HOOK的几种方法之远跳 1. 远跳 不影响寄存器 + 15字节方法 2.远跳 影响寄存器 + 12字节方法 3.影响寄存器,恢复寄存器 进行跳转. 4. 常用 ...
随机推荐
- MVC4.0网站发布和部署到IIS7.0上的方法【转:http://www.th7.cn/Program/net/201403/183756.shtml】
最近在研究MVC4,使用vs2010,开发的站点在发布和部署到iis7上的过程中遇到了很多问题,现在将解决的过程记录下来,以便日后参考,整个过程主要以截图形式呈现 vs2010的安装和mvc4的安装不 ...
- 扒一扒编辑距离(Levenshtein Distance)算法
最近由于工作需要,接触了编辑距离(Levenshtein Distance)算法.赶脚很有意思.最初百度了一些文章,但讲的都不是很好,读起来感觉似懂非懂.最后还是用google找到了一些资料才慢慢理解 ...
- VS中设置#define _CRT_SECURE_NO_WARNINGS的两种方式
1.我们在编译老的用C语言的开源项目如lua源包的时候,可能因为一些老的.c文件使用了strcpy,scanf等不安全的函数,而报警告和错误,而导致无法编译通过. 2.此时我们有两种解决方案: a.在 ...
- 使用Log Explorer查看和恢复数据
由于一次意外操作,把QC数据库中的BUG表数据给删掉了.崩溃-上网找了下恢复方法,找到一款Log Explorer.下载安装使用后,发现这款软件的确不错,收藏ing. 本次的使用的Log Expl ...
- Android -- 获取汉字的首字母
转换 获取一个汉 ...
- Careercup - Microsoft面试题 - 6543214668414976
2014-05-11 02:56 题目链接 原题: Write a function called FooBar that takes input integer n and prints all t ...
- 设计模式 --深入理解javascript
/* 一.单例模式 */ var Universe; (function () { var instance; Universe = function Universe() { if (instanc ...
- Hibernate内存溢出分析一例
公司业务系统在进行压力测试时,压测24小时后系统发生内存溢出.经过分析读dump文件,发现org.hibernate.stat.StatisticsImpl类的hashmap类型的变量存储了大量数据( ...
- cf 61E. Enemy is weak 树状数组求逆序数(WA) 分类: Brush Mode 2014-10-19 15:16 104人阅读 评论(0) 收藏
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> ...
- 【NOI模拟赛(湖南)】DeepDarkFantasy
DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里. ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方,并且这个 ...