通过TopStack方法获取kernel基址简介
来源:互联网 发布:像素大逃杀制作软件 编辑:程序博客网 时间:2024/06/07 20:27
1、简介
本地线程的堆栈里偏移1CH(或者18H)的指针指向kernel32.dll内部,而fs:[0x18]指向当前线程而且往里四个字节指向线程栈,
结合堆栈的top pointer进行对齐遍历,找到PE文件头(DLL的文件格式)的“MZ”MSDOS标志,就拿到了kernel32.dll基址。
先从Windbg里查看一下:
0:000> dt -v -r _NT_TIB $teb
struct _NT_TIB, 8 elements, 0x1c bytes
+0x000 ExceptionList : 0x0013fd0c struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
+0x000 Next : 0xffffffff struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
+0x000 Next : ????
+0x004 Handler : ????
+0x004 Handler : 0x7c92ee18 _EXCEPTION_DISPOSITION ntdll!_except_handler3+0
+0x004 StackBase : 0x00140000
+0x008 StackLimit : 0x0013e000
+0x00c SubSystemTib : (null)
+0x010 FiberData : 0x00001e00
+0x010 Version : 0x1e00
+0x014 ArbitraryUserPointer : (null)
+0x018 Self : 0x7ffdf000 struct _NT_TIB, 8 elements, 0x1c bytes
+0x000 ExceptionList : 0x0013fd0c struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
+0x000 Next : 0xffffffff struct _EXCEPTION_REGISTRATION_RECORD, 2 elements, 0x8 bytes
+0x004 Handler : 0x7c92ee18 _EXCEPTION_DISPOSITION ntdll!_except_handler3+0
+0x004 StackBase : 0x00140000
+0x008 StackLimit : 0x0013e000
+0x00c SubSystemTib : (null)
+0x010 FiberData : 0x00001e00
+0x010 Version : 0x1e00
+0x014 ArbitraryUserPointer : (null)
+0x018 Self : 0x7ffdf000 struct _NT_TIB
其中+0x018 Self是一个指向TEB自己的指针,StackBase指向本线程堆栈的原点,即地址最高处,这里是0x140000,
而StackLimit则指向堆栈所在区间的下部边界,即地址最低处.
————————————————
/*程序3 */
xor esi, esi
mov esi, fs:[esi + 0x18] //TEB
mov eax, [esi+4] //这个是需要的栈顶StackBase,top of the stack
mov eax, [eax - 0x1c] //指向Kernel32.dll内部
//mov eax, [eax - 0x18]
find_kernel32_base:
dec eax //开始遍历页
xor ax, ax
cmp word ptr [eax], 0x5a4d //"MZ"
jne find_kernel32_base //循环遍历,找到则返回eax
————————————————
为了方便测试,我写了一个PEB/TEB/SEH通用测试例程:
/*
* 程序4
* SEH method test for Windows 9x/NT/2k/XP
* asm return eax contained kernel32.dll base address.
* print kernel base address in the console.
*/
__inline __declspec(naked) unsigned int GetKernel32()
{
__asm
{
push esi
push ecx
/* you should replace the follow section if you want to test the others */
xor esi, esi
mov esi, fs:[esi + 0x18]
mov eax, [esi+4]
mov eax, [eax - 0x1c]
find_kernel32_base:
dec eax
xor ax, ax
cmp word ptr [eax], 0x5a4d
jne find_kernel32_base
/* Above is the section needed to replace */
pop ecx
pop esi
ret
}
}
void main(void)
{
printf("Kernel base is located at: 0x%0.8X\n",GetKernel32());
}
注意这几句:
1. mov eax, [eax - 0x1c]
一般地,它将指向kernel32.dll内部,你可以在编译器里单步跟踪调试。其中,eax值为StackBase(0x140000),计算eax-0x1c可得0x0013FFE4;
在我的机器上0x0013FFE4为0x7C839AA8,0x0013FFE8为7C816FE0。
此时栈的分布大致如下:
| ... |
0013FFE0 | FFFFFFFF | SEH链尾部 //哦?有疑问吗?SEH吗?
0013FFE4 | 7C839AA8 | SEH处理程序
0013FFE8 | 7C816FE0 | kernel32.7C816FE0
| 00000000 |
| ... |
2. dec eax
xor ax, ax
这两句的作用就是实现页遍历,单步跟踪结果如下:
0x7C839AA8 -> 0x7C839AA7 -> 0x7C830000 -> 0x7C82FFFF -> 0x7C820000 -> ... -> 0x7C800000
但是,在不同环境下的堆栈不同,如果偏移1C(或18)不指向kernel32.dll内部,将导致获取地址失败,当然这种情况很少发生,
至少我现在还没遇到过;另一个几率很小的失败现象是64K的页边界有"MZ"这样的特征字符出现,这样可能会误导得到错误的地址。
参考文献:http://www.nbjxzx.cn/E_ReadNews.asp?NewsID=1440
- 通过TopStack方法获取kernel基址简介
- 通过PEB获取模块基址
- 通过PEB->LDR_DATA结构获取模块基址
- 获取kernel32基址的另两种方法
- 内核程序中通过KPCR获取内核模块基址
- 通过驱动名字获取驱动基址和大小
- FS获取KERNEL32基址的三种方法
- FS获取KERNEL32基址的三种方法
- 获取kernel 、uboot方法
- 获取进程的基址
- 获取kernel32.dll基址
- 获取进程基址
- 获取ntoskrnl的基址
- 获取模块句柄/基址
- 获取kernel32.dll映像基址
- 动态基址的定位获取
- 基址
- The Linux Kernel Archives-mainline获取方法
- hdu 2102 A计划
- C/C++内存管理
- lucene
- listview的用法总结
- OpenCV参考手册之Mat类详解
- 通过TopStack方法获取kernel基址简介
- Java线程之fork/join框架
- 设计模式之Proxy(代理)
- 微软面经
- C语言中malloc函数返回值是否需要类型强制转换问题
- 下载中文文件名乱码问题
- IE6共存、调试(查看Dom元素,修改元素样式)之我见 + IE6下Firebug Lite的使用
- HDU 2112 单源最短路径+map映射 HDU Today
- 是否还来得及