看本文之前建议先看一下《剖析InfinityHook原理 掀起一场更激烈的攻与防恶战》这篇文章。
了解一下InfinityHook的基本原理。
我们先来看看原作者是如何寻找的,在源码的IfhpInternalGetCpuClock函数内
StackFrame为栈顶,StackMax为栈底,
获取两个值是为了确定范围,要在这两个值范围之间寻找在堆栈中那个要替换的指针。
将StackMax栈底给StackCurrent再给AsUlong,用AsUlong地址里的值与INFINITYHOOK_MAGIC_1相比较,
不相等就回到for循环减一,相等就减1继续与INFINITYHOOK_MAGIC_2比较,不相等就回到for减一循环,
直到找到两个值,也就是说,从栈底往上一个个的比对值是否为INFINITYHOOK_MAGIC,直到找到两个值才继续。这两个值分别为 0x501802 和0xF33,这里记下两个值后面有提及。
找到两个值的位置后,再从这个位置向下,寻找系统调用,找到后,以这个系统调用的位置为基准,
往后找9个,每个8字节,也就是偏移72的位置的值,这样这个函数指针就找到了。
是不是看的一脸懵逼,没错我也是,为什么是那两个特定值,那两个值是怎么来的。
那篇文章没写 ,源码的注释也没说,那换个其他事件这个寻找方式还能用吗?
不能,我试过了。
这里就要理一理思路了,这两个值既然在堆栈中,那么不是当前函数搞进去的,就是前一个函数,
或者前前的函数.........., 那么这个函数就应该在调用栈上,那我们就下个断点,在windbg中看一下调用栈。
从调用栈分析, ntdll!NtCreateEvent+0xa进入系统调用,然后在nt!KiSystemServiceExit+0x26a进入etw的记录函数,那么关键就应该是PerfInfoLogSysCallEntry函数,通过函数头部的二进制,在ida里搜索
PerfInfoLogSysCallEntry很短,看完就能发现两个熟悉的数字,
在0000000140162A5C 的 mov r9d, 0F33h
与0000000140162A6D mov [rsp+48h+var_20], 501802h
0F33与501802h不刚好是在堆栈里搜索的两个数,
这里又要理一理思路了,还记得前面说的吗,找到这两个值后,向下寻找系统调用,
我们都知道,堆栈是先push的在底下,后push的在上面,先下寻找意味着寻找之前的调用函数,
看调用栈之前的函数那就是KiSystemServiceExit。
写个断点,断下后查看StackCurrent,这个基准系统调用的值
StackCurrent为0xfffff880`03b82b88,dq查看存的是 fffff800 03ee0205
u看下汇编,正好是KiSystemServiceExit,正如前面猜想的寻找KiSystemServiceExit
以这个基准偏移9个(不是9个字节,偏移一个指8字节,也就是偏移72的地方)的地方,为地址ffff880`03b82bd0,这地址里的值为fffff960 00134164,也就是要替换的函数指针。
u看一下是什么函数,为win32k!NtUserCallNoParam:,这个地址为UserCallNoParam的开头
调用栈的发起者为user32!NtUserCallNoParam+0xa,
我们都知道调用一个函数,都是push 参数1,push参数 2,push 参数3,然后call ,,
这时候堆栈里上面是返回地址,往下是参数,他以返回地址为基准向下加偏移寻找要替换的函数指针,
那会不会他寻找的就是参数,
windbg查看调用栈显示参数,
为了美观省略了后面的参数,参数为fffff960`00134164,这个不正好和寻找的那个一样
查看这个函数的堆栈,在fffff880 03b82b88是我们寻找的基准系统调用的位置
回过头来再以这个基准系统调用的位置,要替换的函数指针值为fffff960`00134164,
一处为偏移1的(偏移1不是指偏移一个字节,是8个字节)fffff880`03b82b90,
宁一处为偏移9的fffff880`03b82bd0,原作者替换的是偏移9处的函数指针。
总结一下:
作者通过寻找EtwPerfInfoLogSysCallEntry放入堆栈的特定值来寻找,
EtwPerfInfoLogSysCallEntry函数的堆栈位置,
再向下寻找系统调用找到
KiSystemServiceExit函数返回地址在堆栈中位置,
再通过以KiSystemServiceExit为基准,替换偏移9处的参数指针,达到hook的目的。
通过官网查询PROCESS事件的falg为1,修改这个值就行了,
函数虽然变了,但在调用栈的大概位置没变,查看nt! ?? ::NNGAKEGL::`string'+0x21a03
可以在fffff800`0412de3f看见501903h,宁一个特定值不好从代码看,
我们在 mov dword ptr [rsp+28h],501903h在这段系统代码下个断点
断下后记下rsp+28的值,等断在我们的代码后再dq查看内存偏移1处的后三位,经过多次测试,
第二个值为8d0 。
从调用栈看,函数指针应该是PspExitProcess的地址,但我找了半天,u查看没找到PspExitProcess函数。
看了一下PspExitProcess,在fffff800`041912d1 call nt!EtwTraceProcess,这里距离PspExitProcess开头非常近,基本上保存了参数,经过应该一个判断,就进入了etw。
而系统调用的事件,进入etw是在函数快结束的位置,返回就继续返回就结束了。
据此猜想,process事件的要替换的函数指针应该是PspExitProcess里call进etw时保存函数返回地址,
而不是想系统调用一样PspExitProcess的一个新开始地址指针。
如果是新的会有重入问题,而且既然在头部进入etw记录,
返回就继续执行就行了,没必要那么做,当然这不是百分之百的确定,要把PspExitProcess逆一遍,看看返回后是否真的在继续执行PspExitProcess,或者经过一个判断直接跳到末尾然后返回(当然在ida里看跳转图,不能一次到末尾),如果是返回继续执行,那么替换函数返回地址,自己构造一个fakePspExitProcess函数,应该也是可行的。
以上均为个人的逆向分析,如果有错误或是不同观点,欢迎指出。
PVOID
*
StackMax
=
(PVOID
*
)__readgsqword(OFFSET_KPCR_RSP_BASE);
PVOID
*
StackFrame
=
(PVOID
*
)_AddressOfReturnAddress();
PVOID
*
StackMax
=
(PVOID
*
)__readgsqword(OFFSET_KPCR_RSP_BASE);
PVOID
*
StackFrame
=
(PVOID
*
)_AddressOfReturnAddress();
for
(PVOID
*
StackCurrent
=
StackMax;
StackCurrent > StackFrame;
-
-
StackCurrent)
{
/
/
/
/
This
is
intentionally being read as
4
-
byte magic on an
8
/
/
byte aligned boundary.
/
/
PULONG AsUlong
=
(PULONG)StackCurrent;
if
(
*
AsUlong !
=
INFINITYHOOK_MAGIC_1)
{
continue
;
}
/
/
/
/
If the first magic
is
set
, check
for
the second magic.
/
/
-
-
StackCurrent;
PUSHORT AsShort
=
(PUSHORT)StackCurrent;
if
(
*
AsShort !
=
INFINITYHOOK_MAGIC_2)
{
continue
;
}
for
(PVOID
*
StackCurrent
=
StackMax;
StackCurrent > StackFrame;
-
-
StackCurrent)
{
/
/
/
/
This
is
intentionally being read as
4
-
byte magic on an
8
/
/
byte aligned boundary.
/
/
PULONG AsUlong
=
(PULONG)StackCurrent;
if
(
*
AsUlong !
=
INFINITYHOOK_MAGIC_1)
{
continue
;
}
/
/
/
/
If the first magic
is
set
, check
for
the second magic.
/
/
-
-
StackCurrent;
PUSHORT AsShort
=
(PUSHORT)StackCurrent;
if
(
*
AsShort !
=
INFINITYHOOK_MAGIC_2)
{
continue
;
}
for
(;StackCurrent < StackMax;
+
+
StackCurrent)
{
PULONGLONG AsUlonglong
=
(PULONGLONG)StackCurrent;
if
(!(PAGE_ALIGN(
*
AsUlonglong) >
=
SystemCallEntryPage &&
PAGE_ALIGN(
*
AsUlonglong) < (PVOID)((uintptr_t)SystemCallEntryPage
+
(PAGE_SIZE
*
2
))))
{
continue
;
}
void
*
*
SystemCallFunction
=
&StackCurrent[
9
];
if
(IfhpCallback)
{
IfhpCallback(SystemCallIndex, SystemCallFunction);
}
break
;
}
for
(;StackCurrent < StackMax;
+
+
StackCurrent)
{
PULONGLONG AsUlonglong
=
(PULONGLONG)StackCurrent;
if
(!(PAGE_ALIGN(
*
AsUlonglong) >
=
SystemCallEntryPage &&
PAGE_ALIGN(
*
AsUlonglong) < (PVOID)((uintptr_t)SystemCallEntryPage
+
(PAGE_SIZE
*
2
))))
{
continue
;
}
void
*
*
SystemCallFunction
=
&StackCurrent[
9
];
if
(IfhpCallback)
{
IfhpCallback(SystemCallIndex, SystemCallFunction);
}
break
;
}
.text:
0000000140162A40
mov r11, rsp
.text:
0000000140162A43
sub rsp,
48h
.text:
0000000140162A47
lea rax, [r11
+
8
]
.text:
0000000140162A4B
mov [r11
+
8
], rcx
.text:
0000000140162A4F
lea rcx, [r11
-
18h
]
.text:
0000000140162A53
mov [r11
-
18h
], rax
.text:
0000000140162A57
and
[rsp
+
48h
+
var_C],
0
.text:
0000000140162A5C
mov r9d,
0F33h
.text:
0000000140162A62
mov edx,
1
.text:
0000000140162A67
mov r8d,
40000040h
.text:
0000000140162A6D
mov [rsp
+
48h
+
var_20],
501802h
.text:
0000000140162A75
and
qword ptr [r11
-
28h
],
0
.text:
0000000140162A7A
mov [rsp
+
48h
+
var_10],
8
.text:
0000000140162A82
call EtwpTraceKernelEvent
.text:
0000000140162A87
add rsp,
48h
.text:
0000000140162A8B
retn
.text:
0000000140162A40
mov r11, rsp
.text:
0000000140162A43
sub rsp,
48h
.text:
0000000140162A47
lea rax, [r11
+
8
]
.text:
0000000140162A4B
mov [r11
+
8
], rcx
.text:
0000000140162A4F
lea rcx, [r11
-
18h
]
.text:
0000000140162A53
mov [r11
-
18h
], rax
.text:
0000000140162A57
and
[rsp
+
48h
+
var_C],
0
.text:
0000000140162A5C
mov r9d,
0F33h
.text:
0000000140162A62
mov edx,
1
.text:
0000000140162A67
mov r8d,
40000040h
.text:
0000000140162A6D
mov [rsp
+
48h
+
var_20],
501802h
.text:
0000000140162A75
and
qword ptr [r11
-
28h
],
0
.text:
0000000140162A7A
mov [rsp
+
48h
+
var_10],
8
.text:
0000000140162A82
call EtwpTraceKernelEvent
.text:
0000000140162A87
add rsp,
48h
.text:
0000000140162A8B
retn
void
*
*
SystemCallFunction
=
&StackCurrent[
9
];
DbgBreakPoint();
void
*
*
SystemCallFunction
=
&StackCurrent[
9
];
DbgBreakPoint();
kd> dq
0xfffff880
`
03b82b88
fffff880`
03b82b88
fffff800`
03ee0205
fffff960`
00134164
fffff880`
03b82b98
00000000
`
00000000
00000000
`
0000002a
fffff880`
03b82ba8
fffff960`
00133fd6
00000000
`
00000003
fffff880`
03b82bb8
00000000
`
00000000
00000000
`
0192efb0
fffff880`
03b82bc8
00000000
`
00000005
fffff960`
00134164
fffff880`
03b82bd8
fffff800`
03edff93
fffffa80`
31d69660
fffff880`
03b82be8
fffffa80`
31d63910
00000000
`
00000000
fffff880`
03b82bf8
fffffa80`
31d63910
00000000
`
00000000
kd> dq
0xfffff880
`
03b82b88
fffff880`
03b82b88
fffff800`
03ee0205
fffff960`
00134164
fffff880`
03b82b98
00000000
`
00000000
00000000
`
0000002a
fffff880`
03b82ba8
fffff960`
00133fd6
00000000
`
00000003
fffff880`
03b82bb8
00000000
`
00000000
00000000
`
0192efb0
fffff880`
03b82bc8
00000000
`
00000005
fffff960`
00134164
fffff880`
03b82bd8
fffff800`
03edff93
fffffa80`
31d69660
fffff880`
03b82be8
fffffa80`
31d63910
00000000
`
00000000
fffff880`
03b82bf8
fffffa80`
31d63910
00000000
`
00000000
kd> u fffff800`
03ee0205
nt!KiSystemServiceExit
+
0x26a
:
fffff800`
03ee0205
488b4c2420
mov rcx,qword ptr [rsp
+
20h
]
fffff800`
03ee020a
488b542428
mov rdx,qword ptr [rsp
+
28h
]
fffff800`
03ee020f
4c8b442430
mov r8,qword ptr [rsp
+
30h
]
fffff800`
03ee0214
4c8b4c2438
mov r9,qword ptr [rsp
+
38h
]
fffff800`
03ee0219
4c8b542440
mov r10,qword ptr [rsp
+
40h
]
fffff800`
03ee021e
4883c450
add rsp,
50h
fffff800`
03ee0222
41ffd2
call r10
fffff800`
03ee0225
488945b0
mov qword ptr [rbp
-
50h
],rax
kd> u fffff800`
03ee0205
nt!KiSystemServiceExit
+
0x26a
:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!