010 editor手写pe文件

原则:严谨细节

【文章标题】: 010 editor手写pe文件
【文章作者】: Clark
【作者邮箱】: lost_poet@foxmail.com
【作者QQ号】: 515996958
【软件名称】:弹窗Hello World! 
【软件大小】: 3K 
【使用工具】: 010 editor
【操作平台】: Win10 x64
 
【声明:复习PE文件结构】
PE文件的结构的重要性毋庸置疑,在软件逆向,漏洞分析,以及病毒分析中均至关重要,所以PE文件的结构必须不能忘,计划隔一段就自己手写一个PE程序以温故知新

正题:

PE文件结构;(Portable Executable(可移植的执行体)):
--------------------------------------
DOS头部
(IMAGE_DOS_HEADER)
DOS HEADER DosHeader 64byte(40h) 为兼容DOS程序而立
DOS 头使用的数据(此段不重要) DOS STUB DosStub 大小取决于DOS头的最后一个元素
因为e_lfanew记录的NT 头的偏移的位置
(可以将PE头部放在这里,甚至使DOS头与PE头重合
NT头
(IMAGE_NT_HEADER32)
NT HEADRS NtHeader DWORD Signature                             标记4byte
IMAGE_FILE_HEADER FileHeader  文件头20byte
IMAGE_OPTIONAL_HEADER32 OPtionlHeader 扩展头,32位00E0,64位00F0
存储PE文件的全部属性,初始化信息等(包含,文件头,扩展头)
区段头表(结构体数组)
(IMAGE_SECTION_HEADER)
SECTION HEADER SectionHeader 每个区段头40byte 对于PE文件主体属性的分段描述,个数不定
各个区段(常见的区段) .text                   一般是代码段
.data                  一般是数据段
.bss             表示未初始化的数据,像static变量
.rdata                  表示只读的数据,比如字符串
.textbss               和代码有关,暂不清楚作用
.idata和edata      存储导入表导出表的信息
.rsrc                    存储资源的区段
.relcoc                存储重定位的区段
个数不定,
大小视程序决定,
我们自己写的简单的helloworld,三个区段,各200byte 足够了
PE文件的主体,分段存储着可执行的代码,各种数据,资源等
一些调试信息 暂时不表述 暂时不表述 暂时不表述
 
 所有的PE文件(exe,dll)必须以DOS头开始;
 
//DOS头---需要设置的有两个元素
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number(魔数,值恒为4D5A)
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header(NT 头的偏移)可以自己填写
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
//NT头--都很重要,文件头跟扩展头需要细说
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                           //标记,判断是否是PE文件的第二个标志,恒为0x00004550,ASCII为“PE00”
    IMAGE_FILE_HEADER FileHeader;              //文件头
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;    //扩展头 
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
//文件头---共20个字节
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;                                1,文件的运行CPU平台-------0x014c,i386,,0x0200代表64位平台
    WORD    NumberOfSections;                       2,区段的数量-------------我们这个程序写成3个区段
    DWORD   TimeDateStamp;                          3,文件的创建时间---------不太重要,0x00000000
    DWORD   PointerToSymbolTable;                   4,符号表偏移------------对程序执行无影响,0x00000000
    DWORD   NumberOfSymbols;                        5,符号个数--------------对程序执行无影响,0x00000000
    WORD    SizeOfOptionalHeader;                   6,扩展头大小------------扩展头大小一般32位是00E0,64位是00F0
    WORD    Characteristics;                        7,PE文件的一些属性------dll一般是0x0210,exe是0x010F
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
//扩展头31个成员--扩展头大小一般32位是00E0,64位是00F0
typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic;                                                                         1,标志PE文件的类型,32位一般是0X010B,64位是0x020B,0X0107表示ROM映像
    BYTE    MajorLinkerVersion;                                                            2,链接器主板本号,可以0x00000000
    BYTE    MinorLinkerVersion;                                                            3,链接器此版本号,可以0x00000000
    DWORD   SizeOfCode;                                                                    4,代码区段的大小,不影响执行,可以0x00000000
    DWORD   SizeOfInitializedData,                                                         5,已初始化数据的大小,不影响执行,可以0x00000000
    DWORD   SizeOfUninitializedData;                                                       6,未初始化数据的大小,不影响执行,可以0x00000000
    DWORD   AddressOfEntryPoint;                                                           7,程序执行入口RVA,OEP,一般.text段是代码段,所以这个值是.text段的首地址,但是应该是内存对齐后的
                                                                                              而我们整个pe头在内存中对齐后也就能占用1000,所以这个值是1000
    DWORD   BaseOfCode;                                                                    8,起始代码的RVA,不影响执行,可以0x00000000
    DWORD   BaseOfData;                                                                    9,起始数据的RVA,不影响执行,可以0x00000000
    // NT additional fields.                                                         
    DWORD   ImageBase;                                                                     10,默认加载基址:如果没有加载到这个基址,会发生重定位,必须是64K的倍数,DLL是0x100 0000--- PE装载器将尝试把文件装到虚拟地址空间的0040 0000h处。                                                                                                          字眼"优先"表 示若该地址区域已被其他模块占用,那PE装载器会  选用其他空闲地址。我们这里的值设为“00400000”。
    DWORD   SectionAlignment;                                                              11,块对齐单位---一般是0X1000
    DWORD   FileAlignment;                                                                 12,文件对齐单位-一般是0X200
    WORD    MajorOperatingSystemVersion;                                                   13,主操作系统版本号,可以0x00000000
    WORD    MinorOperatingSystemVersion;                                                   14,次操作系统版本号,可以0x00000000
    WORD    MajorImageVersion;                                                             15,主映像版本,可以0x00000000
    WORD    MinorImageVersion;                                                             16,次映像版本,可以0x00000000
    WORD    MajorSubsystemVersion;                                                         17,主子系统版本,可以0x00000000
    WORD    MinorSubsystemVersion;                                                         18,次子系统版本,win32子系统版本。PE文件是专门为Win32设计的,该子系统版本必定是4.0那么此处值为“04”。
    DWORD   Win32VersionValue;                                                             19,保留值,,可以0x00000000
    DWORD   SizeOfImage;                                                                   20,映像大小,要把文件加载进内存需要的总大小,内存对齐后的--文件PE结构总长小于1000h,但是内存中的对齐粒度是1000h,所以PE结构被映射后要占1000h,
                                                                                              尽管很多空间没有使用,另外我们有3个段,每个段的长度小于1000h,但是被映射后同样要占1000h,
                                                                                              所以总共占用内存的大  小为1000h + 3* 1000h = 4000h,因此此值为“00400000”。
    DWORD   SizeOfHeaders;                                                                 21,所有头部大小,也是文件主体相对文件偏移的位置,文件对齐后的,
                                                                                                DOS头+sub+文件头中的Signature+NT头+扩展头+3个区段头;
                                                                                                64   +80 +  4               + 20 +  224 +  3*40   =  512  =  200h,以200h对齐后,实际为200h的空间,0x00020000
    DWORD   CheckSum;                                                                      22,校验和,可以0x00000000
    WORD    Subsystem;                                                                     23,子系统平台,在windows中的合法值只能是2或者3,2是GUI,表示无控制台,3是CUI,表示带控制台
    WORD    DllCharacteristics;                                                            24,指示Dll特征的标志,可以0x00000000
    DWORD   SizeOfStackReserve;                                                            25,进程中栈一般可以增长到的最大值,一般是1MB,可以0x00000000
    DWORD   SizeOfStackCommit;                                                             26,栈的初始值,每次分配增长的值,一般是4kb,填为0x04000000
    DWORD   SizeOfHeapReserve;                                                             27,堆可以增长到的最大值,一般是1mb,可以0x00000000
    DWORD   SizeOfHeapCommit;                                                              28,进程堆的初始值,可以0x00000000
    DWORD   LoaderFlags;                                                                   29,无用,可以0x00000000
    DWORD   NumberOfRvaAndSizes;                                                           30,数据目录表的个数,也就是下面那个数组的元素个数,,按照正常的PE格式此处应该为0x10,可改动,需重新研究位置
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];                  31,数据目录表,
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

