当前位置:文档之家› 手工构造典型PE文件

手工构造典型PE文件

手工构造典型PE文件
手工构造典型PE文件

2009-06-08 11:38:40 https://www.doczj.com/doc/3410205443.html, 来源:黑客防线

一直以来都在学习PE文件结构,从不敢轻视,但是即使如此还是发现自己在这方面有所不足,于是便想到了用纯手工方式打造一个完整的可执行的PE文件。在这期间我也查了大量资料,但是这些资料都有一个通病就是不...

一直以来都在学习PE文件结构,从不敢轻视,但是即使如此还是发现自己在这方面有所不足,于是便想到了用纯手工方式打造一个完整的可执行的PE文件。在这期间我也查了大量资料,但是这些资料都有一个通病就是不完整,看雪得那个只翻译了一部分,加解密技术内幕介绍的更是笼统,而且是打造一个只有180字节的PE文件,是高手们茶余饭后的怡情小游戏。

鉴于此,心想为什么不自己摸索着手工打造一个完整些的呢?一是加强一下自己对于PE文件的了解,二是写出一篇参考性比较强的文章,给有志于在此发展的朋友们铺一铺路,也算是干了一件利国利民的好事。

对于手工打造PE文件,我个人认为至少要分为三篇文章来阐述,每篇相对独立,合起来形成一个相对的体系。第一篇文章(也就是本文)用来介绍怎样用手工打造一个最典型、最简单的PE文件,而后两篇文章的问世还要引用潘爱民先生的一句话“还需要时日与机缘”。

本文介绍的PE文件手工编辑方式,是本着以下三个原则所写的,望读者注意:

1、完整性:对于手工打造PE文件所不需注意的字段也进行了必要的介绍,因此整文可能显得非常臃肿。

2、典型性:完全按照典型的PE文件结构构造,因此对于某些不常见的PE文件结构有一定差距。

3、易学性:对于字段之间的逻辑关系进行了比较细致的介绍,因此对于一部分底子比较好的读者来说可能显得有些啰嗦。

为了方便各位阅读与查阅,我将文章分成了三各部分,以便各位读者各取所需,不用把宝贵的精力浪费在查找上。

1、PE文件整体信息,提供了一个剖析PE文件的图表,以便于读者对于PE文件有一个整体的了解,并监督自己的工作进度。

2、对于重点字段的介绍,以及字段之间的逻辑关系,建议首先从这里开始看。

3、手工构造PE文件字段清单,此清单包含构造一个完整PE文件的每一个字节,跟着这个清单走就可以构造一个PE文件。

对于第一次手工打造PE文件的朋友们来说,你们可以以“一、整体性息”为大纲,并参考第三部分一块一块的慢慢打造,如果有不懂的地方就去看第二部分。

选读:为什么要手工打造PE文件?

我们知道,往往从一个系统可执行文件结构上,就可以看整个操作系统的一些特性。也就是说PE里有Windows操作系统结构与运行机理的影子。由此可见,PE文件必然是一个非常庞杂且逻辑复杂的结构,那么为什么我们还要“自取其辱”来手工制造一个PE文件呢?这就要从PE文件的重要性说起了。

我们现今组成Windows大家庭的主要成员就是PE文件了,里面包括EXE、DLL、OCX、SYS等一切最有价值的文件都是PE文件格式,出于对版权的考虑或对某种技术的渴求,任何一种与Windows系统相关的行为最终都要归集到这里--PE文件。

特别是对于想学习加壳、破解、搞虚拟机的朋友们来说,熟知PE文件结构更是必不可少的基本功!

但也正是由于PE文件的复杂性,我们才要采取一些特别的办法来攻克它,其中手工打造PE文件就是一条捷径。

你可以想像一下,如果你都可以手工打造PE文件的话,那么对于PE文件的了解更是

可见一斑了。但是我还想提醒一下各位读者,即便是如此,我们所了解的也仅仅是一部分,不过一般情况下已经足够了。

一、整体性息

这部分以图表的形式表示PE文件的整体结构。

-------------*-------------------------------------------------*

| DOS Header(IMAGE_DOS_HEADER) | -->64 Byte

DOS头部--------------------------------------------------

| DOS Stub | -->112 Byte

-------------*-------------------------------------------------*

| "PE"00 (Signature) | -->4 Byte

-------------------------------------------------

| IMAGE_FILE_HEADER | -->20 Byte

PE文件头--------------------------------------------------

| IMAGE_OPTIONAL_HEADER32 | -->96 Byte

---------------------------------------------------

| 数据目录表| -->128 Byte

-------------*--------------------------------------------------*

| IMAGE_SECTION_HEADER | -->40 Byte

---------------------------------------------------

块表| IMAGE_SECTION_HEADER | -->40 Byte

--------------------------------------------------

| IMAGE_SECTION_HEADER | -->40 Byte

-------------*--------------------------------------------------*

|.text | -->512 Byte

---------------------------------------------------

块|.rdata | -->512 Byte

---------------------------------------------------

|.data | -->512 Byte

-------------*-------------------------------------------------*

| COFF行号| -->NULL

---------------------------------------------------

调试信息| COFF符号表| -->NULL

---------------------------------------------------

| Code View 调试信息| -->NULL

-------------*--------------------------------------------------*

这部分内容的意义有二:

1、对于PE文件有一个整体的认识。

2、方便审查自己的构造进度。

这里我们重点介绍怎样用其审查自己的构造进度,首先希望各位读者明白我们将要手工构造的一个体积为2560字节的这个小家伙,对于初次上手的读者们来说并不是一件小的工程,因此有必要知道自己现在正做什么,以及做到哪里了。

记得我少年学画时老师教我们构图就要从整体到局部,后来自学编程仍然是先实现大的框架再去解决每一个细节问题。OK,现在到了这里,很显然我们仍然需要本着从整体到局

部的思想来构造我们的PE文件。

那好,我们先搞明白第一个问题“我们的文件体积是怎么计算出来的呢”。

首先我们要知道,PE文件自始至终都是以一种节的思想来构造的,那么我们就要从节开始。

对于本文所讲述的PE文件来讲总共有三个区块(节),他们分别用来存放可执行代码、输入表信息以及全局变量,接触过PE文件的朋友对于区块的概念应该不陌生,我们知道Windows下的很多应用程序的文件对齐粒度,也就是大名鼎鼎的FileAlignment字段的值多为200h Byte,也就是十进制的512 Byte。我们同样应该知道,对于不足512字节的区段,余下部分要用00h填充到512字节大小,对与超过部分(例如513字节的区段)我们就要在多分配给他512字节个空间。

当然,这些基础知识我想有一部分读者应该比较熟悉,那么对于PE文件头部分呢?也是如此吗?例如本例中的PE头就占用了544个字节,但是很显然这要使其填充到1024(400h)字节处才能开始第一个区段.text段。

正是如此,我们整个文件的体积就是PE头+3个区段的体积之和,也就是PE头(512*2)+3个区段(512*3)=2560,这也就是我们所构造的PE文件的最终大小了。

其次我们提前搞清楚一些字段与区段的偏移量也是比较重要的,这里对于计算方式不再多说,请大家直接看下面的表:

1、PE头开始处000000B0h

2、IMAGE_OPTIONAL_HEADER32开始处000000C8h

3、数据目录表开始处00000128h

4、块表开始处000001A8h

5、.text块开始处00000400h

6、.rdata块开始处00000600h

7、.data块开始处00000800h

当然,上面的那些Offset只是针对本文件而言,并不绝对,具体情况还要具体分析。

到此,本段就告一段落了,剩下的两段为了提高效率我并没有加以润色,全都是干货,希望各位读者能吃下这两块营养丰富的压缩饼干……

二、重点字段介绍

这里只对需手工构造的字段进行着重介绍,详细的PE文件结构字段清单请见第三部分。

1、DOS头部

1-1 DOS Header

1-1-1 e_magic [WORD] -->4D 5A (* DOS可执行文件头标记)

注释:此处值总是为MZ的16进制码。

1-1-19 e_lfanew [DWORD] -->B0 00 00 00 (* 指向PE文件头的偏移量。0xB0=64+112)

注释:此处的值正好为为DOS头部的大小,因为DOS头部后面就是PE文件头部分了。

2 PE文件头

2-1 "PE"00

2-1-1 Signature [DWORD] -->50450000h (* PE文件头标记)

注释:此处的值总是为PE的16进制值加0000h。

2-2 IMAGE_FILE_HEADER

2-2-1 Machine [WORD] -->4C 01 (* 可执行文件的目标CPU类型)

注释:此PE文件可以运行于哪个CPU下,其标志就为相应的值。

*------------------------------*

| 机器| 标志|

-------------------------------

| Intel i386 | 14Ch |

-------------------------------

| MIPS R3000 | 162h |

-------------------------------

| MIPS R4000 | 166h |

-------------------------------

| Alpha AXP | 184h |

-------------------------------

| Power PC | 1F0h |

*-----------------------------*

2-2-2 NumberOfSections [WORD] -->03 00 (* 区块数目)

注释:此值决定此PE文件的区块数目,本文件为3个区块。

2-2-6 SizeOfOptionalHeadr [WORD] -->E0 00 (* PE头(IMAGE_OPTIONAL_HEADER32)大小)

