Windows下通过FS定位模块基址的原理及流程


本文将介绍一种通过fs段选择子定位模块基址的方法。在windows系统下,存在着名为TEB(线程环境块)的结构体,包含着当前线程的大量信息,自然也有着线程所属进程的信息,即指向PEB(线程环境块)的指针。

对模块的遍历是从PEB结构开始的,因此我们需要获取PEB结构指针。PEB的结构指针存储在TEB中。TEB结构指针存储在fs寄存器中,于是我们便可以通过fs寄存器来推出对应模块的基址

理论验证

首先我们可以通过VP进行内核结构体TEB的学习。以此来明确整个查询流程的原理

在VP中搜索_TEB得到结构体如下,可以看到PEB对应的结构体在0x30偏移处,也就意味着我们可以通过fs:[0x30]来访问真实的PEB结构体

TEB部分成员

tips:由于NtTib的0x18偏移处为self指针,同时NtTib位于TEB首部,因此我们可以使用fs:[0x18]定位TEB基址;同时TIB结构体首成员指向SEH 链(结构化异常处理链表),因此我们经常说fs指向SEH

Tib结构

接下来我们进入PEB结构体中,关注框出的0xc处偏移成员,查看其类型具体定义

PEB结构

可以看到标出的三个成员都是ModuleList,不同之处在于其中模块的排序方式,由于我们想定位kernel32.dll模块,于是选择按照初始化顺序进行查找(kernel一般在第2位初始化)

三种模块列表

继续查看_LIST_ENTRY结构,可以发现此处是双向链表,那么此处初始的两个节点是如何连接的呢,我们有类似结构图演示

可以看到,其实此处形成了闭环的链表,之前的PEB_LDR_DATA只是一个入口,真正的信息存储的结构另有其人,那么我们也同样的走入该结构体内部进行探索

真实模块链表图

同样的,可以看到前三个模块列表的双向链表结构体。同时我们还可以在0x18处查看到模块加载的基址,0x1c处看到代码块的入口点。如果编程查询指定模块,也可以通过与0x24处的DllName进行比照

1781073024844

注意,此处_LIST_ENTRY结构体的size为0x8,并且我们需要通过BLINK来向后查询,此处一定要区分flink和blink的地址

x86实操

有了以上理论知识的铺垫,我们在winXP系统上进行一次TEP查询kernel32基址的实操

首先在数据窗口中跳转到fs对应的地址,并在其中查询到PEB结构所在的位置,准备跳转

fsTEB

在其中找到对应偏移处,跳转查看PEB_LDR_DATA结构,见到了我们之前所说的三个表,这里我们使用InitOrder的flink跳转

PEBPEB_LDR_DATA

看到进入了ntdll.dll结构体部分,继续使用flink向前查询,得到了kernel32基址

1781086147346


文章作者: yssx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 yssx !
评论
  目录