16位的DOS时代不存在DLL(Dynamic Linked Library)这一概念,只有“库”(Library)一说。比如在C语言中使用printf()函数时,编译器会先从C库中读取相应函数的二进制代码,然后插入到应用程序。Windows OS支持多任务,若仍采用这种包含库的方式,会非常没有效率。于是Windows OS的设计者们根据需要引入了DLL这一概念。
加载DLL的方式有两种:
上面提到了DLL,在各种不同版本的Windows系统中,DLL的版本各不相同,同一函数在不同版本DLL中的位置也可能不同;另外一个原因在于DLL的重定位,DLL文件的ImageBase值一般为10000000,但当两个DLL尝试装载到同一个地址时会发生冲突,因此有一个DLL得寻找另一个地址装载,这就是所谓的DLL重定位。
因此当我们要调用某个DLL中的函数时,需要借助IAT(Import Address Table,导入地址表)作为中间桥梁。PE文件在装载时由PE装载器将导入函数的真实地址写入到IAT时,函数调用时则需要从IAT中获取函数的真实地址。
IAT提供的机制与DLL的隐式链接有关。
下面我在 VS2019 里编译如下代码:
修改几个编译选项:
IDA打开编译好的文件,找到调用 strcmp 函数的位置:
FF 15 是 call 的 opcode ,C8 20 40 00 是小端表示的地址,即0x004020C8,该 call 指令并没有直接跳转到0x004020C8这个地址,而是从.idata段读取了 strcmp 函数的真实地址后再进行跳转。.idata段内的数据被称为IAT(Import Address Table,导入地址表),这个过程被称为从IAT获取函数的真实地址。
然而.idata段内的数据并没有初始化,也就是说,strcmp 函数的真实地址是在运行时才能得到的,准确来说是在PE文件被加载到内存时才能得到,下面我们就来研究IAT是怎样被初始化的。
IMAGE_IMPORT_DESCRIPTOR结构体中记录着PE文件要导入哪些库文件。
其结构如图所示:
OrignalFirstThunk 存储的INT(Import Name Table)的RVA,INT中各元素的值为IMAGE_IMPORT_BY_NAME结构体指针。
我们在 010 editor 中找到 strcmp 函数所在DLL对应的 IMAGE_IMPORT_DESCRIPTOR:
看到 IAT 的 RVA 为 20C8h,INT 的 RVA 为 2630h。
在IDA中查看INT的数据:
再来看看PE装载器是如何把导入函数的真实地址写入IAT中的:
GetProcAddress 函数的作用是获取导入函数的虚拟地址:
随便找个地方下断点:
动态调试查看 ucrtbase.dll 的基址以及 strcmp 函数的地址:
真实的 strcmp 函数:
《逆向工程核心原理》李承远
int
main(){
char
input
[
100
]
=
{
0
};
scanf_s(
"%s"
,
input
);
if
(!strcmp(
input
,
"password"
)) {
printf(
"Right.\n"
);
}
}
int
main(){
char
input
[
100
]
=
{
0
};
scanf_s(
"%s"
,
input
);
if
(!strcmp(
input
,
"password"
)) {
printf(
"Right.\n"
);
}
}
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
/
/
0
for
terminating null
import
descriptor
DWORD OriginalFirstThunk;
/
/
RVA to original unbound IAT (PIMAGE_THUNK_DATA)
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
/
/
0
if
not
bound,
/
/
-
1
if
bound,
and
real date\time stamp
/
/
in
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
/
/
O.W. date
/
time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain;
/
/
-
1
if
no forwarders
DWORD Name;
DWORD FirstThunk;
/
/
RVA to IAT (
if
bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED
*
PIMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-12-13 11:07
被34r7hm4n编辑
,原因: