看Comjiang大牛写的代码,里面有很多他没有详细介绍,也许是他假定对方已经有基础了,当然我最近几天一直都直接看代码,然后查ddk document,并没有参照任何电子书.如果有什么好的入门学习kernel hook的书,希望各位朋友给推荐下.
下面是代码,我自己添加了部分代码,不知道对不对啊,如果错了,还请大牛们客气的指正哦.
//Current Code Inline Hook KiINsertQueueApc Function
//Include Head File To Current Source File
#include <ntddk.h>
#include <ntifs.h>
ULONG g_KiInsertQueueApc; //保存KiInsertQueueApc地址
char g_oricode[8]; //保存KiInsertQueueApc前8字节
ULONG g_uCr0;
char *non_paged_memory; //保存KiInsertQueueApc副本
void WPOFF()
{
ULONG uAttr;
_asm
{
push eax;
mov eax, cr0;
mov uAttr, eax;
and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
mov cr0, eax;
pop eax;
cli
};
g_uCr0 = uAttr; //保存原有的 CRO 屬性
}
VOID WPON()
{
_asm
{
sti
push eax;
mov eax, g_uCr0; //恢復原有 CR0 屬性
mov cr0, eax;
pop eax;
};
}
__declspec(naked) my_function_detour_KiInsertQueueApc()
{
__asm
{
mov edi,edi
push ebp
mov ebp, esp
push ecx
mov eax,ecx
_emit 0xEA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0x08
_emit 0x00
}
}
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
//根据特征值,从KeInsertQueueApc搜索中搜索KiInsertQueueApc
ULONG FindKiInsertQueueApcAddress()
{
char * Addr_KeInsertQueueApc = 0;
int i = 0;
//特征值
char Findcode[] = {
0xE8, //call
0xcc, //short
0x29, //offset
0x00,
0x00
};
ULONG Addr_KiInsertQueueApc = 0;
//获得KeInsertQueueApc地址
Addr_KeInsertQueueApc = (char *) GetFunctionAddr(L"KeInsertQueueApc");
for(i = 0; i < 100; i ++) //0到99 循环100次
{
if(
//判断是否匹配特征值
//特征值是一个函数调用指令
Addr_KeInsertQueueApc[i + 0] == Findcode[0] &&
Addr_KeInsertQueueApc[i + 1] == Findcode[1] &&
Addr_KeInsertQueueApc[i + 2] == Findcode[2] &&
Addr_KeInsertQueueApc[i + 3] == Findcode[3] &&
Addr_KeInsertQueueApc[i + 4] == Findcode[4]
)
{
//获得KiInsertQueueApc地址
Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc[i] + 0x29cc + 5;
break;
}
}
return Addr_KiInsertQueueApc;
}
VOID DetourFunctionKiInsertQueueApc()
{
char *actual_function = (char *)g_KiInsertQueueApc; //获得KiInsertQueueApc函数地址
unsigned long detour_address;
unsigned long reentry_address;
KIRQL oldIrql;
int i = 0;
//用于覆盖KiInsertQueueApc前8字节
char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };
//获得KiInsertQueueApc第8个字节地址
reentry_address = ((unsigned long)actual_function) + 8;
//分配256字节内存空间
non_paged_memory = ExAllocatePool(NonPagedPool, 256);
for(i=0;i<256;i++) //循环256次,从0到255
{
//难道是备份KiInsertQueueApc函数到non_paged_memory ?
((unsigned char *)non_paged_memory)[i] =
((unsigned char *)my_function_detour_KiInsertQueueApc)[i];
}
//detour_address指向KiInsertQueueApc函数副本
detour_address = (unsigned long)non_paged_memory;
//detour_address覆盖到newcode[1]也就替换0x44
*( (unsigned long *)(&newcode[1]) ) = detour_address;
//循环200次,0到199
for(i=0;i<200;i++)
{
if(
(0xAA == ((unsigned char *)non_paged_memory)[i+0]) &&
(0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
(0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
(0xAA == ((unsigned char *)non_paged_memory)[i+3])
)
{
//跳到KiInsertQueueApc之后代码继续执行
*( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
break;
}
}
oldIrql = KeRaiseIrqlToDpcLevel();
//0到7,循环8次
for(i=0;i < 8;i++)
{
//actual_function == KiInsertQueueApc
//备份KiInsertQueueApc前8字节
g_oricode[i] = actual_function[i];
actual_function[i] = newcode[i]; //开始覆盖KiInsertQueueApc前8字节
}
KeLowerIrql(oldIrql);
}
VOID UnDetourFunction()
{
//获得KiInsertQueueApc地址
char *actual_function = (char *)g_KiInsertQueueApc;
KIRQL oldIrql;
int i = 0;
WPOFF();
oldIrql = KeRaiseIrqlToDpcLevel();
//0到7,循环8次
for(i=0;i < 8;i++)
{
//恢复KiInsertQueueApc函数前8字节
actual_function[i] = g_oricode[i];
}
KeLowerIrql(oldIrql);
WPON();
//释放non_paged_memory
ExFreePool(non_paged_memory);
}
//The Routine Unload Driver
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint("In DriverUnload Routine\n");
UnDetourFunction();
}
//Current Driver EntryPoint
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DbgPrint("In DriverEntry Routine\n");
//Set Current Driver Unload Routine
DriverObject->DriverUnload=OnUnload;
//返回KiInsertQueueApc地址
g_KiInsertQueueApc=FindKiInsertQueueApcAddress();
DetourFunctionKiInsertQueueApc();
return STATUS_SUCCESS;
}
下面是我的几点疑惑,希望高手有时间的话,尽量给简单讲下.
我知道non_paged_memory这个全局变量分配了256字节内存,但是它最终保存的是什么啊,难道是KiInsertQueueApc函数的副本吗?
my_function_detour_KiInsertQueueApc这个函数是作什么的啊,我看不懂,希望知道的兄弟给简单说下就行,谢谢.
WPOFF和WPON这2个函数是否是去除写保护与恢复写保护,呵呵,我猜测的.
Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc[i] + 0x29cc + 5;
上面的是从KeInsertQueueApc中查特征码,然后根据一个表达式计算出KiInsertQueueApc的地址,我想知道,这个表达式是怎么知道的,难道是用windbg看到了吗?
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)