注释:此值表示PE文件头的大小。

2-2-7 Characteristics [WORD] -->0F 01 (* 文件属性)

注释:此值为文件的执行属性。EXE文件此值一般为010Fh,DLL文件此值一般为0210h。

2-3 IMAGE_OPTIONAL_HEADER32

2-3-1 Magic [WORD] -->0B 01 (* 标记字)

注释:此处是一个标记字,用于描述次PE文件的映像类型。ROM映像为0107h;普通可执行映像010Bh;PE32+则是020Bh。

2-3-7 AddressOfEntryPoint [DWORD] -->00 10 00 00 (* 程序执行入口RA V)

注释:通俗的说就是指向可执行代码区块(例如.text)的首地址。

2-3-10 ImageBase [DWORD] -->00 00 40 00 (* 程序默认装入基地址)

注释:是指文件在内存中首选的装入地址。

2-3-11 SectionAlignment [DWORD] -->00 10 00 00 (* 内存中区块对齐值)

注释:PE文件被装入内存中时的块对齐大小,也叫做块粒度。其默认的对其尺寸是CPU 的页尺寸。

2-3-12 FileAlignment [DWORD] -->00 02 00 00 (* 文件中区块对齐值)

注释:磁盘上PE文件的区块对齐大小。这个值必须是2的幂,并且最小为200h。

2-3-17 MajorSubsystemVersion [WORD] -->04 00 (* 运行所需最低子系统主版本号)

注释:要求最低的子系统主版本号,一般情况下都为4。

2-3-18 MinorSubsystemVersion [WORD] -->00 00 (* 运行所需最低子系统次版本号)

注释:要求最低的子系统次版本号,一般情况下都为0。

2-3-20 SizeOfImage [DWORD] -->00 40 00 00 (* 映像装入内存后的总尺寸)

注释:指的是装入文件从Image Base到最后一个区块的总大小。

2-3-21 SizeOfHeaders [DWORD] -->00 40 00 00 (* DOS头、PE头、区块表的总大小) 注释:指的是DOS头、PE头与区块表的总大小,并且所有这些项目都出现在PE文件中任何代码或数据块之前。此值遵守文件对齐粒度。

2-3-23 Subsystem [WORD] -->03 00 (* 文件子系统)

注释:标明可执行文件所期望的子系统(用户界面类型)。

*----*-------------------------------------*

| 值| 子系统|

*----*-------------------------------------*

| 0 | 未知|

--------------------------------------------

| 1 | 不需要子系统(如驱动程序)|

---------------------------------------------

| 2 | 图形接口子系统(GUI)|

---------------------------------------------

| 3 | 字符子系统(CUI)|

---------------------------------------------

| 5 | OS/2字符子系统|

---------------------------------------------

| 7 | POSIX字符子系统|

---------------------------------------------

| 8 | 保留|

---------------------------------------------

| 9 | Windows CE图形界面|

*----*--------------------------------------*

2-3-30 NumberOfRvaAndSizes [DWORD] -->10 00 00 00 (* 数据目录标的项数,默认总为16)

注释:数据目录的项数。这个字段字NT系统发布以来就一直是16。

2-4 数据目录表

2-4-2 Import Table

注释:输入表

2-4-2-1 VirtualAddress [DWORD] -->10 20 00 00 (* 数据块的起始RA V)

注释:输入表的起始地址,要去除IAT所占空间,直接从第一个IID开始。

2-4-2-2 Size [DWORD] -->3C 00 00 00 (* 数据块的长度)

注释:从第一个IID到最后一个IMAGE_IMPORT_BY_NAME的总长度。

3 块表

3-1 IMAGE_SECTION_HEADER (1 .text)

3-1-1 Name [BYTE] -->2E 74 65 78 74 00 00 00 (* 8个字节的块名)

注释:此区块的名称,限制在8字节以内。

3-1-2 VirtualSize [DWORD] -->26 00 00 00 (* 被实际使用的区块大小)

注释:此区块包含数据的大小。

3-1-10 Characteristics [DWORD] -->20 00 00 60 (* 该区块的读写、执行属性)

注释:

*----------------------------------------------------------------*

| 字段值| 用途| -----------------------------------------------------------------

| 00000020h | 包含代码,常与10000000h一起设置|

-----------------------------------------------------------------

| 00000040h | 包含已初始化数据|

-----------------------------------------------------------------

| 00000080h | 包含未初始化数据|

-----------------------------------------------------------------

| 02000000h | 可以被丢弃|

-----------------------------------------------------------------

| 10000000h | 共享块|

-----------------------------------------------------------------

| 20000000h | 可执行|

-----------------------------------------------------------------

| 40000000h | 可读|

-----------------------------------------------------------------

| 80000000h | 可写|

-----------------------------------------------------------------

4 块

4-1 .text (* 此区段是一段汇编代码的16进制形式,功能是弹出一个MessageBox提示框)

-->HEX

6A 00 68 00 30 40 00 68 07 30 40 00 6A 00 E8 07

00 00 00 6A 00 E8 06 00 00 00 FF 25 08 20 40 00

FF 25 00 20 40 00

注释:这是下面汇编指令的16进制模式。

-->ASM

00401000 6A 00 PUSH 0

00401002 68 00304000 PUSH first_PE.00403000

00401007 68 07304000 PUSH first_PE.00403007

0040100C 6A 00 PUSH 0

0040100E E8 07000000 CALL

00401013 6A 00 PUSH 0

00401015 E8 06000000 CALL

0040101A FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]

00401020 FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]

4-2 .rdata (* 该区块包含输入表)

4-2-1 IMAGE_THUNK_DA TA32 (IAT 1)

注释:这里有很多人都搞不明白,其实IMAGE_THUNK_DATA32是一个联合体,可以同时代表IAT与INT。

4-2-1-1 AddressOfData [DWORD] -->76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME 的RV A)

注释:作为IAT时我们就会使用他的AddressOfData成员,用来存放指向IMAGE_IMPORT_BY_NAME的RV A,当程序装入内存后,只与IAT交换信息,输入表的其他部分就不再需要了。

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】注释:这里同样有很多人不明白,每当属于某一个DLL文件的API罗列完毕后,就要输入00加以结束。

4-2-3 IMAGE_IMPORT_DESCRIPTOR (IID 1)

注释:这里稍微复杂些,它的作用就是使用INT指定某个DLL文件中的API函数,并配合IAT指向相关API的地址。

4-2-3-1 OriginalFirstThunk [DWORD] -->4C 20 00 00 (* 指向输入名称表INT的RV A) 注释:这里指定某个系统DLL文件中的API函数。

4-2-3-4 Name [DWORD] -->6A 20 00 00 (* 指向DLL名字的RV A与指针)

注释:这里指定某个系统DLL文件。

4-2-3-5 FirstThunk [DWORD] -->08 20 00 00 (* 指向输入地址表IAT的RV A)

注释:这里指定相关的IAT,并由IAT在IMAGE_IMPORT_BY_NAME中获得相应API 的地址。

4-2-4 IMAGE_IMPORT_DESCRIPTOR (IID 2)

4-2-4-1 OriginalFirstThunk [DWORD] -->54 20 00 00 (* 指向输入名称表INT的RV A) 4-2-4-4 Name [DWORD] -->84 20 00 00 (* 指向DLL名字的RV A与指针)

4-2-4-5 FirstThunk [DWORD] -->00 20 00 00 (* 指向输入地址表IAT的RV A) 【填充20个00h空字节做结尾标记】

注释:关于填充20个字节作为IID的结尾标记只是一个规律,还没找到相关资料证实。

4-2-5 IMAGE_THUNK_DA TA32 (INT 1)

4-2-5-1 ForwarderString [DWORD] -->5C 20 00 00 (* 指向一个转向字符的RV A)

注释:直接指向相关API函数。

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】注释:与上面的IAT原理一样,就是这样的一个格式。

4-2-7 IMAGE_IMPORT_BY_NAME ( 1 )

4-2-7-2 Name [BYTE] -->4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16进制码)

注释:相关API函数的16进制代码。

【后跟输出此函数的DLL名称16进制码00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll】

注释:相关系统的API函数罗列完毕后,通常都在最后一个API后空00h,并跟着这个DLL名称的16进制数据。

总结:这里罗列了一些需要手工构建的部分结构,如果想看更加详细的请关注下面的内容。

三、PE文件结构字段清单

1 DOS头部

1-1 DOS Header

1-1-1 e_magic [WORD] -->4D 5A (* DOS可执行文件头标记)

1-1-2 e_cblp [WORD] ->00 00 (文件最后页的字节数)

1-1-3 e_cp [WORD] ->00 00 (文件页数)

1-1-4 e_crlc [WORD] ->00 00 (重定位元素个数)

1-1-5 e_cparhdr [WORD] ->00 00 (以段落为单位的头部大小)

1-1-6 e_minalloc [WORD] ->00 00 (所需的最小附加段)

1-1-7 e_maxalloc [WORD] ->00 00 (所需的最大附加段)

1-1-8 e_ss [WORD] ->00 00 (初始的堆栈段(SS)相对偏移量值)

1-1-9 e_sp [WORD] ->00 00 (初始的堆栈指针(SP)值)

