我的上一篇博客Analysis of notepad process loading涉及的程序是没有ExportTable的,所以这一篇呢,就分析一下DLL里的ExportTable,以KERNEL32.dll为例。
首先在Hex Edit里打开KERNEL32.dll:
可以看出,KERNEL32.dll还是符合PE文件格式滴~
① ExportTable(RVA):00 0B 4D E0,SizeofExportTable:00 00 AA CC
② FileAignment、SectionAlignment都为10 00,嗯,好爽哦,都不用进行RVA和RAW之间的映射换算了~
③ 转到Export Directory处:( 注意不是Descriptor哦,ExportTable和ImportTable对应的数据结构可不一样)
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
关于Export Directory结构(这只是个示意图哈):
可知AddressOfNameOrdinals为00 0B 78 A8;AddressOfFunctions为00 0B 4E 08,也就是紧接着该Directory后面;AddressOfNames为00 0B 63 58:
我们看看00 0B 83 5D处:
可知,函数AcquireSRWLockExclusive()的索引为0,函数AcquireSRWLockShared()的索引为1,......
凭借这个索引查找AddressOfNameOrdinals地址处的对应值:
可知,AcquireSRWLockExclusive()对应00 02,AcquireSRWLockShared()对应00 03,......
转到AddressOfFunctions 00 0B 4E 08处:
(嗯,这里就没验证分析得正不正确了。因为要找到一个被某程序调用的且索引排名靠前的函数有点麻烦啊。。就只好等到之后写程序来验证了。。)
关于GetProcAddress()操作原理:
利用AddressOfNames成员转到“函数名称数组”
“函数名称数组”中存储着字符串地址。通过比较strcmp字符串,查找指定函数名称,记录下相应name_index
利用AddressOfNameOrdinals成员,转到orinal数组,在orinal数组中通过name_index查找相应orinal值
利用AddressOfFunctions成员转到“函数地址数组”(EAT),由orinal作索引得到指定函数的起始地址