以调用CreateFileW()为例该函数位于kernel32.dll中
call dword ptr ds:[01001104] 实现函数的调用
调用CreateFileW()函数时并非直接调用,而是通过获取01001104地址处的值来实现(所有API调用均采用这种方式)。
地址01001 104是notepad.exe中.text节区的内存区域(更确切地说是IAT内存区域)。
01001104地址处的值为7C8107F0
指令与call 7C8107F0 为一个效果
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk; //INT的地址
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name; //库名称字符串地址
DWORD FirstThunk; //IAT的地址
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //ordinal
BYTE Name[1]; //function name string
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
用来说明IAT的IMAGE_ IMPORT_ DESCRIPTOR 结构体以数组形式存在,且拥有多个成员。这样是因为PE文件可以同时导入多个库。
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; //导出文件名的字符串的地址
DWORD Base;
DWORD NumberOfFunctions; //实际Export函数的个数
DWORD NumberOfNames; //Export函数中有名字的函数的个数
DWORD AddressOfFunctions; //Export函数数组地址
DWORD AddressOfNames; //函数名称数组地址
DWORD AddressOfNameOrdinals; //Ordinal数组地址( 数组元素个数=NumberOfNames )
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
从库中获得函数地址的API为GetProcAddress()函数。该API引用EAT来获取指定API的地址。通过GetProcAddress() 获取的函数地址的函数拥有函数名称.
对于没有函数名称的导出函数,可以通过Ordinal 查找到它们的地址。从Ordinal值中减去IMAGE EXPORT_ DIRECTORY.Base 成员后得到一个值,使用该值作为“函数地址数组”的索引,即可查找到相应函数的地址。
GetProcAddress()原理:
(1)利用AddressOfNames成员转到“函数名称数组”。
(2)“函数名称数组”中存储着字符串地址。通过比较( strcmp)字符串,查找指
定的函数名称(此时数组的索引称为name_index)。
(3)利用AddressOfNameOrdinals成员,转到orinal数组。
(4)在ordinal 数组中通过name_ index 查找相应ordinal 值。
(5)利用AddressOfFunctions成员转到“ 函数地址数组”( EAT )。
(6)在“函数地址数组”中将刚刚求得的ordinal用作数组索引,获得指定函数的起
始地址。
原文:https://www.cnblogs.com/l0nmar/p/12851516.html