//区段头表--每一个区段头表中都是以下这个结构体--40个字节
typedef struct _IMAGE_SECTION_HEADER { 
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];     1,区段的名字,只是一些约定俗称的名称
union { 
DWORD PhysicalAddress;                
DWORD VirtualSize; 
} Misc;                                  2,这个区段的大小,pe程序对此值的效验并没有那么严谨,但是最好与SizeOfRawData的值一致
DWORD VirtualAddress;                    3,区段的起始相对虚拟地址RVA,,比如我们.text是第一个区段,之前的所有文件大小对齐后占用的空间为1000h,那么这个值便是1000h,第二个区段的这个值是2000h
DWORD SizeOfRawData;                     4,区段在文件中的大小,是对齐后的,我们的代码较少,则这个值便是200h
DWORD PointerToRawData;                  5,区段的文件偏移,,,我们上面计算的PE文件头的大小刚好是200h,那么这个值便是200h,,后面的每个区段的这个值是,当前区段的SizeOfRawData+前一个区段的PointerToRawData
DWORD PointerToRelocations;              6,区段的重定位的信息的文件偏移,早OBJ文件中可用
DWORD PointerToLinenumbers;              7,没用
WORD NumberOfRelocations;                8,没用
WORD NumberOfLinenumbers;                9,没用
DWORD Characteristics;                  10,重要,这个区段的属性,(如代码/数据/可读/可写)的标志
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

