我正在阅读John Levine的“Linkers and Loaders”一书中的这一段,描述了在Windows中加载dll的过程:对于每个导入的DLL,都有一个导入地址数组,通常在程序的文本段中,程序加载器将解析的地址放入其中。这在两个方面让我感到惊讶:1.文本段不是只读/执行的吗?(也许加载器只在写入后才更改其权限?)1.这不会使文本段在进程之间不可共享吗?Linux不遗余力地保持库的所有示例的文本段相同(“位置独立代码”)。这难道不是Windows的目标吗?
2skhul331#
对于每个导入的DLL,都有一个导入地址数组,通常在程序的文本段中,程序加载器将解析的地址放入其中。过去流行将导入放在读/写.idata部分,然后改为只读.idata,现在(对于64位的ex和dll)导入通常是(只读). rdata的一部分。你也可以把导入的内容放在.text中,但我不记得这是流行的,也许在我之前。顺便说一句,你可以创建一些任意的节名,并把导入放在那里,这没关系,节的实际名称并不重要。也许加载器只在写入后才更改其权限?是的,它可以很容易地做到这一点,但它实际上更糟:延迟加载的DLL呢?因此,如果存在延迟加载的DLL,则无论导入在哪个页面中,都可以在执行期间的各个点处,无论何时加载延迟加载的DLL,被短暂地更改为可写、修改,然后返回到只读。作为一个有趣的事实,在x86内核代码可以直接写入只读页面,除非它专门启用CR0.WP。但是加载程序运行在用户模式下,所以这在这里并不重要。这不会使文本段在进程之间不可共享吗?如果.text中有 are 导入,那么这只会影响实际上有导入的页面,而不是整个部分。导入不是通过在整个代码中更改各种call指令的目标地址来处理的,而是通过填充一个中央地址数组来处理的,这些地址随后被间接调用指令使用。所以代码本身并没有改变,只是在某处增加了一个密集的数组。如果该数组在.text中,那么.text的 that 部分将不可共享,但其余部分仍然可以共享。但是,撇开.text中的 imports 的情况不谈,影响text部分的重定位会使text部分不可共享吗?32位代码通常不会在.text中导入,但通常会对.text进行重定位,这似乎更糟:这会影响大多数页面。但即便如此,代码页最终还是大部分是可共享的。Some trickery is necessary:尝试在多个进程中以一致的地址加载DLL,以便即使重新定位代码页也可以共享它们。但是,由于页面被修改了,因此不能简单地对它们进行内存Map。由于RIP相对寻址,x64代码在大多数情况下自然是位置无关的。顺便说一句,它允许(虽然不推荐)有一个不可重定位的exe或dll。不可重定位意味着它们只能在其“首选”(在本例中是“必需”)基址上加载,并且与ASLR不兼容。exe首先被加载到它的地址空间中,这样就可以工作了。一个不可重定位的dll要么得到它的首选地址,要么没有,如果没有,那么它将无法加载。
call
fjaof16o2#
导入地址数组由PE文件可选头中的16个数据目录之一标识,即 * 导入地址表 (IAT)。它通常位于自己的部分*.idata中,但一些链接器可能会将IAT与 IMPORT Table 或.text部分捆绑在一起。1.是的,.text**代码段仅可读可执行,但只有在Windows加载器解析了导入函数的所有地址并将其存储到IAT后,才能建立访问权限。
2条答案
按热度按时间2skhul331#
对于每个导入的DLL,都有一个导入地址数组,通常在程序的文本段中,程序加载器将解析的地址放入其中。
过去流行将导入放在读/写.idata部分,然后改为只读.idata,现在(对于64位的ex和dll)导入通常是(只读). rdata的一部分。你也可以把导入的内容放在.text中,但我不记得这是流行的,也许在我之前。
顺便说一句,你可以创建一些任意的节名,并把导入放在那里,这没关系,节的实际名称并不重要。
也许加载器只在写入后才更改其权限?
是的,它可以很容易地做到这一点,但它实际上更糟:延迟加载的DLL呢?因此,如果存在延迟加载的DLL,则无论导入在哪个页面中,都可以在执行期间的各个点处,无论何时加载延迟加载的DLL,被短暂地更改为可写、修改,然后返回到只读。
作为一个有趣的事实,在x86内核代码可以直接写入只读页面,除非它专门启用CR0.WP。但是加载程序运行在用户模式下,所以这在这里并不重要。
这不会使文本段在进程之间不可共享吗?
如果.text中有 are 导入,那么这只会影响实际上有导入的页面,而不是整个部分。导入不是通过在整个代码中更改各种
call
指令的目标地址来处理的,而是通过填充一个中央地址数组来处理的,这些地址随后被间接调用指令使用。所以代码本身并没有改变,只是在某处增加了一个密集的数组。如果该数组在.text中,那么.text的 that 部分将不可共享,但其余部分仍然可以共享。但是,撇开.text中的 imports 的情况不谈,影响text部分的重定位会使text部分不可共享吗?32位代码通常不会在.text中导入,但通常会对.text进行重定位,这似乎更糟:这会影响大多数页面。
但即便如此,代码页最终还是大部分是可共享的。Some trickery is necessary:尝试在多个进程中以一致的地址加载DLL,以便即使重新定位代码页也可以共享它们。但是,由于页面被修改了,因此不能简单地对它们进行内存Map。
由于RIP相对寻址,x64代码在大多数情况下自然是位置无关的。
顺便说一句,它允许(虽然不推荐)有一个不可重定位的exe或dll。不可重定位意味着它们只能在其“首选”(在本例中是“必需”)基址上加载,并且与ASLR不兼容。exe首先被加载到它的地址空间中,这样就可以工作了。一个不可重定位的dll要么得到它的首选地址,要么没有,如果没有,那么它将无法加载。
fjaof16o2#
导入地址数组由PE文件可选头中的16个数据目录之一标识,即 * 导入地址表 (IAT)。它通常位于自己的部分*.idata中,但一些链接器可能会将IAT与 IMPORT Table 或.text部分捆绑在一起。
1.是的,.text**代码段仅可读可执行,但只有在Windows加载器解析了导入函数的所有地址并将其存储到IAT后,才能建立访问权限。
微软似乎不太关心PIC,每个DLL可以加载到任意虚拟地址,并在需要时重新定位,使用它们的**.reloc**节。