FindNextFileW的Ring3到Ring0过程分析
-
- SEH的prolog4函数与epilog4函数
- FindNextFileW的实质
- 结论
- 参考文献

FindNextFileW在微软官方看到应该是在kernel32.dll中实现,但实际调试中发现是在kernelBase.dll中。微软官方文档也不可信啊。打开IDA反汇编并加载PDB信息,可以看到_SEH_prolog4函数的使用。遂先学习下这个知识点。
SEH的prolog4函数与epilog4函数

如图所示,是FinNextFileW函数刚断下来时的堆栈以及信息。

可以看到这个函数的栈帧结构是有点不一样的。首先push了四个参数:堆栈大小、scope table entry、_except_handler4、FS:0(pExceptionList),接着开辟堆栈,并在堆栈中用原函数的ebp覆盖了堆栈大小的数据,等等一系列操作,具体实现细节不再深究。

Scope table entry会被-0x2覆盖。也就是图中的0xFFFFFFFFE覆盖。
图中紫色条杠是执行完__SEH_prolog4函数现在的ebp,紫色条杠以下是调用__SEH_prolog4前的堆栈,仍然按照栈帧规则取参数,但是紫色条杠以上都是一些特殊字段的记录,可以参照网址。其中指向下一个SHE记录的指针即是old fs:[0]。
这里简单分析下这个函数是因为这个函数经常被添加到模块函数中做检查堆栈,类似于应用层的GS机制。主要是代码识别,看到要能识别出来是__SEH_prolog4函数。
epilog4函数当然就是去校验被加密的cookie能否被正常还原。
深究的话推荐个学习链接
SEH中的prolog4和epilog
FindNextFileW的实质

Look At This Picture,Sir?!! 红框中得汇编代码按一个模块来看,其实就是对hFindFile句柄值判断是不是为1或者0x-1。总体得分析已经贴图上。这里有一点不明白的地方就是edi是hFindFile,本质是void*,一个存放在进程堆区的四字节指针。但是为什么会有lea eax,[edi+0x1C],就可以断定edi+0x1C的地址是RtlEnterCriticalSection函数的参数?可能是上下文没有分析,也可能是FindFirstFileW也在hFindFile句柄+0x1C处做了手脚吧…

当时的EDI的内存数据…

之后从PEB结构中找到进程的堆区起始地址,并作为参数调用RtlAllocateHeap函数实现了分配堆区。

但在末尾看到了往edi+0x8,edi+0xC,edi+0x10地址写入一些数据信息时,意识到这些只是临时的一些存储数据区,并不是什么官方的结构体。因为FindNextFileW函数是会被调用多次的,所以这些数据可以作为一些后续调用的参照。

之后就去调用了NtQueryDirectoryFile函数。

调用ntdll的NtQueryDirectoryFile函数来枚举文件信息。从这里通往深邃的Windows内核。嘻嘻。

之后从内核获取到的进程堆区的数据疯狂复制到FindFileData数据结构对应的位置。完事儿收工。
结论
循环遍历文件时,FindNextFileW函数在遍历文件时第一次被调用时,在进程堆里申请了空间,并调用NtQueryDirectoryFile函数一次性获取了本目录下所有符合条件的文件的FindFileData数据结构。在后续循环多次调用FindNextFileW中,由于在堆中已经设置好标志位,只需将进程堆区的FindFileData数据信息拷贝到主线程堆栈区的内存中即可。
参考文献
SEH中的prolog4和epilog
https://www.it610.com/article/4637171.htm
Trap_Frame、KPCR、EPROCESS、ETHREAD、PEB结构体
https://www.cnblogs.com/wf751620780/p/10588949.html#autoid-5-0-0
关于FS寄存器与分析环境
https://bbs.pediy.com/thread-226524.htm