共有回帖数 0 个
-
此方法来自《从汇编语言到windows内核编程》,但此书给了思路和错误代码。会蓝屏,网上也没人解决。凡是解决了的,也不希望分享。楼楼会一步一步解释如果hook,然后以后通过这个方法,可以hook任何带函数符号的内核函数。
以IoCallDriver为例子
nt!IoCallDriver:
804f04f2 8bff mov edi,edi
804f04f4 55 push ebp
804f04f5 8bec mov ebp,esp
804f04f7 8b550c mov edx,dword ptr [ebp+0Ch]
804f04fa 8b4d08 mov ecx,dword ptr [ebp+8]//很明显这里是两个参数,没有入栈
804f04fd ff1500d25480 call dword ptr [nt!pIofCallDriver (8054d200)]
804f0503 5d pop ebp
804f0504 c20800 ret 8
以上是IoCallDriver函数的汇编代码
看来调用了一个pIofCallDriver函数指针,那我们跟进去看看。
由于这个是一个指针,所以先要看指针内容
kd dd 8054d200 l1
8054d200 804ef0e8
好了,这里的804ef0e8地址中有真正的函数入口
nt!IopfCallDriver:
804ef0e8 fe4a23 dec byte ptr [edx+23h]//这里是IRP结构中0x23处的内容,自己查看IRP结构就可以知道是什么了。
804ef0eb 8a4223 mov al,byte ptr [edx+23h]
804ef0ee 84c0 test al,al
804ef0f0 7f0e jg nt!IopfCallDriver+0x18 (804ef100)//这里才是真正的函数入口地址,有兴趣可以进去看看,自己还原代码,很简单。
..
从上面看。
804f04fd ff1500d25480 call dword ptr [nt!pIofCallDriver (8054d200)]这条指令是调用了函数指针,那么我们直接hook函数指针就可以了。那函数指针一般放哪里呢?
当然是一个函数表中,这里先不将这个函数表的获取方法。直接告诉你IoCallDriver函数对应了一个函数符号IofCallDriver。那现在看看这个符号下是什么内容。
nt!IofCallDriver:
804ef120 ff2500d25480 jmp dword ptr [nt!pIofCallDriver (8054d200)]
哈哈。居然是一句简单的jmp指令。看看前面的。
kd dd 8054d200 l1
8054d200 804ef0e8
可以发现。调用IoCallDriver函数时,里面的 call dword ptr [nt!pIofCallDriver (8054d200)]其实就是调用了IofCallDriver这个函数符号中jmp后面的函数指针。
那么我们直接hook IofCallDriver这个函数符号后面的函数指针就可以了。这样以后每个程序调用IoCallDriver,都会调用我们的函数。
nt!IofCallDriver:
804ef120 ff2500d25480 jmp dword ptr [nt!pIofCallDriver (8054d200)]
针对这条指令,ff占用两个字节,分别是机器码的前缀和操作码。这里不是我们要hook的。那后面的地址就是我们要hook的。
正确的hook源代码是:
IoCallDriverType HookIoCallDriver(PWCHAR Symbol, bool fHook)
{
UNICODE_STRING uniSymbol;
RtlInitUnicodeString(&uniSymbol, Symbol);
static PVOID tempFunc=NULL;
if (Symbol == NULL) return NULL;
//获取导出函数符号地址
PCHAR address = (PCHAR)MmGetSystemRoutineAddress(&uniSymbol);
if (fHook)
{
OldIoCallDriver = (IoCallDriverType)(*PLONG(address + 2));//获取入口指针(非真实地址)
tempFunc = (PVOID)NewIoCallDriver;//模仿旧函数入口方式,这里很重要
WPOFF();//写保护关
InterlockedExchange(PLONG(address + 2), (LONG)&tempFunc);
WPON();
}
else
{
if (OldIoCallDriver)
{
WPOFF();//这里必须关闭写保护,不然会蓝屏
InterlockedExchange(PLONG(address + 2), (LONG)OldIoCallDriver);
WPON();
}
else
return NULL;
}
return OldIoCallDriver;//返回函数指针
}
下面是关闭和开启写保护的代码
void WPOFF()
{
__asm
{
push eax
mov eax, cr0
mov g_Cr0, eax;//保存原来cr0,自己定义一个ULONG的全局变量
and eax, not 10000h//第16位是控制写保护的
mov cr0, eax
pop eax
cli
}
}
void WPON()
{
__asm
{
sti
push eax
mov eax, g_Cr0
mov cr0, eax//开启写保护
pop eax
}
}
重点在于新函数结构,由于是hook的函数符号表下的函数指针,那么参数在此之前已经被设置好了。所以直接用一个naked函数就可以了(采用c语言和汇编的混编就简单)
__declspec(naked) void NewIoCallDriver(void)
{
__asm
{
push edx
push ecx
}//保存入口参数,这里很重要,不要让入口参数被破坏了
//这里你想干什么就干什么
DbgPrint("IofCallDriver is hookedn");//只是简单的提醒一下这个函数被hook了
__asm
{
pop ecx
pop edx
}
__asm
{
mov eax, OldIoCallDriver //获取函数指针
jmp dword ptr[eax] //此函数最后调用ret,返回到调用IoCallDriver的例程
//这个jmp之后,当前程序就失去对此函数的控制,之后控制权会由ret返回调用IoCallDriver的程序中。千万不要用call,因为IoCallDriver是一个很重要的函数,如果把控制权抢过来,系统会瘫痪,那只有重启了。
}
}


