码迷,mamicode.com
首页 > 其他好文 > 详细

FS获取KERNEL32基址的三种方法

时间:2017-07-22 15:43:45      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:方法   point   底部   获取   data-   dos   bool   struct   地址   

FS寄存器指向当前活动线程的TEB结构(线程结构)

偏移  说明

000  指向SEH链指针

004  线程堆栈顶部

008  线程堆栈底部

00C  SubSystemTib

010  FiberData

014  ArbitraryUserPointer

018  FS段寄存器在内存中的镜像地址

020  进程PID

024  线程ID

02C  指向线程局部存储指针

030  PEB结构地址(进程结构)

034  上个错误号

 

在shellcode中用它来找KERNEL32.DLL基地址是常见的算法了,经典的三种算法都用到了FS寄存器!她们是:

1.       通过PEB(FS:[30])获取KERNEL32.DLL基地址

2.       通过TEB(FS:[18])获取KERNEL32.DLL基地址

3.       通过SEH(FS:[00])获取KERNEL32.DLL基地址

下面分别证明之。

 

命题一:通过PEB(FS:[30])获取KERNEL32.DLL基地址

算法描述:

mov eax,fs:[30h]     ;得到PEB结构地址

mov eax,[eax + 0ch]  ;得到PEB_LDR_DATA结构地址

mov esi,[eax + 1ch]  

lodsd  ; 得到KERNEL32.DLL所在LDR_MODULE结构的

; InInitializationOrderModuleList地址

mov eax,[eax];win7要加

mov edx,[eax + 8h]   ;得到BaseAddress,既Kernel32.dll基址

 

证明:

1.       随便open一个exe,内存中的KERNEL32.DLL基地址是不变的;

2.       获取PEB基地址,

0:000> dd fs:30 L1

003b:00000030  7ffd6000

看到了,7ffd6000

3.       获取PEB_LDR_DATA结构地址7ffd6000+0c

peb的结构定义:

ntdll!_PEB

   +0x000 InheritedAddressSpace : UChar

   +0x001 ReadImageFileExecOptions : UChar

   +0x002 BeingDebugged    : UChar

   +0x003 SpareBool        : UChar

   +0x004 Mutant           : Ptr32 Void

   +0x008 ImageBaseAddress : Ptr32 Void

   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA

   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS

   +0x014 SubSystemData    : Ptr32 Void

   +0x018 ProcessHeap      : Ptr32 Void

   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION

......

0:000>  dd 7ffd6000+0c L1

7ffd600c  00181ea0

PEB_LDR_DATA-> 00181ea0

4.       获取InInitializationOrderModuleList的地址

说一下这个PEB_LDR_DATA,她是ntdll.dll中的undocumented的一个结构,PEB_LDR_DATA的结构定义:

0:000> dt _PEB_LDR_DATA

   +0x000 Length           : Uint4B

   +0x004 Initialized      : UChar

   +0x008 SsHandle         : Ptr32 Void

   +0x00c InLoadOrderModuleList : _LIST_ENTRY

   +0x014 InMemoryOrderModuleList : _LIST_ENTRY

   +0x01c InInitializationOrderModuleList : _LIST_ENTRY

   +0x024 EntryInProgress  : Ptr32 Void

0:000> dd 00181ea0+1c L1

00181ebc  00181f58

InInitializationOrderModuleList->00181f58

5.       获取kernel32的基地址

0:000> dd 00181f58+8 L1

00181f60  7c920000

7c920000就是了?

check一下:

0:000> dd kernel32 L1

7c800000  00905a4d

啊!竟然不是啊,7c920000是ntdll.dll的,哈哈。

不过,算法命题仍然是正确的。因为在shellcode中模块列表的第一个就是kernel32了,当然可以通过镜像名称来check的,不过shellcode的空间不允许的,这就是shellcode的艺术了。我用来测试的exe恰好先加载了ntdll.dll。

 

命题二:通过TEB(FS:[18])获取KERNEL32.DLL基地址

算法描述:

本地线程的栈里偏移18H的指针指向kernel32.dll内部,而fs :[ 0x18 ] 指向当前线程而且往里四个字节指向线程栈,结合栈顶指针进行对齐遍历,找到PE文件头(DLL的文件格式)的“MZ”MSDOS标志,就拿到了kernel32.dll基址。

xor esi , esi

mov esi , fs :[ esi + 0x18 ] // TEB

mov eax , [ esi + 4 ] // 这个是需要的栈顶

mov eax , [ eax - 0x1c ] // 指向Kernel32.dll内部

find_kernel32_base :

dec eax // 开始地毯式搜索Kernel32空间

xor ax , ax

cmp word ptr [ eax ], 0x5a4d // "MZ"

jne find_kernel32_base // 循 环遍 历 ,找到 则 返回 eax

 

证明:

1.       找到TEB,这个好办:

0:000>  dd fs:18 L1

003b:00000018  7ffdd000

TEB->7ffdd000

2.       找到栈顶指针:

0:000> dd 7ffdd000+4 L1

7ffdd004  00070000

3.       进入Kernel32空间:

0:000> dd 00070000-1c L1

0006ffe4  7c839aa8

 

4.       Kernel32空间的大搜索:

0:000> db 7c839aa7 L4

7c839aa7  30 55 8b ec                                      0U..

......一直搞下去

0:000> db 7c800000 L4

7c800000  4d 5a 90 00                                      MZ..

找到了吧,哈哈。有点效率问题,shellcode有时候是要牺牲效率的,没办法,还是艺术问题。

 

命题三:通过SEH(FS:[00])获取KERNEL32.DLL基地址

算法描述:

注意:FS:[ 0 ] 指向的是SHE,它指向kernel32.dll内部链,这样就可以顺藤摸瓜了。FS:[ 0 ] 指向的是SHE的内层链,为了找到顶层异常处理,我们向外遍历找到prev成员等于 0xffffffff 的EXCEPTION_REGISTER结构,该结构的handler值就是系统 默 认的处理例程;这里有个细节,DLL的装载是64K边界对齐的,所以需要利用遍历到的指向最后的异常处理的指针进行页查找,再结合PE文件MSDOS标志部分,只要在每个 64K 边界查找 “MZ ”字符就能找到kernel32.dll基址。

xor ecx , ecx

mov esi , fs :[ ecx ]

find_seh :

mov eax ,[ esi ]

mov esi , eax

cmp [ eax ], ecx

jns find_seh // 0xffffffff

mov eax , [ eax + 0x04 ] // handler

find_kernel32_base :

dec eax

xor ax , ax

cmp word ptr [ eax ], 0x5a4d

jne find_kernel32_base

 

证明:

1.       找到当前SEH:

0:000> dd fs:0 L1

003b:00000000  0006fedc

2.       找到最外层SEH:

round 1:

0:000> dd 0006fedc L1

0006fedc  0006ffb0 ; esi

0:000> dd 0006ffb0 L1

0006ffb0  0006ffe0 ; [eax]

round 2:

0:000> dd 0006ffb0 L1

0006ffb0  0006ffe0 ; esi

0:000> dd 0006ffe0 L1

0006ffe0  ffffffff ; [eax]

不错,第二趟就找到了!此时,eax=0006ffe0

3.       找到MZ:

0:000> dd 0006ffe0+4 L1

0006ffe4  7c839aa8

 

0:000> db 7c839aa7 L4

7c839aa7  30 55 8b ec                                      0U..

......又是一直搞下去

0:000> db 7c800000 L4

7c800000  4d 5a 90 00                                      MZ..

找到!

 

知其然,更要知其所以然!

FS获取KERNEL32基址的三种方法

标签:方法   point   底部   获取   data-   dos   bool   struct   地址   

原文地址:http://www.cnblogs.com/dsli/p/7221313.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!