首页
社区
课程
招聘
[原创]inline hook未导出函数PspTerminateProcess
发表于: 2008-4-3 16:18 37329

[原创]inline hook未导出函数PspTerminateProcess

2008-4-3 16:18
37329

已经把代码附上了....以前的没什么修改,在搜索特征码时没有在非分页内存搜.可能会蓝屏,不过你应该做下适当修改--sysnap
之前inline Hook SSDT中的一些函数学,感觉比较容易,可是想hook一些未导出的函数时,

却发现还有点难,开始是蓝了N次屏,最后HOOK成功了,用一些anti-rootkit的工具却查不出

来,以为没成功.郁闷了好久,最后用windbg看,原来是成功,于是写下这篇文章,很多东西应该讲的不太好,还请矫正

今天就是要inline hook PspTerminateProcess,这是一个没有被导出的函数,这个会了,基本什么函数都会hook,呵呵,先看下它的

定义吧
NTSTATUS
PspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
由于没有被导出的函数,那只能内存搜索定位了,先用windbg看(本机的情况,后面的图是虚拟机的)
lkd> u PspTerminateProcess
nt!PspTerminateProcess:
805d23a0 8bff mov edi,edi
805d23a2 55 push ebp
805d23a3 8bec mov ebp,esp
805d23a5 56 push esi
805d23a6 64a124010000 mov eax,dword ptr fs:[00000124h]
805d23ac 8b7508 mov esi,dword ptr [ebp+8]
805d23af 3b7044 cmp esi,dword ptr [eax+44h]
805d23b2 7507 jne nt!PspTerminateProcess+0x1b (805d23bb)

再用dd命令
lkd> dd PspTerminateProcess
805d23a0 8b55ff8b a16456ec 00000124 3b08758b
805d23b0 07754470 00000db8 575aebc0 0248be8d
805d23c0 47f60000 12742001 0174868d 56500000
805d23d0 5d237268 ef50e880 086affff 0709f058
805d23e0 e856006a 00004f78 ff85f88b 75ff1e74
805d23f0 07e8570c 57fffffd 4f62e856 f88b0000
805d2400 ea75ff85 00bc8639 06740000 ff04e856
805d2410 c033fffe c25d5e5f cccc0008 cccccccc

那它的特征码是8b55ff8b a16456ec 00000124 3b08758b,内存搜索吧,找到地址之后我们

就重写其开头的5个字节,也就是修改
mov edi,edi
push ebp
mov ebp,esp
(现在一般的函数学编译之后都是这样子,个别例外)
为一条jmp指令,这条指令将跳到我们自己的函数学里执行,这就是inline hook
好了,搜索地址吧,怎么搜索,当然是用一种通用的方法来定位,在<<学习笔记之钩住驱动程

序导入表>>中修改一下GetDriverBaseAdress这个函数就可以了,,用

ZwQuerySystemInformation枚举内核模块,第一个模块就是我们要

的,PspTerminateThreadByPointer就是在里面

#include "ntddk.h"
#include "InlineHook.h"

PVOID GetUndocumentFunctionAdress()
{

ULONG size,index;
PULONG buf;
ULONG i;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;
ULONG ntosknlBase;
ULONG ntosknlEndAddr;
ULONG curAddr;
NTSTATUS status;
ULONG retAddr;
ULONG code1_sp2=0x8b55ff8b,code2_sp2=0xa16456ec,code3_sp2=0x00000124,code4_sp2=0x3b08758b;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}

status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}

module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1);
ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
ntosknlBase=(ULONG)module->Base;
curAddr=ntosknlBase;
ExFreePool(buf);

for (i=curAddr;i<=ntosknlEndAddr;i++)
{
if ((*((ULONG *)i)==code1_sp2)&&(*((ULONG *)(i+4))==code2_sp2)&&(*((ULONG *)(i+8))==code3_sp2)&&(((ULONG*)(i+12))==code4_sp2))

{

retAddr=i;
DbgPrint("adress is:%x",retAddr);
return retAddr;

}
}
}

