如图,假设未被hook的代码如黄色图块显示。代码顺序为ABCDE,假设ABC三条指令加起来长度大于14字节,可以放下 ff 25 00 00 00 00 00 00 00 00 00 00 00 00
这个跳转。本框架会自动识别这三条代码的长度,然后将其替换为一个 ff25
jmp。其跳到自己申请的一块空间。跳转完成之后首先进行环境的保存,将所有寄存器保存到栈中。然后call一个C语言写的callback函数。可以在这个函数中进行相应的操作。如果这个函数的返回值是 FALSE
,则跳转回原函数处进行执行。如果为 TRUE
,则直接return,不再执行原函数。如果需要执行原函数,则重新POP所有之前保存的寄存器,然后执行 A B C
三条语句,最后通过一个 ff25
jmp跳到原函数中的下一行处执行(在此示例中是D处)。
第一个参数是需要设置fast_prehandler的hook的编号。第二个参数是自行编写的prehandler的buffer地址,第三个参数是buffer的大小,第四个参数是buffer中 ff25
jmp的地址的偏移。自行编写的代码的格式如下
如果前面cmp判断不需要处理,那么就跳到 @重新运行原来的code,运行原始逻辑,然后跳回到原来位置
。否则通过 ff25
jmp重新跳到原来的hook函数的地址,重新执行原来的hook_handler。
思路如下。将这个短跳的跳转地址改为 jmp 到原函数里面的jx目标地址
代码的地址。最后在执行完 A B C
之后通过一个 EB
短跳跳到原来的 JMP D
处。
其中返回值为FALSE表示执行完本函数后继续执行原来的函数。如果为true则不再执行原始的函数,直接返回。 pcontext
是一个指向之前保存的寄存器的指针。其结构如下
在handler函数中可以通过读取这些寄存器来获取调用的信息,也可以通过修改这些寄存器达到修改调用方调用原函数时的调用参数的目的。
运行结果如下
设置fast_prehandler的代码如下
运行结果如下
这里在fast_prehandler中判断了 rcx
是否等于1,如果不等于1就直接走原流程,因此没有打印出任何信息。我们把他改为 cmp rdx, 0x1000
再试一下
可以看到只有 rdx
为1000的时候才会进入到C语言编写的handler中。否则快速跳回到原流程中执行。
UCHAR buf[]
=
{
0x48
,
0x83
,
0xF9
,
0x01
,
/
/
00007FF806EA094F
| |
cmp
rcx,
1
|
0x74
,
0x0E
,
/
/
00007FF806EA0953
| | je ntdll.
7FF806EA0963
|
0xFF
,
0x25
,
0x00
,
0x00
,
0x00
,
0x00
,
/
/
00007FF806EA0955
| | jmp qword ptr ds : [
7FF806EA095B
] |
0x00
,
0x00
,
/
/
00007FF806EA095B
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA095D
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA095F
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA0961
| | add byte ptr ds : [rax] ,al |
0x90
,
/
/
00007FF806EA0963
| | nop
};
set_fast_prehandler(number, buf, sizeof buf,
12
);
UCHAR buf[]
=
{
0x48
,
0x83
,
0xF9
,
0x01
,
/
/
00007FF806EA094F
| |
cmp
rcx,
1
|
0x74
,
0x0E
,
/
/
00007FF806EA0953
| | je ntdll.
7FF806EA0963
|
0xFF
,
0x25
,
0x00
,
0x00
,
0x00
,
0x00
,
/
/
00007FF806EA0955
| | jmp qword ptr ds : [
7FF806EA095B
] |
0x00
,
0x00
,
/
/
00007FF806EA095B
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA095D
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA095F
| | add byte ptr ds : [rax] ,al |
0x00
,
0x00
,
/
/
00007FF806EA0961
| | add byte ptr ds : [rax] ,al |
0x90
,
/
/
00007FF806EA0963
| | nop
};
set_fast_prehandler(number, buf, sizeof buf,
12
);
/
/
prehandler格式类似如下
/
/
cmp
XXX
/
/
jnz 重新运行原来的code,运行原始逻辑,然后跳回到原来位置 ; 对一些参数进行判断
/
/
jmp [eip] ; 一个ff25 jmp,offset填
0
/
/
00
00
/
/
00
00
/
/
00
00
/
/
00
00
/
/
@重新运行原来的code,运行原始逻辑,然后跳回到原来位置
/
/
; 这后面的原始逻辑由后面的代码自动填入,不用手动写。
/
/
prehandler格式类似如下
/
/
cmp
XXX
/
/
jnz 重新运行原来的code,运行原始逻辑,然后跳回到原来位置 ; 对一些参数进行判断
/
/
jmp [eip] ; 一个ff25 jmp,offset填
0
/
/
00
00
/
/
00
00
/
/
00
00
/
/
00
00
/
/
@重新运行原来的code,运行原始逻辑,然后跳回到原来位置
/
/
; 这后面的原始逻辑由后面的代码自动填入,不用手动写。
BOOLEAN NtOpenProcess_callback(PGuestContext pcontext)
BOOLEAN NtOpenProcess_callback(PGuestContext pcontext)
typedef struct _GuestContext
{
ULONG64 mRflags;
ULONG64 mRax;
ULONG64 mRcx;
ULONG64 mRdx;
ULONG64 mRbx;
ULONG64 mRsp;
ULONG64 mRbp;
ULONG64 mRsi;
ULONG64 mRdi;
ULONG64 mR8;
ULONG64 mR9;
ULONG64 mR10;
ULONG64 mR11;
ULONG64 mR12;
ULONG64 mR13;
ULONG64 mR14;
ULONG64 mR15;
}GuestContext,
*
PGuestContext;
typedef struct _GuestContext
{
ULONG64 mRflags;
ULONG64 mRax;
ULONG64 mRcx;
ULONG64 mRdx;
ULONG64 mRbx;
ULONG64 mRsp;
ULONG64 mRbp;
ULONG64 mRsi;
ULONG64 mRdi;
ULONG64 mR8;
ULONG64 mR9;
ULONG64 mR10;
ULONG64 mR11;
ULONG64 mR12;
ULONG64 mR13;
ULONG64 mR14;
ULONG64 mR15;
}GuestContext,
*
PGuestContext;
ULONG64 num
=
0
;
VOID DRIVERUNLOAD(_In_ struct _DRIVER_OBJECT
*
DriverObject)
{
KdPrintEx((
77
,
0
,
"unload\r\n"
));
reset_hook(num);
}
BOOLEAN NtOpenProcess_callback(PGuestContext pcontext)
{
KdPrintEx((
77
,
0
,
"参数为 %llx %llx %llx %llx\r\n"
, pcontext
-
>mRcx, pcontext
-
>mRdx, pcontext
-
>mR8, pcontext
-
>mR9));
return
FALSE;
/
/
RETURN FALSE表示执行完本函数后继续执行原始的ntopenprocess函数。如果
return
true则不再执行原始的openprocess函数,直接返回。
}
VOID hook_NtOpenProcess()
{
UNICODE_STRING unName
=
{
0
};
RtlInitUnicodeString(&unName, L
"NtOpenProcess"
);
PUCHAR funcAddr
=
MmGetSystemRoutineAddress(&unName);
hook_by_addr(funcAddr, NtOpenProcess_callback, &num);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
KdPrintEx((
77
,
0
,
"entry\r\n"
));
hook_NtOpenProcess();
pDriver
-
>DriverUnload
=
DRIVERUNLOAD;
return
STATUS_SUCCESS;
}
ULONG64 num
=
0
;
VOID DRIVERUNLOAD(_In_ struct _DRIVER_OBJECT
*
DriverObject)
{
KdPrintEx((
77
,
0
,
"unload\r\n"
));
reset_hook(num);
}
BOOLEAN NtOpenProcess_callback(PGuestContext pcontext)
{
KdPrintEx((
77
,
0
,
"参数为 %llx %llx %llx %llx\r\n"
, pcontext
-
>mRcx, pcontext
-
>mRdx, pcontext
-
>mR8, pcontext
-
>mR9));
return
FALSE;
/
/
RETURN FALSE表示执行完本函数后继续执行原始的ntopenprocess函数。如果
return
true则不再执行原始的openprocess函数,直接返回。
}
VOID hook_NtOpenProcess()
{
UNICODE_STRING unName
=
{
0
};
RtlInitUnicodeString(&unName, L
"NtOpenProcess"
);
PUCHAR funcAddr
=
MmGetSystemRoutineAddress(&unName);
hook_by_addr(funcAddr, NtOpenProcess_callback, &num);
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-12-14 17:43
被smallzhong_编辑
,原因: