FS寄存器資料

FS寄存器指向當前活動線程的TEB結構(線程結構)

偏移  說明

000  指向SEH鏈指針

004  線程堆棧頂部

008  線程堆棧底部

00C  SubSystemTib

010  FiberData

014  ArbitraryUserPointer

018  FS段寄存器在內存中的鏡像地址

020  進程PID

024  線程ID

02C  指向線程局部存儲指針

030  PEB結構地址(進程結構)

034  上個錯誤號

 

 

得到KERNEL32.DLL基址的方法

assume fs:nothing             ;打開FS寄存器

mov eax,fs:[30h]            ;得到PEB結構地址

mov eax,[eax + 0ch]        ;得到PEB_LDR_DATA結構地址

mov esi,[eax + 1ch]        ;InInitializationOrderModuleList

lodsd                      ;得到KERNEL32.DLL所在LDR_MODULE結構的InInitializationOrderModuleList地址

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

 

實例分析:如何用FS寄存器查找KERNEL32.DLL

 

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 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

 

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

 

不過,算法命題仍然是正確的。因爲在shellcode中模塊列表的第一個就是kernel32了,當然可以通過鏡像名稱來check的,不過shellcode的空間不允許的,這就是shellcode的藝術了。我用來測試的exe恰好先加載了ntdll.dll

 

 

 

命題二:通過TEB(FS:[18])獲取KERNEL32.DLL基地址

 

算法描述:

 

本地線程的棧裏偏移18H的指針指向kernel32.dll內部,而fs :[ 0x18 ] 指向當前線程而且往裏四個字節指向線程棧,結合棧頂指針進行對齊遍歷,找到PE文件頭(DLL的文件格式)的“MZMSDOS標誌,就拿到了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..

 

找到!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章