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基址的三种方法的更多相关文章

  1. Java中获取键盘输入值的三种方法

    Java中获取键盘输入值的三种方法     Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...

  2. 获取class对象的三种方法以及通过Class对象获取某个类中变量,方法,访问成员

    public class ReflexAndClass { public static void main(String[] args) throws Exception { /** * 获取Clas ...

  3. shell获取本地ip的三种方法

    第一种方法:ifconfig|grep inet |awk '{print $2}'|sed '2d'|awk -F : '{print $2}'第二种方法:ifconfig|grep inet|se ...

  4. javascript 获取html元素的三种方法

    操作HTML元素 你首先找到该元素. 三种方法来做这件事: 通过id找到HTML元素 通过标签名找到HTML元素 通过类名找到HTML元素 通过id查找HTML元素 在DOM中查找HTML元素的最简单 ...

  5. php获取POST数据的三种方法

    方法一,$_POST $_POST或$_REQUEST存放的是PHP以key=>value的形式格式化以后的数据. $_POST方式是通过 HTTP POST 方法传递的变量组成的数组,是自动全 ...

  6. Java入门:Java中获取键盘输入值的三种方法

    Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值的现成函数!Java没有提供这样的函数也不代 ...

  7. Javascript获取value值的三种方法及注意点

    JavaScript获取value值,主要有以下三种: 1.用document.getElementById(“id名”).value来获取(例1): 2.通过form表单中的id名或者name名来获 ...

  8. python获取网页信息的三种方法

    import urllib.request import http.cookiejar url = 'http://www.baidu.com/' # 方法一 print('方法一') req_one ...

  9. JavaScript获取鼠标位置的三种方法

    在一些DOM操作中我们经常会跟元素的位置打交道,鼠标交互式一个经常用到的方面,令人失望的是不同的游览器下会有不同的结果甚至是有的游览器下没结果,这篇文章就鼠标点击位置坐标获取做一些简单的总结. 获取鼠 ...

随机推荐

  1. PHP chgrp() 函数

    定义和用法 chgrp() 函数改变指定文件的用户组. 如果成功则返回 TRUE,如果失败则返回 FALSE. 语法 chgrp(file,group) 参数 描述 file 必需.规定要检查的文件. ...

  2. BZOJ 3622: 已经没有什么好害怕的了(二项式反演)

    传送门 解题思路 首先将\(a\),\(b\)排序,然后可以算出\(t(i)\),表示\(a(i)\)比多少个\(b(i)\)大,根据容斥套路,设\(f(k)\)表示恰好有\(k\)个\(a(i)\) ...

  3. rocketmq集群、配置详解和常用命令

    集群原文地址: http://www.cnblogs.com/520playboy/p/6716235.html 常用命令原文地址: http://www.cnblogs.com/gmq-sh/p/6 ...

  4. Android ROM 开发技能图谱

    # Android ROM 开发技能图谱 ## 1. 操作系统 * Ubuntu(首选)* MacOSX ## 2. 编程语言 * Java * JNI(务必掌握)* C++* C ## 3. 源码 ...

  5. Java第四次作业—面向对象高级特性(继承和多态)

    Java第四次作业-面向对象高级特性(继承和多态) (一)学习总结 1.学习使用思维导图对Java面向对象编程的知识点(封装.继承和多态)进行总结. 2.阅读下面程序,分析是否能编译通过?如果不能,说 ...

  6. 将日志(Microsoft.Extensions.Logging)添加到.NET Core控制台应用程序

    在.NET Core项目中,日志记录是通过依赖项注入进行管理的. 尽管这对于ASP.NET项目效果很好,但在启动Startup.cs中的新项目时,所有这些都会自动创建,而在控制台应用程序中则需要一些配 ...

  7. bash arithmatic

    Arithmetic in bash is done with $ and double parentheses: echo "$(($num1+$num2))" Or $ and ...

  8. Supervisord rce(CVE-2017-11610)

    POST /RPC2 HTTP/1.1 Host: localhost Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compati ...

  9. python学习笔记:模块——自定义模块的3种导入方式

    一.定义 模块就是用一堆的代码实现了一些功能的代码的集合,通常一个或者多个函数写在一个.py文件里,而如果有些功能实现起来很复杂,那么就需要创建n个.py文件,这n个.py文件的集合就是模块.如果不懂 ...

  10. 巧妙的使用jmeter来发送json格式数据

    1. header-manager 修改content-type值. 如果不修改该值, 则默认会是urlencode的数据格式(例如a=5&b=6). 修改为json后,会告诉服务器,发送的数 ...