1.5 编写自定位ShellCode弹窗( 四 )


1.5.4 枚举导出表
在文章开头部分我们通过调试器已经找到了.dll这个动态链接库的基地址,而Dll文件本质上也是PE文件,在Dll文件中同样存在导出表,其内部记录着该Dll的导出函数 。接着我们需要对Dll文件的导出表进行遍历,不断地搜索,从而找到我们所需要的API函数,同样的可以通过如下定式获取到指定的导出表 。
首先我们通过来实现读取导入表及导出表试试,我们以读取ole32.dll为例,首先读者需要通过lmvm ole32.dll查询到该模块的入口地址,如图所示该模块的入口地址为
解析DOS头,DOS头通过结构被定义,在解析时读者应传入模块入口地址,其次DOS头中字段指向了PE头,该字段需要注意;
解析PE头,PE头通过DOS头部的中存储的之加上模块基地址获取到,在本例中则是通过+0n264获取到;
接着需要在ER可选头中找到导出表基地址,通过PE头基址加上0x018也就是的偏移,即可定位到[0]也就是导出表基地址,其地址为
根据上述定义,继续寻找导出表的实际地址,需要注意的是 中的结果是根据ole32模块的基地址与当前地址相加后得到的,如下图所示
当读者需要枚举特定模块时,则可通过模块基地址加上例如Name字段偏移值,来读入模块名称;
如果读者需要枚举所有导出函数,则读者可通过模块基地址加上字段,并通过如下命令实现完整输出;
导入表的枚举与导出表类似,为了节约篇幅此处只给出调试数据,读者可根据自己的掌握情况自行分析学习;
# 根据模块基地址获取模块e_lfanew0:000> dt ole32!_IMAGE_DOS_HEADER 0x75830000+0x000 e_magic: 0x5a4d+0x028 e_res2: [10] 0+0x03c e_lfanew: 0n264# 定位到NT头部0:000> dt ole32!_IMAGE_NT_HEADERS 0x75830000 + 0n264+0x000 Signature: 0x4550+0x004 FileHeader: _IMAGE_FILE_HEADER+0x018 OptionalHeader: _IMAGE_OPTIONAL_HEADER# 基地址与e_lfanew相加得到OPTIONAL0:000> ?0x75830000 + 0n264Evaluate expression: 1971519752 = 75830108# 查询OPTIONAL0:000> dt ole32!_IMAGE_OPTIONAL_HEADER -v -ny DataDirectory 75830108+0x018struct _IMAGE_OPTIONAL_HEADER, 31 elements, 0xe0 bytes+0x060 DataDirectory : [16] struct _IMAGE_DATA_DIRECTORY, 2 elements, 0x8 bytes0:000> ? 75830108+0x018+0x60Evaluate expression: 1971519872 = 75830180# 得到数据目录表地址0:000> dt ole32!_IMAGE_DATA_DIRECTORY 75830180+8+0x000 VirtualAddress: 0xbd9f8+0x004 Size: 0x4600:000> ? 0x75830000+0xbd9f8Evaluate expression: 1972296184 = 758ed9f8# DataDirectory[1]即为导入表,地址为758ed9f80:000> dt ole32!_IMAGE_IMPORT_DESCRIPTOR 758ed9f8+0x000 Characteristics: 0xbe700+0x000 OriginalFirstThunk : 0xbe700+0x004 TimeDateStamp: 0+0x008 ForwarderChain: 0+0x00c Name: 0xbe87a+0x010 FirstThunk: 0xbd8a80:000> da 0x75830000+0xbe87a758ee87a"api-ms-win-crt-string-l1-1-0.dll"# 每一个_IMAGE_IMPORT_DESCRIPTOR的大小为0x140:000> ?? sizeof(_IMAGE_IMPORT_DESCRIPTOR)unsigned int 0x14# 也就是说,每次递增14即可输出下一个导入函数名0:000> dt ole32!_IMAGE_IMPORT_DESCRIPTOR 758ed9f8+14+0x000 Characteristics: 0xbe6f4+0x000 OriginalFirstThunk : 0xbe6f4+0x004 TimeDateStamp: 0+0x008 ForwarderChain: 0+0x00c Name: 0xbe89c+0x010 FirstThunk: 0xbd89c0:000> da 0x75830000+0xbe89c758ee89c"api-ms-win-crt-runtime-l1-1-0.dl"0:000> dt ole32!_IMAGE_IMPORT_DESCRIPTOR 758ed9f8+28+0x000 Characteristics: 0xbe64c+0x000 OriginalFirstThunk : 0xbe64c+0x004 TimeDateStamp: 0+0x008 ForwarderChain: 0+0x00c Name: 0xbeb88+0x010 FirstThunk: 0xbd7f40:000> da 0x75830000+0xbeb88758eeb88"api-ms-win-crt-private-l1-1-0.dl"# 分析第一个IID的IAT和INT# 先看INT: IMAGE_THUNK_DATA其实就是一个DWORD,如IID一样,也是一个接一个,最后一个为NULL第一个:0:000> dd 0xbe6f4+0x75830000 L1758ee6f4000be86c# 最高位不为1(为1表示为序号输入)指向_IMAGE_IMPORT_BY_NAME结构.foreach(place {dd 758ee6f4}) {r @$t0 = ${place}+75830000+2; .if (@$t0