1-1-10 e_csum [WORD] ->00 00 (校验和)

1-1-11 e_ip [WORD] ->00 00 (初始的指令指针(IP)值)

1-1-12 e_cs [WORD] ->00 00 (初始的代码段(CS)相对偏移量值)

1-1-13 e_lfarlc [WORD] ->00 00 (重定位表在文件中的偏移地址)

1-1-14 e_ovno [WORD] ->00 00 (覆盖号)

1-1-15 e_res [WORD] 4 dup ->00 00 (保留字,一般都是为确保对齐而预留)

1-1-16 e_oemid [WORD] ->00 00 (OEM 标识符,相对于e_oeminfo)

1-1-17 e_oeminfo [WORD] ->00 00 (OEM 信息,即e_oemid 的细节) 1-1-18 e_res2 [WORD] 10 dup ->00 00 (保留字,一般都是为确保对齐而预留) 1-1-19 e_lfanew [DWORD] -->B0 00 00 00 (* 指向PE文件头的偏移量。0xB0=64+112)

1-2 DOS Stub

全部填00h

2 PE文件头

2-1 "PE"00

2-1-1 Signature [DWORD] -->50450000h (* PE文件头标记)

2-2 IMAGE_FILE_HEADER

2-2-1 Machine [WORD] -->4C 01 (* 可执行文件的目标CPU类型)

2-2-2 NumberOfSections [WORD] -->03 00 (* 区块数目)

2-2-3 TimeDateStamp [DWORD] ->00 00 00 00 (文件创建的时间与日期)

2-2-4 PointerToSymbolTable [DWORD] ->00 00 00 00 (指向符号表,用于调试)

2-2-5 NumberOfSymbols [DWORD] ->00 00 00 00 (符号表中的符号个数,用于调试)

2-2-6 SizeOfOptionalHeadr [WORD] -->E0 00 (* PE头(IMAGE_OPTIONAL_HEADER32)大小)

2-2-7 Characteristics [WORD] -->0F 01 (* 文件属性)

2-3 IMAGE_OPTIONAL_HEADER32

2-3-1 Magic [WORD] -->0B 01 (* 标记字)

2-3-2 MajorLinkerVersion [BYTE] ->00 (连接程序主版本号)

2-3-3 MinorLinkerVersion [BYTE] ->00 (连接程序次版本号)

2-3-4 SizeOfCode [DWORD] ->00 00 00 00 (所有含代码区块的总大小)

2-3-5 SizeOfInitializedData [DWORD] ->00 00 00 00 (所有初始化数据区块大总大小)

2-3-6 SizeOfUninitializedData [DWORD] ->00 00 00 00 (所有未初始

化数据区块大总大小)

2-3-7 AddressOfEntryPoint [DWORD] -->00 10 00 00 (* 程序执行入口RA V)

2-3-8 BaseOfCode [DWORD] ->00 00 00 00 (代码区块起始RA V)

2-3-9 BaseOfData [DWORD] ->00 00 00 00 (数据区块起始RA V)

2-3-10 ImageBase [DWORD] -->00 00 40 00 (* 程序默认装入基地址)

2-3-11 SectionAlignment [DWORD] -->00 10 00 00 (* 内存中区块对齐值)

2-3-12 FileAlignment [DWORD] -->00 02 00 00 (* 文件中区块对齐值)

2-3-13 MajorOperatingSystemVersion [WORD] ->00 00 (操作系统主版本号)

2-3-14 MinorOperatingSystemVersion [WORD] ->00 00 (操作系统次版本号)

2-3-15 MajorImageVersion [WORD] ->00 00 (用户自定义主版本号)

2-3-16 MinorImageVersion [WORD] ->00 00 (用户自定义次版本号)

2-3-17 MajorSubsystemVersion [WORD] -->04 00 (* 运行所需最低子系统主版本号)

2-3-18 MinorSubsystemVersion [WORD] -->00 00 (* 运行所需最低子系统次版本号)

2-3-19 Win32VersionValue [DWORD] ->00 00 00 00 (保留值,通常为0)

2-3-20 SizeOfImage [DWORD] -->00 40 00 00 (* 映像装入内存后的总尺寸)

2-3-21 SizeOfHeaders [DWORD] -->00 40 00 00 (* DOS 头PE头区块表的总大小)

2-3-22 CheckSum [DWORD] ->00 00 00 00 (映像效验和)

2-3-23 Subsystem [WORD] -->03 00 (* 文件子系统)

2-3-24 DllCharacteristics [WORD] ->00 00 (显示DLL特性的旗标)

2-3-25 SizeOfStackReserve [DWORD] ->00 00 00 00 (初始化堆栈总大小)

2-3-26 SizeOfStackCommit [DWORD] ->00 00 00 00 (初始化实际提交堆栈大小)

2-3-27 SizeOfHeapReserve [DWORD] ->00 00 00 00 (初始化保留堆栈大小)

2-3-28 SizeOfHeapCommit [DWORD] ->00 00 00 00 (初始化实际保留堆栈大小)

2-3-29 LoaderFlags [DWORD] ->00 00 00 00 (与调

试相关,默认值为0)

2-3-30 NumberOfRvaAndSizes [DWORD] -->10 00 00 00 (* 数据目录标的项数,默认总为16)

2-4 数据目录表

2-4-1 Export Table

2-4-1-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-1-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-2 Import Table

2-4-2-1 VirtualAddress [DWORD] -->10 20 00 00 (* 数据块的起始RA V)

2-4-2-2 Size [DWORD] -->3C 00 00 00 (* 数据块的长度)

2-4-3 Resources Table

2-4-3-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-3-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-4 Exception Table

2-4-4-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-4-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-5 Security Table

2-4-5-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-5-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-6 Base relocation Table

2-4-6-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-6-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-7 Debug

2-4-7-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-7-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-8 Copyright

2-4-8-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-8-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-9 Global ptr

2-4-9-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-9-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-10 Threda local storage(TLS)

2-4-10-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-10-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-11 Load configuration

2-4-11-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-11-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-12 Bound import

2-4-12-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-12-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-13 Import Address Table(IAT)

2-4-13-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-13-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-14 Delay import

2-4-14-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-14-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-15 COM descriptor

2-4-15-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-15-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

2-4-16 保留

2-4-16-1 VirtualAddress [DWORD] ->00 00 00 00 (数据块的起始RA V)

2-4-16-2 Size [DWORD] ->00 00 00 00 (数据块的长度)

3 块表

3-1 IMAGE_SECTION_HEADER (1 .text)

3-1-1 Name [BYTE] -->2E 74 65 78 74 00 00 00 (* 8个字节的块名)

3-1-2 VirtualSize [DWORD] -->26 00 00 00 (* 被实际使用的区块大小)

3-1-3 VirtualAddress [DWORD] -->00 10 00 00 (* 区块的RA V地址) 3-1-4 SizeOfRawData [DWORD] -->00 02 00 00 (* 该块在磁盘中所占的大小)

3-1-5 PointerToRawData [DWORD] -->00 04 00 00 (* 该块在磁盘文件中的偏移)

3-1-6 PointerToRelocations [DWORD] ->00 00 00 00 (在OBJ文件中使用,重定位偏移)

3-1-7 PointerToLinenumbers [DWORD] ->00 00 00 00 (行号表的偏移,调试中使用)

3-1-8 NumberOfRelocations [WORD] ->00 00 (在OBJ文件中使用,重定位项数目)

3-1-9 NumberOfLinenumbers [WORD] ->00 00 (行号表中行号的数目)

3-1-10 Characteristics [DWORD] -->20 00 00 60 (* 该区块的读写执行属性)

3-2 IMAGE_SECTION_HEADER (2 .rdata)

3-2-1 Name [BYTE] -->2E 72 64 61 74 61 00 00 (* 8个字节的块名)

3-2-2 VirtualSize [DWORD] -->92 00 00 00 (* 被实际使用的区块大小)

3-2-3 VirtualAddress [DWORD] -->00 20 00 00 (* 区块的RA V地址) 3-2-4 SizeOfRawData [DWORD] -->00 02 00 00 (* 该块在磁盘中所占的大小)

3-2-5 PointerToRawData [DWORD] -->00 06 00 00 (* 该块在磁盘文件中的偏移)

3-2-6 PointerToRelocations [DWORD] ->00 00 00 00 (在OBJ文件中使用,重定位偏移)

3-2-7 PointerToLinenumbers [DWORD] ->00 00 00 00 (行号表的偏移,调试中使用) 3-2-8 NumberOfRelocations [WORD] ->00 00 (在OBJ文件中使用,重定位项数目)

3-2-9 NumberOfLinenumbers [WORD] ->00 00 (行号表中行号的数目)

3-2-10 Characteristics [DWORD] -->40 00 00 40 (* 该区块的读写执行属性)

3-3 IMAGE_SECTION_HEADER (3 .data)

3-3-1 Name [BYTE] -->2E 64 61 74 61 00 00 00 (* 8个字节的块名)

3-3-2 VirtualSize [DWORD] -->3E 00 00 00 (* 被实际使用的区块大小)

3-3-3 VirtualAddress [DWORD] -->00 30 00 00 (* 区块的RA V地址)

