写在前面的话

继续上篇,在获得了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 = 0;
    int ENTAddr = 0;
    int EOTAddr = 0;
_asm {push eax;
        push ebx;
        mov eax, [kernel32Addr]; // ExportStart_RVAmov eax, [eax + 0x168]; // ExportStart_RVAadd eax, kernel32Addr; // ExportStart_VAmov ebx, eax;
        add ebx, 0x28; // EATmov EATAddr, ebx;
        mov ebx, eax;
        add ebx, 0x1914;
        mov ENTAddr, ebx; // ENTmov ebx, eax;
        add ebx, 0x3200;
        mov EOTAddr, ebx; // EOTpop 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, 13;
        mov esi, ENTAddr; // ENT RVAmov esi, [esi + 4 * ebx];
        add esi, kernel32Addr; // ENT VAlea edi, srcLoadLibraryExA;
        repe cmpsb;
        je _ENT_OK;
        inc ebx;
        dec eax;
        cmp eax, 0;
        jg _ENT_FIND;
        jmp _ENT_END;
_ENT_OK:mov ecx, EOTAddr; // EOT Numbermov ecx, [ecx + 2 * ebx];
        and ecx, 0xFFFF;
        mov esi, EATAddr; // EAT Address RVAmov esi, [esi + 4 * ecx];
        add esi, kernel32Addr; // EAT Address VAlea eax, srcuser32;
        push eax;
        call esi;
_ENT_END:pop edi;
        pop esi;
        pop ecx;
        pop ebx;
        pop eax;
    }

至此,对Kernel32.dll的导出表解析便告一段落了;

转载于:https://www.cnblogs.com/Reginald-S/p/8763130.html

windbg分析Kernel32.dll导出表相关推荐

  1. c++ dll返回容器_Windows x86 Shellcode开发:寻找Kernel32.dll地址

    前言 针对一个已经学习了Linux Shellcode开发,并开始在Windows上尝试的研究人员来说,这一过程可能要比想象的更加艰难.Windows内核与Linux完全不同.尽管如此,但Linux内 ...

  2. Windbg 分析内存泄漏

    1. 首先添加这样的一段代码到头文件中. #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) ...

  3. Windbg分析程序崩溃实践

    1. 项目场景 本故事纯属虚构. 初入职场的小木,负责维护一个博客系统,后端采用C++编写,部署在Windows服务器上.刚刚熟悉完产品的小木,接到了后台服务的报警,服务器后端偶尔会程序崩溃.刚开始小 ...

  4. 重定位(搜索KERNEL32.DLL得到API地址)

    1 ;-------------------------------- 2 ;动态加载功能实现 3 ;moriarty 4 ;2012/04/13 5 ;----------------------- ...

  5. postman安装报错 无法定位_VS2010 + winxp 无法定位程序输入点GetTickCount64 在动态链接库kernel32.dll上 错误...

    winxp系统,使用VS2010, 在使用boost中的thread中的sleep的时候出现 "无法定位程序输入点GetTickCount64 在动态链接库kernel32.dll上&quo ...

  6. 使用 Windbg 分析一个 异步操作 引发的 Crash 异常

    上周我们收到了一个客户的紧急求助,他们的一个 iis应用程序池 经历了频繁重启,即使从错误日志中也不得到任何有用的信息,异常信息如下: System.NullReferenceException : ...

  7. Windows x64平台 获取PEB表,并获取kernel32.dll的基址,并获取它的函数

    参考了:https://www.cnblogs.com/aliflycoris/p/5185097.html 和另一位博主 话不多说,进入正题: 首先是获取PEB基址,先得懂怎么在64位平台嵌入汇编代 ...

  8. Windbg分析dump及调试程序

    1. Windbg生成dump文件 程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件. 步骤: 1) 打 ...

  9. Windbg分析高内存占用问题

    1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...

  10. Win32的缓冲区溢出攻击(涉及用WinDbg分析 overflow函数的返回地址所在的地址与buffer首地址的距离 OFF_SET)

    Win32的缓冲区溢出攻击 一.学习过程 二.学习成果(求OFF_SET) 三.扩展阅读 一.学习过程 1.overflow函数的源代码 #include <stdio.h> #inclu ...

最新文章

  1. 阿里云助力合作伙伴帮助政府、企业体验云计算大数据魅力!
  2. ML之Kmeans:利用自定义Kmeans函数实现对多个坐标点(自定义四个点)进行自动(最多迭代10次)分类
  3. 如何备份桌面文件呢?
  4. jsoncpp判断Value中是否含有指定的key
  5. html5qq邮箱代码,使用qq邮箱批量发送邮件 实例源码(支持富文本)
  6. 代码控制树视图 c# 1614262980
  7. Python正则表达式案例一则:单词非两端字符改为小写
  8. 中源数聚携手中科点击共推管理咨询变革
  9. 用JS让文章内容指定的关键字加亮
  10. 史上最全面的C语言的学习路线及方法
  11. Landsat系列卫星介绍​
  12. Leetcode刷题 2021.02.15
  13. 微软webcast系列视频课程索引(zt)
  14. BART 文本摘要示例
  15. 组合总和(python实现)
  16. 2017GDKOI酱油记
  17. final37另一种插值方法:在端点处插入相等的值
  18. 计算机存储周期越长运算速度,计算机组成原理作业答案
  19. mysql骚操作_关于MySQL的一些骚操作——提升正确性,抠点性能
  20. IPWorks IPC .NET 2022.0.85 Crack

热门文章

  1. mysql高可用架构_MySQL高可用架构对比
  2. opencv外接矩形矫正
  3. Keras中的时间分布层TimeDistributed Layer使用教程
  4. python实现常见的整数进制、字符进制、ASCII码进制之间的转换
  5. latex table 表格 显示每行横线
  6. nginx IP 443 路由到其它地址
  7. Kubernetes 小白学习笔记(18)--集群存储-volume、PV、PVC
  8. java 缓存ech_java ehcache 分布式缓存配置实例 .
  9. 计算机科学与技术志愿意愿,高考志愿填报如何得高分
  10. 安装nuxt_一天上手Nuxt基于vue服务端渲染