Longene是一个源自中国的自由、开源的操作系统项目,目的是要把Linux的内核扩充成一个既支持Linux应用、也支持Windows应用,既支持Linux设备驱动、也支持Windows设备驱动的兼容内核;使用户可以直接在Linux操作系统上高效运行Windows应用。2006年发布了其第一个版本,但是自2014年以来,项目开发已停止,2018年5月其官网无法访问。这里就不多做介绍了,直接开始从源码角度分析Longene是怎么在Linux内核中实现PE加载器的。
Longene中PE可执行文件的加载以及动态链接的过程主要在/module/ke/文件夹中的代码实现。
Longene采用内核模块的形式,在内核中注册了pe格式的文件。(之前有分析过了如何扩展可支持的文件格式),该结构体为pe_format。
当执行某exe文件,例如在命令行里面敲入 ./notepad.exe的时候,首先linux内核调用execve系统调用最终走到会走到longene兼容模块的load_pe_bianry函数中(这也是前面分析过的)。
进入load_pe_binary函数,首先判断父进程是否是win32程序。
接下来就是一堆常规的操作,比如预留进程地址空间,将二进制文件映射至内存,调整堆栈大小,为解释器预留空间等。
然后是一个重要的步骤,搜索ntdll.dll.so,也就是wine代码生成的builtin dll。在$ PATH中搜索ntdll.dll.so,默认是/usr/local/lib/wine/ntdll.dll.so。找到后才可以执行下面的代码。
search_ntdll函数如下图所示:
调用函数map_system_dll映射ntdll.dll.so。该函数在sysdll.c中定义,先通过load_elf_interp函数将ntdll.dll.so装入,该函数主体部分基本是参考linux内核源码中ELF文件加载启动的那部分代码(binfmt_elf.c)