windbg分析Kernel32.dll导出表
写在前面的话:
继续上篇,在获得了Kernel32.dll基址的基础上,分析它的导出表结构;
对PE结构不太熟悉的同学,可以参考看雪论坛里的一篇帖子:https://bbs.pediy.com/thread-224265.htm
零、思路说明
分析之前,要明确我们的目的是,为了能在程序里获得某些API的地址;
I) 遍历导出名称表(下面统称为ENT),匹配到需要的函数【匹配过程中,设置一个自增的变量,这样找到后,变量里就是该函数在ENT里的下标】
II) 根据导出序号表(下面统称EOT),结合下标,找到该函数在导出地址表(EAT)里的索引
III) 然后,从EAT里取出来这个索引处的地址,就是我们要搜寻的函数的地址了;
一、分析Kernel32.dll在文件中的结构
由于是在win10_64位上进行的分析;不得不提的一点:
I) 如果程序是32位的,那么程序会链接C:\Windows\SysWOW64\kernel32.dll
II) 如果程序是64位的,那么程序会链接C:\Windows\System32\kernel32.dll
这一点,也可以通过分析基址开始80处的偏移得知;大家可以自行去分析,上篇获得基址后,db 看下内存,然后和这两个文件对比下内容就明白了;
这里,就以32位程序为例,进行分析,那么自然,我们首先需要在010里看下kernel32.dll的结构;


对应的文件偏移是:

这里,再次看下导出表的数据结构体(40Byte)
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; // DLL的名称地址
DWORD Base; // 索引基数
DWORD NumberOfFunctions; // 函数地址表大小
DWORD NumberOfNames; // 函数名表大小 == 函数序号表大小
DWORD AddressOfFunctions; // 函数地址表——首地址
DWORD AddressOfNames; // 函数名表——首地址
DWORD AddressOfNameOrdinals; // 函数序号表——首地址
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
00 00 00 00
CE 65 47 74【时间戳】
00 00 【主版本】
00 00 【次版本】 ]
B6 45 08 00【DLL名称地址】
01 00 00 00【索引基数】
3B 06 00 00【函数地址表大小】
3B 06 00 00【函数名表大小 == 函数序号表大小】
68 07 08 00【函数地址表——首地址】
54 20 08 00【函数名表——首地址】
40 39 08 00【函数序号表——首地址】
至此,我们可以得出以下几个结论:
I) 扩展头里的导入表区段偏移RVA:00080740,距离PE头位置0x168
II) 都是函数名导入
III) EAT_Offset:80768 - 80740 = 0x28
ENT_Offset:82054 - 80740 = 0x1914
EOT_Offset:83940 - 80740 = 0x3200
下面的图,可以帮助大家理解这些偏移的含义,以及如何根据这些偏移找到运行时,载入内存后的对应位置;

0. 根据BaseAddr+0x168,我们可以找到ExportStart RVA
1. 根据BaseAddr + ExportStart_RVA + EAT/ENT/EOT_Offset就能知道真正载入内存后的EAT/ENT/EOT位置了;
二、分析Kernel32.dll在内存中的结构
根据上面的分析,其实,我们已经知道了偏移量,接下来,事情就简单了,同样的,用windbg附加打开一个进程,方法和上一篇帖子一致;
我们要做的,就是根据我们计算的偏移,算出真正的3张表的地址,并进行解析;

ExportStart_RVA = 0x80740;

拿一个举例,就第1个吧,RVA+基址,看下

这个函数是AcquireSRWLockExclusive,ENT里的第0号元素;那看下EOT[0]的内容:

EOT[0] = 0x03;也就是说,这个函数的地址,在EAT[0x3]里;那看下EAT[3]的内容:

EAT[3] = 0x08463a,这是RVA,那么函数地址就是BaseAddr + 0x08463A = 7536463a

看到这,说实话,有点怀疑人生了,这不是个字符串吗,我们不是在看EAT吗,不应该是函数地址了吗?
这里,不得不再说下Kernel32.dll的奇葩之处,它会“转发”别的dll的导出函数,就像我们在调试器中见识到的那样的导入表结构:

为了方便大家进一步看清楚EAT的正常的真实情况,这里,就再次分析一个别的函数LoadLibraryExA,
套路也是一样,ENT->EOT->EAT,EAT里存放的是RVA,因为一个一个去在ENT里匹配LoadLibraryExA实在是太繁琐,而且,在上面的分析中,
相信大家都已经理解了ENT和EOT以及EAT的相互间的关系;这里,就直接在LoadPE里找到这个函数的RVA,我们看下:

RVA = 159A0,然后,我们在windbg里用基址加上这个偏移,对齐进行反汇编,看下是不是和我们想的一致:

结论得到了验证,我们也可以在调试器中,进行再次确认,Ctrl + G,输入LoadLibraryExA,如下:

注意看那个地址,这也从侧面证明,我们对EAT的解析是成功的;
三、编写代码,实现加载user32.dll
char srcLoadLibraryExA[] = "LoadLibraryA";
char srcuser32[] = "user32.dll";
int kernel32Addr = GetKernel32Base(); // 上一篇中已经写过了
int EATAddr = ;
int ENTAddr = ;
int EOTAddr = ; _asm {
push eax;
push ebx;
mov eax, [kernel32Addr]; // ExportStart_RVA
mov eax, [eax + 0x168]; // ExportStart_RVA
add eax, kernel32Addr; // ExportStart_VA
mov ebx, eax;
add ebx, 0x28; // EAT
mov EATAddr, ebx;
mov ebx, eax;
add ebx, 0x1914;
mov ENTAddr, ebx; // ENT
mov ebx, eax;
add ebx, 0x3200;
mov EOTAddr, ebx; // EOT
pop ebx;
pop eax;
} _asm {
push eax;
push ebx;
push ecx;
push esi;
push edi;
xor ebx, ebx;
mov eax, 0x63B;
cld; _ENT_FIND:
mov ecx, ;
mov esi, ENTAddr; // ENT RVA
mov esi, [esi + * ebx];
add esi, kernel32Addr; // ENT VA
lea edi, srcLoadLibraryExA;
repe cmpsb;
je _ENT_OK;
inc ebx;
dec eax;
cmp eax, ;
jg _ENT_FIND;
jmp _ENT_END; _ENT_OK:
mov ecx, EOTAddr; // EOT Number
mov ecx, [ecx + * ebx];
and ecx, 0xFFFF;
mov esi, EATAddr; // EAT Address RVA
mov esi, [esi + * ecx];
add esi, kernel32Addr; // EAT Address VA lea eax, srcuser32;
push eax;
call esi; _ENT_END:
pop edi;
pop esi;
pop ecx;
pop ebx;
pop eax;
}
至此,对Kernel32.dll的导出表解析便告一段落了;
windbg分析Kernel32.dll导出表的更多相关文章
- windbg查找Kernel32.dll基址
一.首先准备好一个程序,运行起来,用windbg进行附加调试,由于每个windows下的程序都会加载kernel32.dll,因此,找基址的过程是一样的: 二.查看PEB地址: 法一.r $peb ...
- 如何用windbg分析内存泄露
1. 必须在命令行中设置为要分析的进程打开用户堆栈信息:C:\Program Files\Debugging Tools for Windows (x64)>gflags.exe -i ...
- Windbg分析高内存占用问题
1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...
- WinDbg分析Dump常用方法和命令
记录下自己使用WinDbg分析Dump时常用的一些方法和命令 !analyze -v //找出出错的堆 .exrc //找到程序崩溃的位置 !heap //打印出错函数的局部位置 !for_each_ ...
- 使用 WinDbg 分析dump文件
步骤一: 生成dump文件. #include <Windows.h> #include <iostream> #include <DbgHelp.h> #incl ...
- 记一次 WinDbg 分析 .NET 某工厂MES系统 内存泄漏分析
一:背景 1. 讲故事 上个月有位朋友加微信求助,说他的程序跑着跑着就内存爆掉了,寻求如何解决,截图如下: 从聊天内容看,这位朋友压力还是蛮大的,话说这貌似是我分析的第三个 MES 系统了,看样子 . ...
- kernel32.dll出错解决方案
kernel32.dll 一.什么是kernel32内核文件 kernel32.dll是Windows 9x/Me中非常重要的32位动态链接库文件,属于内核级文件.它控制着系统的内存管理.数据的输入输 ...
- [DllImport("kernel32.dll")]是什么意思??
转载自:http://blog.csdn.net/sp6645597/article/details/8683737 1.简单说明 这叫引入kernel32.dll这个动态连接库(顾名思义就是一个链接 ...
- 旧书重温:0day2【2】 实验:三种获取kernel32.dll基址的方法
0x01 找kernel32基地址的方法一般有三种: 暴力搜索法.异常处理链表搜索法.PEB法. 0x02 基本原理 暴力搜索法是最早的动态查找kernel32基地址的方法.它的原理是几乎所有的win ...
随机推荐
- Java Swing应用程序JLable超链接
在HTML中设置一个超链接是很容易的,使用<a></a>标签就可以完成了. 在客户端应用程序中,并没有这样的标签,但是可以使用按钮来实现,But 有时候就是想好看一点,不想要按 ...
- 值得 .NET 开发者了解的15个特性
本文列举了 15 个值得了解的 C# 特性,旨在让 .NET 开发人员更好的使用 C# 语言进行开发工作. 1. ObsoleteAttribute ObsoleteAttribute 适用于除组件. ...
- 基于Jmeter的自动化测试实施方案设计
前言: Jmeter是目前最流行的一种测试工具,基于此工具我们搭建了一整套的自动化方案,包括了脚本添加配置.本地配置和运行.服务器配置等内容,完成了自动化测试闭环,通过这种快捷简便高效的方式,希望可以 ...
- Linux压缩命令总结
2018-02-28 10:43:18 linux压缩和解压缩命令大全 tar命令:tar本身仅是一个打包的命令,不具有压缩的功能.打包后源文件仍然存在,具有将多个文件归档成一个文件的功能[root ...
- centos上的grub文件修改
centos上的grub文件修改 author:headsen chen 2017-10-10 17:36:42 个人原创,转载请注明作者和出处,否则追究法律责任 1,centos6上的修改:vim ...
- 以太坊挖矿源码:ethash算法
本文具体分析以太坊的共识算法之一:实现了POW的以太坊共识引擎ethash. 关键字:ethash,共识算法,pow,Dagger Hashimoto,ASIC,struct{},nonce,FNV ...
- Java枚举类使用
用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...
- 使用html元素的getBoundingClientRect来获取dom元素的时时位置和大小
使用: var section = $('.section'):这是jquery包装的dom元素,其他前端框架返回的可能也是一个包装元素, 我们需要获得的是里面的html的dom元素 然后:secti ...
- 用golang 实现一个代理池
背景 写爬虫的时候总会遇到爬取速度过快而被封IP的情况,这个时候就需要使用代理了.在https://github.com/henson/ProxyPool 的启发下,决定自己实现一个代理池.项目已经开 ...
- Mycat 介绍
Mycat 是什么 Mycat是什么?从定义和分类来看,它是一个开源的分布式数据库系统,是一个实现了 MySQL协议的的Server,前端用户可以把它看作是一个数据库代理,用 MySQL客户端工具和命 ...