赞
踩
什么是编程
我们编程普通理解是编写各种语法和代码,学习了专门的语法就可以将程序编好。我学习编程这么久才发现编程最终编的不是代码而是编的文件。
程序员将代码编好后,编译器要将这些代码融入到可执行文件中去组成一个完整的文件结构才能执行,光有代码部分是无法执行的。就比如说我们平常看到的文本文件,作为一个文件没有任何格式需求随便写点内容到里面,然后点开就可以看到你写入的东西。这就是最简单的文件,当然还有很多文件类型,之所以说不同的文件类型其实就是文件格式不一样,特殊的文件类型都有一定的文件格式,文件的内容由多个固定或者不固定的部分组成。比如说我们常见的可执行文件,后缀名为.exe ,也就是程序员口中的PE文件,也是我最近研究过的文件格式,这些资料网上都有,要想完整的理解程序世界就得从文件开始理解。
简单的说PE文件分为两个部分,第一部分就是头部,也就是文件头,第二部分就是尾部,也就是映射部分。头部又分为多个部分,DOS部分,附加部分,NT部分。这些部分又细分到各个结构,结构里面的数据又分为多种长度。这些数据主要是存放的代码部分和资源部分在内存中的映射偏移量。这样系统程序就可以通过文件的头部数据知道要从那些地方执行,需要资源部分的那些数据,光说不练嘴把式,下面我会贴出部分代码,后续我还会上传自己编写的辅助工具供大家参考和了解。同时如果自己想编一种文件格式的话也是可以的,我学习的是C#,还了解一点点汇编,现在比较流行的和未来的趋势是64位的程序,所以我也是编写的64位的相关程序,我代码里面将整个PE文件的格式用枚举和结构体写进了我的程序里面,本人写这些东西的第一目的是了解程序,同时也可以用来了解其他人写的程序。下面是部分代码:
/上面是PE文件头结构里的补充部分,下面是PE文件结构,从DOS结构体到可选头结构体/// /// <summary> /// /这个结构64个字节中,除了e_magic偏移为零,值为固定值常数0x4D5A,然后 最后一个变量e_lfanew偏移为0x3C指向PE文件头,其他的都没多少意义 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct IMAGE_DOS_HEADER { //这个结构64个字节中,除了e_magic偏移为零,值为固定值常数0x4D5A,然后 最后一个变量e_lfanew偏移为0x3C指向PE文件头,其他的都没多少意义,可以不用弄太明白,后面的备注有些是自己根据字面意思翻译的,不一定正确 //结构总共占64个字节,前面的数字表示元素在此结构中的偏移量 public char e_magic; //0//WORD e_magic; // Magic number DOS可执行文件标记,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'MZ'开头。 public char e_cblp; //2//WORD e_cblp; // Bytes on last page of file 文件最后一页占的字节数 ,占2个字节,最大值FFFF远大于0x200和0x1000所以用两个字节也是绰绰有余的,其他长度 也是一样的,2个字节就够了 public char e_cp; //4//WORD e_cp; // Pages in file 文件占了多少页,一页512个字节,大小用16进制表示就是0x200 , public char e_crlc; //6//WORD e_crlc; // Relocations 重定位表数量, public char e_cparhdr; //8//WORD e_cparhdr; // Size of header in paragraphs 段中头部的大小,反正没什么用, public char e_minalloc; //10//WORD e_minalloc; // Minimum extra paragraphs needed 所需扩展段最小值 public char e_maxalloc; //12//WORD e_maxalloc; // Maximum extra paragraphs needed 所需扩展段最大值, public char e_ss; //14//WORD e_ss; // Initial (relative) SS value DOS代码的初始化堆栈SS public char e_sp; //16//WORD e_sp; // Initial SP value DOS代码的初始化堆栈指针SP public char e_csum; //18//WORD e_csum; // Checksum public char e_ip; //20//WORD e_ip; // Initial IP value DOS代码的初始化指令入口[指针IP] public char e_cs; //22//WORD e_cs; // Initial (relative) CS value DOS代码的初始堆栈入口 public char e_lfarlc; //24//WORD e_lfarlc; // File address of relocation table 重定位表在文件中的起始偏移地址,也就是指向文件中的重定位表。 public char e_ovno; //26//WORD e_ovno; // Overlay number public E_RES e_res; //28//WORD e_res[4]; // Reserved words 保留字符,据说这里是占8个字节,类型用自定义的一个结构体代替 public char e_oemid; //36//WORD e_oemid; // OEM identifier (for e_oeminfo) public char e_oeminfo; //38//WORD e_oeminfo; // OEM information; e_oemid specific public E_RES2 e_res2; //40//WORD e_res2[10]; // Reserved words 保留字符,据说这里占20个字节 ,类型用自定义的一个结构体代替 public int e_lfanew; //60//LONG e_lfanew; // File address of new exe header 此数据所在文件中的偏移固定为0x3C ,此处的值也是一个文件偏移,32为系统占4个字节,64位系统也是占4个字节,因为在文件里都是相对于文件起始处的偏移量占用4个字节对于一个头部结构来说足够了,至于64位地址只要加载地址是64位然后加上文件偏移即可为内存中的地址,用来指向PE文件头结构开始的偏移地址,通过这个偏移可以找到PE文件头结构,得到PE文件标识“PE00”即0x50450000。 }
上面是PE文件头部的第一个固定部分DOS头部分,根据网上的资料,我将数据类型写入了这个固定的结构体里面,数据类型我也写成了C#里面对应的数据类型。下面全是相关的结构体,根据这些结构体数据的偏移位置,我们就可以准确的将映射到内存中的PE文件相关数据分离出来存储,同时也可以将其他加载的加壳程序有用的数据部分分离出来组成可运行程序,这些是之前一些破解加壳程序的常规办法,本人写这些东西仅供学习,知识是无罪的,学习的同时一定要知法守法。
/// <summary>
/// PE文件头是一个结构体(IMAGE_NT_HEADERS32),里面还包含两个其它结构体,占用4B + 20B + 224B
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_NT_HEADERS32
{
//PE文件头是一个结构体(IMAGE_NT_HEADERS32),里面还包含两个其它结构体,占用4B + 20B + 224B
//32+(64位)结构总共占4+20+240=264个字节,32位结构总共占4+20+224=248前面的数字表示元素在此结构中的偏移量
//64位//32位
public int Signature; //0//0//DWORD Signature; // PE文件标识 4Bytes,Signature字段设置为0x00004550,ANCII码字符是“PE00”,标识PE文件头的开始,PE标识不能破坏。0x00004550是读取后的值,内存中实际是50450000
public IMAGE_FILE_HEADER FileHeader; //4//4//IMAGE_FILE_HEADER FileHeader; // 20 Bytes
public IMAGE_OPTIONAL_HEADER32 OptionalHeader; //24//24//IMAGE_OPTIONAL_HEADER32 OptionalHeader; // 224 Bytes PE32可执行文件,PE32+的情况为240字节,我这里主要是尽力完善PE32+的,也就是64位系统的。
}
大家可以看到我结构体中又包含了其他结构体,右边注释里面我还标明的数据在结构里面的偏移量,将这些结构体和偏移对应到内存或者文件中去,就可以读取到准确的数据了。所以说编代码就是编文件,这些头部分其实是编译器完成的工作,虽然不需要我们去编写,但是可以通过文件结构了解自己编写的或者他人编写的程序。同一种文件类型任何程序员写出来的程序都要符号文件格式,不然的话系统是无法解读和运行的,所以只要你了解透了一种文件格式就能更容易的了解和掌控程序,其他的代码太多我就不贴了,后续我还会上传一些相关的自编软件和源码,喜欢C#编程的同志们一起努力吧。下面的代码我还没有写完整可以随便看一下:
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Data; using System.Threading; namespace myInjectest1 { public class PEClass64 { //这个类主要是根据PE文件结构及其映射读取内存中目标进程相关数据,这里主要就读取部分IMAGE_NT_HEADERS32结构和IMAGE_SECTION_HEADER结构中的数据。用于辅助判断相关地址所在的位置。 //比如说,我查询一个进程中的属性,我从那里开始收索,收索范围多大,最后收索到的结构到底是在那个段中。是代码段还是数据段中,就比较清楚,而且有些数据还可以用于作为基址。 //想写一个通用型辅助工具,首先就是要实现界面通信的模拟控制,其次获取界面的一些数据作为判断依据也是很重要的,所有这个类是用于实现获取数据及比对的。这里只是预备类,为后面做准备。 MyGame64 _game64;//定义一个对象 MyGame0 _game0;//定义一个对象 IntPtr _ProcessHand64;//定义一个进程句柄,64位系统的 IntPtr _ProcessHand0;//定义一个进程句柄,32位系统的 int _ProcID64;//定义一个进程ID,64位系统的 int _ProcID0;//定义一个进程ID,32位系统的 PE_File _PEFile64;//这里定义一个PE文件结构对象,可以根据这个对象的内容组成一个完整的PE文件,前提是要先读取文件信息,这个结构体是64位系统的。 public PEClass64() { //构造函数,实列话对象的时候运行 _game64 = new MyGame64();//将对象实列化 _game0 = new MyGame0();//将对象实列化 _ProcessHand64 = _game64.ProcessHand;//赋值,方便 使用 _ProcessHand0 = _game0.ProcessHand;//赋值,方便 使用 _ProcID64 = _game64.ProcessID;//赋值,方便 使用 _ProcID0 = _game0.ProcessID;//赋值,方便 使用 _PEFile64 = new PE_File();//虽然这里实列化了结构体对象,但这个对象里面包含的字节数组现在都还是空的,实际数据要读取PE文件信息的时候写入进去。 } /// <summary> /// 这是一个MyGame64类的对象属性,可读可赋值 /// </summary> public MyGame64 Game64 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值,有利于传递对象 set { _game64=value;} get { return _game64; } } /// <summary> /// 这是一个MyGame0类的对象,可读可赋值,这个类支持的是32位的一些方法 /// </summary> public MyGame0 Game0 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值,有利于传递对象 set { _game0 = value; } get { return _game0; } } /// <summary> /// 这个属性表示一个进程的句柄,初始化是从MyGame64类中的属性赋值得到的,可读可赋值 /// </summary> public IntPtr ProcessHand64 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值 set { _ProcessHand64 = value; } get { return _ProcessHand64; } } /// <summary> /// 这个属性表示一个进程的句柄,初始化是从MyGame0类中的属性赋值得到的,可读可赋值 /// </summary> public IntPtr ProcessHand0 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值 set { _ProcessHand0 = value; } get { return _ProcessHand0; } } /// <summary> /// 这个属性表示一个进程的唯一标识ID,初始化是从MyGame64类中的属性赋值得到的,可读可赋值 /// </summary> public int ProcID64 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值 set { _ProcID64 = value; } get { return _ProcID64; } } /// <summary> /// 这个属性表示一个进程的唯一标识ID,初始化是从MyGame0类中的属性赋值得到的,可读可赋值 /// </summary> public int ProcID0 { //这里定义一个对象属性,表明除了构造函数实列化一个对象外,也可以直接将现有的对象传递过来赋值 set { _ProcID0 = value; } get { return _ProcID0; } } /// <summary> /// 这个结构体类型属性保存的是一个完成的PE文件相关的信息,可以用此结构体对象中的数据组成完整PE文件,也可以修改这个结构体中包含的字节数组里的相关数据,可读可赋值。此结构体只支持64位系统。实际上只有数据目录多了几个固定的大小而已,其他的都是一样的偏移量。 /// </summary> public PE_File PEfileData64 { //这个PE文件属性说明可以根据PE文件结构数据既可读也可写 set { _PEFile64 = value; } get { return _PEFile64; } } //这个类是用于PE文件,及内存中结构的学习和研究,微软对64位Windows平台上的PE文件结构叫做PE32+,就是把那些原来32位的字段变成了64位。 //识别一个文件是不是PE文件不应该只看文件后缀名,还应该通过PE指纹,打开一个exe文件,发现文件的头两个字节都是MZ,0x3C位置保存着一个地址,查该地址处发现保存着“PE”,通过这些重要的信息(“MZ”和“PE”)验证文件是否为PE文件,这些信息即PE指纹。 //PE结构,此部分只用来注释结构组成,用来说明和展示PE结构包含的相关部分,真正的结构在后面定义 /* DOS部分 { IMAGE_DOS_HEADER结构; DOS MZ 文件头 实际是一个64字节的IMAGE_DOS_HEADER结构体 DOS Stub; 链接器填充的信息,大小不确定,不重要,主要有一段DOS上运行的代码段说,this Program cannot be run in DOS mode 说这个程序不能在DOS模式下运行。 虽然链接器填充的信息大小不确定,但是IMAGE_DOS_HEADER结构体的最后一个元素指明了下一个结构体PE文件头的偏移量。 } PE文件头 {包含多个结构的IMAGE_NT_HEADER32结构体 “PE”.0.0 ; PE文件头标志,signature 占4个字节 IMAGE_FILE_HEADER结构;PE文件表头,占20个字节 IMAGE_OPTIONAL_HEADER32结构;PE文件表头可选部分,占224字节 16xIMAGE_DATE_DIRECTORY结构;也是PE文件表头可选部分IMAGE_OPTIONAL_HEADER32的最后一部分,是数据目录表结构,16x表示有16个这样的结构,这是32位程序,64位程序多两个这样的结构,所以是18个。32位占224个字节,64位占240个字节。 } 节表 { n x IMAGE_SECTION_HEADER结构; 由n个IMAGE_DOS_HEADER结构组成的,每个结构占40个字节且是按顺序排列,其中包含了块名、位置、长度、属性 、调试相关 } 节数据;由不同属性数据组成的不同节,其中包括.text节、.data节、.rsrc节、.reloc节等等 */ //PE文件到内存的映射 //PE文件存储在磁盘时的结构和加载到内存后的结构有所不同。 //当PE文件通过Windows加载器载入内存后,内存中的版本称为模块(Module),映射文件的起始地址称为模块句柄(hModule),也称为基地址(ImageBase)。 //文件数据一般512字节(1扇区)对齐(现也多4k),32位内存一般4k(1页)对齐,512D = 200H,4096D = 1000H 文件中块的大小为200H的整数倍,内存中块的大小为1000H的整数倍,映射后实际数据的大小不变,多余部分可用0 //填充:PE文件头部(DOS头+PE头)到块表之间没有间隙,然而他们却和块之间有间隙,大小取决于对齐参数 /// <summary> /// 这里定义一个占8个字节的结结构体是专门为了IMAGE_DOS_HEADER结构,不重要的数据 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct E_RES { //这里定义一个占8个字节的结结构体是专门为了IMAGE_DOS_HEADER结构,不重要的数据 public char e_res1; public char e_res2; public char e_res3; public char e_res4; } /// <summary> /// 这里定义一个占20个字节的结结构体是专门为了IMAGE_DOS_HEADER结构,不重要的数据 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct E_RES2 { //这里定义一个占20个字节的结结构体是专门为了IMAGE_DOS_HEADER结构,不重要的数据 public char e_res1; public char e_res2; public char e_res3; public char e_res4; public char e_res5; public char e_res6; public char e_res7; public char e_res8; public char e_res9; public char e_res10; } /// <summary> /// 这里定义一个占8个字节的结构专门为IMAGE_SECTION_HEADER放置节名称的如:.text节、.data节、.rsrc节、.reloc节等等 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct IMAGE_SIZEOF_SHORT_NAME { //这里定义一个占8个字节的结构专门为IMAGE_SECTION_HEADER放置节名称的如:.text节、.data节、.rsrc节、.reloc节等等 public byte bt1; public byte bt2; public byte bt3; public byte bt4; public byte bt5; public byte bt6; public byte bt7; public byte bt8; } /// <summary> ///这个结构是为IMAGE_OPTIONAL_HEADER32最后一个元素准备的数据结构表,最大有18个IMAGE_DATA_DIRECTORY结构,也就是数据目录表,32位系统最大有16个IMAGE_DATA_DIRECTORY结构,64位系统多给出16个字节,经验证应该是多给出了两个IMAGE_DATA_DIRECTORY结构,所以是18个。即使没有这么多表也是用零补齐的。数据目录表的第1个成员指向输出表 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct IMAGE_DATA_DIRECTORY_S { //这个结构是为IMAGE_OPTIONAL_HEADER32最后一个元素准备的数据结构表,最大有18个IMAGE_DATA_DIRECTORY结构,也就是数据目录表,即使没有这么多表也是用零补齐的。数据目录表的第1个成员指向输出表 //这个数据目录表结构总共占8*18=144个字节,前面的数字表示元素在此结构中的偏移量。32位系统最大有16个IMAGE_DATA_DIRECTORY结构,64位系统多给出16个字节,经验证应该是多给出了两个IMAGE_DATA_DIRECTORY结构,所以是18个。 public IMAGE_DATA_DIRECTORY DataDirectory1; //0//第一个结构指向输出表 public IMAGE_DATA_DIRECTORY DataDirectory2; //8// public IMAGE_DATA_DIRECTORY DataDirectory3; //16// public IMAGE_DATA_DIRECTORY DataDirectory4; //24// public IMAGE_DATA_DIRECTORY DataDirectory5; //32// public IMAGE_DATA_DIRECTORY DataDirectory6; //40// public IMAGE_DATA_DIRECTORY DataDirectory7; //48// public IMAGE_DATA_DIRECTORY DataDirectory8; //56// public IMAGE_DATA_DIRECTORY DataDirectory9; //64// public IMAGE_DATA_DIRECTORY DataDirectory10; //72// public IMAGE_DATA_DIRECTORY DataDirectory11; //80// public IMAGE_DATA_DIRECTORY DataDirectory12; //88// public IMAGE_DATA_DIRECTORY DataDirectory13; //96// public IMAGE_DATA_DIRECTORY DataDirectory14; //104// public IMAGE_DATA_DIRECTORY DataDirectory15; //112// public IMAGE_DATA_DIRECTORY DataDirectory16; //120// public IMAGE_DATA_DIRECTORY DataDirectory17; //128// public IMAGE_DATA_DIRECTORY DataDirectory18; //136 } /// <summary> /// IMAGE_FILE_HEADER 的最后一个元素的值的枚举,表示文件属性,指示文件是什么属性,而且文件属性可以多个属性用"或运算"的方法同时拥有,也就是可以多个属性并存 /// </summary> public enum FILE_Characteristics { //IMAGE_FILE_HEADER 的最后一个元素的值的枚举,表示文件属性,指示文件是什么属性,而且文件属性可以多个属性用"或运算"的方法同时拥有,也就是可以多个属性并存 IMAGE_FILE_RELOCS_STRIPPED = 0x0001, //文件中不存在重定位信息 IMAGE_FILE_EXECUTABLE_IMAGE= 0x0002, //文件是可执行的 IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004, //不存在行信息 IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008, //不存在符号信息 IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010, //调整工作集 IMAGE_FILE_LARGE_ADDRESS_AWARE=0x0020, //应用程序可以处理大于2G的地址 IMAGE_FILE_BYTES_REVERSED_LO = 0x0080, //小尾方式 IMAGE_FILE_32BIT_MACHINE = 0x0100, //只在32位平台上运行 IMAGE_FILE_DEBUG_STRIPPED = 0x0200, //不包含调试信息 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400, //不能从可移动磁盘运行 IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800, //不能从网络运行 IMAGE_FILE_SYSTEM = 0x1000, //系统文件(如驱动程序)不能直接运行 IMAGE_FILE_DLL = 0x2000, //这是一个DLL文件 IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000, //文件不能在多处理器计算机上运行 IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 //大尾方式 } /// <summary> /// 这个属性主要是跟映射基址的模式相关,不过现在高级版本的系统都实现了加载基址的随机化的保护,这些属性设置了也没用,已经一去不复返。 /// </summary> public enum OPTIONAL_DllCharacteristics { //这些值来源于网页:https://blog.csdn.net/qwq1503/article/details/102511054 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040, // DLL can move.() IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080, // Code Integrity Image (统一基址) IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100, // Image is NX compatible () IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, // Image understands isolation and doesn't want it () IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, // Image does not use SEH. No SE handler may reside in this image () IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, // Do not bind this image.() Reserved1 = 0x1000, // Reserved. IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, // Driver uses WDM model () Reserved2 = 0x4000, // Reserved. IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 } /// <summary> /// IMAGE_SECTION_HEADER 的最后一个元素的值的枚举,表示节的属性,也类似于内存属性,表示这段数据是只读,能读能写,或者是可执行代码等等属性,也是可以通过“或运算”同时拥有多个属性的。 /// </summary> public enum SECTION_Characteristics:uint { //IMAGE_SECTION_HEADER 的最后一个元素的值的枚举,表示节的属性,也类似于内存属性,表示这段数据是只读,能读能写,或者是可执行代码等等属性,也是可以通过“或运算”同时拥有多个属性的。 Reserved1 = 0x00000000,//是一个保留枚举元素 Reserved2 = 0x00000001,//是一个保留枚举元素 Reserved3 = 0x00000002,//是一个保留枚举元素 Reserved4 = 0x00000003,//是一个保留枚举元素 IMAGE_SCN_TYPE_NO_PAD = 0x00000008, Reserved5 = 0x00000010,//是一个保留枚举元素 IMAGE_SCN_CNT_CODE = 0x00000020,//表明节中包含代码 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,//节中包含已初始化数据 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,//节中包含未初始化数据 IMAGE_SCN_LNK_OTHER = 0x00000100,//这也是一个保留枚举元素 IMAGE_SCN_LNK_INFO = 0x00000200,//The section contains comments or other information. This is valid only for object files. Reserved6 = 0x00000400,//是一个保留枚举元素 IMAGE_SCN_LNK_REMOVE = 0x00000800,//The section will not become part of the image. This is valid only for object files. IMAGE_SCN_LNK_COMDAT = 0x00001000,//The section contains COMDAT data. This is valid only for object files. Reserved7 = 0x00002000,//是一个保留枚举元素 IMAGE_SCN_NO_DEFER_SPEC_EXC = 0x00004000,//Reset speculative exceptions handling bits in the TLB entries for this section. IMAGE_SCN_GPREL = 0x00008000,//The section contains data referenced through the global pointer. Reserved8 = 0x00010000,//是一个保留枚举元素 IMAGE_SCN_MEM_PURGEABLE = 0x00020000,//这也是一个保留枚举元素 IMAGE_SCN_MEM_LOCKED = 0x00040000,//这也是一个保留枚举元素 IMAGE_SCN_MEM_PRELOAD = 0x00080000,//这也是一个保留枚举元素 IMAGE_SCN_ALIGN_1BYTES = 0x00100000,//Align data on a 1-byte boundary. This is valid only for object files.意思就是对齐数据以一个字节为边界,只对应用程序对象文件有效,与映射内存无关的 IMAGE_SCN_ALIGN_2BYTES = 0x00200000,//数据以2个字节对齐,也只适用于对象文件,后面的都是差不多,就是对齐的字节数不同,最大是8K IMAGE_SCN_ALIGN_4BYTES = 0x00300000,// IMAGE_SCN_ALIGN_8BYTES = 0x00400000,// IMAGE_SCN_ALIGN_16BYTES = 0x00500000,// IMAGE_SCN_ALIGN_32BYTES = 0x00600000,// IMAGE_SCN_ALIGN_64BYTES = 0x00700000,// IMAGE_SCN_ALIGN_128BYTES = 0x00800000,// IMAGE_SCN_ALIGN_256BYTES = 0x00900000,// IMAGE_SCN_ALIGN_512BYTES = 0x00A00000,// IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000,// IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,// IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,// IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,// IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,//NumberOfRelocations field in the section header is 0xffff, the actual relocation count is stored in the VirtualAddress field of the first relocation. It is an error ifIMAGE_SCN_LNK_NRELOC_OVFL is set and there are fewer than 0xffff relocations in the section. IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,//节中数据在进程开始以后将被丢弃,如.reloc节 IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,//节中数据不会经过缓存 IMAGE_SCN_MEM_NOT_PAGED = 0x08000000,//节中数据不会被交换到磁盘 IMAGE_SCN_MEM_SHARED = 0x10000000,//节中的数据将被不同的进程共享 IMAGE_SCN_MEM_EXECUTE = 0x20000000,//映射到内存后的页面包含可执行属性 IMAGE_SCN_MEM_READ = 0x40000000,//映射到内存后的页面包含可读属性 IMAGE_SCN_MEM_WRITE = 0x80000000//映射到内存后的页面包含可写属性 } /// <summary> /// IMAGE_FILE_HEADER 的第一个元素,可运行的机器上,也就是表示能在什么CPU上运行,这里是机器种类也是CPU种类 /// </summary> public enum IMAGE_FILE_MACHINE { //IMAGE_FILE_HEADER 的第一个元素,可运行的机器上,也就是表示能在什么CPU上运行,这里是机器种类也是CPU种类 IMAGE_FILE_MACHINE_I386 = 0x014c, //x86 也就是32位系统 IMAGE_FILE_MACHINE_IA64 = 0x0200, //Intel Itanium 安腾处理器也是64位的 IMAGE_FILE_MACHINE_AMD64 = 0x8664 //x64 也就是64位系统 } /上面是PE文件头结构里的补充部分,下面是PE文件结构,从DOS结构体到可选头结构体/// /// <summary> /// /这个结构64个字节中,除了e_magic偏移为零,值为固定值常数0x4D5A,然后 最后一个变量e_lfanew偏移为0x3C指向PE文件头,其他的都没多少意义 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct IMAGE_DOS_HEADER { //这个结构64个字节中,除了e_magic偏移为零,值为固定值常数0x4D5A,然后 最后一个变量e_lfanew偏移为0x3C指向PE文件头,其他的都没多少意义,可以不用弄太明白,后面的备注有些是自己根据字面意思翻译的,不一定正确 //结构总共占64个字节,前面的数字表示元素在此结构中的偏移量 public char e_magic; //0//WORD e_magic; // Magic number DOS可执行文件标记,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'MZ'开头。 public char e_cblp; //2//WORD e_cblp; // Bytes on last page of file 文件最后一页占的字节数 ,占2个字节,最大值FFFF远大于0x200和0x1000所以用两个字节也是绰绰有余的,其他长度 也是一样的,2个字节就够了 public char e_cp; //4//WORD e_cp; // Pages in file 文件占了多少页,一页512个字节,大小用16进制表示就是0x200 , public char e_crlc; //6//WORD e_crlc; // Relocations 重定位表数量, public char e_cparhdr; //8//WORD e_cparhdr; // Size of header in paragraphs 段中头部的大小,反正没什么用, public char e_minalloc; //10//WORD e_minalloc; // Minimum extra paragraphs needed 所需扩展段最小值 public char e_maxalloc; //12//WORD e_maxalloc; // Maximum extra paragraphs needed 所需扩展段最大值, public char e_ss; //14//WORD e_ss; // Initial (relative) SS value DOS代码的初始化堆栈SS public char e_sp; //16//WORD e_sp; // Initial SP value DOS代码的初始化堆栈指针SP public char e_csum; //18//WORD e_csum; // Checksum public char e_ip; //20//WORD e_ip; // Initial IP value DOS代码的初始化指令入口[指针IP] public char e_cs; //22//WORD e_cs; // Initial (relative) CS value DOS代码的初始堆栈入口 public char e_lfarlc; //24//WORD e_lfarlc; // File address of relocation table 重定位表在文件中的起始偏移地址,也就是指向文件中的重定位表。 public char e_ovno; //26//WORD e_ovno; // Overlay number public E_RES e_res; //28//WORD e_res[4];
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。