3-3-4 SizeOfRawData [DWORD] -->00 02 00 00 (* 该块在磁盘中所占的大小)

3-3-5 PointerToRawData [DWORD] -->00 08 00 00 (* 该块在磁盘文件中的偏移)

3-3-6 PointerToRelocations [DWORD] ->00 00 00 00 (在OBJ文件中使用,重定位偏移)

3-3-7 PointerToLinenumbers [DWORD] ->00 00 00 00 (行号表的偏移,调试中使用)

3-3-8 NumberOfRelocations [WORD] ->00 00 (在OBJ文件中使用,重定位项数目)

3-3-9 NumberOfLinenumbers [WORD] ->00 00 (行号表中行号的数目)

3-3-10 Characteristics [DWORD] -->40 00 00 C0 (* 该区块的读写、执行属性)

【由于FileAlignment为0x200大小,而此时整个PE头已经超过200,所以要填0到0x400处】

4 块

4-1 .text (* 此区段是一段汇编代码的16进制形式,功能是弹出一个MessageBox提示框)

-->HEX

6A 00 68 00 30 40 00 68 07 30 40 00 6A 00 E8 07

00 00 00 6A 00 E8 06 00 00 00 FF 25 08 20 40 00

FF 25 00 20 40 00

-->ASM

00401000 6A 00 PUSH 0

00401002 68 00304000 PUSH first_PE.00403000

00401007 68 07304000 PUSH first_PE.00403007

0040100C 6A 00 PUSH 0

0040100E E8 07000000 CALL

00401013 6A 00 PUSH 0

00401015 E8 06000000 CALL

0040101A FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]

00401020 FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]

【由于FileAlignment为0x200大小,而此时整个PE头未超过200,所以要填0到0x600处】

4-2 .rdata (* 该区块包含输入表)

4-2-1 IMAGE_THUNK_DA TA32 (IAT 1)

4-2-1-1 AddressOfData [DWORD] -->76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME 的RV A)

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】4-2-2 IMAGE_THUNK_DA TA32 (IAT 2)

4-2-1-2 AddressOfData [DWORD] -->5C 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME 的RV A)

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】4-2-3 IMAGE_IMPORT_DESCRIPTOR (IID 1)

4-2-3-1 OriginalFirstThunk [DWORD] -->4C 20 00 00 (* 指向输入名称表INT的RV A) 4-2-3-2 TimeDateStamp [DWORD] ->00 00 00 00 (32位的时间标志)

4-2-3-3 ForwarderChain [DWORD] ->00 00 00 00 (被转向API的索引)

4-2-3-4 Name [DWORD] -->6A 20 00 00 (* 指向DLL名字的RV A与指针)

4-2-3-5 FirstThunk [DWORD] -->08 20 00 00 (* 指向输入地址表IAT的RV A)

4-2-4 IMAGE_IMPORT_DESCRIPTOR (IID 2)

4-2-4-1 OriginalFirstThunk [DWORD] -->54 20 00 00 (* 指向输入名称表INT的RV A) 4-2-4-2 TimeDateStamp [DWORD] ->00 00 00 00 (32位的时间标志)

4-2-4-3 ForwarderChain [DWORD] ->00 00 00 00 (被转向API的索引)

4-2-4-4 Name [DWORD] -->84 20 00 00 (* 指向DLL名字的RV A与指针)

4-2-4-5 FirstThunk [DWORD] -->00 20 00 00 (* 指向输入地址表IAT的RV A)

【填充20个00h空字节做结尾标记】

4-2-5 IMAGE_THUNK_DA TA32 (INT 1)

4-2-5-1 ForwarderString [DWORD] -->5C 20 00 00 (* 指向一个转向字符的RV A)

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】4-2-6 IMAGE_THUNK_DA TA32 (INT 2)

4-2-6-1 ForwarderString [DWORD] -->76 20 00 00 (* 指向一个转向字符的RV A)

【由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。】4-2-7 IMAGE_IMPORT_BY_NAME ( 1 )

4-2-7-1 Hint [WORD] -->00 00 (* 此函数所驻留DLL的输出表序号)

4-2-7-2 Name [BYTE] -->4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16进制码)

【后跟输出此函数的DLL名称16进制码00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll】

4-2-8 IMAGE_IMPORT_BY_NAME ( 2 )

4-2-8-1 Hint [WORD] -->00 00h (* 此函数所驻留DLL的输出表序号)

4-2-8-2 Name [BYTE] -->45 78 69 74 50 72 6F 63 65 73 73 (* ExitProcess的16进制码)

【后跟输出此函数的DLL名称16进制码00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 kernel32.dll】

【由于FileAlignment为0x200大小,而此时整个PE头未超过200,所以要填0到0x800

处】

4-3 .data

填充数据

-->HEX

CF FB CF A2 BF F2 00 54 68 65 20 66 69 72 73 74

20 50 45 20 66 69 6C 65 21 20 42 59 3A 41 31 50

61 73 73 20 48 74 74 70 3A 2F 2F 61 31 70 61 73

73 2E 62 6C 6F 67 2E 31 36 33 2E 63 6F 6D 00

-->TEXT

消息框The first PE file! BY:A1Passhttps://www.doczj.com/doc/3410205443.html,

【由于FileAlignment为0x200大小,而此时整个PE头未超过200,所以要填0到0x9FF 处】

到此,介绍手工构造典型PE文件的知识就讲完了,虽然过程枯燥,但是当第一个first_PE.EXE从你手中诞生时,你会觉得这一切都太值了!这点你应该相信我,因为我当时就是这种感觉,最后祝各位成功!

本篇文章来源于黑客基地-全球最大的中文黑客站原文链接:https://www.doczj.com/doc/3410205443.html,/tech/2009-06-08/53143.html

根的形态与结构教案

华师大版《科学》八(上)第六章《植物的新陈代谢》 第一节绿色植物的营养器官(第一课时:“根的形态和结构”) 宁海县教育局教研室邵万亮 一、教材分析: 1、本节内容的地位:是学习营养器官、新陈代谢的重要基础。 2、教学目标的确立: 知识与技能:了解根的形态与结构,知道根的结构与功能相适应的辩证关系。 过程和方法:通过对不同根形态的观察、根内部结构的显微图片的观察和讨论、新培养的生有大量根毛的根尖的观察,培养学生的观察、对比、分析、归纳和协作等能力。 情感和态度:通过结构与功能相适应的关系、从根形态的一般到特殊等教育,使学生形成辩证思想;通过观察、分析讨论,激发学习兴趣,逐步形成协作精神;通过根尖的感性认识,激发学生的探究兴趣。 3、教学重点:根尖的结构及其功能是学习新陈代谢的重要基础,因此是本节教学的重点。 4、教学难点:根的伸长过程、识别根尖各部分的细胞特点,因内容抽象,故是本节教学的难点。 5、教科书内容编排:①由表及里(形态→结构→功能);②由一般到特殊、共性到个性;③重视观察、对比、分析、归纳、辩证思维等能力的培养;④了解根的一般知识。 二、课前准备 1、布置学生采集不同类型的根,教师再准备一些学生不易带来的变态根; 2、培养学生分组观察用的根尖(带根毛); 3、分组实验有关的仪器:放大镜、显微镜、根尖纵切永久切片、镊子等 三、教学过程 (一)复习引入 师:青菜是同学们熟知的植物,你们知道它有哪些器官吗? 生:根、茎、叶。 师:知道哪部分是茎吗?(展示处于营养生长期的青菜图片)。 生:指认图片上的根、茎、叶。 师:青菜还有其它器官吗? 生:花、果实、种子。 师(展示处于生殖生长期的青菜图片,认学生再认植物的整体结构,并对学生回答给予肯定,):青菜的这些器官如何分类? 生:根、茎、叶是营养器官,花、果实、种子是生殖器官。 师:这节课我们开始学习“§6-1绿色植物的营养器官”(板书)。 设计意图:复习初一知识,为引入新课作铺垫。 (二)新课教学 师:植物含有人体必须的多种营养,我们天天都要与食用一些植物,你们能各举出一种分别食用某一种器官的植物名称吗? 生:花生主食种子、黄花菜主食花、西瓜主食果实、甘蔗主食茎、萝卜主食根、菠菜主食叶(学生回答活跃,需要教师进行调控,并对答案进行评价,当教师无法评价时,可问学生“你是怎么知道它是ΧΧ器官的?”) 师:看来同学们已经认识了不少的植物,接下来认我们对植物作进一步的了解。 活动1、同学间交换观察并比较课前采集的不同根的形态和组成,根据根的形态和组成的特

pe文件格式