PE文件识别区段靠的不是区段的名字,是区段的属性
//比较重要的区段属性值
IAMGE_SCN_CNT_CODE                           0x20h            包含代码,常与10000000h 一起设置
IMAGE_SCN_CNT_INITIALIZED_DATA               0x40h            该块包含已初始化的数据
IMAGE_SCN_CNT_UNINITIALIZED_DATA             0x80h            该块包含未初始化的数据
IAMGE_SCN_MEM_DISCARDABLE              0x02000000h            该块可被丢弃,一旦加载可被丢弃的块.reloc(重定位块)
IAMGE_SCN_MEM_SHARED                   0x10000000h            该块为共享块
IAMGE_SCN_MEM_EXECUTE                  0x20000000h            该块可执行通常与0x20标志一起被设置
IAMGE_SCN_MEM_READ                     0x40000000h            该块可读
IAMGE_SCN_MEM_WRITE                    0x80000000h            该块可写


常用区段设置的值:
.text              0x6000 0020 内存中 20 00 00 60
.textbss           0xE000 00A0 内存中 A0 00 00 E0
.data              0xC000 0040 内存中 40 00 00 C0
.rdata             0x4000 0040 内存中 40 00 00 40
.idata             0x4000 0040 内存中 40 00 00 40
.rerc              0x4000 0040 内存中 40 00 00 40
以上填写完毕后代码如下:
4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 90 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50 45 00 00 4C 01 03 00 00 00 00 00 00 00 00 00
00 00 00 00 E0 00 0F 01 0B 01 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00
00 00 00 00 00 00 40 00 00 10 00 00 00 02 00 00
00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
00 40 00 00 00 02 00 00 00 00 00 00 03 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
10 20 00 00 3C 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 2E 74 65 78 74 00 00 00
00 02 00 00 00 10 00 00 00 02 00 00 00 02 00 00
00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 60
2E 72 64 61 74 61 00 00 00 02 00 00 00 20 00 00
00 02 00 00 00 04 00 00 00 00 00 00 00 00 00 00
00 00 00 00 40 00 00 40 2E 64 61 74 61 00 00 00
00 02 00 00 00 30 00 00 00 02 00 00 00 06 00 00
00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 C0
以上我们已经完全解析了文件头部的问题,还有个问题就是数据目录表的结构:
我们这个手写程序只需要用到导入表,所以我门只需要解析导入表即可,其余全部置零即可
导入表是数据目录表的第二项,当前我们暂时把它也置零 ,后面我们把.rdata段写好,来填写这两个值
 