VOID Unload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("Unload Called \r\n");

}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING str)
{

DriverObject->DriverUnload = Unload;
PspTerminateProcess = GetUndocumentFunctionAdress();
return STATUS_SUCCESS;
}

编译一下,加载运行,嗯,DebugView输出了:adress is:805c8620
那就是我们的函数地址找到了,找到地址当然是引用拉
只需这样声明一下:
typedef NTSTATUS (*PSPTERMINATETPROCESS)(
PEPROCESS Process,
NTSTATUS ExitStatus
);
PSPTERMINATETPROCESS PspTerminateProcess;
PspTerminateProcess=(PSPTERMINATETPROCESS)PspTerminateThreadByPointerAdrr;
好了,至此我们就获得了PspTerminateThreadByPointer在内存中的地址,也做了一些工作,

现在PspTerminateThreadByPointer就可以像正常的导出函数一样直接使用了,不过我们是

要它的地址就可以,如果你想用PspTerminateProcess就可以按上面的声明,就可以用.
好了,解决了地址问题,接着就是修改这个地址开始的5个字节
805d23a0 8bff mov edi,edi
805d23a2 55 push ebp
805d23a3 8bec mov ebp,esp
在修改之前应该做一下检查,看我们要HOOK的函数有没有被别人先HOOK了,这是必要的,否

则有可能导致系统崩溃
检查只需要添加一个函数就可以
NTSTATUS CheckPspTerminateProcessIsHook()
{
int i=0;
char *addr = (char *)PspTerminateProcess;

char code[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec};

while(i<5)
{
DbgPrint(" - 0x%02X ", (unsigned char)addr[i]);
if(addr[i] != code[i])
{
return STATUS_UNSUCCESSFUL;
}
i++;
}
return STATUS_SUCCESS;
}

嗯,DriverEntry添加
if(STATUS_SUCCESS != CheckPspTerminateProcessIsHook())
{
DbgPrint("PspTerminateProcess Match Failed !");
return STATUS_UNSUCCESSFUL;
}
编译测试一下,嗯正常没问题,既然没什么问题,那下面我们就开始对这个函数进行inline

hook了,
接着开始核心部分
添加函数
_declspec(naked) T_PspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{

_asm
{
mov edi, edi
push ebp
mov ebp ,esp
push [ebp+0ch]
push [ebp+8]
call MyPspTerminateProcess
cmp eax,1
jz end
mov eax,PspTerminateProcess
add eax,5
jmp eax

end:
pop ebp
retn 8
}
}
}

我们就是要修改PspTerminateProcess的前5个字节,代替为一条近jmp指令,跳转到

我们的这个函数里来,在T_PspTerminateProcess里call MyPspTerminateProcess ,MyPspTerminateProcess 是我们的功能函数,就是你hook后想做什么事情,这里我们简单的输出点字符就好

那怎样改PspTerminateProcess的前5个字节,代替为一条jmp

指令,跳到T_PspTerminateProcess里面来呢????????带着问题开始吧

VOID InlineHookPspTerminateProcess()
{

int JmpOffSet;
unsigned char JmpCode[5] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };
KIRQL oldIrql;

if (PspTerminateProcess == 0)
{
DbgPrint("PspTerminateProcess NOT FOUND\n");
return;
}

DbgPrint( "PspTerminateProcess is found at:0x%08x\n", (ULONG)PspTerminateProcess );

DbgPrint("T_PspTerminateProcess is:%x\n",T_PspTerminateProcess);
JmpOffSet= (char*)T_PspTerminateProcess - (char*)PspTerminateProcess - 5;
DbgPrint("JmpOffSet is:%x\n",JmpOffSet);
RtlCopyMemory ( JmpCode+1, &JmpOffSet, 4 );

_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
oldIrql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory ( PspTerminateProcess, JmpCode, 5 );
DbgPrint("PspTerminateProcess is hook now \n");
KeLowerIrql(oldIrql);

_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}

}
好了,测试一下,只需要在DriverEntry添加
InlineHookPspTerminateThreadByPointer();嗯,运行正常,没有蓝屏,呵呵,那就继续
既然在T_PspTerminateProcess里面调用了MyPspTerminateProcess ,那就写这个函数吧,这里只是简单的输出PspTerminateProcess hello,你可以根据需要重写这个函数
int MyPspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{
DbgPrint("PspTerminateProcess hello\n");

return 1;
}
返回了1,那cmp eax,1 ,呵呵放行原来的函数执行
好了,现在基本工作都完成了,就写卸载驱动部分
VOID Unload(PDRIVER_OBJECT DriverObject)
{

unsigned char Code[5]={0x8b,0xff,0x55,0x8b,0xec};

_asm
{
CLI
MOV eax, CR0
AND eax, NOT 10000H
MOV CR0, eax

pushad
mov edi, PspTerminateProcess
mov eax, dword ptr Code[0]
mov [edi], eax
mov al, byte ptr Code[4]
mov [edi+4], al
popad

MOV eax, CR0
OR eax, 10000H
MOV CR0, eax
STI
}

DbgPrint("Unload Called \r\n");

}
到此,我们的工作基本完成了,不过这只是一个测试的,还有待加强,运行后就是下面这样


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (41)
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
2
汗..怎么标题是【原创】【原创】【原创,.....
2008-4-3 16:40
0
雪    币: 200
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
好文,学习
2008-4-3 17:52
0
雪    币: 70
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
特征码搜索看滴偶汗直冒
2008-4-3 17:58
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
5
汗......
2008-4-3 18:09
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
6
嘿嘿,不错不错~~~

不过因为内核补丁不同,这样搜索可能会BSOD的哦~~~~
2008-4-3 18:14
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
7
嗯..我今天蓝了很多次...刚刚看了一遍帖子,发现搜索特征码那个函数可能错了..后面的就没有问题
2008-4-3 18:20
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
8
汗...我想问一句.....函数地址是不是会变的啊....刚才用以前的方法搜索PspTerminateProcess得到的地址和这帖里面搜索到的一摸一样.....可记得以前搜得到的地址跟现在不一样
2008-4-3 18:27
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
9
函数的地址在不同的系统上可能会不同.

主要是函数内部的实现可能会因为补丁或系统的不同等缘故而使得特征码发生变化。

所以你的这个特征码搜索不通用,很危险~~
2008-4-3 18:52
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
10
这样啊....谢拉
2008-4-3 18:58
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
11
刚才做了个实验,按特征码搜索到的确是PspTerminateProcess的..地址真的跟以前的不一样 ....可以顺利结束冰刃..
2008-4-3 19:07
0
雪    币: 51
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
PspTerminateProcess学习、学习
2008-4-12 17:19
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
太感谢楼主了,怀着激动的心情,还有对楼主的崇高敬意。
先顶再看
2008-4-26 22:02
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
总结下,
A 调用ZwQuerySystemInformation()函数枚举内核模块,找到ntosknl.exe 模块的起始地址和模块大小

B 在找出的模块地址空间内,搜索特定的关键字串,找到 PspTerminateProcess() 函数的起始地址

C HOOK  PspTerminateProcess()函数,修改这个函数起始地址的5个字节
  重点分析下楼主用于HOOK的函数,以帮助新人 ^_^
  _declspec(naked) T_PspTerminateProcess(
    PEPROCESS Process,
    NTSTATUS ExitStatus
    )
{

  
_asm
{
   mov   edi, edi         
   push ebp
   mov   ebp ,esp;从函数开始到这里指令长度共5个字节,它们是正常的PspTerminateProcess() 函数开头的5字节
   push   [ebp+0ch]
   push   [ebp+8]
   call   MyPspTerminateProcess ;这是作者自己的功能函数,前面的两个PUSH指令是为该函数传递参数,详细见图
   cmp   eax,1    ;函数返回结果与1比较
   jz     end     ;如果返回结果等于1,就直接game over 结束函数运行
   mov   eax,PspTerminateProcess    ;否则就调用真正的PspTerminateProcess() 函数
   add   eax,5    ;因为我们在开始实现了原始函数的5个字节,所以这里JMP 到 原始函数地址 +5字节
   jmp   eax      ;开始跳了,跳到原始的函数那里

   end:  
   pop   ebp   ;对应函数开头的push ebp指令
   retn 8      ;返回,8 表示的是函数参数的长度
}
   }
}

