我把一个Windows API函数挂在了文档中 RtlGetFullPathName_U
(驻留在ntdll.dll中),来检测游戏中的进程注入。然而,当在IDA中查看该函数时,该函数类型看起来不一样,而当通过我能找到的关于该函数的唯一信息(从ReactOS的文档中)查看该函数时,也不一样。
在IDA中查看时。
上面分析的文件是 ntdll.dll
通过x32dbg找到。
当在ReactOS的 文件我明白了 RtlGetFullPathName_U
看起来像这样。
ULONG
NTAPI
RtlGetFullPathName_U(
IN PCWSTR FileName,
IN ULONG Size,
IN PWSTR Buffer,
OUT PWSTR *ShortName
);
使用ReactOS版本的 RtlGetFullPathName_U
钩子的时候可以用,但我注意到参数的数量有差别,这是为什么呢?我的意思是我的方法通常是通过IDA查看导出的函数,而不是通过ReactOS的文档。
最后一个问题;我还有没有其他相关的函数可以钩住来检测进程注入?除了LoadLibraryAWEx?
正如你在拆解中所看到的,该函数使用的是 push ecx
早期,其次是将刚刚推送的值的地址保存在 eax
. 地址在 eax
因此,你在反编译器输出中读到的内容在技术上并没有错:它将ecx的值存储在一个局部变量中,然后将该局部变量的地址传递给了 RtlGetFullPathName_UEx
.为了捕获这一点,IDA假设传递给函数的值在 ecx
可能很重要,并将其作为一个参数。
然而,最可能的是,真正的目的是将 push ecx
的值,这里的指令是不保存 ecx
,但只是在堆栈上为一个局部变量保留四个字节(一个更常见的习惯用语是 sub esp, 4
). 使用 push
是一种优化。
要想明确证实这一点,你必须分析被调用的函数。RtlGetFullPathName_UEx
,看看它是否曾经读取过它最后一个参数所指向的内存的内容。如果像我强烈怀疑的那样,它没有,而且这个参数只用于输出,那么调用器中的值可以简单地认为是未初始化的。
在你确认了这一点之后(或者如果出于其他原因,比如相信ReactOS的声明,你相信是这样的),你可以修改函数原型,使用 __stdcall
并去除 void *this
参数,它将显示出它(可能)是什么:传递一个指向未初始化的局部变量的指针。