吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2547|回复: 4
收起左侧

[分享] 快速查询PE文件知识点和PE文件解析(上)

[复制链接]
fz12 发表于 2022-5-4 01:24
本帖最后由 fz12 于 2022-5-5 10:48 编辑

PE(Portable Executable)
PE文件的全称是Portable Executable ,意为可移植的可执行文件,常见的有EXE,DLL,SYS,COM,OCX,PE文件是微软Windows操作系统上的程序文件
pe文件内存映射.png
PE节
节名
说明
.text.text 节是供机器指令使用的默认节。一般情况下,在最终生成的可执行文件中,链接器将把每个.OBJ文件的.text节合并成一个巨大的、统一的.text节。
.data全局和静态变量存储(在编译时初始化)
.bss全局和静态变量存储(在编译时不初始化)
.textbss启用增量链接
.rsrc.rsrc节用于储存模块资源,这些资源是可以嵌入到可执行文件中的二进制对象。例如,定制的鼠标光标、字体、程序图标、字符串表及版本信息都是标准的资源。资源还可以是应用程序需要的任意数据块(例如另一个可执行文件)。
.IDAta存储有关导入库例程信息
.edata存储有关导出库例程信息
.reloc重定位
.rdata数据段(只读)
.crtc++ 运行时库 runtime
.tls线程局部存储

基础知识
  • 基地址(ImageBase):当PE文件通过Windows加载器载入内存后,内存中的版本称为模块,映射文件的起始地址称为模块句柄,可通过模块句柄访问内存中其他数据结构,这个内存起始地址就称为基地址。
  • 虚拟地址(VA,Virtual Address):在Windows系统中,PE文件被系统加载到内存后,每个程序都有自己的虚拟空间,这个虚拟空间的内存地址称为虚拟地址。
  • 相对虚拟地址(RVA,Relative Virtual Address):可执行文件中,有许多地方需要指定内存中的地址。例如,应用全局变量时需要指定它的地址。为了避免在PE文件中出现绝对内存地址引入了相对虚拟地址,它就是在内存中相对于PE文件载入地址的偏移量。
它们之间的关系:虚拟地址(VA)  = 基地址(Image Base)+相对虚拟地址(RVA)
  • 文件偏移地址(Offset):当PE文件存储在磁盘中时,某个数据的位置相对于文件头的偏移量称为文件偏移地址(File Offset)。文件偏移地址从PE文件的第一个字节开始计数,起始值为0

PE 头解析
DOS头
DOS头和DOS存根,它们的存在主要是用来兼容DOS系统。当我们的程序运行在DOS系统的时候,就会运行DOS存根中的代码,代码内容就是输出一段字符串告诉用户,这个程序不能在16位系统运行。
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // DOS头签名,4D5A
    WORD   e_cblp;                      // 最后(部分)页中的字节数
    WORD   e_cp;                        // 文件中的全部和部分页数
    WORD   e_crlc;                      // 重定位表中的指针数
    WORD   e_cparhdr;                   // 头部尺寸,以段落为单位
    WORD   e_minalloc;                  // 所需的最小附加段
    WORD   e_maxalloc;                  // 所需的最大附加段
    WORD   e_ss;                        // 初始化的SS值(相对偏移量)
    WORD   e_sp;                        // 初始化的SP值
    WORD   e_csum;                      // 补码检验值
    WORD   e_ip;                        // 初始化的IP值
    WORD   e_cs;                        // 初始化的CS值(相对偏移量)
    WORD   e_lfarlc;                    // 重定位表的字节偏移量
    WORD   e_ovno;                      // 覆盖号
    WORD   e_res[4];                    // 保留字
    WORD   e_oemid;                     // OEM 标识符(相对 e_oeminfo)
    WORD   e_oeminfo;                   // OEM 信息; e_oemid specific
    WORD   e_res2[10];                  // 保留字
    LONG   e_lfanew;                    // PE头的偏移位置
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

DOS存根
在DOS头下方,是个可选项,大小不固定,由代码与数据混合而成,一般从0x40开始
标识头
[Asm] 纯文本查看 复制代码
#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_OS2_SIGNATURE                 0x454E      // NE
#define IMAGE_OS2_SIGNATURE_LE              0x454C      // LE
#define IMAGE_VXD_SIGNATURE                 0x454C      // LE
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