D  修改原始PspTerminateProcess() 函数开头的5字节,添加一个跳转指令,跳转到我们自己的HOOK函数

附上 函数调用时的堆栈分布图


最后,
★volatile关键字
遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
volatile _declspec (naked) void NewKeyboardHandler(void) // - Non-Paged
2008-4-26 22:44
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
楼主,能给份工程文件吗,我测试要用哈。谢谢先。
我的 E-MAIL  53338564@qq.com

保证不散布出去
2008-4-26 23:31
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
16
哈哈...gdlian分析的很好.....当时因为快没什么说明.........这个代码对inline hook未导出的算是比较好的模仿........代码给你没问题....散发出去也没问题......呵呵...
2008-4-27 15:01
0
雪    币: 269
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
17
恩....不同机器的特征码可能不一样就会蓝掉...

网咯上搜了一下

hook PspTerminateProcess 的文基本都是这篇的转载...呵呵...
2008-5-18 11:15
0
雪    币: 269
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
18
正好帮助我这样的新人...
2008-5-18 11:17
0
雪    币: 327
活跃值: (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
19
我本菜鸟,可也想要份工程文件吗学习学习,谢谢啦。
我的 E-MAIL  sh_wsf@163.com
2008-5-19 16:13
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
接触内核不久,楼主能给我一份工程文件吗?
qwertycs@21cn.com
2008-5-20 12:51
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
谢谢楼主分享
2008-5-22 08:29
0
雪    币: 10936
活跃值: (3293)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
22
如果函数事先被hook了 通过搜索0x8b,0xff,0x55,0x8b,0xec 能找到函数地址吗?
楼主是先找到函数地址再比较检查是否被hook了 就不需要了。
不知道是不是这样?
2008-5-22 10:01
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
23
的确是这样...这是我以前的代码....现在如果想inline ...最好是在ring3自己分析PE..通过计算找到地址再传给驱动....这样就好了...而且可以解决在内核搜索特征码可能造成的蓝屏
不过我觉得这个inline hook的意义不是这些..而是后面自己实现的功能的函数....
2008-5-22 11:46
0
雪    币: 235
活跃值: (23)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
24
“ring3自己分析PE..通过计算找到地址再传给驱动”这个如何实现 sysnap能不能发篇教程介绍一下呢
2008-5-22 12:07
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
25
其实也没什么难的....都是体力活...我说下思路吧
自己映射ntkrnlpa.exe...在我机器是这个..可能有些是ntoskrnl.exe或者其他
得到IMAGE_OPTIONAL_HEADER的SizeOfImage
接着就是VirtualAlloc,ReadFile
然后就自己搜索了.....
__try{
        for (i=0;i<FileSize;i++)
                {
                       
                   if ((BufferAddr[i]==code_1)&&(BufferAddr[i+1]==code_2)&&(BufferAddr[i+2]==code_3)&&(BufferAddr[i+3])==code_4)
                   {
                           printf("codes matched at   :0x%x\n",&BufferAddr[i]);
                                                  
                           funrva2=&BufferAddr[i];
                           funrva=(ULONG)&BufferAddr[i]-(ULONG)BufferAddr;
                                                     break;
                   }
                 }
        }__except ( Deal_Exception(lpvBase))
        {
               
        }

        if(funrva2==NULL)
        {
                printf("codes not matched!!\n");
                return 0;
        }

         
         re_addr=Offset2RVA((ULONG)funrva, (PIMAGE_SECTION_HEADER)sectionheader, numberofsection);
         bSuccess = VirtualFree(lpvBase, 0, MEM_RELEASE);
         printf ("Release %s.\n", bSuccess ? "succeeded" : "failed" );
         return re_addr;
2008-5-22 12:32
0
游客
登录 | 注册 方可回帖
返回
//