Wow64 栈回溯和模块枚举

来自:信安之路(微信号:xazlsec),作者:Anhkgg(信安之路病毒分析小组成员)

很久没写驱动代码,最近又摸了一下。

在驱动中回溯调用栈,找到特定模块,获取模块地址、大小、路径等信息,然后...。

堆栈回溯

驱动中通常使用 RtlWalkFrameChain 来获取调用栈信息,接口如下:

ULONG
RtlWalkFrameChain(OUTPVOID*CallersINULONGCountINULONGFlags);
//Callers一个PVOID数组,保存栈中retaddr值
//Count表示数组大小
//Flags=0获取内核层栈信息,=1获取应用层栈信息
//返回值表示栈的层数

还有其他函数,未使用:

VOID
RtlGetCallersAddress(
   OUTPVOID*CallersAddress//address to save the first caller.
   OUTPVOID*CallersCaller  //address to save the second caller.
)
RtlCaptureStackBackTrace

其实对于单纯的 x86(ring3)->x86(ring0),和 x64(ring3)->x64(ring0) 没甚么好说的,就是普通的栈信息。

我这里要着重提的是 x86(ring3)->x64(ring0),也就是64位系统的32位程序在进行系统调用时的堆栈(称为 Wow64)。

先看看 CreateFile 的栈信息。Windbg 并不能直接通过 k 显示 wow64 到内核的所有栈信息,wow64 部分需要通过扩展指令切换,具体如下:

而 RtlWalkFrameChain(x, n, 1) 是可以完整获取到 wow64 到 nt 之前的所有应用层栈信息。如下:

00000000`7796c08a//ntdll!ZwCreateFile+0xa
00000000`73c8c1ff
00000000`73c7d18f
00000000`73c02776
00000000`73c7d286
00000000`73c7c69e
00000000`7795f9b6
00000000`779bbb89
00000000`7794a0ee
//00000000`00000000 没有这层
76f1c76b//ntdll_77b00000!NtCreateFile+0x12
75583f66
755853c4
013259e2

需要注意的是,两个 ntdll 并不一样(ntdll_77b00000 是 32 位 dll),并且 ntdll 中间出现了 wow64 和 wow64cpu 两个模块,这就涉及到具体 x86 调用(wow64)如何切换到 x64 了,这里不展开。

进程模块枚举

可能大家都知道驱动中枚举模块的一种方法(非 ZwQuerySystemInformation、SystemModuleInformation ),使用进程 Peb->Ldr 链表枚举,可以获取到模块的路径、基址、大小等信息。

下面是通常驱动下获取模块信息的代码,适用于 x64 内核获取 x64 进程模块信息以及 x86 内核获取 x86 进程模块信息。

那特殊的 Wow64 又有什么不同呢?(x64 内核获取 x86 进程模块信息)。

对于 wow64 进程来说,EPROCESS 结构中有个特殊字段保存 wow64 的 peb 结构。

struct_EPROCESS
{
PVOIDWow64Process;//
}

Win7 之前 Wow64Process 是 _WOW64_PROCESS 结构,内部包含字段位 wow64 的 peb,win7 后 Wow64Process 直接就是 wow64 的 peb。

直接就可以通过 PsGetProcessWow64Process(未文档化函数)来获取到该字段。

Peb=PsGetProcessWow64Process(Process); //Process->Wow64Process

wow64 的 peb 结构不再是 _PEB,而是使用于 wow64 的 _PEB32,一大特点就是所有的地址都是 32 位的,为了在 x64 下定义这种字段,只好使用 ULONG。

#pragma pack(push, 1)
typedefstruct_PEB32{
BOOLEANInheritedAddressSpace;      // These four fields cannot change unless the
BOOLEANReadImageFileExecOptions;   //
BOOLEANBeingDebugged;              //
BOOLEANSpareBool;                  //
ULONGMutant;                      // INITIAL_PEB structure is also updated.

ULONGImageBaseAddress;
ULONGLdr;//PPEB_LDR_DATA32
}PEB32*PPEB32;
#pragma pack(pop)

结构中 Ldr 位 32 位地址指针,使用 ULONG 定义,Ldr 也是特殊的 _PEB_LDR_DATA32 结构,字段和普通的 _PEB_LDR_DATA 完全一致,只是地址全为 ULONG(32 位,x64 地址为 64 位)。

typedefstruct_PEB_LDR_DATA32{
ULONGLength;
ULONGInitialized;//bool
ULONGSsHandle;
LIST_ENTRY32InLoadOrderModuleList;
LIST_ENTRY32InMemoryOrderModuleList;
LIST_ENTRY32InInitializationOrderModuleList;
ULONGEntryInProgress;//pvoid
PEB_LDR_DATA32*PPEB_LDR_DATA32;

如此 wow64 进程模块信息获取的方法也出来了。

搞定。

参考:

http://www.cnblogs.com/welfear/archive/2010/11/16/1878503.html

http://www.kernelmode.info/forum/viewtopic.php?t=2516

http://rce.co/category/wow64/

来自:信安之路(微信号:xazlsec)

信安之路.png

推荐↓↓↓
黑客技术与网络安全
上一篇:初创公司从创业之初到上市的安全建设之路 下一篇:轻松理解端口转发和端口映射