解析DOS头
[Asm] 纯文本查看 复制代码
#include<Windows.h>
#include<iostream>
using namespace std;

void ImageDosHeader(_In_z_ const char* path)
{
        // 获取文件对象
        HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        // 获取文件大小
        DWORD fSize = GetFileSize(hfile, NULL);
        char* pBuff = new char[fSize];
        DWORD dwReadSize = 0;
        
        // 读文件
        BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
        if (bSuccess)
        {
                PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
                // DOS头签名
                cout << hex << pDosHeader->e_magic << endl;
                // PE头的偏移位置
                cout << hex << pDosHeader->e_lfanew << endl;
        }
        else (cout.write("打开文件失败", 20));
        CloseHandle(hfile);
        delete[] pBuff;
}

void main()
{
        ImageDosHeader(R"(C:\Users\11981\Desktop\Project1\1.exe)");
}

NT头
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature; // 标识,0x00004550
    IMAGE_FILE_HEADER FileHeader; // 文件头
    IMAGE_OPTIONAL_HEADER64 OptionalHeader; // 可选头
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

NT头:文件头
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine; // 运行平台
    WORD    NumberOfSections; // 文件存在的区段数量
    DWORD   TimeDateStamp; // PE文件的创建时间,一般有连接器填写
    DWORD   PointerToSymbolTable; // COFF文件符号表在文件中的偏移
    DWORD   NumberOfSymbols; // 符号表的数量
    WORD    SizeOfOptionalHeader; // 可选PE头的大小
    WORD    Characteristics; // 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Machine:运行平台
[C++] 纯文本查看 复制代码
#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST       0x0001  // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2  // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

Characteristics:文件属性
[C++] 纯文本查看 复制代码
#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // 文件中不存在重定位信息
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // 文件是可执行的
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // 不存在行信息
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // 不存在符合信息
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // 调整工作集
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // 应用程序可处理大于2GB的地址
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 只在32为平台上运行
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // 不包含调试信息
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // 不能从可移动盘运行
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // 不能从网络运行
#define IMAGE_FILE_SYSTEM                    0x1000  // 系统文件,不能直接运行
#define IMAGE_FILE_DLL                       0x2000  // DLL文件
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // 文件不能在多处理器计算机上运行
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

NE头:可选头
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_OPTIONAL_HEADER {
    WORD    Magic; // PE类型
    BYTE    MajorLinkerVersion; // 链接器的版本号
    BYTE    MinorLinkerVersion; // 链接器的版本号
    DWORD   SizeOfCode; // 代码段的长度,如果有多个代码段,则是代码段长度的总和
    DWORD   SizeOfInitializedData; // 初始化的数据长度
    DWORD   SizeOfUninitializedData; // 未初始化的数据长度
    DWORD   AddressOfEntryPoint; // 程序入口的RVA,对于exe这个地址可以理解为WinMain的RVA。对于DLL,这个地址可以理解为DllMain的RVA,如果是驱动程序,可以理解为DriverEntry的RVA
    DWORD   BaseOfCode; // 代码段起始地址的RVA
    DWORD   BaseOfData; // 数据段起始地址的RVA
    DWORD   ImageBase; // 映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
    DWORD   SectionAlignment; // 节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0
    DWORD   FileAlignment; // 节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment
    WORD    MajorOperatingSystemVersion; // 所需操作系统的版本号
    WORD    MinorOperatingSystemVersion; // 所需操作系统的版本号
    WORD    MajorImageVersion; // 映象的版本号,这个是开发者自己指定的,由连接器填写
    WORD    MinorImageVersion; // 映象的版本号,这个是开发者自己指定的,由连接器填写
    WORD    MajorSubsystemVersion; // 所需子系统版本号
    WORD    MinorSubsystemVersion; // 所需子系统版本号
    DWORD   Win32VersionValue; // 保留,必须为0
    DWORD   SizeOfImage; // 映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小
    DWORD   SizeOfHeaders; // 所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的
    DWORD   CheckSum; // 映象文件的校验和
    WORD    Subsystem; // 运行该PE文件所需的子系统
    WORD    DllCharacteristics; // 映像文件的DLL特性
    DWORD   SizeOfStackReserve; // 运行时为每个线程栈保留内存的大小
    DWORD   SizeOfStackCommit; // 运行时每个线程栈初始占用内存大小
    DWORD   SizeOfHeapReserve; // 运行时为进程堆保留内存大小
    DWORD   SizeOfHeapCommit; // 运行时进程堆初始占用内存大小
    DWORD   LoaderFlags; // 保留,必须为0
    DWORD   NumberOfRvaAndSizes; // 数据目录的项数
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录的结构体
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_OPTIONAL_HEADER64 {
    WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    ULONGLONG   ImageBase;
    DWORD       SectionAlignment;
    DWORD       FileAlignment;
    WORD        MajorOperatingSystemVersion;
    WORD        MinorOperatingSystemVersion;
    WORD        MajorImageVersion;
    WORD        MinorImageVersion;
    WORD        MajorSubsystemVersion;
    WORD        MinorSubsystemVersion;
    DWORD       Win32VersionValue;
    DWORD       SizeOfImage;
    DWORD       SizeOfHeaders;
    DWORD       CheckSum;
    WORD        Subsystem;
    WORD        DllCharacteristics;
    ULONGLONG   SizeOfStackReserve;
    ULONGLONG   SizeOfStackCommit;
    ULONGLONG   SizeOfHeapReserve;
    ULONGLONG   SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

Magic:PE类型
[C++] 纯文本查看 复制代码
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107

Subsystem:子系统
[C++] 纯文本查看 复制代码
#define IMAGE_SUBSYSTEM_UNKNOWN              0   // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE               1   // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI              5   // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI            7   // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8   // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9   // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION      10  //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12  //
#define IMAGE_SUBSYSTEM_EFI_ROM              13
#define IMAGE_SUBSYSTEM_XBOX                 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG    17

DllCharacteristics:DLL特性
[C++] 纯文本查看 复制代码
//      IMAGE_LIBRARY_PROCESS_INIT            0x0001     // Reserved.
//      IMAGE_LIBRARY_PROCESS_TERM            0x0002     // Reserved.
//      IMAGE_LIBRARY_THREAD_INIT             0x0004     // Reserved.
//      IMAGE_LIBRARY_THREAD_TERM             0x0008     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA    0x0020  // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY    0x0080     // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT    0x0100     // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200     // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH       0x0400     // Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND      0x0800     // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000     // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER   0x2000     // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF     0x4000     // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE     0x8000

数据目录项
该字段定义了PE 文件中出现的所有不同类型的数据的目录信息
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress; // 就是数据目录表的RVA
    DWORD   Size; // 数据块的长度,起始地址+尺寸 = 结束的位置
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

IMAGE_DATA_DIRECTORY
[C++] 纯文本查看 复制代码
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // 导出表地址和大小
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // 导入表地址和大小
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // 资源表地址和大小
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // 异常表地址和大小
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // 属性证书数据地址和大小
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // 基地址重定位表地址和大小
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // 调试信息地址和大小
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // 预留为0
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS地址和大小
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // 加载配置表地址和大小
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // 绑定导入表地址和大小
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // 导入函数地址表地址和大小
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // 延迟导入表地址和大小
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

区段头
定义了每个区段的属性
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称,如“.text” 
    union {
            DWORD   PhysicalAddress; // 物理地址
            DWORD   VirtualSize; // 内存中区段所占大小
    } Misc;
    DWORD   VirtualAddress; // 内存中区段起始位置(RVA)
    DWORD   SizeOfRawData; // 硬盘文件中区段所占大小
    DWORD   PointerToRawData; // 硬盘文件中区段起始位置
    DWORD   PointerToRelocations; // 在OBJ文件中使用,重定位的偏移
    DWORD   PointerToLinenumbers; // 行号表的偏移(供调试使用地)
    WORD    NumberOfRelocations; // 在OBJ文件中使用,重定位项数目
    WORD    NumberOfLinenumbers; // 行号表中行号的数目
    DWORD   Characteristics; // 区段属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

Characteristics:区段属性
[C++] 纯文本查看 复制代码
//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
//      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
//      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
//      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
//      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

#define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.

#define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
//      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
//                                           0x00002000  // Reserved.
//      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA                0x00008000
//      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
#define IMAGE_SCN_MEM_16BIT                  0x00020000
#define IMAGE_SCN_MEM_LOCKED                 0x00040000
#define IMAGE_SCN_MEM_PRELOAD                0x00080000

#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
// Unused                                    0x00F00000
#define IMAGE_SCN_ALIGN_MASK                 0x00F00000

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.
#define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.

NT头解析
[C++] 纯文本查看 复制代码
#include<Windows.h>
#include<iostream>
using namespace std;

void ImageNtHeader(_In_z_ const char* path)
{
        // 获取文件对象
        HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        // 获取文件大小
        DWORD fSize = GetFileSize(hfile, NULL);
        char* pBuff = new char[fSize];
        DWORD dwReadSize = 0;

        // 读文件
        BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
        if (bSuccess)
        {
                PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
                PIMAGE_NT_HEADERS64 pNtHeader{ 0 };
                pNtHeader = (PIMAGE_NT_HEADERS64)(pDosHeader->e_lfanew + pBuff);
                // 标识
                cout << hex << pNtHeader->Signature << endl;

                PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;
                // 运行平台
                cout << pFileHeader->Machine << endl;

                PIMAGE_OPTIONAL_HEADER64 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&pNtHeader->OptionalHeader;
                PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
                for (int i = 0; i < pFileHeader->NumberOfSections; i++)
                {
                        // 节表名称
                        cout << pSectionHeader->Name << endl;
                        // 硬盘文件中区段所占大小
                        cout << pSectionHeader->SizeOfRawData << endl;
                        pSectionHeader++;
                }
        }
        else (cout.write("打开文件失败", 20));
        CloseHandle(hfile);
        delete[] pBuff;
}

void main()
{
        ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\1.exe)");
}

导入表
当使用到一个dll中的函数时,会出现在导入表中(隐式调用)导入表位于数据目录表中第1项
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // 指向导入名称表(INT)的RAV
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain; // 转发链,如果不转发则此值为0
    DWORD   Name; // 指向导入映像文件的名字
    DWORD   FirstThunk; // 指向导入地址表(IAT)的RAV
} IMAGE_IMPORT_DESCRIPTOR;

OriginalFirstThunk和FirstThunk分别指向两个不同的IMAGE_THUNK_DATA结构的数组。这两个数组都以一个空的IMAGE_THUNK_DATA结构结尾。一般情况下,导入表只需要关注OriginalFirstThunk和FirstThunk这两个字段。
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_THUNK_DATA64 {
    union {
        ULONGLONG ForwarderString;  // PBYTE 
        ULONGLONG Function;         // PDWORD
        ULONGLONG Ordinal;
        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;

#include "poppack.h"                        // Back to 4 byte packing

//@[comment("MVI_tracked")]
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // 指向一个转向者字符串的RVA
        DWORD Function;   // 被输入的函数的内存地址;
        DWORD Ordinal;  // 被输入的API的序数值
        DWORD AddressOfData;       // 指向IMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;

导入表解析
[C++] 纯文本查看 复制代码
#include<Windows.h>
#include<iostream>
using namespace std;

DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{
        for (int i = 0; i < f->NumberOfSections; i++)
        {
                // FOA = 数据的RVA + 区段的RVA - 区段的FOA
                if (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->SizeOfRawData))
                {
                        return rva - p->VirtualAddress + p->PointerToRawData;
                }
                f++;
                p++;
        }
        return 0;
}

void ImageNtHeader(_In_z_ const char* path)
{
        // 获取文件对象
        HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        // 获取文件大小
        DWORD fSize = GetFileSize(hfile, NULL);
        char* pBuff = new char[fSize];
        DWORD dwReadSize = 0;
        // 读文件
        BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
        if (bSuccess)
        {
                PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
                PIMAGE_NT_HEADERS32 pNtHeader{ 0 };
                pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);
                PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;
                PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;
                PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
                PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
                // 导入表地址
                PIMAGE_IMPORT_DESCRIPTOR pImportDescrtiptor = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);
                while (pImportDescrtiptor->OriginalFirstThunk)
                {
                        char* dllName = (RvaToFoa(pImportDescrtiptor->Name, pSectionHeader, pFileHeader) + pBuff);
                        cout << "DLL名称[DllName]:" << dllName << endl;
                        cout << "日期时间标志[TimeDateStamp]:" << hex << pImportDescrtiptor->TimeDateStamp << endl;
                        cout << "转发链[ForWarderChain]:" << hex << pImportDescrtiptor->ForwarderChain << endl;
                        cout << "名称OFFSET[Name]:" << hex << pImportDescrtiptor->Name << endl;
                        cout << "FirstThunk:" << hex << pImportDescrtiptor->FirstThunk << endl;
                        cout << "OriginalFirstThunk:" << hex << pImportDescrtiptor->OriginalFirstThunk << endl;
                        //指向地址表中的RVA
                        PIMAGE_THUNK_DATA pInt = (PIMAGE_THUNK_DATA)(RvaToFoa(pImportDescrtiptor->OriginalFirstThunk, pSectionHeader, pFileHeader) + pBuff);
                        DWORD Index = 0;
                        DWORD ImportOffset = 0;
                        //被导入函数的序号
                        while (pInt->u1.Ordinal)
                        {
                                // 说明序号导入,这个函数没有名字
                                if (pInt->u1.Ordinal & 0x80000000)
                                {
                                        int a = pInt->u1.Ordinal & 0x7FFFFFFF;
                                        cout << a << endl;
                                }
                                //  最高位是0,表示这个是一个有名称的函数 RVA
                                else
                                {
                                        PIMAGE_IMPORT_BY_NAME importName = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(pInt->u1.AddressOfData, pSectionHeader, pFileHeader) + pBuff);
                                        cout << "API名称:" << importName->Name << endl;
                                        cout << "API序号:" << importName->Hint << endl;
                                        cout << "ThunkValue:" << pInt->u1.Function << endl;
                                }
                                pInt++;
                        }
                        pImportDescrtiptor++;
                }
        }
        else (cout.write("打开文件失败", 20));
        CloseHandle(hfile);
        delete[] pBuff;
}