每个数据目录表的结构:
typedef struct _IMAGE_DATA_DIRECTORY { 
DWORD VirtualAddress;        数据的相对虚拟地址 
DWORD Size;                  数据的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

数据目录表的16个成员
IMAGE_DIRECTORY_ENTRY_EXPORT            (0)导出表  
IMAGE_DIRECTORY_ENTRY_IMPORT            (1)导入表    
IMAGE_DIRECTORY_ENTRY_RESOURCE          (2)资源表    
IMAGE_DIRECTORY_ENTRY_EXCEPTION         (3)异常表    
IMAGE_DIRECTORY_ENTRY_SECURITY          (4)安全目录    
IMAGE_DIRECTORY_ENTRY_BASERELOC         (5)重定位表    
IMAGE_DIRECTORY_ENTRY_DEBUG             (6)调试目录
IMAGE_DIRECTORY_ENTRY_COPYRIGHT         (7)描述版权串    
IMAGE_DIRECTORY_ENTRY_GLOBALPTR         (8)机器值    
IMAGE_DIRECTORY_ENTRY_TLS               (9)指向线程局部存储(Thread local storage)初始化节
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG       (10)载入配置表    
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT      (11)绑定输入目录    
IMAGE_DIRECTORY_ENTRY_IAT               (12)导入地址表目录
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT      (13)延迟载入描述
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR    (14)COM信息

导出表(此程序用不到,仅供复习);

//导出表结构---40字节
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;                //1,没用,保留值,长为0
    DWORD   TimeDateStamp;                  //2,没用,和文件头中的时间一样的
    WORD    MajorVersion;                   //3,没用,主板本号
    WORD    MinorVersion;                   //4,没用,次版本号
    DWORD   Name;                           //5,有用,本PE文件的名字,也就是谁导出的这些函数(变量,类)
    DWORD   Base;                           //6,有用,序号基数
    DWORD   NumberOfFunctions;              //7,重要,函数数量
    DWORD   NumberOfNames;                  //8,函数名称数量
    DWORD   AddressOfFunctions;             //9,重要,函数地址表的相对虚拟地址// RVA from base of image
    DWORD   AddressOfNames;                 //10,重要,函数名称表的相对虚拟地址/// RVA from base of image
    DWORD   AddressOfNameOrdinals;          //11,重要,函数序号表的相对虚拟地址/// RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

下面解析导入表:

//导入表结构---20字节
如果程序从10个不同的dll中导入函数,那么这个数组就有10个成员,该数组以一个全0的成员结尾
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 
        DWORD   OriginalFirstThunk;         //1,重要,指向一个结构体数组的相对虚拟地址,RVA,结构体数组名叫做INT,(import Name table)
    } DUMMYUNIONNAME;                    
    DWORD   TimeDateStamp;                  //2,(没用)   
    DWORD   ForwarderChain;                 //3,转发机制用,这里用不到       
    DWORD   Name;                           //4,导入的PE文件的名字
    DWORD   FirstThunk;                     //5,指向一个结构体数组的相对虚拟地址,RVA,结构体数组叫做IAT,(Import Address Table)
} IMAGE_IMPORT_DESCRIPTOR;

1,第一个元素OriginalFirstThunk与第五个元素FirstThunk指向的是相同的结构体 IMAGE_THUNK_DATA;
2,在磁盘文件中,OriginalFirstThunk 与 FirstThunk中的数据是相同的,可以将输入名称表INT看做是输入地址表IAT的一个备份,
但是在加载到内存中的时候,输入地址表会 由加载器把相应的PE文件的函数地址 覆盖到这里来,这时候 IAT才是真正的IAT
--INT是原始的,加载到内存中的时候,就是IAT了

3,在有些文件中,输入名称表是空的,全零,什么都没有。这说明输入地址表有时候没有备份。所以解析输入表的时候最好使用输入地址表来解析,也可以两个分别查看
4,指向的结构体以全零为结尾,可以作为解析时的结束条件

