漫谈兼容内核之六:二进制映像的类型识别

上传人:子 文档编号:41880341 上传时间:2018-05-31 格式:DOC 页数:16 大小:51.50KB
返回 下载 相关 举报
漫谈兼容内核之六:二进制映像的类型识别_第1页
第1页 / 共16页
漫谈兼容内核之六:二进制映像的类型识别_第2页
第2页 / 共16页
漫谈兼容内核之六:二进制映像的类型识别_第3页
第3页 / 共16页
漫谈兼容内核之六:二进制映像的类型识别_第4页
第4页 / 共16页
漫谈兼容内核之六:二进制映像的类型识别_第5页
第5页 / 共16页
点击查看更多>>
资源描述

《漫谈兼容内核之六:二进制映像的类型识别》由会员分享,可在线阅读,更多相关《漫谈兼容内核之六:二进制映像的类型识别(16页珍藏版)》请在金锄头文库上搜索。

1、漫谈兼容内核之六:二进制映像的类型识别漫谈兼容内核之六:二进制映像的类型识别漫谈兼容内核之六:二进制映像的类型识别bsize=4align=center漫谈兼容内核之六:二进制映像的类型识别/align/size/balign=centeri毛德操/i/align除了某些嵌入式系统之外,一般而言操作系统都有个在创建(或转化成)新进程时如何装入目标程序的二进制映像并启动其运行的问题。由于在计算机技术的发展历史中并没有形成某种单一的、为所有操作系统和编译/连接工具所共同遵循的标准,这个装入/启动的过程就不可避免地呈现出多样性。而且,即使是同一种操作系统,也会在其发展的过程中采用多种不同的目标映像格

2、式和装入机理。而动态连接库技术的出现,则又使这个过程进一步地复杂化了,因为此时需要装入的不仅是目标程序的映像,还有动态连接库的映像,并且还要解决目标程序与具体库函数的动态连接问题。至于这个过程的重要性,那是不言而喻的,要不然操作系统就要么实际上不能做“有用功” ,要么失去了通用性和灵活性。以 Linux 应用软件为例,就既有 a.out 格式,又有 ELF 格式,又支持动态连接库。我在“情景分析”一书中只讲了 a.out 映像的装入和启动,是因为 a.out 相对比较简单,否则篇幅太大。读者也许会问,既然有了更复杂、功能更强的 ELF 格式,为什么还要保留a.out 格式呢?这当然是为了向后兼

3、容,一种技术一旦被广泛采用以后就不会很快消失。与 Linux 相比,Windows 采用的格式就更多了,因为它还需要支持 DOS 时代的应用软件。兼容内核既要支持 Linux 和 Windows 两种操作系统的应用软件,这个问题当然就更复杂、难度更大了。幸而 Wine 已经在我们之前以它的方式解决了这个问题,使我们至少有了可以借鉴的榜样。在讲述 Wine 的软件映像的装入/启动过程之前,我们先考察一下,为了兼容 Windows 软件,Wine 需要支持那一些映像格式,以及如何识别一个映像所属的格式和类型。为此,我们看一下 Wine 的一段代码,这段代码在 dlls/kernel/module.

4、c 中,是在用户空间执行的。这是一个名为 MODULE_GetBinaryType()的函数,其作用是辨认一个已打开文件所属的映像格式并进而判定其类型,已定义的类型有:codeenum binary_typeBINARY_UNKNOWN,BINARY_PE_EXE,BINARY_PE_DLL,BINARY_WIN16,BINARY_OS216,BINARY_DOS,BINARY_UNIX_EXE,BINARY_UNIX_LIB;/code除 BINARY_UNKNOWN 表示无法辨认/判定以外,这里定义了 7 种映像类型。其中 BINARY_PE_EXE 和 BINARY_PE_DLL 是 W

5、indows 的 32位“PE 格式”映像,前者为目标应用程序,后者为动态连接库DLL。注意前者是“有源”的主体,可以成为一个进程;而后者是“无源”的库程序,不能独立成为一个进程。BINARY_WIN16 和BINARY_OS216 则为 16 位 Windows 应用;后者实际上是 OS/2 操作系统的应用程序,但是因为微软和 IBM 曾经紧密合作,所以 Windows也支持 OS/2 的应用程序。再往下 BINARY_DOS 显然是 DOS 的应用软件,但是 DOS 上的可执行程序有.exe 和.com 两种,这里并未加以区分,其原因留待以后再说。最后是 BINARY_UNIX_EXE 和

6、BINARY_UNIX_LIB,Linux 是 Unix 的继承者,所以也适用于 Linux的应用程序和动态连接库。下面可以看代码了,我们分段阅读。codeenum binary_typeMODULE_GetBinaryType( HANDLE hfile, void *res_start, void *res_end )unionstructunsigned char magic4;unsigned char ignored12;unsigned short type; elf;structunsigned long magic;unsigned long cputype;unsigned

