今天,突然想对 hook 进行一些学习,因为对于一些底层的操作,都是在于ANTI-HOOK 。。。然后才能得到最后的使用权,为此,
自己也要掌握这种很强大的编程手法,那么首先,我们应该知道的一些是,在 win2000 以后,对于 SSDT 的操作,系统都是写了保护的,
那么我们首先应该做的是怎么样来解除掉它们,替换我们的执行地址,当然在这里,我们必须要知道这个结构:
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; // 由于KeServiceDescriptorTable只有一项,这里就简单点了
他就是SSDT 表了,这张表就类似于 PE 文件中的 IAT ,存储着一系列的函数地址,我们都知道,现在的系统都是基于保护模式的,当我们要访问内核的时候,MS 已经为我们定义好了接口,那么当我们调用哪些接口的时候,哪些接口会在这张表中查找需要的服务的地址函数,
我们在这里可以截获我们要过滤的函数请求,达到我们的目的。。。
这个结构有四个域:
反汇编得到:
HookApi!_SERVICE_DESCRIPTOR_TABLE
+0x000 ServiceTableBase : Ptr32 Void
+0x004 ServiceCounterTableBase : Ptr32 Uint4B
+0x008 NumberOfService : Uint4B
+0x00c ParamTableBase : Uint4B
//我们的替代的函数,是一个裸函数,编译器不会像其他的函数一样处理它。。。
__declspec(naked) NTSTATUS MyApiAddress(PHANDLE phandle,
ACCESS_MASK DesireAddress,
POBJECT_ATTRIBUTES pObjectAttributes,
PCLIENT_ID pClientID)
{
KdPrint(("NtPOpenProcess...Call"));
__asm
{
push 0C4h; //这两个域,是通过我们要HOOK 的 API 定位得到的
push 804daaa8h;
jmp [g_JmpServerAddr];
}
}
kd> u 805c2296
nt!NtOpenProcess:
这里是我们要调用的函数的入口点:
两个参数,遵循 C 的调用方式,手工清栈。。。就得到了
805c2296 68c4000000 push 0C4h //
805c229b 68a8aa4d80 push offset nt!ObWatchHandles+0x25c (804daaa8)
805c22a0 e86b6cf7ff call nt!_SEH_prolog (80538f10)
805c22a5 33f6 xor esi,esi
805c22a7 8975d4 mov dword ptr [ebp-2Ch],esi
805c22aa 33c0 xor eax,eax
805c22ac 8d7dd8 lea edi,[ebp-28h]
805c22af ab stos dword ptr es:[edi]
有两种方法获得我们要HOOK 的地址,可以通过函数,推荐PVOID
MmGetSystemRoutineAddress(
IN PUNICODE_STRING SystemRoutineName
);
比较方便,不用涉及其他的操作,返回的是要查的地址。。。。
不然的话,需要查MS 定义的服务描述表,而且个个平台还不一样,难以做到跨平台。。。
上边就完成了我们的导向工作,只要获取到了需要跳转的地址就 OK 了。。。
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; // KeServiceDescriptorTable为导出函数
操作之前:
我们需要:
// 去掉内存保护
VOID ClearMemoryProtect()
{
__asm
{
cli;
mov eax, cr0;
and eax, not 10000h;
mov cr0, eax;
}
}
// 跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了,完成替换
g_JmpServerAddr = (ULONG)NtOpenProcess + 10;
// 回复内存的保护
VOID RecoverMemoryProtect()
{
__asm
{
cli;
mov eax, cr0;
or eax, not 10000h;
mov cr0, eax;
sti;
}
}
*((ULONG*)uAddress) = (ULONG)MyApiAddress; // HOOK SSDT
去除内存的写保护,操作完成自后,回复之。。。。
然后我们就可以完成监视的功能。。。