既然写到这里了。那就还原一个xp sp3下的IoCallDriver吧。书上给的是vista下的代码。那我们就直接来xp下的代码学习学习。看看IoCallDriver是怎么运行的。
首先要知道irp结构
typedef struct _IRP{
CSHORT Type;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP *MasterIrp;
__volatile LONG IrpCount;
PVOID SystemBuffer;
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
KIRQL CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
PIO_STATUS_BLOCK UserIosb;
PKEVENT UserEvent;
union {
struct {
union {
PIO_APC_ROUTINE UserApcRoutine;
PVOID IssuingProcess;
};
PVOID UserApcContext;
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;
} Overlay;
__volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[4];
};//0x10字节
};
PETHREAD Thread;//0x4字节
PCHAR AuxiliaryBuffer;//0x4
struct {
LIST_ENTRY ListEntry;//0x8
union {
struct _IO_STACK_LOCATION *CurrentStackLocation;//此处相对于Tail偏移地址为0x20
ULONG PacketType;
}h1;
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
} IRP,*FIRP;
在windbg下只能看到Tail字段的偏移地址是0x40,但是看不到Tail的内容。所以里面的字段要自己推算。我已经为大家推算好了。因为IoCallDriver要用到0x60处的字段。
由于上面说了,CurrentStackLocation相对于Tail是0x20,那么加上Tail相对于结构头的偏移地址0x40,那CurrentStackLocation便是0x60了。
来看看汇编代码和注释:
IoCallDriver:
nt!IoCallDriver:
804f04f2 8bff mov edi,edi
804f04f4 55 push ebp
804f04f5 8bec mov ebp,esp
804f04f7 8b550c mov edx,dword ptr [ebp+0Ch]//irp,edx
804f04fa 8b4d08 mov ecx,dword ptr [ebp+8]//deviceobject,ecx
804f04fd ff1500d25480 call dword ptr [nt!pIofCallDriver (8054d200)]
804f0503 5d pop ebp
804f0504 c20800 ret 8
IopfCallDriver:
nt!IopfCallDriver:
804ef0e8 fe4a23 dec byte ptr [edx+23h]//CurrentLocation--
804ef0eb 8a4223 mov al,byte ptr [edx+23h]
804ef0ee 84c0 test al,al//CurrentLocation是否为0
804ef0f0 7f0e jg nt!IopfCallDriver+0x18 (804ef100)
804ef0f2 6a00 push 0
804ef0f4 6a00 push 0
804ef0f6 6a00 push 0
804ef0f8 52 push edx
804ef0f9 6a35 push 35h
804ef0fb e89aab0000 call nt!KeBugCheckEx (804f9c9a)//报错
804ef100 8b4260 mov eax,dword ptr [edx+60h]//Tail.Overlay.CurrentStackLocation
804ef103 83e824 sub eax,24h//IO_STACK_LOCATION为0x24字节
804ef106 56 push esi//--Tail.Overlay.CurrentStackLocation
804ef107 894260 mov dword ptr [edx+60h],eax//irpStack(PIO_STACK_LOCATION)
804ef10a 894814 mov dword ptr [eax+14h],ecx//irpStack-DeviceObject=deviceobject
804ef10d 0fb600 movzx eax,byte ptr [eax]//irpStack-MajorFunction
804ef110 8b7108 mov esi,dword ptr [ecx+8]//deviceobject-DriverObject
804ef113 52 push edx
804ef114 51 push ecx
804ef115 ff548638 call dword ptr [esi+eax*4+38h]//deviceobject-DriverObject-MajorFuntion[eax]
804ef119 5e pop esi
804ef11a c3 ret//返回到调用函数
那么还原成C语言:
NTSTATUS _IoCallDriver(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpStack;
if (--irp-CurrentLocation == 0)
KeBugCheckEx(0x35, (ULONG_PTR)irp, 0, 0, 0);
else
{
irpStack=irp-Tail.Overlay.CurrentStackLocation--;//指针减少1,这个IO_STACK_LOCATION结构是0x24大小
irpStack-DeviceObject = DeviceObject;
}
return DeviceObject-DriverObject-MajorFunction[irpStack-MajorFunction](DeviceObject, irp);
}
楼主 2015-10-23 13:30 回复
Copyright © 2010~2015 直线网 版权所有,All Rights Reserved.沪ICP备10039589号
意见反馈 |
关于直线 |
版权声明 |
会员须知