void main()
{
        ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}

导出表
导出的行为一般是dll给其他程序提供函数,变量,类导出表位于数据目录表的第0项
[C++] 纯文本查看 复制代码
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics; // 未使用,总是定义为0
    DWORD   TimeDateStamp; // 文件生成时间
    WORD    MajorVersion; // 未使用,总是定义为0
    WORD    MinorVersion; // 未使用,总是定义为0
    DWORD   Name; // 模块的真实名称
    DWORD   Base; // 基数,加上序数就是函数地址数组的索引值
    DWORD   NumberOfFunctions; // 导出函数的总数
    DWORD   NumberOfNames; // 以名称方式导出的函数的总数
    DWORD   AddressOfFunctions; // 导出地址表(EAT),指向输出函数地址的RVA
    DWORD   AddressOfNames;// 导出名称表(ENT),指向输出函数名字的RVA
    DWORD   AddressOfNameOrdinals;//  指向导出序号数组(EOT),指向输出函数序号的RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

导出表解析
[C++] 纯文本查看 复制代码
#include<Windows.h>
#include<iostream>
using namespace std;

DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{
        for (int i = 0; i < f->NumberOfSections; i++)
        {
                // FOA = 数据的RVA + 区段的RVA - 区段的FOA
                if (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->SizeOfRawData))
                {
                        return rva - p->VirtualAddress + p->PointerToRawData;
                }
                f++;
                p++;
        }
        return 0;
}