PE文件格式详解(一)――基础知识 什么是PE文件格式: 我们知道所有文件都是一些连续(当然实际存储在磁盘上的时候不一定是连续的)的数据组织起来的,不同类型的文件肯定组织形式也各不相同;PE文件格式便是一种文件组织形式,它是32位Wind ow系统中的可执行文件EXE以及动态连接库文件DLL的组织形式。为什么我们双击一个EXE文件之后它就会被Window运行,而我们双击一个DOC文件就会被Word打开并显示其中的内容;这说明文件中肯定除了存在那些文件的主体内容(比如EXE文件中的代码,数据等,DOC文件中的文件内容等)之外还存在其他一些重要的信息。这些信息是给文件的使用者看的,比如说EXE文件的使用者就是Window,而DOC文件的使用者就是Word。Window可以根据这些信息知道把文件加载到地址空间的那个位置,知道从哪个地址开始执行;加载到内存后如何修正一些指令中的地址等等。那么PE文件中的这些重要信息都是由谁加入的呢?是由编译器和连接器完成的,针对不同的编译器和连接器通常会提供不同的选项让我们在编译和 联结生成PE文件的时候对其中的那些Window需要的信息进行设定;当然也可以按照默认的方式编译连接生成Window中默认的信息。例如:WindowNT默认的程序加载基址是0x40000;你可以在用VC连接生成EXE文件的时候使用选项更改这个地址值。在不同的操作系统中可执行文件的格式是不同的,比如在Linux上就有一种流行的ELF格式;当然它是由在Linux上的编译器和连接器生成的,

所以编译器、连接器是针对不同的CPU架构和不同的操作系统而涉及出来的。在嵌入式领域中我们经常提到交叉编译器一词,它的作用就是在一种平台下编译出能在另一个平台下运行的程序;例如,我们可以使用交叉编译器在跑Linux的X86机器上编译出能在Arm上运行的程序。 程序是如何运行起来的: 一个程序从编写出来到运行一共需要那些工具,他们都对程序作了些什么呢?里面都涉及哪些知识需要学习呢?先说工具:编辑器-》编译器-》连接器-》加载器;首先我们使用编辑器编辑源文件;然后使用编译器编译程目标文件OBJ,这里面涉及到编译原理的知识;连接器把OBJ文件和其他一些库文件和资源文件连接起来生成EXE文件,这里面涉及到不同的连接器的知识,连接器根据OS的需要生成EXE文件保存着磁盘上;当我们运行EXE文件的时候有W indow的加载器负责把EXE文件加载到线性地址空间,加载的时候便是根据上一节中说到的PE文件格式中的哪些重要信息。然后生成一个进程,如果进程中涉及到多个线程还要生成一个主线程;此后进程便开始运行;这里面涉及的东西很多,包括:PE文件格式的内容;内存管理(CPU内存管理的硬件环境以及在此基础上的OS内存管理方式);模块,进程,线程的知识;只有把这些都弄清楚之后才能比较清楚的了解这整个过程。下面就让我们先来学习PE文件格式吧。

PE格式基础及程序的装入

DOS MZ header部分是DOS时代遗留的产物,是PE文件的一个遗传基因,一个Win32程序如果在DOS下也是可以执行,只是提示:“This program cannot be run in DOS mode.”然后就结束执行,提示执行者,这个程序要在Win32系统下执行。 DOS stub 部分是DOS插桩代码,是DOS下的16位程序代码,只是为了显示上面的提示数据。这段代码是编译器在程序编译过程中自动添加的。 PE header 是真正的Win32程序的格式头部,其中包括了PE格式的各种信息,指导系统如何装载和执行此程序代码。 Section table部分是PE代码和数据的结构数据,指示装载系统代码段在哪里,数据段在哪里等。对于不同的PE文件,设计者可能要求该文件包括不同的数据的Section。所以有一个Section Table 作为索引。Section多少可以根据实际情况而不同。但至少要有一个Section。如果一个程序连代码都没有,那么他也不能称为可执行代码。在Section Table后,Section数目的多少是不定的。 二、程序的装入 当我们在explorer.exe(资源管理器)中双击某文件,执行一个可执行程序,系统会根据文件扩展名启动一个程序装载器,称之为Loader。Loader会首先检查DOS MZ Header,如果存在,就继续寻找PE header,如果这两项都不存在,就认为是DOS 16位代码,如果只存在DOS MZ Header,而其中又指示了而其中又指示了PE Header 的位置,那么Loader 就判定此文件不一个有效的PE文件,拒绝执行。 如果DOS Header 和PE Header都正常有效,那么Loader就会根据PE Header 及Section Table的指示,将相应的代码和数据映射到内存中,然后根据不同的Section进行数据的初始化,最后开始执行程序段代码。 三、PE格式高级分析 下面我们以一个真实的程序为例详细分析PE格式,分析PE格式最好有PE分析器,常用的软件是Lord PE,也有其它的分析工具和软件如PE Editor 、Stud PE等。 先分析一下磁盘文件的内容,这里我们使用UltraEdit32(UE)工具,这是一个实用的文件编辑器,可以编辑文本和二进制文件。

(完整版)肌学知识点归纳

肌学 大纲: A总论 1.了解肌的概念 2.掌握肌的形态、构造,肌的起止和作用。 3.了解肌群配布与关节运动关系 4.了解肌的命名法,肌的辅助装置及肌的血管和神经 B头肌 1.了解面肌的配布特点及其功能 2.掌握咀嚼肌的名称、位置和功能,了解其形态,起止 C颈肌 1.了解颈肌的分层、分群及功能 2.掌握胸锁乳突肌的形态,起止和功能 3.了解舌骨上下肌群的配布和各肌群的名称 4.了解颈深肌的配布,掌握斜角肌间隙构成及其通过的内容 D躯干肌 1.了解躯干肌的组成 2.掌握背浅肌、深层各肌的名称位置、形态和主要功能。掌握斜方肌、背阔肌和竖脊肌的 起止 3.掌握胸上肢肌、胸固有肌的名称、位置、形态和功能。掌握胸大肌、前锯肌和肋间肌的 起止 4.掌握膈的位置形态,膈的裂孔的位置及其穿经结构。了解膈的生理性薄弱点位置和临床 意义 5.了解腹肌位置排列关系,掌握腹前外侧壁各肌的名称、位置、形态结构,起止和作用 6.掌握腹股沟管、腹股沟三角的构成和特点及其临床意义 E上肢肌 1.了解上肢肌的分群 2.掌握上肢带肌的配布、名称及各肌群的主要作用。掌握三角肌和大圆肌的起止 3.掌握臂肌的分群、各肌群的名称、位置和作用。了解各肌的起止 4.了解手肌的分群,各肌群的名称、位置及功能 5.了解上肢局部的位置、构成和内容 F下肢肌 1.了解下肢肌的分群 2.掌握髋肌的分群及各肌群的名称、位置和功能。掌握髂腰肌、臀大肌和梨状肌的起止 3.掌握大腿前后内侧肌群的位置、各群肌名称和功能。掌握小腿三头肌的起止 4.了解足底肌反而分群 5.了解下肢局部结构的位置、构成和内容

要点:

重要肌肉

西安邮电大学编译原理语法分析器的制作

《编译原理》实验报告题目: 语法分析器的制作 学生姓名:江荣吉 班级: 学号: 指导教师: 成绩: 西安邮电大学计算机学院 2015 年 6 月 7 日

