PE文件 需要认真学的地方了,我多次学这个都放弃了,这次得认真学下去
手动解析PE文件 dos头 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct _IMAGE_DOS_HEADER { WORD e_magic; WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD e_res[4 ]; WORD e_oemid; WORD e_oeminfo; WORD e_res2[10 ]; LONG e_lfanew; } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
总大小为60+4 = 64 = 0x3c + 4
我以吾爱破解od的exe为例进行观察
带*为必背的
e_magic e_lfanew 第一个ascii为MZ ,一般用于判断是否是DOS_HEADER
第二个表示NT_HEADER的偏移地址 (计算方法 0+e_lfanew) 0代表基址
变量名 变量值 e_magic 5A4D e_cblp 0050 e_cp 0002 e_crlc 0000 e_cparhdr 0004 e_minalloc 000F e_maxalloc FFFF e_ss 0000 e_sp 00B8 e_csum 0000 e_ip 0000 e_cs 0000 e_lfarlc 0040 e_ovno 001A e_res[4] 0000 * 0x4 e_oemid 0000 e_oeminfo 0000 e_res2[10] 0000 * 0xA e_lfanew 0000 0200
1 2 3 4 5 struct NT_HEADER { DWORD signature; struct IMAGE_FILE_HEADER fileHeader ; struct IMAGE_OPTIONAL_HEADER optionalHeader ; }
1 2 3 4 5 6 7 8 9 typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
变量名 变量值 Machine 014C NumberOfSections 0009 TimeDateStamp 40B10868 PointerToSymbolTable 00000000 NumberOfSymbols 00000000 SizeOfOptionalHeader 00E0 Characteristics 010E
总大小为: 20 = 0x14
Machine 代表的是PE文件的类型,只会为三个值0x014c(x86架构) 0x0200(英特尔安腾架构 已基本废弃) 0x8664(64架构程序) NumberOfSections 表示节(块, 区段)的数量 TimeDateStamp 文件编译的时间 SizeOfOptionalHeader 是可选头的大小 Characteristics 文件属性,dll跟exe标志存放 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD 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; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
Standard fields.
变量名 变量值 Magic 010B MajorLinkerVersion 05 MinorLinkerVersion 00 SizeOfCode 000AF000 SizeOfInitializedData 0016CE00 SizeOfUninitializedData 00000000 AddressOfEntryPoint 00001000 BaseOfCode 00001000 BaseOfData 000B0000
NT additional fields.
变量名 变量值 ImageBase 00400000 SectionAlignment 00001000 FileAlignment 00000200 MajorOperatingSystemVersion 0004 MinorOperatingSystemVersion 0000 MajorImageVersion 0000 MinorImageVersion 0000 MajorSubsystemVersion 0004 MinorSubsystemVersion 0000 Win32VersionValue 00000000 SizeOfImage 001AF000 SizeOfHeaders 00000600 CheckSum 00000000 Subsystem 0002 DllCharacteristics 0000 SizeOfStackReserve 00100000 SizeOfStackCommit 00020000 SizeOfHeapReserve 01000000 SizeOfHeapCommit 00001000 LoaderFlags 00000000 NumberOfRvaAndSizes 00000010 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] 非常多暂时不管
Magic: The state of the image file.0x010b IMAGE_NT_OPTIONAL_HDR32_MAGIC The file is an executable image. 0x020b IMAGE_NT_OPTIONAL_HDR64_MAGIC The file is an executable image. 0x0107 IMAGE_ROM_OPTIONAL_HDR_MAGIC The file is a ROM image. SizeOfCode: The size of the code section, in bytes, or the sum of all such sections if there are multiple code sections. 简单来说就是代码段有多大 SizeOfInitializedData: The size of the initialized data section, in bytes, or the sum of all such sections if there are multiple initialized data sections. 初始化数据段长度 SizeOfUninitializedData: The size of the uninitialized data section, in bytes, or the sum of all such sections if there are multiple uninitialized data section 未初始化数据段长度 AddressOfEntryPoint: A pointer to the entry point function, relative to the image base address. For executable files, this is the starting address. For device drivers, this is the address of the initialization function. The entry point function is optional for DLLs. When no entry point is present, this member is zero. 入口点地址 BaseOfCode: A pointer to the beginning of the code section, relative to the image base. BaseOfData: A pointer to the beginning of the data section, relative to the image base ImageBase: The preferred address of the first byte of the image when it is loaded in memory. This value is a multiple of 64K bytes. The default value for DLLs is 0x10000000. The default value for applications is 0x00400000, except on Windows CE where it is 0x00010000. SectionAlignment: The alignment of sections loaded in memory, in bytes. This value must be greater than or equal to the FileAlignment member. The default value is the page size for the system. FileAlignment: The alignment of the raw data of sections in the image file, in bytes. The value should be a power of 2 between 512 and 64K (inclusive). The default is 512. If the SectionAlignment member is less than the system page size, this member must be the same as SectionAlignment . SizeOfImage: The size of the image, in bytes, including all headers. Must be a multiple of SectionAlignment . SizeOfHeaders: The combined size of the following items, rounded to a multiple of the value specified in the FileAlignment member.e_lfanew member of IMAGE_DOS_HEADER 4 byte signature size of IMAGE_FILE_HEADER size of optional header size of all section headers CheckSum: The image file checksum. The following files are validated at load time: all drivers, any DLL loaded at boot time, and any DLL loaded into a critical system process. SizeOfStackReserve: The number of bytes to reserve for the stack. Only the memory specified by the SizeOfStackCommit member is committed at load time; the rest is made available one page at a time until this reserve size is reached. SizeOfStackCommit: The number of bytes to commit for the stack. SizeOfHeapReserve: The number of bytes to reserve for the local heap. Only the memory specified by the SizeOfHeapCommit member is committed at load time; the rest is made available one page at a time until this reserve size is reached. The number of bytes to commit for the local heap. pe文件解析 doc头
WORD e_magic * “MZ标记” 用于判断是否为可执行文件. DWORD e_lfanew; * PE头相对于文件的偏移,用于定位PE文件
标准pe头
WORD Machine; * 程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器 WORD NumberOfSections; * 文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值. DWORD TimeDateStamp; * 时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的. DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; * 可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h 大小可以自定义. WORD Characteristics; * 每个位有不同的含义,可执行文件值为10F 即0 1 2 3 8位置1
可选PE头:
WORD Magic; * 说明文件类型:10B 32位下的PE文件 20B 64位下的PE文件 BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode;* 所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用 DWORD SizeOfInitializedData;* 已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用 DWORD SizeOfUninitializedData;* 未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用 DWORD AddressOfEntryPoint;* 程序入口 DWORD BaseOfCode;* 代码开始的基址,编译器填的 没用 DWORD BaseOfData;* 数据开始的基址,编译器填的 没用 DWORD ImageBase;* 内存镜像基址 DWORD SectionAlignment;* 内存对齐 DWORD FileAlignment;* 文件对齐 WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage;* 内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍 DWORD SizeOfHeaders;* 所有头+节表按照文件对齐后的大小,否则加载会出错 DWORD CheckSum;* 校验和,一些系统文件有要求.用来判断文件是否被修改. WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve;* 初始化时保留的堆栈大小 DWORD SizeOfStackCommit;* 初始化时实际提交的大小 DWORD SizeOfHeapReserve;* 初始化时保留的堆大小 DWORD SizeOfHeapCommit;* 初始化时实践提交的大小 DWORD LoaderFlags; DWORD NumberOfRvaAndSizes;* 目录项数目
编写exe读取PE头 name.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #ifndef NAME_H_INCLUDED #define NAME_H_INCLUDED typedef unsigned int DWORD;typedef short WORD;typedef char BYTE;typedef unsigned int LONG;typedef char * LPRVOID;typedef short * PWORD;typedef long * PDWORD;#define IMAGE_DOS_SIGNATURE 0x5A4D #define IMAGE_NT_SIGNATURE 0x4550 #define IMAGE_SIZEOF_FILE_HEADER 20 typedef struct _IMAGE_DOS_HEADER { WORD e_magic; WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD e_res[4 ]; WORD e_oemid; WORD e_oeminfo; WORD e_res2[10 ]; LONG e_lfanew; } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD 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; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _NT_HEADER { DWORD signature; IMAGE_FILE_HEADER fileHeader; IMAGE_OPTIONAL_HEADER32 optionalHeader; } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; #endif
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 #include <stdio.h> #include <stdlib.h> #include "name.h" LPRVOID ReadPEFile (LPRVOID fileName) { FILE *pFile = NULL ; DWORD fileSize = 0 ; LPRVOID pFileBuffer = NULL ; if (!(pFile=fopen(fileName, "rb" ))) { printf ("无法打开exe文件\n" ); return NULL ; } if (fseek(pFile, 0 , SEEK_END)!=0 ) { printf ("fseek end error\n" ); return NULL ; } if ((fileSize = ftell(pFile)) == -1 ) { printf ("size error\n" ); return NULL ; } if (fseek(pFile, 0 , SEEK_SET)!=0 ) { printf ("fseek start error\n" ); return NULL ; } if (!(pFileBuffer = malloc (fileSize))) { printf ("malloc error\n" ); fclose(pFile); return NULL ; } if (!fread(pFileBuffer, fileSize, 1 , pFile)) { printf ("read error\n" ); free (pFileBuffer); fclose(pFile); return NULL ; } fclose(pFile); return pFileBuffer; } void PrintHeaders (LPRVOID addr) { LPRVOID pFileBuffer = addr; PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; if (!pFileBuffer) { printf ("Read file error\n" ); return ; } if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) { printf ("Not a pe file!!!\n" ); free (pFileBuffer); return ; } pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; printf ("********************DOS头********************\n" ); printf ("MZ标志: 0x%x\n" , pDosHeader->e_magic); printf ("PE偏移: 0x%x\n" , pDosHeader->e_lfanew); if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { printf ("不是有效的PE标志\n" ); free (pFileBuffer); return ; } pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); printf ("********************NT头********************\n" ); printf ("NT: 0x%x\n" , pNTHeader->signature); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); printf ("********************PE头********************\n" ); printf ("PE: 0x%x\n" , pPEHeader->Machine); printf ("NumberOfSections: 0x%x\n" , pPEHeader->NumberOfSections); printf ("TimeDateStamp: 0x%x\n" , pPEHeader->TimeDateStamp); printf ("SizeOfOptionHeader: 0x%x\n" , pPEHeader->SizeOfOptionalHeader); printf ("Characteristics: 0x%x\n" , pPEHeader->Characteristics); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); printf ("********************OPTIOIN_PE头********************\n" ); printf ("OPTION_PE: 0x%x\n" , pOptionHeader->Magic); printf ("AddressOfEntryPoint: 0x%x\n" , pOptionHeader->AddressOfEntryPoint); printf ("ImageBase: 0x%x\n" , pOptionHeader->ImageBase); printf ("SectionAlignment: 0x%x\n" , pOptionHeader->SectionAlignment); printf ("FileAlignment: 0x%x\n" , pOptionHeader->FileAlignment); printf ("SizeOfImage: 0x%x\n" , pOptionHeader->SizeOfImage); printf ("SizeOfHeaders: 0x%x\n" , pOptionHeader->SizeOfHeaders); printf ("CheckSum: 0x%x\n" , pOptionHeader->CheckSum); printf ("SizeOfStackReserve: 0x%x\n" , pOptionHeader->SizeOfStackReserve); printf ("SizeOfStackCommit: 0x%x\n" , pOptionHeader->SizeOfStackCommit); printf ("SizeOfHeapReserve: 0x%x\n" , pOptionHeader->SizeOfHeapReserve); printf ("SizeOfHeapCommit: 0x%x\n" , pOptionHeader->SizeOfHeapCommit); printf ("The real entrypoint is: 0x%x" , pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint); free (pFileBuffer); } int main () { LPRVOID addr = ReadPEFile("C:\\吾爱破解[LCG].exe" ); PrintHeaders(addr); return 0 ; }
通过StudyPE对比一致
节表学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
节表通过pPEHeader的NumberOfSection 还有 SizeOfOptionHeader两个来查找,通过SizeOfOptionHeader可以找到节表起始地址,而NumberOfSection可以当做循环的终止条件,进行遍历查找
8+4*6+4+4=40
Name:8个字节,一般情况下是以”\0”结尾的ASCII吗字符串来标识的名称,内容可以自定义.注意:该名称并不遵守必须以”\0”结尾的规律,如果不是以”\0”结尾,系统会截取8个字节的长度进行处理. Misc: 双字 是该节在没有对齐前的真实尺寸,该值可以不准确。 VirtualAddress 节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址. SizeOfRawData 节在文件中对齐后的尺寸. PointerToRawData 节区在文件中的偏移. PointerToRelocations 在obj文件中使用 对exe无意义 //不用背 PointerToLinenumbers 行号表的位置 调试的时候使用//不用背 NumberOfRelocations 在obj文件中使用 对exe无意义//不用背 NumberOfLinenumbers 行号表中行号的数量 调试的时候使用//不用背 Characteristics 节的属性
PE加载的过程:
根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer). 根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer 根据节表中的信息循环讲FileBuffer中的节拷贝到ImageBuffer中.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 PIMAGE_SECTION_HEADER pSectionHeader =(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); printf ("********************IMAGE_SECTIONS_HEADER********************\n" );int i = 0 ;for (; i<pPEHeader->NumberOfSections; i++){ printf ("Name: %s\n" , pSectionHeader->Name); printf ("Misc: 0x%x\n" , pSectionHeader->Misc.PhysicalAddress); printf ("VirtualAddress: 0x%x\n" , pSectionHeader->VirtualAddress); printf ("SizeOfRawData: 0x%x\n" , pSectionHeader->SizeOfRawData); printf ("PointerToRawData: 0x%x\n" , pSectionHeader->PointerToRawData); printf ("Characteristics: 0x%x\n" , pSectionHeader->Characteristics); pSectionHeader += 1 ; }
FileBuffer和ImageBuffer PE加载的过程: 1、根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer). 2、根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer 3、根据节表中的信息循环讲FileBuffer中的节拷贝到ImageBuffer中. 4、Misc.VirtualSize 和 SizeOfRawData谁大? 看情况,VirtualSize是内存中的,而SizeOfRawData是文件中的 5、FileBuffer与ImageBuffer谁大? ImageBuffer大
练习
2、编写一个函数,能够将RVA的值转换成FOA.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 #include "name.h" #include <stdio.h> #include <stdlib.h> #include <string.h> DWORD ReadPEFile (IN LPSTR fileName,OUT LPVOID* pFileBuffer) { FILE *pFile = NULL ; DWORD fileSize = 0 ; if (!(pFile=fopen(fileName, "rb" ))) { printf ("无法打开exe文件\n" ); return 0 ; } if (fseek(pFile, 0 , SEEK_END)!=0 ) { printf ("fseek end error\n" ); return 0 ; } if ((fileSize = ftell(pFile)) == -1 ) { printf ("size error\n" ); return 0 ; } if (fseek(pFile, 0 , SEEK_SET)!=0 ) { printf ("fseek pSectionHeader error\n" ); return 0 ; } if (!(*pFileBuffer = malloc (fileSize))) { printf ("malloc error\n" ); fclose(pFile); return 0 ; } if (!fread(*pFileBuffer, fileSize, 1 , pFile)) { printf ("read error\n" ); free (pFileBuffer); fclose(pFile); return 0 ; } fclose(pFile); return fileSize; } DWORD CopyFileBufferToImageBuffer (IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; DWORD copyNum = 0 ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); DWORD ImageSize = pOptionHeader->SizeOfImage; if (!(*pImageBuffer = calloc (ImageSize, 1 ))) { printf ("malloc error\n" ); return 0 ; } DWORD HeadersSize = pOptionHeader->SizeOfHeaders; memcpy (*pImageBuffer, pFileBuffer, HeadersSize); copyNum += HeadersSize; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; int i = 0 ; for (; i<NumberOfSection; i++) { DWORD SizeOfRawData = pSectionHeader->SizeOfRawData; memcpy ((LPVOID)((DWORD)*pImageBuffer + pSectionHeader->VirtualAddress), (LPVOID)((DWORD)pFileBuffer + pSectionHeader->PointerToRawData), SizeOfRawData); copyNum += SizeOfRawData; pSectionHeader += 1 ; } return copyNum; } DWORD CopyImageBufferToNewBuffer (IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; DWORD copyNum = 0 ; pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); DWORD HeadersSize = pOptionHeader->SizeOfHeaders; memcpy (*pNewBuffer, pImageBuffer, HeadersSize); copyNum += HeadersSize; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; int i = 0 ; for (; i<NumberOfSection; i++) { DWORD SizeOfRawData = pSectionHeader->SizeOfRawData; memcpy ( (LPVOID)((DWORD)*pNewBuffer + (pSectionHeader->PointerToRawData)), (LPVOID)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress), SizeOfRawData); copyNum += SizeOfRawData; pSectionHeader += 1 ; } return copyNum; } DWORD MemeryTOFile (IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile) { FILE *pFile = NULL ; DWORD fileSize = 0 ; if (!(pFile=fopen(lpszFile, "wb" ))) { printf ("无法创建文件\n" ); return 0 ; } if (!fwrite(pMemBuffer, size, 1 , pFile)) { printf ("write error\n" ); fclose(pFile); return 0 ; } fclose(pFile); return fileSize; } DWORD RvaToFileOffset (IN LPVOID pFileBuffer,IN DWORD dwRva) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; DWORD result = 0 ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; int i = 0 ; for (; i<NumberOfSection; i++) { DWORD VirtualAddress = pSectionHeader->VirtualAddress; DWORD NextVirtualAddress = VirtualAddress + pSectionHeader->Misc.VirtualSize; if (dwRva > VirtualAddress && dwRva < NextVirtualAddress) { result = (dwRva - VirtualAddress) + pSectionHeader->PointerToRawData; break ; } pSectionHeader += 1 ; } return result; } void PrintHeaders (LPVOID pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; if (!pFileBuffer) { printf ("Read file error\n" ); return ; } if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) { printf ("Not a pe file!!!\n" ); free (pFileBuffer); return ; } pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; printf ("********************DOS头********************\n" ); printf ("MZ标志: 0x%x\n" , pDosHeader->e_magic); printf ("PE偏移: 0x%x\n" , pDosHeader->e_lfanew); if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { printf ("不是有效的PE标志\n" ); free (pFileBuffer); return ; } pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); printf ("********************NT头********************\n" ); printf ("NT: 0x%x\n" , pNTHeader->signature); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); printf ("********************PE头********************\n" ); printf ("PE: 0x%x\n" , pPEHeader->Machine); printf ("NumberOfSections: 0x%x\n" , pPEHeader->NumberOfSections); printf ("TimeDateStamp: 0x%x\n" , pPEHeader->TimeDateStamp); printf ("SizeOfOptionHeader: 0x%x\n" , pPEHeader->SizeOfOptionalHeader); printf ("Characteristics: 0x%x\n" , pPEHeader->Characteristics); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); printf ("********************OPTIOIN_PE头********************\n" ); printf ("OPTION_PE: 0x%x\n" , pOptionHeader->Magic); printf ("AddressOfEntryPoint: 0x%x\n" , pOptionHeader->AddressOfEntryPoint); printf ("ImageBase: 0x%x\n" , pOptionHeader->ImageBase); printf ("SectionAlignment: 0x%x\n" , pOptionHeader->SectionAlignment); printf ("FileAlignment: 0x%x\n" , pOptionHeader->FileAlignment); printf ("SizeOfImage: 0x%x\n" , pOptionHeader->SizeOfImage); printf ("SizeOfHeaders: 0x%x\n" , pOptionHeader->SizeOfHeaders); printf ("CheckSum: 0x%x\n" , pOptionHeader->CheckSum); printf ("SizeOfStackReserve: 0x%x\n" , pOptionHeader->SizeOfStackReserve); printf ("SizeOfStackCommit: 0x%x\n" , pOptionHeader->SizeOfStackCommit); printf ("SizeOfHeapReserve: 0x%x\n" , pOptionHeader->SizeOfHeapReserve); printf ("SizeOfHeapCommit: 0x%x\n" , pOptionHeader->SizeOfHeapCommit); printf ("The real entrypoint is: 0x%x\n" , pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint); free (pFileBuffer); }
手动在代码区添加Shellcode 1、获取MessageBox地址,构造ShellCode代码. 2、E8 E9计算公式 3、在代码区手动添加代码 4、修改OEP,指向ShellCode.
选了PE提取这个exe,然后发觉他FileAlign跟SectionAlign都是0x1000,所以
计算笔记:
7DCBFD1E > 8BFF mov edi,edi 42409D + x = 7DCBFD1E 4240A2 + x = 40A301
6A 00 6A 00 6A 00 6A 00 E8 81 BC 89 7D E9 5F 62 FE FF
任意节添加Shellcode 编写exe实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 void AddShellcode (LPVOID* pImageBuffer,DWORD where) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; DWORD copyNum = 0 ; pDosHeader = (PIMAGE_DOS_HEADER)*pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); DWORD HeadersSize = pOptionHeader->SizeOfHeaders; copyNum += HeadersSize; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; int i = 0 ; for (; i<NumberOfSection; i++, pSectionHeader++) { if (where != i) continue ; DWORD length = sizeof (shellcode)/sizeof (shellcode[0 ])+0x10 ; if (pSectionHeader->SizeOfRawData - pSectionHeader->Misc.VirtualSize < length) { printf ("Not enough space to write this shellcode" ); return ; } DWORD SectionNullBegin= (DWORD)*pImageBuffer+ pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize; DWORD shellcodeStart = pOptionHeader->ImageBase + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize; DWORD align = (0x10 - (shellcodeStart & 0xf )); SectionNullBegin += align; shellcodeStart += align; memcpy ((LPVOID)SectionNullBegin, shellcode, length); *(PDWORD)(SectionNullBegin+0x9 ) = (DWORD)(MessageBoxA_addr - (shellcodeStart+0xd )); *(PDWORD)(SectionNullBegin+0xe ) = (DWORD)((DWORD)(pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - shellcodeStart-0x12 ); pOptionHeader->AddressOfEntryPoint = shellcodeStart - (pOptionHeader->ImageBase); break ; } if (i == NumberOfSection) { printf ("没有足够多的Section" ); } return ; }
添加节
添加节,特别要注意SizeOfImage,还有VirtualAddress,这里跟视频讲解不太一样,照着视频的会出错,高能高能,节属性要设置可读可写可执行,不要随便设置复制,会出错的,我被坑惨了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 void AddSection (LPVOID* pImageBuffer, DWORD length) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeaderEnd = NULL ; PIMAGE_SECTION_HEADER pSectionHeaderBefore = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)*pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); DWORD HeadersSize = pOptionHeader->SizeOfHeaders; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; pSectionHeaderEnd = pSectionHeader + NumberOfSection; pSectionHeaderBefore = pSectionHeader + (NumberOfSection-1 ); DWORD restSize = HeadersSize - pDosHeader->e_lfanew - 20 - pPEHeader->SizeOfOptionalHeader - 0x28 *NumberOfSection; if (restSize < 0x28 *2 ) { printf ("Not enough space to add Section" ); return ; } *pSectionHeaderEnd = *pSectionHeader; BYTE NAME[8 ] = {".NewSec" }; int i=0 ; for (; i<8 ; i++) pSectionHeaderEnd->Name[i] = NAME[i]; memset (pSectionHeaderEnd + 1 , 0 , 0x28 ); pSectionHeaderEnd->Misc.VirtualSize = getAlign(length, pOptionHeader->SectionAlignment); pSectionHeaderEnd->VirtualAddress = getAlign(pOptionHeader->SizeOfImage, pOptionHeader->SectionAlignment); pSectionHeaderEnd->SizeOfRawData = getAlign(length, pOptionHeader->FileAlignment); pSectionHeaderEnd->PointerToRawData = pSectionHeaderBefore->PointerToRawData + pSectionHeaderBefore->SizeOfRawData; printf ("%x\n" , pSectionHeaderEnd->PointerToRawData); pSectionHeaderEnd->Characteristics = 0xE00000C0 ; pPEHeader->NumberOfSections += 1 ; pOptionHeader->SizeOfImage += getAlign(length, pOptionHeader->SectionAlignment); *pImageBuffer = realloc (*pImageBuffer, pOptionHeader->SizeOfImage); memset ((DWORD)*pImageBuffer+pOptionHeader->SizeOfImage - length, 0 , length); }
扩展节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 void ExtendSection (LPVOID* pImageBuffer, DWORD where, DWORD length) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeaderEnd = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)*pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; if (where >= NumberOfSection) { printf ("OverFlow the Section table\n" ); return ; } pSectionHeaderEnd = pSectionHeader + where; pSectionHeaderEnd->Misc.VirtualSize += length; pSectionHeaderEnd->SizeOfRawData += length; pOptionHeader->SizeOfImage += length; realloc (*pImageBuffer, pOptionHeader->SizeOfImage); memset (*pImageBuffer+pOptionHeader->SizeOfImage - length, 0 , length); }
移动节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void MoveSection (LPVOID* pImageBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)*pImageBuffer; if (pDosHeader->e_lfanew - sizeof (IMAGE_DOS_HEADER) < 0x28 *2 ) { printf ("No enough space to add Section\n" ); return ; } DWORD peStart = sizeof (IMAGE_DOS_HEADER); pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); DWORD HeadersSize = pOptionHeader->SizeOfHeaders; DWORD copyNum = HeadersSize - pDosHeader->e_lfanew; memcpy ((LPVOID)(*pImageBuffer+peStart), pNTHeader, copyNum); pDosHeader->e_lfanew = peStart; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); }
通过移动节可以增大剩余节的空间,通过扩展节,可以添加shellcode
问题:
1 2 3 4 5 pSectionHeaderEnd->Misc.VirtualSize += 0x1000 ; pSectionHeaderEnd->SizeOfRawData += length; pOptionHeader->SizeOfImage += 0x1000 ;
这里不能是三个相同,因为我添加shellcode代码要求SizeOfRawData-VirtualSize > 0x28*2
经过测试,SizeOfImage和VirtualSize不能乱改,改错就直接执行不了
合并节 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 DWORD MergeSection (LPVOID* pImageBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)*pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)*pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; DWORD FinalSize = pOptionHeader->SizeOfImage - pSectionHeader->VirtualAddress; pSectionHeader->SizeOfRawData = pSectionHeader->Misc.VirtualSize = FinalSize; pSectionHeader->Characteristics = 0xE0000020 ; memset (pSectionHeader+1 , 0 , 0x28 ); pPEHeader->NumberOfSections = 1 ; return pOptionHeader->SizeOfImage; }
内存对齐
1 2 3 4 DWORD getAlign (DWORD x, DWORD y) { return x/y == x/(float )y ? x: (x/y+1 )*y; }
x为值,y为对齐的值
动态链接和静态链接 codeblock静态链接
动态链接 名称导出 序号导出 导出表 函数数量= 最大序号-最小序号+1,所以可能会不准
2,3,5,6 6-2+1 = 5,实际是4个函数
序号表存的减去base的,所以要base+序号表才是真正序号导出
手动找导出表 ReadPEFile->FileBuffer->pOptionHeader->DataDirectory->Export_Table
然后获取到三张表地址,AddressOfFunction, AddressOfName, AddressOfNameOrdinals
查表过程
注意:
三个Address都是RVA的地址 AddressOfFunction 4个字节,AddressOfNameOrdinals 2个字节, AddressOfName 4个字节 AddressOfName里存的是名字的RVA,AddressOfFunction里存的也是RVA 序号查:
将序号减去导出表的Base,然后直接从AddressOfFunction里找对应目录项,获取到RVA,然后在转成FOA
名称查:
将名字同AddressOfName里每个目录项对比,若相同,则去对应的AddressOfNameOrdinals里找序号,然后转到AddressOfFunction里
练习 获取导出表并打印
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void getExportTable (LPVOID pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_EXPORT_DIRECTORY pExportDirectory= NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; printf ("Export_Table: %x %x\n" , pDataDirectory->VirtualAddress, pDataDirectory->Size); pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pDataDirectory->VirtualAddress)); printf ("ImageBase: %x\n" , pOptionHeader->ImageBase); PrintfExportDirectory(pFileBuffer, pExportDirectory); char Name[]="Sub" ; printf ("%s: %x\n" , Name, GetFunctionAddrByName(pFileBuffer, Name)); printf ("序号3: %x\n" , GetFunctionAddrByOrdinals(pFileBuffer, 3 )); }
打印重定位表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void PrintfExportDirectory (LPVOID pFileBuffer, PIMAGE_EXPORT_DIRECTORY pExportDirectory) { printf ("Characteristics: %x\n" , pExportDirectory->Characteristics); printf ("TimeDateStamp: %x\n" , pExportDirectory->TimeDateStamp); printf ("MajorVersion: %x\n" , pExportDirectory->MajorVersion); printf ("MinorVersion: %x\n" , pExportDirectory->MinorVersion); printf ("Base: %x\n" , pExportDirectory->Base); printf ("NumberOfFunctions: %x\n" , pExportDirectory->NumberOfFunctions); printf ("NumberOfNames: %x\n" , pExportDirectory->NumberOfNames); int i = 0 ; printf (" |函数地址表|函数序号表|函数名称表|\n" ); DWORD max = pExportDirectory->NumberOfFunctions > pExportDirectory->NumberOfNames ? pExportDirectory->NumberOfFunctions:pExportDirectory->NumberOfNames; for (; i< max; i++) { printf ("%2x" , i); if (i < pExportDirectory->NumberOfFunctions) printf ("|%9x |" , RvaToFileOffset(pFileBuffer, ((PDWORD)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfFunctions)))[i])); else printf ("|---------|" ); if (i < pExportDirectory->NumberOfNames) { printf ("%9x |" , ((PWORD)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfNameOrdinals)))[i]); printf ("%9x |" , RvaToFileOffset(pFileBuffer, ((PDWORD)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfNames)))[i])); } printf ("\n" ); } }
通过两种方式获取地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 DWORD GetFunctionAddrByName (LPVOID pFileBuffer, LPVOID pName) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_EXPORT_DIRECTORY pExportDirectory= NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pDataDirectory->VirtualAddress)); PDWORD AddressName = pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfNames); DWORD i = 0 ; DWORD NumberOfNames = pExportDirectory->NumberOfNames; for (; i < NumberOfNames ; i++) { if (!strcmp ( (PDWORD)(pFileBuffer + RvaToFileOffset(pFileBuffer, AddressName[i])), pName)) break ; } if (i >= NumberOfNames) { printf ("Not found" ); return 0 ; } PWORD AddressOfNameOrdinals = pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfNameOrdinals); PDWORD AddressOfFunction = pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfFunctions); DWORD result = RvaToFileOffset(pFileBuffer, AddressOfFunction[AddressOfNameOrdinals[i]]); return result; } DWORD GetFunctionAddrByOrdinals (LPVOID pFileBuffer, DWORD num) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_EXPORT_DIRECTORY pExportDirectory= NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, pDataDirectory->VirtualAddress)); PDWORD AddressOfFunction = pFileBuffer + RvaToFileOffset(pFileBuffer, pExportDirectory->AddressOfFunctions); return RvaToFileOffset(pFileBuffer, AddressOfFunction[num - pExportDirectory->Base]); }
重定位表 获取重定位表
重定位表就是处理地址冲突的表,假设有个dll是0x10000000,另一个dll的ImageBase也是,加载到内存中必然会冲突,所以重定位的话,假设让他放到0x20000000,然后就可以处理冲突了,但是代码的偏移都需要改变
打印重定位表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 void getRelaction (LPVOID pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_BASE_RELOCATION pBaseRelocation= NULL ; PBYTE pName = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory; pBaseRelocation = (PIMAGE_BASE_RELOCATION)(pFileBuffer + RvaToFileOffset(pFileBuffer, pDataDirectory[5 ].VirtualAddress)); printf ("Relocation_Table: %x %x\n" , RvaToFileOffset(pFileBuffer, pDataDirectory[5 ].VirtualAddress), pDataDirectory[5 ].Size); DWORD i = 0 ; do { DWORD VirtualAddress = pBaseRelocation->VirtualAddress; DWORD SizeOfBlock = pBaseRelocation->SizeOfBlock; pName = getSectionName(pFileBuffer, VirtualAddress); DWORD NumberOfBlock = (SizeOfBlock - 8 )/2 ; PWORD pSection = (DWORD)pBaseRelocation + 8 ; printf ("%s VirtualAddress: %x Size: %x\n" , pName, VirtualAddress, SizeOfBlock); for (i=0 ; i<NumberOfBlock; i++) { printf ("第%d项: Address:%x 属性:%x\n" ,i, VirtualAddress + (((WORD)(pSection[i]<<4 ))>>4 ), pSection[i]>>12 ); } pBaseRelocation = (DWORD)pBaseRelocation + SizeOfBlock; }while (pBaseRelocation->VirtualAddress!=0 && pBaseRelocation->SizeOfBlock!=0 ); }
移动导出表 新增一个节 移动AddressOfFunctions表 移动AddressOfNameOrdinals表 移动AddressOfName表 移动AddressOfName表中每个地址的内容,同时修复AddressOfName 移动整个表结构,同时修复AddressOfFunctions,AddressOfNameOrdinals,AddressOfName三个的RVA 修复pDataDirectory[0].VirtualAddress为新表的VirtualAddress 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 void TestAddSectionAndMoveExportTable (DWORD size, PBYTE NAME) { LPVOID pFileBuffer = NULL ; DWORD num = ReadPEFile(peFile, &pFileBuffer); if (!num) { printf ("ReadPEFile error\n" ); return ; } else { printf ("ReadPEFile finish: %x\n" , num); } DWORD FOA = AddSectionFromFileBuffer(&pFileBuffer, num, NAME, size); printf ("FOA is: %x\n" , FOA); MoveExportTable(pFileBuffer, FOA); MemeryTOFile(pFileBuffer, num+size, "1.dll" ); } void MoveExportTable (LPVOID pFileBuffer, DWORD FOA) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_EXPORT_DIRECTORY pExportDirectory= NULL ; PIMAGE_EXPORT_DIRECTORY pCopyPlace = NULL ; PIMAGE_EXPORT_DIRECTORY pNewExportDirectory = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; pSectionHeader = pSectionHeader + (NumberOfSection-1 ); DWORD VirtualAddress = pSectionHeader->VirtualAddress; pDataDirectory = pOptionHeader->DataDirectory; printf ("Export_Table: %x %x\n" , pDataDirectory->VirtualAddress, pDataDirectory->Size); pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + getFOA(pDataDirectory->VirtualAddress)); pCopyPlace = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer + FOA); PDWORD AddressOfFunction = pFileBuffer + getFOA(pExportDirectory->AddressOfFunctions); DWORD NumberOfFunction = pExportDirectory->NumberOfFunctions; DWORD length = 0 ; memcpy ((LPVOID)pCopyPlace, (LPVOID)AddressOfFunction, NumberOfFunction*4 ); length += NumberOfFunction*4 ; DWORD AddressOfNameOrdinals = (DWORD)pFileBuffer + getFOA(pExportDirectory->AddressOfNames); DWORD NumberOfNames = pExportDirectory->NumberOfNames; printf ("%x\n" , AddressOfNameOrdinals); memcpy ((DWORD)pCopyPlace+length, AddressOfNameOrdinals, 2 *NumberOfNames); length += 2 *NumberOfNames; PDWORD AddressOfName = (DWORD)pFileBuffer + getFOA(pExportDirectory->AddressOfNames); DWORD i = 0 ; DWORD size = 0 ; DWORD realAddr = 0 ; memcpy ((DWORD)pCopyPlace+length, AddressOfName, 4 *NumberOfNames); length += 4 *NumberOfNames; for (; i<NumberOfNames; i++) { realAddr = (DWORD)pFileBuffer + getFOA(AddressOfName[i]); size = strlen ((PBYTE)realAddr)+1 ; memcpy ((DWORD)pCopyPlace+length, realAddr, size); AddressOfName[i] = VirtualAddress+ length; length += size; } memcpy ((DWORD)pCopyPlace+length, pExportDirectory, sizeof (IMAGE_EXPORT_DIRECTORY)); pNewExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(DWORD)pCopyPlace+length; pNewExportDirectory->AddressOfFunctions = VirtualAddress; pNewExportDirectory->AddressOfNameOrdinals = pNewExportDirectory->AddressOfFunctions + NumberOfFunction*4 ; pNewExportDirectory->AddressOfNames = pNewExportDirectory->AddressOfNameOrdinals + NumberOfNames*2 ; pDataDirectory->VirtualAddress = VirtualAddress + length ; printf ("%x\n" , getFOA(pDataDirectory->VirtualAddress)); length += sizeof (IMAGE_EXPORT_DIRECTORY); }
移动重定位表 新增一个节 将重定位表整体移动到新节里 修改pDataDirectory[5].VirtualAddress为新增节的VirtualAddress 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 void TestAddSectionAndMoveRelocationTable (DWORD size, PBYTE NAME) { LPVOID pFileBuffer = NULL ; DWORD num = ReadPEFile(peFile, &pFileBuffer); if (!num) { printf ("ReadPEFile error\n" ); return ; } else { printf ("ReadPEFile finish: %x\n" , num); } DWORD FOA = AddSectionFromFileBuffer(&pFileBuffer, num, NAME, size); printf ("FOA is: %x\n" , FOA); MoveRelocationTable(pFileBuffer, FOA); MemeryTOFile(pFileBuffer, num+size, "1.dll" ); } void MoveRelocationTable (LPVOID pFileBuffer,DWORD FOA) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_BASE_RELOCATION pBaseRelocation = NULL ; PIMAGE_BASE_RELOCATION pCopyPlace = NULL ; PIMAGE_BASE_RELOCATION pNewExportDirectory = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; pSectionHeader = pSectionHeader + (NumberOfSection-1 ); DWORD VirtualAddress = pSectionHeader->VirtualAddress; pDataDirectory = pOptionHeader->DataDirectory; pDataDirectory += 5 ; printf ("Relocation_Table: %x %x\n" , pDataDirectory->VirtualAddress, pDataDirectory->Size); pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + getFOA(pDataDirectory->VirtualAddress)); pCopyPlace = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + FOA); DWORD i = 0 ; DWORD length = 0 ; do { DWORD SizeOfBlock = pBaseRelocation->SizeOfBlock; DWORD realAddr = (DWORD)pFileBuffer + getFOA(pBaseRelocation->VirtualAddress); memcpy ((DWORD)pCopyPlace+length, pBaseRelocation, SizeOfBlock); pBaseRelocation = (DWORD)pBaseRelocation + SizeOfBlock; length += SizeOfBlock; }while (pBaseRelocation->VirtualAddress!=0 && pBaseRelocation->SizeOfBlock!=0 ); memcpy ((DWORD)pCopyPlace+length,pBaseRelocation, sizeof (PIMAGE_BASE_RELOCATION)); pDataDirectory->VirtualAddress = VirtualAddress; printf ("%x\n" , pDataDirectory->VirtualAddress); printf ("%x\n" , getFOA(pDataDirectory->VirtualAddress)); }
模拟操作系统重定位过程 修改ImageBase 找到重定位表 根据重定位表修改每个地址原来的值 注意单位应该是4个字节,因为ImageBase也是4个字节 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 void ChangeImageBase (LPVOID pFileBuffer,DWORD Size) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_BASE_RELOCATION pBaseRelocation = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; pSectionHeader = pSectionHeader + (NumberOfSection-1 ); DWORD VirtualAddress = pSectionHeader->VirtualAddress; pDataDirectory = pOptionHeader->DataDirectory; printf ("Relocation_Table: %x %x\n" , pDataDirectory[5 ].VirtualAddress, pDataDirectory[5 ].Size); pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + getFOA(pDataDirectory[5 ].VirtualAddress)); printf ("%x\n" , pOptionHeader->ImageBase); pOptionHeader->ImageBase += Size; DWORD i = 0 ; do { DWORD VirtualAddress = pBaseRelocation->VirtualAddress; DWORD SizeOfBlock = pBaseRelocation->SizeOfBlock; DWORD NumberOfBlock = (SizeOfBlock - 8 )/2 ; PWORD pSection = (DWORD)pBaseRelocation + 8 ; printf ("VirtualAddress: %x Size: %x\n" , VirtualAddress, SizeOfBlock); for (i=0 ; i<NumberOfBlock; i++) { if ((pSection[i]>>12 ) == 0x3 ) { PDWORD Addr = (DWORD)pFileBuffer + getFOA(VirtualAddress + (((WORD)(pSection[i]<<4 ))>>4 )); printf ("%p\n" , Addr); *Addr += Size; } } pBaseRelocation = (DWORD)pBaseRelocation + SizeOfBlock; }while (pBaseRelocation->VirtualAddress!=0 && pBaseRelocation->SizeOfBlock!=0 ); } void TestChangeImageBase () { LPVOID pFileBuffer = NULL ; DWORD num = ReadPEFile(peFile, &pFileBuffer); if (!num) { printf ("ReadPEFile error\n" ); return ; } else { printf ("ReadPEFile finish: %x\n" , num); } ChangeImageBase(pFileBuffer, 0x10000000 ); MemeryTOFile(pFileBuffer, num, "1.dll" ); }
IAT表 导入表hook, 修改导入表,然后让其跳转到我们的代码
动态解析导入的函数
导入表 打印导入表,有个问题,DLL跟EXE的导入表不一样,DLL的IAT是正确的,他的INT存的是地址,而且是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 void PrintImportTable (LPVOID pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_BASE_RELOCATION pBaseRelocation = NULL ; PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL ; PIMAGE_THUNK_DATA32 pThunkData32 = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; printf ("Import_Table: %x Size: %x\n" , pDataDirectory[1 ].VirtualAddress, pDataDirectory[1 ].Size); pImportDescriptor = (DWORD)pFileBuffer + getFOA(pDataDirectory[1 ].VirtualAddress); DWORD count = 0 ; do { printf ("Name: %s\n" , (DWORD)pFileBuffer + getFOA(pImportDescriptor[count].Name)); printf ("OriginalFirstThunk: %x\n" , pImportDescriptor[count].OriginalFirstThunk); printf ("FirstThunk: %x\n" , pImportDescriptor[count].FirstThunk); printf ("------------------OriginalFirstThunk------------------\n" ); pThunkData32 = (DWORD)pFileBuffer + getFOA(pImportDescriptor[count].OriginalFirstThunk); DWORD i = 0 ; do { if ( pThunkData32[i].u1.Ordinal & 0x80000000 ) { printf ("序号导出: %d\n" , pThunkData32[i].u1.Ordinal &0x7fffffff ); } else { printf ("名称导出: %s\n" , (DWORD)pFileBuffer + getFOA(pThunkData32[i].u1.AddressOfData)+2 ); } i++; }while (pThunkData32[i].u1.AddressOfData!=NULL ); printf ("------------------FirstThunk------------------\n" ); pThunkData32 = (DWORD)pFileBuffer + getFOA(pImportDescriptor[count].FirstThunk); i = 0 ; do { if ( pThunkData32[i].u1.Ordinal & 0x80000000 ) { printf ("序号导出: %x\n" , pThunkData32[i].u1.Ordinal &0x7fffffff ); } else { printf ("名称导出: %s\n" , (DWORD)pFileBuffer + getFOA(pThunkData32[i].u1.AddressOfData)+2 ); } i++; }while (pThunkData32[i].u1.AddressOfData!=NULL ); count ++; }while (pImportDescriptor[count].Name!=NULL ); }
绑定导入表 解决了导入表输出错误的问题,根据TimeStamp来判断是否是绑定的,绑定的话,地址就写死在那里
PE加载EXE相关的DLL时,首先会根据IMAGE_IMPORT_DESCRIPTOR结构中的TimeDateStamp来判断是否要重新计算IAT表中的地址。
TimeDateStamp == 0 未绑定
TimeDateStamp == -1 已绑定 真正的绑定时间为IMAGE_BOUND_IMPORT_DESCRIPTOR的TimeDateStamp
绑定导入表位于数据目录的第12项
还有ModuleOffset是相对于第一个的偏移,不是相对每个模块的偏移
打印绑定导入表…找不到一个有绑定导入表的,dll的VirtualAddress看不懂,然后打印不出来,到后面一节视频才知道VirtualAddress在节表里是找不到的,PEheader不用转换,因为直接复制过去的所以RVA->FOA需要考虑小于sizeOfHeader,小于的默认就是那个值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void PrintBoundImportTable (LPVOID pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_BASE_RELOCATION pBaseRelocation = NULL ; PIMAGE_BOUND_IMPORT_DESCRIPTOR pBoundImportDescriptor = NULL ; PIMAGE_BOUND_FORWARDER_REF pBoundForwarderRef = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; printf ("Import_Table: %x Size: %x\n" , pDataDirectory[11 ].VirtualAddress, pDataDirectory[11 ].Size); pBoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + pDataDirectory[11 ].VirtualAddress); DWORD i = 0 ; DWORD j = 0 ; do { printf ("TimeStamp: %x\n" , pBoundImportDescriptor[i].TimeDateStamp); printf ("OffsetModuleName: %x\n" , pBoundImportDescriptor[i].OffsetModuleName); printf ("NumberOfModuleForwarderRefs: %x\n" , pBoundImportDescriptor[i].NumberOfModuleForwarderRefs); printf ("Name: %s\n" , (DWORD)pBoundImportDescriptor + pBoundImportDescriptor[i].OffsetModuleName); i++; pBoundForwarderRef = &pBoundImportDescriptor[i]; for (j = 0 ; j<pBoundImportDescriptor[i].NumberOfModuleForwarderRefs; j++) { printf ("TimeStamp: %x\n" , pBoundForwarderRef[j].TimeDateStamp); printf ("OffsetModuleName: %x\n" , pBoundForwarderRef[j].OffsetModuleName); printf ("Name: %s\n" , (DWORD)pBoundImportDescriptor + pBoundForwarderRef[j].OffsetModuleName); printf ("Reserved: %x\n" , pBoundForwarderRef->Reserved); } printf ("\n" ); if (j >= pBoundImportDescriptor[i].NumberOfModuleForwarderRefs && j!=0 ) j--; i = i + j ; }while (pBoundImportDescriptor[i].OffsetModuleName!=0 ); }
导入表注入 真的坑,以为自己代码写错,对着16进制数据一通对比也没发现错误,重新按一种规格写了一遍,还是不行,草,最后发觉是节属性的问题,被节属性坑了好几遍了,所以把代码改了就行了,
1 2 pSectionHeaderEnd->Characteristics = 0xE00000C0 ;
写了两个版本的,第一种不为什么,就是知道什么填什么,然后慢慢填满的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 void InjectDll (LPVOID pFileBuffer, DWORD FOA, char * NAME, char * FuncName) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL ; PIMAGE_IMPORT_DESCRIPTOR pCopyPlace = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; PIMAGE_THUNK_DATA32 pThunkData32 = NULL ; PIMAGE_IMPORT_DESCRIPTOR pNewImportDescriptor = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; printf ("Import_Table: %x Size: %x\n" , pDataDirectory[1 ].VirtualAddress, pDataDirectory[1 ].Size); pImportDescriptor = (DWORD)pFileBuffer + getFOA(pDataDirectory[1 ].VirtualAddress); pCopyPlace = (DWORD)pFileBuffer + FOA; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; DWORD length = sizeof (IMAGE_IMPORT_DESCRIPTOR); DWORD num = 0 ; do { memcpy ((DWORD)pCopyPlace+num, pImportDescriptor, length); pImportDescriptor++; num += length; }while (pImportDescriptor->Name!=NULL ); pNewImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pCopyPlace + num); pNewImportDescriptor->TimeDateStamp = 0 ; pNewImportDescriptor->ForwarderChain = 0 ; num += (length*2 ); DWORD temp = strlen (NAME); memcpy (((DWORD)pCopyPlace + num), NAME, temp); pNewImportDescriptor->Name = pSectionHeader[NumberOfSection-1 ].VirtualAddress + num; num += (getAlign(temp+1 ,4 )); temp = strlen (FuncName); memset ((DWORD)pCopyPlace+num, 0 , 2 ); memcpy ((DWORD)pCopyPlace+num+2 , FuncName, temp); DWORD align = getAlign(3 +temp, 4 ); *((PDWORD)((DWORD)pCopyPlace + num + align)) = pSectionHeader[NumberOfSection-1 ].VirtualAddress + num; *((PDWORD)((DWORD)pCopyPlace + num + align + 4 )) = 0 ; pNewImportDescriptor->OriginalFirstThunk = pSectionHeader[NumberOfSection-1 ].VirtualAddress + num + align; pNewImportDescriptor->FirstThunk = pNewImportDescriptor->OriginalFirstThunk; *((PDWORD)((DWORD)pCopyPlace + num + align + 8 )) = pSectionHeader[NumberOfSection-1 ].VirtualAddress + num; *((PDWORD)((DWORD)pCopyPlace + num + align + 8 + 4 )) = 0 ; num += (align + 8 ); pNewImportDescriptor->FirstThunk = pSectionHeader[NumberOfSection-1 ].VirtualAddress + num; pDataDirectory[1 ].VirtualAddress = pSectionHeader[NumberOfSection-1 ].VirtualAddress; pDataDirectory[1 ].Size += length; printf ("Name: %x\n" , getFOA(pNewImportDescriptor->Name)); printf ("Original: %x\n" , getFOA(pNewImportDescriptor->OriginalFirstThunk)); printf ("First_Thunk: %x\n" , getFOA(pNewImportDescriptor->FirstThunk)); }
第二个版本,先设计好在进行填充的,所以写的很快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 void InjectDll (LPVOID pFileBuffer, DWORD FOA, char * NAME, char * FuncName) { PIMAGE_DOS_HEADER pDosHeader = NULL ; PIMAGE_NT_HEADERS pNTHeader = NULL ; PIMAGE_FILE_HEADER pPEHeader = NULL ; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL ; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL ; PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL ; PIMAGE_IMPORT_DESCRIPTOR pCopyPlace = NULL ; PIMAGE_SECTION_HEADER pSectionHeader = NULL ; PIMAGE_THUNK_DATA32 pThunkData32 = NULL ; PIMAGE_IMPORT_DESCRIPTOR pNewImportDescriptor = NULL ; pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4 ); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pDataDirectory = pOptionHeader->DataDirectory; printf ("Import_Table: %x Size: %x\n" , pDataDirectory[1 ].VirtualAddress, pDataDirectory[1 ].Size); pImportDescriptor = (DWORD)pFileBuffer + getFOA(pDataDirectory[1 ].VirtualAddress); pCopyPlace = (DWORD)pFileBuffer + FOA; pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); DWORD NumberOfSection = pPEHeader->NumberOfSections; DWORD length = sizeof (IMAGE_IMPORT_DESCRIPTOR); DWORD copyNum = 0 ; DWORD temp = 0 ; DWORD funcNameAddr = 0 ; DWORD IATAddr = 0 ; DWORD INTAddr = 0 ; DWORD VirtualAddress = pSectionHeader[NumberOfSection-1 ].VirtualAddress; temp = strlen (NAME); memcpy (pCopyPlace, NAME, temp); temp = getAlign(temp+1 , 4 ); copyNum += temp; funcNameAddr = copyNum; temp = strlen (FuncName); memset ((DWORD)pCopyPlace+copyNum, 0 , 2 ); memcpy ((DWORD)pCopyPlace+copyNum+2 , FuncName, temp); temp = getAlign(temp+3 , 4 ); INTAddr = copyNum+temp; *((PDWORD)((DWORD)pCopyPlace +INTAddr)) = VirtualAddress + funcNameAddr; *((PDWORD)((DWORD)pCopyPlace + INTAddr)+1 ) = 0 ; IATAddr = INTAddr + 8 ; *((PDWORD)((DWORD)pCopyPlace + IATAddr)) = VirtualAddress + funcNameAddr; *((PDWORD)((DWORD)pCopyPlace + IATAddr)+1 ) = 0 ; copyNum = (IATAddr+8 ); printf ("%x\n" , copyNum); printf ("%x\n" , (DWORD)pCopyPlace); printf ("%x\n" , (DWORD)pImportDescriptor); do { memcpy ((DWORD)pCopyPlace+copyNum, pImportDescriptor, length); pImportDescriptor++; copyNum += length; }while (pImportDescriptor->Name!=NULL ); pNewImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pCopyPlace+copyNum); pNewImportDescriptor->Characteristics = 0 ; pNewImportDescriptor->TimeDateStamp = 0 ; pNewImportDescriptor->ForwarderChain = 0 ; pNewImportDescriptor->Name = VirtualAddress; pNewImportDescriptor->OriginalFirstThunk = VirtualAddress + INTAddr; pNewImportDescriptor->FirstThunk = VirtualAddress + IATAddr; pDataDirectory[1 ].VirtualAddress = VirtualAddress + (IATAddr+8 ); pDataDirectory[1 ].Size += length; printf ("Name: %x\n" , getFOA(pNewImportDescriptor->Name)); printf ("Original: %x\n" , getFOA(pNewImportDescriptor->OriginalFirstThunk)); printf ("First_Thunk: %x\n" , getFOA(pNewImportDescriptor->FirstThunk)); }
启动不了有可能是节的属性出问题
本文作者 :NoOne本文地址 : https://noonegroup.xyz/posts/6fd44671/ 版权声明 :转载请注明出处!