利用FS寄存器获取KERNEL32.DLL基址算法的证明
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 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
+0x00cLdr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01cFastPebLock : Ptr32 _RTL_CRITICAL_SECTION
......
0:000> dd 7ffd6000+0cL1
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
+0x00cInLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01cInInitializationOrderModuleList : _LIST_ENTRY
+0x024 EntryInProgress : Ptr32 Void
0:000> dd 00181ea0+1cL1
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-1cL1
0006ffe4 7c839aa8
4. Kernel32空间的大搜索:
0:000> db 7c839aa7 L4
7c839aa7 30 55 8b ec 0U..
......一直搞下去
0:000> db 7c800000 L4
7c800000 4d 5a90 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 5a90 00 MZ..
找到!
知其然,更要知其所以然!
利用FS寄存器获取KERNEL32.DLL基址算法的证明相关推荐
- 利用FS寄存器获取KERNEL32.DLL基址算法的证明(ZZ)
转自:http://blog.csdn.net/int2e/archive/2008/01/09/2032732.aspx FS寄存器指向当前活动线程的TEB结构(线程结构) 偏移 说明 000 ...
- 获取kernel32.dll基址
获取kernel32.dll基址 一 原理和概述 找kernel32基地址的方法一般有三种:暴力搜索法.异常处理链表搜索法.PEB法. 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理 ...
- Windows x64平台 获取PEB表,并获取kernel32.dll的基址,并获取它的函数
参考了:https://www.cnblogs.com/aliflycoris/p/5185097.html 和另一位博主 话不多说,进入正题: 首先是获取PEB基址,先得懂怎么在64位平台嵌入汇编代 ...
- 重定位(搜索KERNEL32.DLL得到API地址)
1 ;-------------------------------- 2 ;动态加载功能实现 3 ;moriarty 4 ;2012/04/13 5 ;----------------------- ...
- GetModuleHandle(NULL)获取当前DLL模块基址?
做一项目想在DLL内部代码实现获取本DLL的模块基址,而且不知道本DLL名称 最简单的方法是想到GetModuleHandle(NULL),是否可以呢? 参看http://blog.csdn.net/ ...
- Python Pymem 游戏内存基址读取修改 - 获取游戏DLL模块基址
运行环境 python3.9.0 - 64位 安装pymem pip install pymem Pymem 的文档 https://pymem.readthedocs.io/en/latest/ 读 ...
- 问C#高手: [DllImport(“kernel32.dll“)]是什么意思??
这叫引入kernel32.dll这个动态连接库. 这个动态连接库里面包含了很多WindowsAPI函数,如果你想使用这面的函数,就需要这么引入.举个例子: [DllImport("kerne ...
- R3获取kernel32地址
获取Kernel32地址 如果是搞PE变形或者PE重构,再或者代码注入,很多时候我们要动态获取Loadlibrary()以及GetPeocAddress()两个函数的地址,通过这两个函数再动态获取其他 ...
- c++ dll返回容器_Windows x86 Shellcode开发:寻找Kernel32.dll地址
前言 针对一个已经学习了Linux Shellcode开发,并开始在Windows上尝试的研究人员来说,这一过程可能要比想象的更加艰难.Windows内核与Linux完全不同.尽管如此,但Linux内 ...
最新文章
- matplotlib如何把坐标轴一横一竖给绘制出来
- 如何用Curl 来post xml 数据
- ArcGIS License Manager 更新
- JZOJ 5462. 【NOIP2017提高A组冲刺11.8】好文章
- Libre OJ 「BalticOI 2013」非回文数 数位dp
- Linux 环境下搭建 Jenkins(Hudson)平台
- 学习微信公众号oauth2.0
- 重磅盘点!过去一年里最受欢迎的技术干货,全在这里了
- Onvif备忘录(2)----客户端端设备发现
- spring security oauth2_SpringBoot2 整合OAuth2实现统一认证
- python人脸识别库教程_OpenCV-最优秀的Python人脸识别库安装及入门教程
- 添加负载机_从 Coco 转向 Koko,Jumpserver 堡垒机 V1.5.3 发布
- 博文视点大讲堂第15期:猎头揭秘
- 将byte[]转为各种进制的字符串
- 靠,竟然有如此沙雕的代码注释!
- Kafka ACL使用实战
- 从零基础入门Tensorflow2.0 ----九、44.5 keras转换成具体函数
- Java的强、软、弱、虚四种引用类型
- VMware卸载不干净导致的重装失败(100%解决问题)
- 五款经典GPRS无线上网卡比拼
热门文章
- UNIX/Linux-进程控制(实例入门篇)
- 3、Python 基础类型 -- List 列表类型
- 1.记住密码 提示框
- Vue 路由知识三(过渡动画及路由钩子函数)
- [转]Create Custom Exception Filter in ASP.NET Core
- hiho1249 Xiongnu's Land
- 浅谈Python和VC中的编码问题(转)
- GridView RadioButton 解决办法(一) -- 实现单选
- 表单身份验证(受保护的目录)
- 图像中值处理MATLAB实现