一:实验目的 熟悉语法分析的过程; 理解相关文法的步骤; 熟悉First集和Follow集生成 二:实验要求 对于给定的文法,试编写调试一个语法分析程序: 要求和提示: (1)可选择一种你感兴趣的语法分析方法(LL(1)、算符优先、递归下降、SLR(1)等)作为编制语法分析程序的依据。 (2)对于所选定的分析方法,如有需要,应选择一种合适的数据结构,以构造所给文法的机内表示。 (3)能进行分析过程模拟。如输入一个句子,能输出与句子对应的语法树,能对语法树生成过程进行模拟;能够输出分析过程每一步符号栈的变化情 况。 设计一个由给定文法生成First集和Follow集并进行简化的算法动态模拟。 三:实验过程 1:文法: E->TE’ E’->+TE’|ε T->FT’ T’->*FT’|ε F->(E)|i: 2程序描述(LL(1)文法) 本程序是基于已构建好的某一个语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。 基本实现思想:接收用户输入的字符串(字符串以“#”表示结束)后,对用做分析栈的一维数组和存放分析表的二维数组进行初始化。然后取出分析栈的栈顶字符,判断是否为终结符,若为终结符则判断是否为“#”且与当前输入符号一样,若是则语法分析结束,输入的字符串为文法的一个句子,否则出错若不为“#”且与当前输入符号一样则将栈顶符号出栈,当前输入符号从输入字符串中除去,进入下一个字符的分析。若不为“#”且不与当前输入符号一样,则出错。

肌学重点总结

大纲要求: 1039熟悉骨骼肌或随意肌概念。肌的形态和构造,肌的起止、配在和作用。 1040描写肌的命名法,肌的辅助装置。 1041掌握头肌分部,面肌(颅顶肌、眼轮匝肌、颊肌和口轮匝肌等)分布和功能。 1042掌握咀嚼肌(颞肌、咬肌、翼内肌和翼外肌)位置和功能。 1043掌握颈肌分组,颈阔肌和胸锁乳突肌位置和功能。 1044掌握颈前肌的分群和功能。 1045掌握颈深肌的分群和功能,斜角肌间隙的概念。 1046掌握躯干肌分群。 1047掌握背浅、深肌位置和功能。 1048掌握胸肌分群,胸上肢肌和胸固有肌位置和功能。 1049掌握膈位置、形态构造特点和作用。 1050掌握腹肌分群,前外侧群和后群肌的位置和功能,腹部的局部结构。 1051掌握上肢肌分群。 1052掌握上肢带肌位置和功能,“肌腱袖”的概念。 1053掌握臂前群、后群肌的位置和功能。 1054掌握前臂前、后肌分层、位置和功能。 1055掌握手部分群,内、外侧和中间群肌的位置和功能。 1056掌握下肢肌分群。 1057掌握前、后群髋肌的位置和功能。 1058掌握前、后和内侧群大腿肌的位置和功能。 1059掌握前、后和外侧群小腿肌的位置和功能。 1060熟悉足肌分群。 肌学重点总结 1、肌根据组织结构和功能的不同可为骨骼肌、心肌和平原肌。骨骼肌是运动系统中的动力部分,多附 着于骨骼,主要存在于躯干和四肢,可随人的意志而收缩,又称随意肌。 2、每块骨骼肌包括肌腹和肌腱两部分:肌腹为肌性部分,主要由肌纤维即肌细胞组成,色红而柔软, 有收缩能力;肌腱主要由平行致密的胶原纤维束构成,色白,强韧而无收缩功能。 3、肌的形态:长肌:肌束与肌的长轴平行,收缩时肌显著缩短,可引起大幅度的运动,多见于四肢;

PE文件头解析大全

PE可选头部 PE可执行文件中接下来的224个字节组成了PE可选头部。虽然它的名字是“可选头部”,但是请确信:这个头部并非“可选”,而是“必需”的。OPTHDROFFSET宏可以获得指向可选头部的指针: PEFILE.H #define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \ ((PIMAGE_DOS_HEADER)a)->e_lfanew + \ SIZE_OF_NT_SIGNATURE + \ sizeof(IMAGE_FILE_HEADER))) 可选头部包含了很多关于可执行映像的重要信息,例如初始的堆栈大小、程序入口点的位置、首选基地址、操作系统版本、段对齐的信息等等。IMAGE_OPTIONAL_HEADER结构如下: WINNT.H typedef struct _IMAGE_OPTIONAL_HEADER { // // 标准域 // USHORT Magic; UCHAR MajorLinkerVersion; UCHAR MinorLinkerVersion; ULONG SizeOfCode; ULONG SizeOfInitializedData; ULONG SizeOfUninitializedData; ULONG AddressOfEntryPoint; ULONG BaseOfCode; ULONG BaseOfData; // // NT附加域 // ULONG ImageBase; ULONG SectionAlignment;

ULONG FileAlignment; USHORT MajorOperatingSystemVersion; USHORT MinorOperatingSystemVersion; USHORT MajorImageVersion; USHORT MinorImageVersion; USHORT MajorSubsystemVersion; USHORT MinorSubsystemVersion; ULONG Reserved1; ULONG SizeOfImage; ULONG SizeOfHeaders; ULONG CheckSum; USHORT Subsystem; USHORT DllCharacteristics; ULONG SizeOfStackReserve; ULONG SizeOfStackCommit; ULONG SizeOfHeapReserve; ULONG SizeOfHeapCommit; ULONG LoaderFlags; ULONG NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; 如你所见,这个结构中所列出的域实在是冗长得过分。为了不让你对所有这些域感到厌烦,我会仅仅讨论有用的——就是说,对于探究PE文件格式而言有用的。 标准域 首先,请注意这个结构被划分为“标准域”和“NT附加域”。所谓标准域,就是和UNIX可执行文件的COFF 格式所公共的部分。虽然标准域保留了COFF中定义的名字,但是Windows NT仍然将它们用作了不同的目的——尽管换个名字更好一些。 ·Magic。我不知道这个域是干什么的,对于示例程序EXEVIEW.EXE示例程序而言,这个值是0x010B

编译原理语法分析器实验

语法分析器的设计 一、实验内容 语法分析程序用LL(1)语法分析方法。首先输入定义好的文法书写文件(所用的文法可以用LL(1)分析),先求出所输入的文法的每个非终结符是否能推出空,再分别计算非终结符号的FIRST集合,每个非终结符号的FOLLOW集合,以及每个规则的SELECT集合,并判断任意一个非终结符号的任意两个规则的SELECT 集的交集是不是都为空,如果是,则输入文法符合LL(1)文法,可以进行分析。对于文法: G[E]: E->E+T|T T->T*F|F F->i|(E) 分析句子i+i*i是否符合文法。 二、基本思想 1、语法分析器实现 语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行词法检查,为语义分析和代码生成作准备。这里采用自顶向下的LL(1)分析方法。 语法分析程序的流程图如图5-4所示。 语法分析程序流程图 该程序可分为如下几步: (1)读入文法 (2)判断正误 (3)若无误,判断是否为LL(1)文法 (4)若是,构造分析表; (5)由句型判别算法判断输入符号串是为该文法的句型。 三、核心思想 该分析程序有15部分组成: (1)首先定义各种需要用到的常量和变量;

(2)判断一个字符是否在指定字符串中; (3)读入一个文法; (4)将单个符号或符号串并入另一符号串; (5)求所有能直接推出&的符号; (6)求某一符号能否推出‘& ’; (7)判断读入的文法是否正确; (8)求单个符号的FIRST; (9)求各产生式右部的FIRST; (10)求各产生式左部的FOLLOW; (11)判断读入文法是否为一个LL(1)文法; (12)构造分析表M; (13)句型判别算法; (14)一个用户调用函数; (15)主函数; 下面是其中几部分程序段的算法思想: 1、求能推出空的非终结符集 Ⅰ、实例中求直接推出空的empty集的算法描述如下: void emp(char c){ 参数c为空符号 char temp[10];定义临时数组 int i; for(i=0;i<=count-1;i++)从文法的第一个产生式开始查找 { if 产生式右部第一个符号是空符号并且右部长度为1, then将该条产生式左部符号保存在临时数组temp中 将临时数组中的元素合并到记录可推出&符号的数组empty中。 } Ⅱ、求某一符号能否推出'&' int _emp(char c) { //若能推出&,返回1;否则,返回0 int i,j,k,result=1,mark=0; char temp[20]; temp[0]=c; temp[1]='\0'; 存放到一个临时数组empt里,标识此字符已查找其是否可推出空字 如果c在可直接推出空字的empty[]中,返回1 for(i=0;;i++) { if(i==count) return(0); 找一个左部为c的产生式 j=strlen(right[i]); //j为c所在产生式右部的长度 if 右部长度为1且右部第一个字符在empty[]中. then返回1(A->B,B可推出空) if 右部长度为1但第一个字符为终结符,then 返回0(A->a,a为终结符) else

PE文件结构

检验PE文件的有效性 <1>首先检验文件头部第一个字的值是否等于IMAGE_DOS_SIGNATURE,是则表示DOS MZ header有效 <2>一旦证明文件的Dos header 有效后,就可用e_lfanew来定位PE header <3>比较PE header 的第一个字的值是否等于IMAGE_NT_HEADER,如果前后两个值都匹配. PS.WinHex使用方法 1.Alt+G跳到指定位置 2.Ctrl+Shift+N放入新文件 3.大文件扩容,新建一个扩容大小+1的文件,把这个文件的数据复制后写入整个文件的尾地址. 4.文本搜索ctrl+F 5.十六进制搜索ctrl+alt+x 6.文本显示F7 7.打开内存alt+F9 8.进制转换器F8 9.分析选块F2 10.计算HASH ctrl+F2 11.收集文本信息ctrl+F10 12.编辑模式F6 一.IMAGE_DOS_HEADER <1>位置00H,WORD(2个字节)的e_magic为4D5A,即MZ <2>位置3CH,60,LONG(4个节节)的e_lfanew为64+112=176即B0H, 二.IMAGE_NT_HEADERS <1>位置B0H,DWORD(4个字节),PE开始标记,写入50450000,即PE <2>位置B4H,WORD,PE所要求的CPU,对于Intel平台,为4C01 <2>位置B6,WORD,PE中段总数,计划有3个段,.text代码段,.rdata只读数据段,.data全局变量数据段,所以值为0300, <3>位置C4,WORD,表示后面的PE文件可选头的占空间大小,即224字节(E0),值为E000 <4>位置C6,WORD,表示文件是EXE还是DLL,如果是可执行文件写0200,如果是dll,写0020, <5>位置C8,WORD,表示文件格式,如果是0B01表示.exe,如果是0701表示ROM映像

编译原理课程设计报告C语言词法与语法分析器的实现

编译原理课程设计报告 课题名称:编译原理课程设计 C-语言词法与语法分析器的实现

C-词法与语法分析器的实现 1.课程设计目标 (1)题目实用性 C-语言拥有一个完整语言的基本属性,通过编写C-语言的词法分析和语法分析,对于理解编译原理的相关理论和知识有很大的作用。通过编写C-语言词法和语法分析程序,能够对编译原理的相关知识:正则表达式、有限自动机、语法分析等有一个比较清晰的了解和掌握。(2)C-语言的词法说明 ①语言的关键字: else if int return void while 所有的关键字都是保留字,并且必须是小写。 ②专用符号: + - * / < <= > >= == != = ; , ( ) [ ] { } /* */ ③其他标记是ID和NUM,通过下列正则表达式定义: ID = letter letter* NUM = digit digit* letter = a|..|z|A|..|Z digit = 0|..|9 注:ID表示标识符,NUM表示数字,letter表示一个字母,digit表示一个数字。 小写和大写字母是有区别的。 ④空格由空白、换行符和制表符组成。空格通常被忽略。 ⑤注释用通常的c语言符号/ * . . . * /围起来。注释可以放在任何空白出现的位置(即注释不能放在标记)上,且可以超过一行。注释不能嵌套。

(3)程序设计目标 能够对一个程序正确的进行词法及语法分析。 2.分析与设计 (1)设计思想 a.词法分析 词法分析的实现主要利用有穷自动机理论。有穷自动机可用作描述在输入串中识别模式的过程,因此也能用作构造扫描程序。通过有穷自动机理论能够容易的设计出词法分析器。b.语法分析 语法分析采用递归下降分析。递归下降法是语法分析中最易懂的一种方法。它的主要原理是,对每个非终结符按其产生式结构构造相应语法分析子程序,其中终结符产生匹配命令,而非终结符则产生过程调用命令。因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。其中子程序的结构与产生式结构几乎是一致的。 (2)程序流程图 程序主流程图: 词法分析: 语法分析:

编译原理实验三LL(1)语法分析器的构造教材

集美大学计算机工程学院实验报告 课程名称:编译原理指导教师:付永钢实验成绩: 实验编号:实验三实验名称:LL(1)语法分析器的构造 班级:计算12姓名:学号: 上机实践日期:2014.12上机实践时间:6学时 一、实验目的 1、掌握LL(1)分析法的基本原理; 2、掌握LL(1)分析表的构造方法; 3、掌握LL(1)驱动程序的构造方法。 二、实验环境 Windows7 x64、VC6.0 三、实验原理 1、对文法要求 LL(1)分析法属于自顶向下分析方法,因此需要预测匹配的产生式。即在LL(1)分析法中,每当在符号栈的栈顶出现非终结符时,要预测用哪个产生式的右部去替换该非终结符。LL(1)分析方法要求文法满足如下条件:对于任一非终结符A,其任意两个产生式A→α,A→β,都要满足下面条件:First(A→α)∩First(A→β)=? 2、分析表构造 LL(1)分析表的作用是对当前非终结符和输入符号确定应该选择用哪个产生式进行推导。它的行对应文法的非终结符,列对应终结符,表中的值有两种:一是产生式的编号,一是错误编号。若用T表示LL(1)分析表,则T可表示如下: T: V N×V T→P∪{Error} T(A, t) = A→α,当t∈First(A→α) T(A, t) = Error,否则 其中P表示所有产生式的集合。显然,一个文法G是LL(1)文法,当且仅当T的元素包含唯一的一个产生式或Error。 3、驱动程序构造 LL(1)分析主要包括以下四个动作,其中X为符号栈栈顶元素,a为输入流当前字符。 ●替换:当X∈V N时选相应产生式的右部β去替换X。 ●匹配:当X∈V T时它与a进行匹配,其结果可能成功,也可能失败,如果成功则 符号栈中将X退栈并将输入流指针向前移动一位,否则报错。 ●成功:当格局为(空,空)时报告分析成功。 ●报错:出错后,停止分析。 四、实验内容 已知文法G[E]: E→E+T|T T→T*F|F F→(E)|i 说明:终结符号i为用户定义的简单变量, 即标识符的定义。

编译原理实验报告《LL(1)语法分析器构造》(推荐文档)

《LL(1)分析器的构造》实验报告 一、实验名称 LL(1)分析器的构造 二、实验目的 设计、编制、调试一个LL(1)语法分析器,利用语法分析器对符号串的识别,加深对语法分析原理的理解。 三、实验内容和要求 设计并实现一个LL(1)语法分析器,实现对算术文法: G[E]:E->E+T|T T->T*F|F F->(E)|i 所定义的符号串进行识别,例如符号串i+i*i为文法所定义的句子,符号串ii+++*i+不是文法所定义的句子。 实验要求: 1、检测左递归,如果有则进行消除; 2、求解FIRST集和FOLLOW集; 3、构建LL(1)分析表; 4、构建LL分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。 四、主要仪器设备 硬件:微型计算机。 软件: Code blocks(也可以是其它集成开发环境)。 五、实验过程描述 1、程序主要框架 程序中编写了以下函数,各个函数实现的作用如下: void input_grammer(string *G);//输入文法G

//将文法G预处理得到产生式集合P,非终结符、终结符集合U、u, int eliminate_1(string *G,string *P,string U,string *GG);//消除文法G中所有直接左递归得到文法GG int* ifempty(string* P,string U,int k,int n);//判断各非终结符是否能推导为空 string* FIRST_X(string* P,string U,string u,int* empty,int k,int n);求所有非终结符的FIRST集 string FIRST(string U,string u,string* first,string s);//求符号串s=X1X2...Xn的FIRST集 string** create_table(string *P,string U,string u,int n,int t,int k,string* first);//构造分析表 void analyse(string **table,string U,string u,int t,string s);//分析符号串s 2、编写的源程序 #include #include #include using namespace std; void input_grammer(string *G)//输入文法G,n个非终结符 { int i=0;//计数 char ch='y'; while(ch=='y'){ cin>>G[i++]; cout<<"继续输入?(y/n)\n"; cin>>ch; } } void preprocess(string *G,string *P,string &U,string &u,int &n,int &t,int &k)//将文法G预处理产生式集合P,非终结符、终结符集合U、u, { int i,j,r,temp;//计数 char C;//记录规则中()后的符号 int flag;//检测到() n=t=k=0; for( i=0;i<50;i++) P[i]=" ";//字符串如果不初始化,在使用P[i][j]=a时将不能改变,可以用P[i].append(1,a) U=u=" ";//字符串如果不初始化,无法使用U[i]=a赋值,可以用U.append(1,a) for(n=0;!G[n].empty();n++) { U[n]=G[n][0]; }//非终结符集合,n为非终结符个数 for(i=0;i

手动变速器图文稿

手动变速器 集团文件版本号:(M928-T898-M248-WU2669-I2896-DQ586-M1988)

手动变速器的结构、拆装及检修 一、手动变速器的类型及功能 单选题 1.手动变速器按照齿轮的传动方式分为二轴式和(C )。 A、单轴式 B、一般式 C、三轴式 D、五轴式 2.发动机的旋转方向从前往后看为顺时针方向,且不能改变,为了实现汽车的倒向行驶,变速器中设置了( A ) A、倒档 B、空档 C、前进挡 3.下列哪一项不是变速器的功用(C) A、实现变速、变矩 B、实现倒车 C、平稳起步 D、中断动力输出 4.按变速器操纵方式分手动变速器、自动变速器和(D) A、无级变速器 B、综合变速器 C、有级变速器 D、手自一体变速器 5.无级变速器的英文缩写为(B) A、MT B、CVT C、AT D、ECVT 判断题 1.手动变速器按传动比变化的方式分为有级式、无级式和其它式 (错误)

2.手动变速器在发动机旋转方向不变的前提下,使汽车能倒退行驶。 (正确) 3.手动变速器按变速器操纵方式可分为强制操纵式、自动操纵式和半自动操纵式三种。 (正确) 4.手动变速器功用是改变传动比,不扩大驱动轮的转矩和转速的变化范围,以适应经常变化的行驶条件,如起步、加速、上坡等,使发动机在有利的工况下工作。 (错误) 5.手动变速器功用是利用倒档,中断动力传递,以使发动机能够启动,怠速,并便于变速器的换档或进行动力输出。 (错误) 二、手动变速器变速传动机构的结构 (一)、二轴式手动变速器传动机构的结构及工作原理 单选题 1.二轴式变速器的变速传动机构的输入轴和输出轴平行布置,输入轴也是( C )从动轴,输出轴也是主减速器的主动锥齿轮轴。 A、发动机 B、变速器 C、离合器 D、差速器 2.二轴式变速器用于发动机( A )的汽车。 A、前置前驱 B、后置后驱 C、前置后驱 D、4WD

根的基础知识形态种类与结构

根的基础知识形态种类与结构 根的作用是吸收土壤中水分及溶于水中的无机盐类,此外有研究报道称,大根也是合成激素、氨基酸的场所。根系对环境的水土保持作用也是很明显的。 一、根的形态及种类 胚根首先形成的是主根,主根直接与茎相连。主根上再产生的根为侧根,包括支根等。有些根不从主根产生,从茎、侧茎基部、叶产生根,称为不定根。一般单子叶植物的须根和扦插繁殖产生的根都是不定根。有些根上发出芽能生长茎,称为不定芽。植物真正吸收土壤水分、养分的根部为根毛部位,肉眼可以看到这个部位靠近根尖附近。主根、侧根、不定根都在这个部位长有根毛。 1、按根的起源和形态分为二类根系 ①直根系 主根发达,明显比侧根粗壮。大部分双子叶植物和裸子植物属此类型。 ②须根系 主根不发达或早已停止生长,从茎基部丛生许多粗细不一的不定根。大部分单子叶植物属此类型,如竹、棕榈、小麦、水稻。 2、按根在土壤中分布的深浅程度分为二类根系 ①深根系 主根发达,深入土壤,垂直向下生长,如马尾松、樟子松的根系。 ②浅根系https://www.doczj.com/doc/3410205443.html,

主根不发达,侧根或不定根向四面扩张,根系大部分在土壤表层,如刺槐、悬铃木的根系。 二、根的结构 根结构分为根尖、根初生结构、根次生结构三部分,根尖具很强的细胞分裂功能,根生长主要靠这部分。根尖、根初生结构与根伸长及各组织形成有关,根次生结构则是对根加粗的描述。以根尖结构为例,从根顶端到根上端开始生根毛的部位为根尖,一般长约0.5-1厘米,是根生长最活跃的部位。从根顶端自下而上为根冠、分生区、伸长区和根毛区(又称成熟区)四个部分。分生区也叫生长锥,由分生组织细胞组成,不断分裂细胞,往顶端分化形成根冠,往伸长区方向分裂,细胞分化形成根。根冠为几层薄壁组织细胞,不断由分生区产生,又不断与土壤摩擦损伤,因此根冠始终保持一定厚度,使根在土壤中生长时分生区不受伤害。www.lvy https://www.doczj.com/doc/3410205443.html, 根毛区密生根毛使根表面增加了吸收面,是根吸收水分、养分的主要部分。根毛区1~3周即死亡失去吸收功能,由伸长区不断形成根毛区来补充。因此,根只有不断生长才能顺利吸收土壤中的水分。 三、根瘤和菌根 某些高等植物在长期进化中,与根瘤菌(真菌)、菌根菌(细菌)相互利用,提高根的功能,形成共生关系。这些植物的根表面为根瘤和菌根。这在林业、农业上有很重要的意义。林业造林常选具有根瘤、菌根树种或接种菌种使苗木发育健康,改良土壤。 1、根瘤

语法分析器构造

编译原理实验报告实验题目:语法分析器构造 ~ 指导教师: 姓名: 班级: 学号: 。 实验成绩:

实验题目语法分析器构造 ? 实验目的和要求借助于词法分析程序提供的分析结果,编写一个算符优先语法分析程序,程序能进行语法结构分析和错误检查并产生相应的归约信息。同时给出出错信息和错误类型,从而加深对语法分析的理解。 设计思想与框架* main函数: 算术表达式函数:

算符优先算法:

核心算法主要数据结构说明: 符号栈:stack[N] 栈顶指针:top 】 记录归约步骤号:No[N] 输入字符串:strings[N] 算术表达式:old_strings[N] 记录下一个输入符号:a 可归约字符串:*word[6] 手动生成的算符优先表:x[9][9] 查找算符表达式:expression(char *str) 入栈:push(char ch)

int top=-1; int k=0;表示项.F表示因子.i表示变量或常数.\n"); printf(" 优先表\n"); printf(" + - * / ( ) i #\n"); printf(" + > > < < < > < >\n"); printf(" - > > < < < > < >\n"); printf(" * > > > > < > < >\n"); printf(" / > > > > < > < >\n"); printf(" ( < < < < < = < e1\n"); … printf(" ) > > > > e2 > e2 >\n"); printf(" i > > > > e2 > e2 >\n"); printf(" # < < < < < e3 < =\n"); if((fp=fopen("预处理.txt","r"))==NULL) { printf("文件打开失败!"); exit(0); } char ch[4048]={'\0'}; int i=0,j=0; — ch[0]=fgetc(fp); while(ch[i]!='#')//将预处理文件的内容读入至数组ch中 ch[++i]=fgetc(fp); ch[++i]='\0'; fclose(fp); i=0; while(ch[i]!='#') { memset(strings,0,sizeof(strings));//输入表达式strings初始化 memset(old_strings,0,sizeof(old_strings)); 。 expression(ch);//查找算术表达式 if(ch[sr]=='\0') break; printf("算术表达式%d为:%s\n",id,old_strings); printf("转换为输入串:%s\n",strings); printf(" 步骤号符号栈优先关系当前分析符剩余输入串动作\n"); analysis();//算符优先分析 int n=0; printf("\n算术表达式%d的归约产生式步骤号为:",id++); while(No[n]) 》 {

语法分析器的设计

编译原理 语法分析器的设计 ◆根据某一文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号串 进行分析。 ◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分 析程序。 ◆分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号 以及LL(1)分析表,对输入符号串自上而下的分析过程。 实验设计方案 1、设计思想 (1)、LL(1)文法的定义 LL(1)分析法属于确定的自顶向下分析方法。LL(1)的含义是:第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式(规则)进行推导。 LL(1)文法的判别需要依次计算FIRST集、FOLLOW集和SELLECT集,然后判断是否为LL(1)文法,最后再进行句子分析。 需要预测分析器对所给句型进行识别。即在LL(1)分析法中,每当在符号栈的栈顶出现非终极符时,要预测用哪个产生式的右部去替换该非终极符;当出现终结符时,判断其与剩余输入串的第一个字符是否匹配,如果匹配,则继续分析,否则报错。LL(1)分析方法要求文法满足如下条件:对于任一非终极符A的两个不同产生式A→α,A→β,都要满足下面条件:SELECT(A→α)∩SELECT(A→β)=? (2)、预测分析表构造 LL(1)分析表的作用是对当前非终极符和输入符号确定应该选择用哪个产生式进行推导。它的行对应文法的非终极符,列对应终极符,表中的值有两种:一是产生式的右部的字符串,一是null。若用M表示LL(1)分析表,则M可表示如下: M: VN×VT→P∪{Error} M(A, t) = A→α,当t∈select(A→α) ,否则 M(A, t) = Error

pe文件结构 入门 教程

三年前,我曾经写了一个手工打造可执行程序的文章,可是因为时间关系,我的那篇文章还是有很多模糊的地方,我一直惦记着什么时候再写一篇完美的,没想到一等就等了三年。因为各种原因直到三年后的今天我终于完成了它。现在把它分享给大家,希望大家批评指正。 我们这里将不依赖任何编译器,仅仅使用一个十六进制编辑器逐个字节的手工编写一个可执行程序。以这种方式讲解PE结构,通过这个过程读者可以学习PE结构中的PE头、节表以及导入表相关方面的知识。为了简单而又令所有学习程序开发的人感到亲切,我们将完成一个Hello World! 程序。功能仅仅是运行后弹出一个消息框,消息框的内容是Hello World!。 首先了解一下Win32可执行程序的大体结构,就是通常所说的PE结构。 如图1所示PE结构示意图: 图1 标准PE结构图 由图中可以看出PE结构分为几个部分: MS-DOS MZ 头部:所有PE文件必须以一个简单的DOS MZ 头开始。有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随MZ header 之后的DOS程序。以此达到对Dos系统的兼容。(通常情况DOS MZ header总共占用64byte)。 MS-DOS 实模式残余程序:实际上是个有效的EXE,在不支持PE文件格式的操作系统中,它将简单显

示一个错误提示,大多数情况下它是由汇编编译器自动生成。通常,它简单调用中断21h,服务9来显示字符串"This program cannot run in DOS mode"。(在我们写的程序中,他不是必须的,可以不予以实现,但是要保留其大小,大小为112byte,为了简洁,可以使用00来填充。) PE文件标志:是PE文件结构的起始标志。(长度4byte, Windows程序此值必须为0x50450000) PE文件头:是PE相关结构 IMAGE_NT_HEADERS 的简称,其中包含了许多PE装载器用到的重要域。执行体在支持PE文件结构的操作系统中执行时,PE装载器将从DOS MZ header中找到PE header的起始偏移量,跳过了MS-DOS 实模式残余程序,直接定位到真正的文件头PE header,长度20byte。 PE文件可选头:虽然它的名字是“可选头部”,但是请确信:这个头部并非“可选”,而是“必需”的。(长度 224byte )。 各段头部:又称节头部,一个Windows NT的应用程序典型地拥有9个预定义段(节),它们是“.text”、“.bss”、“.rdata”、“.data”、“.rsrc”、“.edata”、“.idata”、“.pdata”和“.debug”。一些应用程序不需要所有的这些段,同样还有些应用程序为了自己特殊的需要而定义了更多的段。(每个段头部占40byte,我们这里也不需要所有的段,仅需3个段。) 通常我们是将PE整个结构分成四个部分,把MS-DOS MZ 头部和MS-DOS 实模式残余程序作为第一部分,可以称他为DOS部分,而PE文件标志、PE文件头、PE文件可选头三个部分作为第二部分,称之为PE头部分,因为这部分才是Windows下真正需要的部分,所以从PE文件标志开始才是真正的PE部分。各段头部是第三部分,称之为节表。它详细描述了PE文件中各个节的详细信息。最后就是各个节的实体部分了,称为节数据。 以上仅仅是对PE结构各部分的大体讲解。接下来再手写这个Hello World!程序过程中,我将详细介绍每个部分的含义。 首先准备一下工具,一个十六进制编辑器足以。我们这里使用VC++ 6.0所携带的十六进制编辑器,您也可以使用如WinHex等十六进制编辑工具。 打开VC,选择文件,新建菜单项,然后选择一个二进制文件,单击确定。一切就绪了,下面就开始手写可执行程序,如图2所示:

相关主题
文本预览
相关文档 最新文档