7、long cpusubtype;unsigned long filetype; macho;IMAGE_DOS_HEADER mz; header;DWORD len;/* Seek to the start of the file and read the header information. */if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) = -1)return BINARY_UNKNOWN;if (!ReadFile( hfile, /code无论是 Linux 还是 Windows,在文件系统的目录项中都没有关于文件格式/类型的说明,

8、所以只能采取在文件的实际内容前面加上头部的方法来表明。但是,不同可执行映像的头部结构和大小又各不相同。而且,头部还可能是级连或嵌套的,即先由一级的头部进行大的分类,然后再由二级的头部作进一步的细分。所以这里定义了一个包含几种一级头部结构的 Union。其中的 elf 当然是 Linux的 ELF 格式映像的头部(但是 a.out 格式不在内,所以也并不完整);macho 大约是针对 MACH 操作系统的,我们并不关心;而 mz 是 DOS以及 Windows 格式的一级头部,这是个相对较大的数据结构:codetypedef struct _IMAGE_DOS_HEADER WORD e_mag

9、ic; /* 00: MZ Header signature */WORD e_cblp; /* 02: Bytes on last page of file */WORD e_cp; /* 04: Pages in file */WORD e_crlc; /* 06: Relocations */WORD e_cparhdr; /* 08: Size of header in paragraphs */WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */WORD e_maxalloc; /* 0c: Maximum extra

10、paragraphs needed */WORD e_ss; /* 0e: Initial (relative) SS value */WORD e_sp; /* 10: Initial SP value */WORD e_csum; /* 12: Checksum */WORD e_ip; /* 14: Initial IP value */WORD e_cs; /* 16: Initial (relative) CS value */WORD e_lfarlc; /* 18: File address of relocation table */WORD e_ovno; /* 1a: Ov

11、erlay number */WORD e_res4; /* 1c: Reserved words */WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */WORD e_oeminfo; /* 26: OEM information; e_oemid specific */WORD e_res210; /* 28: Reserved words */DWORD e_lfanew; /* 3c: Offset to extended header */ IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;/code这个

12、数据结构提供了不少信息,都是与 DOS 环境下的目标映像装入/启动密切相关的。例如 e_ss 和 e_sp 就说明了堆栈的位置是预定的(而不是动态分配的),而 e_ss 的使用又表明目标程序是在“实模式”下运行。如此等等,这里就不详说了。不过,当微软从 DOS发展到 Windows 和 WinNT 时,仍旧套用了这个数据结构作为其应用程序目标映像的一级头部,而 WinNT 显然是在“保护模式”下运行。所以,这里的许多字段对于 Windows 目标映像实际上已经不再使用。代码中首先通过类似于 lseek()的 SetFilePointer()把目标文件的读/写指针移到文件的开头,再按上述 Uni

13、on 的大小读出,这就可以把几种头部、特别是 Linux 和 Windows 目标映像的头部都包含在内了。下面就来辨认识别:code if (!memcmp( header.elf.magic, “177ELF“, 4 )/* FIXME: we dont bother to check byte order, architecture, etc. */switch(header.elf.type)case 2: return BINARY_UNIX_EXE;case 3: return BINARY_UNIX_LIB;return BINARY_UNKNOWN;./code先看是否 Linu

14、x 的 ELF 格式。ELF 头部的数据结构定义见上,其第一个字段是 4 字节的标识码 magic,也称为“签名” 。ELF 格式签名的第一个字节是八进制的177 ,即十六进制的0x7f ,然后是E 、 L 、 F三个字符。ELF 头部的 type 字段则进一步表明映像的性质,目前只定义了两种类型,即 BINARY_UNIX_EXE 和BINARY_UNIX_LIB。我们跳过对 macho 头部的辨认,往下看 DOS/Windows 头部的辨认。DOS 头部的签名定义于 include/winnt.h:code#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ *

15、/#define IMAGE_OS2_SIGNATURE 0x454E /* NE */#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */#define IMAGE_VXD_SIGNATURE 0x454C /* LE */#define IMAGE_NT_SIGNATURE . 0x00004550 /* PE00 */code数值 0x5A4D 实际上是M 、 Z两个字符的代码,因为 Intel的 CPU 芯片采用“Little Ending” ,所以次序是反的。注意这里只有 MZ 用于一级头部,其余都用于二级头部。继续往下看代码:code /* Not ELF, try DOS */if (header.mz.e_magic = IMAGE_DOS_SIGNATURE)unionIMAGE_OS2_HEADER os2;IMAGE_NT_HEADERS nt; ext_header;/* We do have a DOS image so we will now try to seek into* the file by the amou

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号