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

 

找到!

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值