void ImageNtHeader(_In_z_ const char* path)
{
        // 获取文件对象
        HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        // 获取文件大小
        DWORD fSize = GetFileSize(hfile, NULL);
        char* pBuff = new char[fSize];
        DWORD dwReadSize = 0;
        // 读文件
        BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
        if (bSuccess)
        {
                PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
                PIMAGE_NT_HEADERS32 pNtHeader{ 0 };
                pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);
                PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;
                PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;
                PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
                PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

                PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) + pBuff);
                char* szName = (char*)(RvaToFoa(pExport->Name, pSectionHeader, pFileHeader) + pBuff);

                if (pExport->AddressOfFunctions == 0)
                {
                        cout.write("没有导出表", 20);
                        return;
                }
                cout << "导出表OFFSET:" << RvaToFoa(dataDirectory->VirtualAddress, pSectionHeader, pFileHeader) << endl;
                cout << "特征值:" << pExport->Characteristics << endl;
                cout << "基:" << pExport->Base << endl;
                cout << "名称OFFSET:" << pExport->Name << endl;
                cout << "名称:" << szName << endl;
                cout << "函数数量:" << pExport->NumberOfFunctions << endl;
                cout << "函数名数量:" << pExport->NumberOfNames << endl;
                cout << "函数地址:" << pExport->AddressOfFunctions << endl;
                cout << "函数名称地址:" << pExport->AddressOfNames << endl;
                cout << "函数名称序号地址:" << pExport->AddressOfNameOrdinals << endl;
                //函数地址数量
                DWORD dwNumOfFun = pExport->NumberOfFunctions;
                //函数名数量
                DWORD dwNumOfNames = pExport->NumberOfNames;
                //基
                DWORD dwBase = pExport->Base;
                //导出地址表
                PDWORD pEAt32 = (PDWORD)(RvaToFoa(pExport->AddressOfFunctions, pSectionHeader, pFileHeader) + pBuff);
                //导出名称表
                PDWORD pENt32 = (PDWORD)(RvaToFoa(pExport->AddressOfNames, pSectionHeader, pFileHeader) + pBuff);
                //导出序号表
                PWORD pId = (PWORD)(RvaToFoa(pExport->AddressOfNameOrdinals, pSectionHeader, pFileHeader) + pBuff);
                for (DWORD i = 0; i < dwNumOfFun; i++)
                {
                        if (pEAt32[i] == 0)
                        {
                                continue;
                        }
                        DWORD Id = 0;
                        for (; Id < dwNumOfNames; Id++)
                        {
                                if (pId[Id] == i)
                                {
                                        break;
                                }
                        }
                        if (Id == dwNumOfNames)
                        {
                                cout << "Id:%x" << i + dwBase << endl;
                                cout << "Address:" << pEAt32[i];
                        }
                        else
                        {
                                char* szFunName = (char*)(RvaToFoa(pENt32[Id], pSectionHeader, pFileHeader) + pBuff);
                                cout << "Id:" << i + dwBase << endl;
                                cout << "Address" << pEAt32[i];
                                cout << "Name" << szFunName;
                        }
                }

        }
        else (cout.write("打开文件失败", 20));
        CloseHandle(hfile);
        delete[] pBuff;
}

void main()
{
        ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}

重定位表
Windows使用重定位机制保证代码无论模块加载到哪个基址都能正确被调用

[C++] 纯文本查看 复制代码
typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress; // 重定位内存页的起始地址RVA
    DWORD   SizeOfBlock; // 重定位块的长度
//  WORD    TypeOffset[1]; 偏移12位,类型4位
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION[/size][size=16px];[/size][size=16px]

TypeOffset高位字节
[C++] 纯文本查看 复制代码
#define IMAGE_REL_BASED_ABSOLUTE              0 // 无意义,对齐用[/size]
[size=16px]#define IMAGE_REL_BASED_HIGH                  1 // 双字中,仅高16位被修正[/size]
[size=16px]#define IMAGE_REL_BASED_LOW                   2 // 双字中,仅低16位被修正[/size]
[size=16px]#define IMAGE_REL_BASED_HIGHLOW               3 // 双字32位都需要修正[/size]
[size=16px]#define IMAGE_REL_BASED_HIGHADJ               4  // 进行基地址重定位时将差值的高16位加到指定偏移处的一个16位域上[/size]
[size=16px]#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5    5[/size]
[size=16px]#define IMAGE_REL_BASED_RESERVED              6[/size]
[size=16px]#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7    7[/size]
[size=16px]#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8    8[/size]
[size=16px]#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9    9[/size]
[size=16px]#define IMAGE_REL_BASED_DIR64                 10   // 进行基地址重定位时将差值加到指定偏移处的一个64位域上[/size]

[size=16px]//[/size]
[size=16px]// Platform-specific based relocation types.[/size]
[size=16px]//[/size]

[size=16px]#define IMAGE_REL_BASED_IA64_IMM64            9[/size]
[size=16px]#define IMAGE_REL_BASED_MIPS_JMPADDR          5  // 对MIPS平台的跳转指令进行基地址重定位[/size]
[size=16px]#define IMAGE_REL_BASED_MIPS_JMPADDR16        9 // 对MIPS16平台的跳转指令进行基地址重定位[/size]
[size=16px]#define IMAGE_REL_BASED_ARM_MOV32             5[/size]
[size=16px]#define IMAGE_REL_BASED_THUMB_MOV32           7[/size]
[size=16px]

重定位表解析
[C++] 纯文本查看 复制代码
#include<Windows.h>
#include<iostream>
using namespace std;

