现在的位置: 首页 > 综合 > 正文

汇编fs 寄存器

2014年02月10日 ⁄ 综合 ⁄ 共 9989字 ⁄ 字号 评论关闭

   

分类: 逆向资料2010-07-22 14:35 965人阅读 评论(0) 收藏 举报

转自 http://blog.csdn.net/yushiqiang1688/archive/2010/01/04/5127180.aspx

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

 

啊!竟然不是啊,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..

 

找到!

分享到: 
查看评论
  暂无评论

发表评论
  • 用 户 名:
  • tangyanzhi1111
  • 评论内容:
  • 插入代码
      
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
TOP
公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告
QQ客服 微博客服 论坛反馈 联系邮箱:webmaster@csdn.net 服务热线:400-600-2320
京 ICP 证 070598 号
北京创新乐知信息技术有限公司 版权所有
世纪乐知(北京)网络技术有限公司 提供技术支持
江苏乐知网络技术有限公司 提供商务支持
Copyright © 1999-2012, CSDN.NET, All Rights Reserved GongshangLogo

转自 http://blog.csdn.net/yushiqiang1688/archive/2010/01/04/5127180.aspx

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

 

啊!竟然不是啊,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..

 

找到!

抱歉!评论已关闭.