实现kernel-mode inline function hook的简单方法

看了uty的《kernel inline hook 绕过vice检测》,思路很好,但实现起来麻烦了点。
这里以CmEnumerateKey为例介绍实现inline hook的简单方法,尽量依靠编译器做更多的事情。

1、编写fake_CmEnumerateKey,在其中对CmEnumerateKey的调用做后续处理。

NTSTATUS
fake_CmEnumerateKey(
IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
IN ULONG Index,
IN KEY_INFORMATION_CLASS KeyInformationClass,
IN PVOID KeyInformation,
IN ULONG Length,
IN PULONG ResultLength
)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("[cmhook] nt!CmEnumerateKey() called./n"));

status = JMP_CmEnumerateKey(KeyControlBlock, Index, KeyInformationClass, KeyInformation, Length, ResultLength);

return status;
}

2、取得CmEnumerateKey的地址,备份前7个字节,之后修改CmEnumerateKey的前5个字节为jmp xxxxxxxx(fake_CmEnumerateKey入口偏移地址)。

// 保存原始的7个字节代码
BYTE g_cOrigCode[7] = {0};

// JMP xxxxxxxx
BYTE g_cHookCode[5] = { 0xe9, 0, 0, 0, 0 };

RtlCopyMemory(g_cOrigCode, (BYTE*)CmEnumerateKey, 7);

// calc jmp offset
*( (ULONG*)(g_cHookCode+1) ) = (ULONG)fake_CmEnumerateKey - (ULONG)CmEnumerateKey - 5;

DisableWriteProtect(&ulAttr);
RtlCopyMemory((BYTE*)CmEnumerateKey, g_cHookCode, 5);
EnableWriteProtect(ulAttr);

3、编写__declspec(naked) JMP_CmEnumerateKey,这个例程实现CmEnumerateKey被修改个7个字节的代码,并转入nt!CmEnumerateKey+7处开始执行。

__declspec(naked)
NTSTATUS
JMP_CmEnumerateKey(
IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
IN ULONG Index,
IN KEY_INFORMATION_CLASS KeyInformationClass,
IN PVOID KeyInformation,
IN ULONG Length,
IN PULONG ResultLength
)
{
__asm
{
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
_emit 0x90
}
}

JMP_CmEnumerateKey的主要实现代码在程序运行时进行填充,以下是实现代码:

BYTE jmp_orig_code[7] = { 0xEA, 0, 0, 0, 0, 0x08, 0x00 };

// jmp 0008:nt!CmEnumerateKey+7
*( (ULONG*)(jmp_orig_code+1) ) = (ULONG)((BYTE*)CmEnumerateKey + 7);

DisableWriteProtect(&ulAttr);

//
// CmEnumerateKey修改之前的前7个字节的代码
// 6a18         push 18h
// 68d0de4d80   push offset nt!`string'+0xf8 (804dded0)
//
RtlCopyMemory((BYTE*)JMP_CmEnumerateKey, g_cOrigCode, 7);

// jmp 0008:nt!CmEnumerateKey+7
RtlCopyMemory((BYTE*)JMP_CmEnumerateKey+7, jmp_orig_code, 7);
EnableWriteProtect(ulAttr);

这里要注意一个细节,虽然只CmEnumerateKey修改了前5个字节,但这5个字节里面包含两条指令(共7个字节),因此要保存前7个字节。
修改前:

kd> u nt!CmEnumerateKey
nt!CmEnumerateKey:
80605f54 6a18            push    18h
80605f56 68d0de4d80      push    offset nt!`string'+0xf8 (804dded0)
80605f5b e80839f2ff      call    nt!_SEH_prolog (80529868)
80605f60 e829abffff      call    nt!CmpLockRegistry (80600a8e)
80605f65 8b4508          mov     eax,dword ptr [ebp+8]
80605f68 f6400502        test    byte ptr [eax+5],2
80605f6c 7407            je      nt!CmEnumerateKey+0x21 (80605f75)
80605f6e be7c0100c0      mov     esi,0C000017Ch

修改后:

kd> u nt!CmEnumerateKey
nt!CmEnumerateKey:
80605f54 e999143279      jmp     cmhook+0x3f2 (f99273f2)
80605f59 4d              dec     ebp
80605f5a 80e808          sub     al,8
80605f5d 39f2            cmp     edx,esi
80605f5f ff              ???
80605f60 e829abffff      call    nt!CmpLockRegistry (80600a8e)
80605f65 8b4508          mov     eax,dword ptr [ebp+8]
80605f68 f6400502        test    byte ptr [eax+5],2


by CDrea
 

你可能感兴趣的:(实现kernel-mode inline function hook的简单方法)