DWORD RvaToFoa(_In_ DWORD rva, _In_ PIMAGE_SECTION_HEADER p, _In_ PIMAGE_FILE_HEADER f)
{
        for (int i = 0; i < f->NumberOfSections; i++)
        {
                // FOA = 数据的RVA + 区段的RVA - 区段的FOA
                if (rva >= p->VirtualAddress && rva < (p->VirtualAddress + p->Misc.VirtualSize))
                {
                        return rva - p->VirtualAddress + p->PointerToRawData;
                }
                f++;
                p++;
        }
        return 0;
}

void ImageNtHeader(_In_z_ const char* path)
{
        // 获取文件对象
        HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        // 获取文件大小
        DWORD fSize = GetFileSize(hfile, NULL);
        char* pBuff = new char[fSize];
        DWORD dwReadSize = 0;
        // 读文件
        BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
        if (bSuccess)
        {
                typedef struct _TYPE {
                        WORD Offset : 12;   //大小 2bit 重定位的偏移
                        WORD Tyoe : 4;
                }TYPE, * PTYPE;
                PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
                PIMAGE_NT_HEADERS32 pNtHeader{ 0 };
                pNtHeader = (PIMAGE_NT_HEADERS32)(pDosHeader->e_lfanew + pBuff);
                PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)&pNtHeader->FileHeader;
                PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&pNtHeader->OptionalHeader;
                PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
                // PIMAGE_DATA_DIRECTORY dataDirectory = (PIMAGE_DATA_DIRECTORY)&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
                PIMAGE_BASE_RELOCATION pRel = (PIMAGE_BASE_RELOCATION)(pBuff + RvaToFoa(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, pSectionHeader, pFileHeader));
                DWORD dwCount = 0;
                while (*(PLONGLONG)pRel)
                {
                        printf("[%d] VirtualAddress-> [0x%08x] SizeOfBlock-> [0x%08x] \r\n", dwCount++, pRel->VirtualAddress, pRel->SizeOfBlock);

                        //需要修复重定位项个数
                        DWORD dwRelEntry = (pRel->SizeOfBlock - 8) / 2;

                        //指向重定位项
                        PWORD pRelData = (PWORD)pRel + 8;

                        for (size_t i = 0; i < dwRelEntry; i++)
                        {
                                //判断高4位
                                //32位高4位0011
                                //64位高4位1010
                                if ((pRelData[i] & 0x3000) == 0x3000)
                                {
                                        //低12位 + VirtualAddress为真正需要修复数据的RVA
                                        DWORD dwData = pRelData[i] & 0xFFF;
                                        DWORD dwDataRVA = dwData + pRel->VirtualAddress;
                                        printf("[%d] DATA[0x%04x] RVA[0x%08x]\r\n", i, dwData, dwDataRVA);
                                }
                        }
                        //指向下一个重定位结构
                        pRel = (PIMAGE_BASE_RELOCATION)((PUCHAR)pRel + pRel->SizeOfBlock);
                }

        }
        else (cout.write("打开文件失败", 20));
        CloseHandle(hfile);
        delete[] pBuff;
}

void main()
{
        ImageNtHeader(R"(C:\Users\11981\Desktop\Project1\2.exe)");
}

&#8203;参考文章
https://blog.csdn.net/Gamma_lab/article/details/123869956
https://blog.csdn.net/adam001521/article/details/84658708
查考书
加密与解密
Windows PE权威指南
最后说明
导出和导入表,重定位代码可能有点问题,可以参考别的链接,目前不知道什么原因,有大佬发现可以指出&#8203;
PE格式结构图.jpg

免费评分

参与人数 4吾爱币 +10 热心值 +4 收起 理由
bailemenmlbj + 1 + 1 谢谢@Thanks!
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
metoo2 + 1 + 1 谢谢@Thanks!
Jack.yang + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

metoo2 发表于 2022-5-7 13:34
点赞支持,感谢楼主
metoo2 发表于 2022-5-7 13:42
 楼主| fz12 发表于 2022-5-7 17:57
metoo2 发表于 2022-5-7 13:42
代码源文件能够一起发一下么?

链接:https://pan.baidu.com/s/16iinLPqRWpcMAQKLUOd8GA
提取码:fkvz
--来自百度网盘超级会员V5的分享
ysysc 发表于 2022-5-13 00:35
谢谢大神,非常的有用。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-25 01:58

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表