//这是指向的那个结构体 32位下
//可以看到是一个联合体,共4字节,但是不要忘记每一个这个结构体后面都需要一个全零的结构体来作为结尾
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // 转发才用到
        DWORD Function;             // 导入函数的地址,在加载到内存后,这里才起作用
        DWORD Ordinal;              // 假如是序号导入到的,用到这里
        DWORD AddressOfData;        // 假如是函数名称导入的,用这里,它指向一个PIMAGE_IMPORT_BY_NAME的结构体
    } u1;
} IMAGE_THUNK_DATA32;
//1,在磁盘文件中,起作用的只有后面两个成员
//2,这个结构占4个字节,假如最高位是1,那么序号导入起作用,只需输出一个序号,
//                    假如最高位是0,那么是最后一个成员起作用,指向一个_IMAGE_IMPORT_BY_NAME
//下面这个包含了序号和函数名
typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

 

那么OK,我们的.rdata段的导入表解析完成了,然后我们之前在数据目录表的导入表的位置空置着的两个值也可以填入了, VirtualAddress是2010h(在内存对齐后的),Size是三个结构体的大小是60==3Ch
整个.rdata段的代码
 
76 20 00 00 00 00 00 00 5C 20 00 00 00 00 00 00
4C 20 00 00 00 00 00 00 00 00 00 00 6A 20 00 00
08 20 00 00 54 20 00 00 00 00 00 00 00 00 00 00
84 20 00 00 00 20 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 5C 20 00 00
00 00 00 00 76 20 00 00 00 00 00 00 00 00 4D 65
73 73 61 67 65 42 6F 78 41 00 75 73 65 72 33 32
2E 64 6C 6C 00 00 00 00 45 78 69 74 50 72 6F 63
65 73 73 00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

.Text 段

我们暂时在OD,或者x64DBG 里面写下如下的汇编指令;
 
push 0;
push 0;
push 0;
push 0;
call [00402008];//导入表内MessageBoxA地址
push 0;
call [00402000];//导入表内ExitProcess的地址

得到的OPCode代码为:
6A 00 6A 00 6A 00 6A 00 FF 15 08 20 40 00 6A 00
FF 15 00 20 40 00
粘贴到010里面;
即:
6A 00 6A 00 6A 00 6A 00 FF 15 08 20 40 00 6A 00
FF 15 00 20 40 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

程序完成!

我们的helloworld 还没有弹出来呢,那就很简单了:
.data段
 
把字符串“消息框”“helloworld”转换成opcode;
CF FB CF A2 BF F2 00 48 65 6C 6C 6F 2C 20 57 6F
72 6C 64 20 21 00
粘贴到.data段
然后修改.text段的push的时候的地址即可;
push 0的时候的OPCode:
6A 00 6A 00 6A 00 6A 00 FF 15 08 20 40 00 6A 00
FF 15 00 20 40 00
修改为我们push 字符串地址--》即 :
push 0;
push 00403000;
pusn 00403008;
push 0;
call [00402008];//导入表内MessageBoxA地址
push 0;
call [00402000];//导入表内ExitProcess的地址
即:
6A 00 68 00 30 40 00 68 07 30 40 00 6A 00 FF 15
08 20 40 00 6A 00 FF 15 00 20 40 00
以上,即可;

 修正后:

6A 00 68 00 30 40 00 68 07 30 40 00 6A 00 FF 15
08 20 40 00 6A 00 FF 15 00 20 40 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
76 20 00 00 00 00 00 00 5C 20 00 00 00 00 00 00
4C 20 00 00 00 00 00 00 00 00 00 00 6A 20 00 00
08 20 00 00 54 20 00 00 00 00 00 00 00 00 00 00
84 20 00 00 00 20 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 5C 20 00 00
00 00 00 00 76 20 00 00 00 00 00 00 00 00 4D 65
73 73 61 67 65 42 6F 78 41 00 75 73 65 72 33 32
2E 64 6C 6C 00 00 00 00 45 78 69 74 50 72 6F 63
65 73 73 00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
CF FB CF A2 BF F2 00 48 65 6C 6C 6F 2C 20 57 6F
72 6C 64 20 21 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

 

 完成
原文地址:https://www.cnblogs.com/by-clark/p/9129135.html