课堂上很好理解的一副,贴进来;
合并节算法解释
1.读取文件,拉伸到内存; 2.第一种算法; (1)取最后一个节中(SizeOfRawData和VirtualSize)的值,谁大就取谁,下面是简单的算法表达式; 最后一个节Max = SizeOfRawData>VirtualSize?SizeOfRawData:VirtualSize; (2)通过最后一个节的VirtualAddress + 上面得到的最后一个节Max - 拉伸后的SizeOfHeaders内存对齐后的大小 (3)将上面算出来的值分别将其置为一样 --> SizeOfRawData = VirtualSize; 第二种算法; (1)直接获取拉伸后的SizeOfImage大小减去拉伸后的第一个节VirtualAddress大小即可得到一个值;SizeOfImage-VirtualAddress (2)将上面算出来的值分别将其置为一样 --> SizeOfRawData = VirtualSize; 3.将第一个节的属性改为包含所有节的属性,这一步操作其实就是上面的算法操作; 4.修改节的数量为1; 5.上面操作完成就是动态申请内存,完成初始化置0,然后内存复制数据,存盘的操作即可;
核心代码部分
1 // gbpeall.cpp: implementation of the gbpeall class. 2 // 3 ////////////////////////////////////////////////////////////////////// 4 5 #include "stdafx.h" 6 #include "gbpeall.h" 7 8 9 ////////////////////////////////////////////////////////////////////// 10 // Construction/Destruction 11 ////////////////////////////////////////////////////////////////////// 12 13 14 //定义一个全局变量 15 BYTE ShellCode[] = 16 { 17 0x6A,00,0x6A,00,0x6A,00,0x6A,00, //MessageBox push 0的硬编码 18 0xE8,00,00,00,00, // call汇编指令E8和后面待填充的硬编码 19 0xE9,00,00,00,00 // jmp汇编指令E9和后面待填充的硬编码 20 }; 21 22 //ExeFile->FileBuffer 返回值为计算所得文件大小 23 //读取一个exe文件,然后输出为FileBuffer 24 DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer) 25 { 26 //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展; 27 //啥也不干,即使理解成干,也是扩展成空白,这个是C++语法中允许的; 28 //LPSTR ----> typedef CHAR *LPSTR, *PSTR; 意思就是char* 指针;在WINNT.H头文件里面 29 FILE* pFile = NULL; 30 //定义一个FILE结构体指针,在标准的Stdio.h文件头里面 31 //可参考:https://blog.csdn.net/qq_15821725/article/details/78929344 32 DWORD fileSize = 0; 33 // typedef unsigned long DWORD; DWORD是无符号4个字节的整型 34 LPVOID pTempFileBuffer = NULL; 35 //LPVOID ----> typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型 36 37 //打开文件 38 pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来 39 if (!pFile) 40 { 41 printf("打开文件失败! "); 42 return 0; 43 } 44 /* 45 关于在指针类型中进行判断的操作,下面代码出现的情况和此一样,这里解释下: 46 1.因为指针判断都要跟NULL比较,相当于0,假值,其余都是真值 47 2.if(!pFile)和if(pFile == NULL), ----> 为空,就执行语句;这里是两个等于号不是一个等于号 48 3.if(pFile)就是if(pFile != NULL), 不为空,就执行语句; 49 */ 50 51 //读取文件内容后,获取文件的大小 52 fseek(pFile,0,SEEK_END); 53 fileSize = ftell(pFile); 54 fseek(pFile,0,SEEK_SET); 55 56 /* 57 fseek 通过使用二进制的方式打开文件,移动文件读写指针的位置,在stdio.h头文件里 58 59 int fseek(FILE * stream, long offset, int fromwhere); 60 61 上面是fseek的函数原型 62 第一个参数stream 为文件指针 63 第二个参数offset 为偏移量,整数表示正向偏移,负数表示负向偏移 64 第三个参数fromwhere 为指针的起始位置,设定从文件的哪里开始偏移,可能取值为:SEEK_CUR,SEEK_END,SEEK_SET 65 SEEK_SET 0 文件开头 66 SEEK_CUR 1 当前读写的位置 67 SEEK_END 2 文件尾部 68 69 下面是相关用法和例子: 70 fseek(fp,100L,0);把fp指针移动到离文件开头100字节处; 71 fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处; 72 fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。 73 fseek(fp,0,SEEK_SET);将读写位置移动到文件开头; 74 fseek(fp,0,SEEK_END);将读写位置移动到文件尾时; 75 fseek(fp,100L,SEEK_SET);将读写位置移动到离文件开头100字节处; 76 fseek(fp,100L,SEEK_CUR);将读写位置移动到离文件当前位置100字节处; 77 fseek(fp,-100L,SEEK_END);将读写指针退回到离文件结尾100字节处; 78 fseek(fp,1234L,SEEK_CUR);把读写位置从当前位置向后移动1234字节; 79 fseek(fp,0L,2);把读写位置移动到文件尾; 80 其中 ---> L后缀表示长整数 81 82 ftell()用于返回文件当前指针指向的位置,与fseek配合可以算出文件元素数据总数。 83 参考:http://c.biancheng.net/cpp/html/2519.html 84 85 ftell()函数用来获取文件读写指针的当前位置,其原型为:long ftell(FILE * stream); 同样在stdio.h头文件里 86 参数:stream 为已打开的文件指针。 87 */ 88 89 //动态申请内存空间 90 pTempFileBuffer = malloc(fileSize); 91 92 /* 93 参考:http://c.biancheng.net/cpp/html/137.html 94 原型:void* malloc (size_t size); 95 size_t ---> typedef unsigned int size_t; 无符号整型别名是size_t 96 void* ---> 函数的返回值类型是 void* ;void并不是说没有返回值或者返回空指针,而是返回的指针类型未知; 97 所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型; 98 例如:char *ptr = (char *)malloc(10); //分配10个字节的内存空间,用来存放字符 99 参数说明 ---> size 为需要分配的内存空间的大小,以字节(Byte)计。 100 函数说明 ---> malloc()在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化; 101 它们的值是未知的,所以分配完成内存之后需要初始化; 102 返回值:分配成功返回指向该内存的地址,失败则返回 NULL。 103 */ 104 105 if (!pTempFileBuffer) 106 { 107 printf("内存分配失败! "); 108 fclose(pFile); 109 return 0; 110 } 111 112 //根据申请到的内存空间,读取数据 113 114 size_t n = fread(pTempFileBuffer,fileSize,1,pFile); 115 if (!n) 116 { 117 printf("读取数据失败! "); 118 free(pTempFileBuffer); // 释放内存空间 119 fclose(pFile); // 关闭文件流 120 return 0; 121 } 122 123 //数据读取成功,关闭文件 124 *pFileBuffer = pTempFileBuffer; // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer 125 pTempFileBuffer = NULL; // 初始化清空临时申请的内存空间 126 fclose(pFile); // 关闭文件 127 return fileSize; // 返回获取文件的大小 128 } 129 130 //CopyFileBuffer --> ImageBuffer 131 //将读取的FileBuffer拉伸加载到ImageBuffer,用作测试验证文件拉伸; 132 DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer) 133 { 134 //LPVOID ----> typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型 135 PIMAGE_DOS_HEADER pDosHeader = NULL; 136 PIMAGE_NT_HEADERS pNTHeader = NULL; 137 PIMAGE_FILE_HEADER pPEHeader = NULL; 138 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 139 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 140 LPVOID pTempImageBuffer = NULL; 141 /* 142 上面都是PE里面的相关结构体类型,使用其类型进行自定义变量,并初始化值为NULL 143 PIMAGE_DOS_HEADER ---> 指向结构体,别名为这两个 IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER 144 PIMAGE_NT_HEADERS ---> 指向结构体,typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; 145 PIMAGE_FILE_HEADER ---> 指向结构体,别名为这两个 IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 146 PIMAGE_OPTIONAL_HEADER32 ---> 指向结构体,别名为这两个 IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 147 PIMAGE_SECTION_HEADER ---> 指向结构体,别名为这两个 IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; 148 */ 149 150 if (pFileBuffer == NULL) 151 { 152 printf("FileBuffer 获取失败! "); 153 return 0; 154 } 155 156 //判断是否是有效的MZ标志 157 if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) 158 { 159 printf("无效的MZ标识 "); 160 return 0; 161 } 162 /* 163 IMAGE_DOS_SIGNATURE 这个在头文件WINNT.H里面,对应是个无参数宏; 164 #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ 165 在宏扩展的时候就会替换为0x5A4D ,然后根据架构的不同进行排序存储,分大端和小端模式; 166 使用上面方式进行比对是否是有效的MZ头是非常有效; 167 而且IMAGE_DOS_SIGNATURE存储的值是两个字节,刚好就是PWORD ---> typedef WORD near *PWORD; 168 所以在进行比较的时候需要强制类型转换为相同的类型进行比较 169 */ 170 171 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 172 //这里的定义,就相当于已经确定了,其头肯定是MZ了,然后强制转换类型为PIMAGE_DOS_HEADER,就是Dos头 173 174 //判断是否是有效的PE标志 175 if (*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 176 { 177 printf("无效的PE标记 "); 178 return 0; 179 } 180 /* 181 IMAGE_NT_SIGNATURE ---> #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 182 上述同样是个宏扩展,在头文件WINNT.H里面; 183 在进行比对的时候因为在Dos头里面有个值是 e_lfanew 对应的时候DWORD类型,所以在进行指针相加的时候 184 需要先进行强制类型转换,然后相加,即移动指针位置;然后最终需要比对的结果是0x4550站两个字节 185 所以又要强制转换类型为PWORD; 186 */ 187 //定位NT头 188 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); 189 //上面偏移完成之后pFileBuffer的指针偏移到了NT头---> pNTHeader 190 //**************************************************************************************** 191 //定位PE文件头 192 pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4); 193 //根据PE头的结构体内容,PE文件头位置在NT头首地址偏移4个字节即可得到pPEHeader 194 //**************************************************************************************** 195 //定位可选PE头 196 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 197 /* 198 要得到可选PE的首地址位置,就根据上面得到的PE文件头位置里面的IMAGE_SIZEOF_FILE_HEADER来定位; 199 IMAGE_SIZEOF_FILE_HEADER也是个宏扩展,里面字节描述了PE文件头的大小是20个字节; 200 #define IMAGE_SIZEOF_FILE_HEADER 20,所以只要在PE文件头的首地址偏移20个字节即可移动到可选PE头; 201 指针相加的时候,此处的类型依然是DWORD 202 */ 203 //**************************************************************************************** 204 //第一个节表指针 205 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); 206 /* 207 这里要移动到第一个节表指针的首地址,就需要根据上面标准PE文件头中的SizeOfOptionalHeader获取具体可选PE 208 头的大小,然后根据这个大小进行偏移即可; 209 */ 210 //**************************************************************************************** 211 212 /* 213 到了节表的首地址位置之后,因为需要将FileBuffer复制到ImageBuffer,这个过程中,节表之前的Dos头,NT头 214 PE文件头,可选PE头,她们的大小都是不变的,所以定位出来之后,到后面的操作中直接复制即可,而节表不一样 215 她在FileBuffer状态和ImageBuffer状态是不相同的,她们节表之间复制转换到ImageBuffer是需要拉长节表,所以 216 在操作的时候是需要确定FileBuffer到ImageBuffer之后ImageBuffer的大小是多少,而这个大小,已经在可选PE头 217 里面的某一个值中已经给出来了 ---> SizeOfImage ; 218 注意:FileBuffer和ImageBuffer都是在内存中的展示,只不过FileBuffer是使用winhex等类似的形式打开查看其 219 二进制的形式,而ImageBuffer则是双击打开应用程序,将其加载至内存中显示的二进制的形式; 220 */ 221 //**************************************************************************************** 222 223 //根据SizeOfImage申请新的内存空间 224 pTempImageBuffer = malloc(pOptionHeader->SizeOfImage); 225 226 if (!pTempImageBuffer) 227 { 228 printf("再次在堆中申请一块内存空间失败 "); 229 return 0; 230 } 231 232 //因为下面要开始对内存空间进行复制操作,所以需要初始化操作,将其置为0,避免垃圾数据,或者其他异常 233 //初始化新的缓冲区 234 memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage); 235 /* 236 参考:http://c.biancheng.net/cpp/html/157.html 237 238 在头文件string.h里面 239 240 void* memset( void* ptr,int value,size_t num ); 241 memset()函数用来将指定内存的前n个字节设置为特定的值; 242 243 参数说明: 244 ptr 为要操作的内存的指针; 245 value 为要设置的值;既可以向value传递int类型的值,也可以传递char类型的值,int和char可以根据ASCII码相互转换; 246 num 为ptr的前num个字节,size_t就是unsigned int。 247 函数说明:memset()会将ptr所指的内存区域的前num个字节的值都设置为value,然后返回指向ptr的指针; 248 */ 249 //**************************************************************************************** 250 251 //根据SizeOfHeaders大小的确定,先复制Dos头 252 memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders); 253 /* 254 参考:http://c.biancheng.net/cpp/html/155.html 255 256 在头文件string.h里面 257 258 void* memcpy (void* dest,const void* src,size_t num); 259 memcpy()函数功能用来复制内存的;她会复制src所指向内容的首地址,作为起始位置,然后偏移num个字节到dest所指的内存地址 260 的位置;此函数有个特征就是,她并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性, 261 可以面向任何数据类型进行复制; 262 263 需要注意的是: 264 dest 指针要分配足够的空间,也就是要大于等于num字节的空间,如果没有分配足够的空间会出现错误; 265 dest和src所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全)。 266 267 所以上面的代码的含义如下: 268 (1)pDosHeader ---> 是指向pFileBuffer的首地址,也就是内存复制的时候从这里开始; 269 (2)pTempImageBuffer ---> 这里是表示上面要复制的目的,要把内容复制到这块内存来; 270 (3)pOptionHeader->SizeOfHeaders ---> 这里表示复制多大的内容到pTempImageBuffer里面去; 271 (4)从上面看来我们就知道复制到目标pOptionHeader->SizeOfHeaders所在的内存空间一定要比pTempImageBuffer大; 272 */ 273 //**************************************************************************************** 274 275 //上面把已经确定的头都复制好了,那么下面就可以开始复制节的里面的内容,因为节不仅仅是一个,所以需要用到for循环进行操作 276 //根据节表循环copy节的内容 277 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 278 //定义一个临时节表的指针 279 for (int i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++) 280 { 281 memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress), 282 (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData); 283 } 284 /* 285 上面的大概操作就是根据标准PE文件头里面的值 NumberOfSections确定有几个节,然后不断的计算并增加指针偏移位置,不停的复制 286 287 PointerToRawData ---> 节在文件中的偏移地址; 288 VirtualAddress ---> 节在内存中的偏移地址; 289 SizeOfRawData ---> 节在文件中对齐后的尺寸; 290 291 (void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress) ---> Dest(目的地) 292 上面我们已经知道了函数memcpy是怎么复制操作的,所以这里我们依依解释下: 293 首先我们知道,上面展示的是目的地,而且我们的目的是要从FileBuffer节内容复制到ImageBuffer节的内容, 294 那么要使用到的是文件被双击打开之后在内存中的偏移地址,这个地址就是VirtualAddress;这里举个例子: 295 正常打开notepad.exe,然后使用winhex加载这个notepad.exe的内存数据,同时使用PE解析工具得到两个值的信息如下: 296 可选PE头 ---> ImageBase ---> 0x01000000 297 第一个节表显示的VirtualAddress ---> 00001000 298 上面两个值相加就得到了文件被打开在内存中第一个节的真实数据的起始位置 ---> 0x01001000 299 查看winhex对应的地址,确认是对的; 300 301 (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData) ---> Src(源复制的起始内存地址) 302 同样是上面的例子: 303 PointerToRawData是节在文件中的偏移地址,而我们知道,在文件中和在内存中是不一样的,因为在内存中有ImageBase的说法, 304 但在文件中没有,所以她的起始位置就是文件存储在硬盘的时候使用winhex打开的开头位置,为这里同样使用winhex以二进制的形式 305 打开notepad.exe(非双击打开),发现文件的起始位置是0x00000000,同时使用PE解析工具确认出了PointerToRawData的值 306 PointerToRawData ---> 0x00000400 ; 起始位置为0x00000000 ,她们相加就得到第一个节表的起始位置为0x00000400 307 查看winhex对应的地址,确认是对的; 308 所以这里总结下来的Src,就是内存复制的时候,从这个偏移地址开始拿数据开始复制; 309 310 pTempSectionHeader->SizeOfRawData 311 这里就是告诉我们上面复制要复制多大的内容到 (void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress) 312 SizeOfRawData ---> 节在文件中对齐后的尺寸; 313 例子还是以上面的为例: 314 通过PE解析工具确认SizeOfRawData的大小为:0x00007800 315 316 总结: 317 memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress), 318 (void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), 319 pTempSectionHeader->SizeOfRawData); 320 321 上面代码就是在文件中的形式找到要复制的位置0x00000400的起始位置开始复制,要复制0x00007800个字节大小,也就是从 322 0x00000400这个地址开始向后偏移7800个字节,将这些数据复制到文件双击被打开时候的内存地址0x01001000为起点向后覆盖复制 323 完成即可,为这里测试算了下;0x00000400+0x00007800=0x00007C00 ; 0x00007C00这个地址刚好是第二个节的PointerToRawData 324 这样就可以很好的理解for循环对第二个节的复制; 325 */ 326 327 //**************************************************************************************** 328 //返回数据 329 *pImageBuffer = pTempImageBuffer; 330 //将复制好后节的首地址保存到指针pImageBuffer中 331 pTempImageBuffer = NULL; 332 //初始化清空临时使用的pTempImageBuffer 333 334 return pOptionHeader->SizeOfImage; 335 } 336 337 //FileBuffer ---> NewImageBuffer(新增节操作)? 338 //通过复制FileBuffer并增加1000H到新的NewImageBuffer,用作新增节; 339 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer) 340 { 341 PIMAGE_DOS_HEADER pDosHeader = NULL; 342 PIMAGE_NT_HEADERS pNTHeader = NULL; 343 PIMAGE_FILE_HEADER pPEHeder = NULL; 344 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 345 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 346 PIMAGE_SECTION_HEADER pLastSectionHeader = NULL; 347 LPVOID pTempNewImageBuffer = 0; 348 DWORD sizeOfFile = 0; 349 DWORD numberOfSection = 0; 350 DWORD okAddSections = 0; 351 352 353 //判断读取pFileBuffer读取是否成功 354 if (!pFileBuffer) 355 { 356 printf("缓冲区指针无效 "); 357 return 0; 358 } 359 360 //判断是否为MZ标志 361 362 if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ 363 { 364 printf("不是一个有效的MZ标志 "); 365 return 0; 366 } 367 368 //判断是否为PE标志 369 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 370 if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE 371 { 372 printf("不是有效的PE标志 "); 373 return 0; 374 } 375 376 //*********************申请开辟内存空间***************************************************************** 377 378 sizeOfFile = fileSize+0x1000; 379 pTempNewImageBuffer = malloc(sizeOfFile); 380 381 //判断内存空间开辟是否成功 382 if (!pTempNewImageBuffer) 383 { 384 printf("pTempNewImageBuffer开辟内存空间失败 "); 385 return 0; 386 } 387 388 //初始化内存内容 389 memset(pTempNewImageBuffer,0,sizeOfFile); 390 391 //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间 392 memcpy(pTempNewImageBuffer,pFileBuffer,fileSize); 393 394 //定位Dos头地址 395 pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer); 396 397 //定位NT头的地址 398 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew); 399 400 //定位标志PE头地址 401 pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节 402 403 //定位可选PE头地址 404 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节 405 406 //定位第一个节表地址 407 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader); 408 409 //定位最后一个节表的地址 410 pLastSectionHeader = &pSectionHeader[pPEHeder->NumberOfSections-1]; 411 412 //判断是否有足够的空间添加一个节表 413 //判断条件: 414 /* 415 SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小 416 SizeOfHeader在可选PE头里面 417 */ 418 419 okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + 420 sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) 421 * pPEHeder->NumberOfSections)); 422 423 if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER)) 424 { 425 printf("这个exe文件头不剩余空间不够 "); 426 free(pTempNewImageBuffer); 427 return 0; 428 } 429 430 //上面没问题,就开始修改内容了 431 //*************************修改内容******************************************************************* 432 433 //初始化新节表信息 434 PWORD pNumberOfSection = &pPEHeder->NumberOfSections; 435 PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage; 436 437 numberOfSection = pPEHeder->NumberOfSections; 438 PVOID pSecName = &pSectionHeader[numberOfSection].Name; 439 PDWORD pSecMisc = &pSectionHeader[numberOfSection].Misc.VirtualSize; 440 PDWORD pSecVirtualAddress = &pSectionHeader[numberOfSection].VirtualAddress; 441 PDWORD pSecSizeOfRawData = &pSectionHeader[numberOfSection].SizeOfRawData; 442 PDWORD pSecPointToRawData = &pSectionHeader[numberOfSection].PointerToRawData; 443 PDWORD pSecCharacteristics = &pSectionHeader[numberOfSection].Characteristics; 444 445 //修改PE文件头里面的节数量信息 446 447 printf("*pNumberOfSection:%#X ",pPEHeder->NumberOfSections); 448 *pNumberOfSection = pPEHeder->NumberOfSections + 1; 449 printf("*pNumberOfSection:%#X ",pPEHeder->NumberOfSections); 450 451 //修改PE可选头里面SizeOfImage信息 452 printf("*pSizeOfImage:%#X ",pOptionHeader->SizeOfImage); 453 *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000; 454 printf("*pSizeOfImage:%#X ",pOptionHeader->SizeOfImage); 455 456 //向节表中添加数据 457 458 memcpy(pSecName,".newSec",8); 459 *pSecMisc = 0x1000; 460 //这里VirtualAddress的地址需要根据最后一个节表中对齐前内存中的实际大小? 461 //和文件中对齐后的大小,分别使用VirtualAddress加上她们的值,哪个大,就是 462 //哪个; 463 //VirtualAddress+max(VirtualSize,SizeOfRawData) 464 //就是上面的公式 465 466 //判断出要添加的值 467 DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData? 468 pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData; 469 //上面是个三目运算符 470 471 printf("pLastSectionHeader: %#X ",pLastSectionHeader); 472 printf("add_size: %#X ",add_size); 473 printf("numberOfSection: %#X ",pPEHeder->NumberOfSections); 474 printf("pLastSectionHeader->Misc.VirtualSize: %#X ",pLastSectionHeader->Misc.VirtualSize); 475 printf("pLastSectionHeader->SizeOfRawData: %#X ",pLastSectionHeader->SizeOfRawData); 476 printf("add_size: %#X ",add_size); 477 478 *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size; 479 480 //SectionAlignment对齐 481 482 if (*pSecVirtualAddress % pOptionHeader->SectionAlignment) 483 { 484 *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * 485 pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment; 486 } 487 488 *pSecSizeOfRawData = 0x1000; 489 *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData; 490 491 //FileAlignment对齐 492 493 if (*pSecPointToRawData % pOptionHeader->FileAlignment) 494 { 495 *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * 496 pOptionHeader->FileAlignment + pOptionHeader->FileAlignment; 497 } 498 499 *pSecCharacteristics = 0xFFFFFFFF; 500 501 *pNewImageBuffer = pTempNewImageBuffer; 502 pTempNewImageBuffer = NULL; 503 504 return sizeOfFile; 505 } 506 507 //求对齐后的大小 508 //Actuall_size ---> 内存中对齐前实际的大小 ---> VirtualSize 509 //Align_size ---> 文件中对齐后的大小 ---> SizeOfRawData 510 DWORD AlignLength(DWORD Actuall_size,DWORD Align_size) 511 { 512 if (Actuall_size % Align_size == 0) 513 { 514 return Actuall_size; 515 } 516 else 517 { 518 DWORD n = Actuall_size / Align_size; 519 return Align_size*(n+1); 520 } 521 } 522 523 //另一种对齐计算方式 524 DWORD Alignment(DWORD alignment_value, DWORD addend, DWORD address) 525 { 526 int n = 0; 527 if (addend / alignment_value) 528 { 529 if (addend % alignment_value) 530 { 531 n = addend / alignment_value + 1; 532 } 533 else 534 { 535 n = addend / alignment_value; 536 } 537 } 538 else 539 { 540 if (addend) 541 { 542 n = 1; 543 } 544 else 545 { 546 n = 0; 547 } 548 } 549 address += n * alignment_value; 550 return address; 551 } 552 553 //ImageBuffer ---> NewImageBuffer 554 //将拉伸后加载到内存的ImageBuffer存入到NewImageBuffer,修改数据完成之后,准备存盘操作 555 DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer) 556 { 557 PIMAGE_DOS_HEADER pDosHeader = NULL; 558 PIMAGE_NT_HEADERS pNTHeader = NULL; 559 PIMAGE_FILE_HEADER pPEHeader = NULL; 560 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 561 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 562 PIMAGE_SECTION_HEADER pLastSectionHeader = NULL; 563 LPVOID pTempNewImageBuffer = NULL; 564 DWORD ImageBuffer_Size = 0; 565 DWORD numberOfSection = 0; 566 567 //判断读取pImageBuffer是否成功 568 if (!pFileBuffer) 569 { 570 printf("缓冲区指针无效 "); 571 } 572 573 //判断是否是有效的MZ头 574 if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) 575 { 576 printf("不是有效的MZ头 "); 577 return 0; 578 } 579 580 //判断是否是有效的PE头 581 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 582 if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 583 { 584 printf("不是有效的PE头 "); 585 return 0; 586 } 587 588 //定位NT头 589 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); 590 591 //定位标准的PE文件头 592 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04); 593 594 //定位可选PE头 595 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 596 597 //定位第一个节表地址 598 numberOfSection = pPEHeader->NumberOfSections; 599 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader); 600 601 //定位最后一个节表地址 602 pLastSectionHeader = &pSectionHeader[numberOfSection-1]; 603 // printf("numberOfSection --> %#X ",numberOfSection); 604 // printf("*pSectionHeader --> %#X ",pSectionHeader->Misc.VirtualSize); 605 // printf("*pLastSectionHeader --> %#X ",&pLastSectionHeader); 606 607 //开始操作需要修改的部分 608 609 //最后一个节中内存中对齐前的大小; 610 PDWORD pVirtualSize = &pLastSectionHeader->Misc.VirtualSize; 611 //最后一个节在文件中对齐后的大小; 612 PDWORD pSizeOfRawData = &pLastSectionHeader->SizeOfRawData; 613 //文件中SizeOfImage的大小; 614 PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage; 615 616 //扩展修改之前的数据 617 // printf("&pLastSectionHeader->Misc.VirtualSize --> %#X ",pVirtualSize); 618 // printf("*pLastSectionHeader->Misc.VirtualSize --> %#X ",*pVirtualSize); 619 // 620 // printf("&pLastSectionHeader->SizeOfRawData --> %#X ",pSizeOfRawData); 621 // printf("*pLastSectionHeader->SizeOfRawData --> %#X ",*pSizeOfRawData); 622 // 623 // printf("&pOptionHeader->SizeOfImage --> %#X ",pSizeOfImage); 624 // printf("*pOptionHeader->SizeOfImage --> %#X ",*pSizeOfImage); 625 626 //扩展修改pVirtualSize 627 *pVirtualSize = AlignLength(*pVirtualSize,pOptionHeader->SectionAlignment)+0x1000; 628 // printf("&pLastSectionHeader->Misc.VirtualSize --> %#X ",pVirtualSize); 629 // printf("*pLastSectionHeader->Misc.VirtualSize --> %#X ",*pVirtualSize); 630 // printf("&pLastSectionHeader->SizeOfRawData --> %#X ",pSizeOfRawData); 631 // printf("*pLastSectionHeader->SizeOfRawData --> %#X ",*pSizeOfRawData); 632 // 633 //扩展修改pSizeOfRawData 634 *pSizeOfRawData = AlignLength(*pSizeOfRawData,pOptionHeader->SectionAlignment)+0x1000; 635 // printf("&pLastSectionHeader->Misc.VirtualSize --> %#X ",pVirtualSize); 636 // printf("*pLastSectionHeader->Misc.VirtualSize --> %#X ",*pVirtualSize); 637 // printf("&pLastSectionHeader->SizeOfRawData --> %#X ",pSizeOfRawData); 638 // printf("*pLastSectionHeader->SizeOfRawData --> %#X ",*pSizeOfRawData); 639 // printf("&pOptionHeader->SizeOfImage --> %#X ",pSizeOfImage); 640 // printf("*pOptionHeader->SizeOfImage --> %#X ",*pSizeOfImage); 641 642 //修改SizeOfImage 643 *pSizeOfImage += 0x1000; 644 // printf("&pLastSectionHeader->Misc.VirtualSize --> %#X ",pVirtualSize); 645 // printf("*pLastSectionHeader->Misc.VirtualSize --> %#X ",*pVirtualSize); 646 // printf("&pLastSectionHeader->SizeOfRawData --> %#X ",pSizeOfRawData); 647 // printf("*pLastSectionHeader->SizeOfRawData --> %#X ",*pSizeOfRawData); 648 // printf("&pOptionHeader->SizeOfImage --> %#X ",pSizeOfImage); 649 // printf("*pOptionHeader->SizeOfImage --> %#X ",*pSizeOfImage); 650 651 //得到修改之后的大小准备申请内存空间 652 653 ImageBuffer_Size = pOptionHeader->SizeOfImage; 654 pTempNewImageBuffer = malloc(ImageBuffer_Size); 655 656 if (!pTempNewImageBuffer) 657 { 658 printf("分配内存空间失败 "); 659 return 0; 660 } 661 662 //初始化内存空间 663 memset(pTempNewImageBuffer,0,ImageBuffer_Size); 664 665 //复制SizeOfHeaders 666 memcpy(pTempNewImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders); 667 668 //创建临时节的结构体指针,遍历数据 669 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 670 671 for (DWORD i = 0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++) 672 { 673 memcpy((PVOID)((DWORD)pTempNewImageBuffer+pTempSectionHeader->VirtualAddress), 674 (void*)((DWORD)pFileBuffer+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData); 675 } 676 677 *pNewImageBuffer = pTempNewImageBuffer; 678 pTempNewImageBuffer = NULL; 679 return *pSizeOfImage; 680 } 681 682 //将ImageBuffer更改为一个节表和节然后压缩为NewBuffer,供存盘准备 683 DWORD ImageBufferMergeSections(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer) 684 { 685 PIMAGE_DOS_HEADER pDosHeader = NULL; 686 PIMAGE_NT_HEADERS pNTHeader = NULL; 687 PIMAGE_FILE_HEADER pPEHeader = NULL; 688 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 689 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 690 PIMAGE_SECTION_HEADER pLastSectionHeader = NULL; 691 LPVOID pTempMergeSection = NULL; 692 DWORD finalSections_Size = 0; 693 DWORD numberOfSection = 0; 694 DWORD lastSectionsMax_Size = 0; 695 DWORD sizeOfFile = 0; 696 DWORD NewSecCharacteristics = 0; 697 DWORD NewSectionsBuffer = 0; 698 699 //判断读取pImageBuffer是否成功 700 if (pImageBuffer == NULL) 701 { 702 printf("缓冲区指针无效 "); 703 } 704 //判断是否是有效的MZ标志 705 if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE) 706 { 707 printf("不是有效的MZ头 "); 708 free(pImageBuffer); 709 return 0; 710 } 711 //判断是否是有效的PE标志 712 713 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; 714 if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 715 { 716 printf("不是有效的PE标志 "); 717 free(pImageBuffer); 718 return 0; 719 } 720 721 722 //定位NT头 723 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew); 724 725 //定位标准的PE文件头 726 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04); 727 728 //定位可选PE头 729 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 730 731 //定位第一个节表地址 732 numberOfSection = pPEHeader->NumberOfSections; 733 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader); 734 735 //定位最后一个节表地址 736 pLastSectionHeader = &pSectionHeader[numberOfSection - 1]; 737 738 //定义一个临时节表指针 739 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 740 741 //先计算出SizeOfHeaders 742 pOptionHeader->SizeOfHeaders = Alignment(pOptionHeader->SectionAlignment,pOptionHeader->SizeOfHeaders,0); 743 744 745 //最后一个节中内存对齐前的大小; 746 DWORD pVirtualSize = pLastSectionHeader->Misc.VirtualSize; 747 //最后一个节在文件中对齐后的大小; 748 DWORD pSizeOfRawData = pLastSectionHeader->SizeOfRawData; 749 750 //计算最后一个节中最大值是SizeOfRawData还是VirtualSize 751 lastSectionsMax_Size = (pSizeOfRawData > pVirtualSize ? pSizeOfRawData : pVirtualSize); 752 753 //测试一把 754 if (!debug) 755 { 756 printf("pLastSectionHeader->SizeOfRawData: %#X ", pSizeOfRawData); 757 printf("pLastSectionHeader->Misc.VirtualSize: %#X ", pVirtualSize); 758 printf("lastSectionsMax_Size: %#X ", lastSectionsMax_Size); 759 } 760 761 //计算最终合并后节对应SizeOfRawData或VirtualSize的大小 762 finalSections_Size = (pLastSectionHeader->VirtualAddress + lastSectionsMax_Size - pOptionHeader->SizeOfHeaders); 763 764 //遍历到最后一个节表,具体操作就是将每个节都置为0 765 for (DWORD i = 0; i < numberOfSection; i++, pTempSectionHeader++) 766 { 767 NewSecCharacteristics |= pTempSectionHeader->Characteristics; 768 //上述 |= 按位或然后赋值,因为NewSecCharacteristics为0,所以新的节对应的值也都置为0了 769 if (i > 0) 770 { 771 memset(&pSectionHeader[i],0,IMAGE_SIZEOF_SECTION_HEADER);//将每个节都置为0 772 } 773 } 774 775 //IMAGE_SIZEOF_SECTION_HEADER --> 40 776 777 //修改第一个节的SizeOfRawData和VirtualSize的值,将其更改为上面计算出来的最终值 778 pSectionHeader->Misc.VirtualSize = finalSections_Size; 779 pSectionHeader->SizeOfRawData = finalSections_Size; 780 781 //修改新节的Characteristics的值 782 pSectionHeader->Characteristics = NewSecCharacteristics; 783 784 //修改pPEHeader->NumberOfSections的属性为0x01 785 pPEHeader->NumberOfSections = 0x01; 786 787 //继续测试一把 788 if (!debug) 789 { 790 printf("pSectionHeader->Characteristics: %#X ", pSectionHeader->Characteristics); 791 printf("pSectionHeader->SizeOfRawData: %#X ", pSectionHeader->SizeOfRawData); 792 printf("pSectionHeader->Misc.VirtualSize: %#X ", pSectionHeader->Misc.VirtualSize); 793 } 794 795 //根据SizeOfImage申请新的空间,到此处说明上面已经更改完成了各个相关的属性值,可以申请内存空间为存盘做准备了; 796 pTempMergeSection = malloc(pOptionHeader->SizeOfImage); 797 798 //sizeOfFile = pOptionHeader->SizeOfHeaders + finalSections_Size; 799 //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小 800 // for(DWORD i = 0;i<numberOfSection;i++) 801 // { 802 // sizeOfFile += pSectionHeader[i].SizeOfRawData; // pSectionHeader[i]另一种加法 803 // } 804 805 //pTempNewBuffer = malloc(sizeOfFile); 806 807 if (!pTempMergeSection) 808 { 809 printf("申请内存空间失败 "); 810 return 0; 811 } 812 813 //初始化新的缓冲区 814 memset(pTempMergeSection,0,pOptionHeader->SizeOfImage); 815 //根据SizeOfHeaders 先copy头 816 memcpy(pTempMergeSection,pDosHeader,pOptionHeader->SizeOfHeaders); 817 //开始复制节的信息,因为这里是合并节,只有一个节,所以不需要使用for循环进行遍历复制,直接复制即可; 818 memcpy((PDWORD)((DWORD)pTempMergeSection+pSectionHeader->PointerToRawData), 819 (PDWORD)((DWORD)pImageBuffer+pSectionHeader->VirtualAddress), 820 pSectionHeader->SizeOfRawData); 821 822 //返回数据 823 *pNewBuffer = pTempMergeSection; 824 pTempMergeSection = NULL; 825 return pOptionHeader->SizeOfImage; 826 } 827 828 //ImageBuffer ---> NewBuffer 829 //将拉伸后加载到内存的ImageBuffer存入到NewBuffer里面,然后准备存盘; 830 DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer) 831 { 832 //下面大部分操作都是跟上面一样的,这里就不再赘述了 833 PIMAGE_DOS_HEADER pDosHeader = NULL; 834 PIMAGE_NT_HEADERS pNTHeader = NULL; 835 PIMAGE_FILE_HEADER pPEHeader = NULL; 836 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 837 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 838 LPVOID pTempNewBuffer = NULL; 839 DWORD sizeOfFile = 0; 840 DWORD numberOfSection = 0; 841 842 if (pImageBuffer == NULL) 843 { 844 printf("缓冲区指针无效 "); 845 } 846 //判断是否是有效的MZ标志 847 if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE) 848 { 849 printf("不是有效的MZ头 "); 850 return 0; 851 } 852 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; 853 //判断是否是有效的PE标志 854 if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 855 { 856 printf("不是有效的PE标志 "); 857 return 0; 858 } 859 //NT头地址 860 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew); 861 //标准PE文件头 862 pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4); 863 //可选PE头 864 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 865 //第一个节表地址 866 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); 867 868 //计算文件需要的空间--最后一个节的文件偏移+节对齐后的长度 869 /* 870 numberOfSection = pPEHeader->NumberOfSections; 871 pSectionHeader = pSectionHeader[numberOfSection-1]; 872 sizeOfFile = (pSectionHeader->PointerToRawData + pSectionHeader->Misc.VirtualSize + pOptionHeader->FileAlignment); 873 printf("sizeOfFile %X ",sizeOfFile); 874 875 for (DWORD i=0;i<=numberOfSection;i++) 876 { 877 sizeOfFile += sizeOfFile[i]; 878 } 879 */ 880 881 sizeOfFile = pOptionHeader->SizeOfHeaders; 882 //使用winhex打开notepad.exe 是0x00000400,这是第一个节之前的所有大小 883 for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++) 884 { 885 sizeOfFile += pSectionHeader[i].SizeOfRawData; // pSectionHeader[i]另一种加法 886 } 887 888 /* 889 上面的for循环大概意思就是基于几个节的数量依次循环叠加sizeOfFile的值;因为SizeOfRawData是文件中对齐后的大小; 890 所以循环计算如下: 891 sizeOfFile = 0x00000400 + 0x00007800 = 0x00007C00 892 sizeOfFile = 0x00007C00 + 0x00000800 = 0x00008400 893 sizeOfFile = 0x00008400 + 0x00008000 = 0x00010400 894 895 */ 896 897 //根据SizeOfImage申请新的空间 898 pTempNewBuffer = malloc(sizeOfFile); 899 900 if (!pTempNewBuffer) 901 { 902 printf("申请内存空间失败 "); 903 return 0; 904 } 905 //初始化新的缓冲区 906 memset(pTempNewBuffer,0,sizeOfFile); 907 //根据SizeOfHeaders 先copy头 908 memcpy(pTempNewBuffer,pDosHeader,pOptionHeader->SizeOfHeaders); 909 //根据节表循环复制节 910 //PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader); 911 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 912 for (int j=0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++) 913 { 914 /*memcpy((LPVOID)((DWORD)pTempNewBuffer + pTempSectionHeader->PointerToRawData), 915 (LPVOID)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), 916 pTempSectionHeader->SizeOfRawData);*/ 917 //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸 918 memcpy((PDWORD)((DWORD)pTempNewBuffer+pTempSectionHeader->PointerToRawData), 919 (PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress), 920 pTempSectionHeader->SizeOfRawData); 921 //printf("%X --> PoniterToRadata ",pTempSectionHeader->PointerToRawData); 922 //printf("%X --> VirtualAddress ",pTempSectionHeader->VirtualAddress); 923 //printf("%X --> VirtualSize ",pTempSectionHeader->Misc.VirtualSize); 924 } 925 926 //返回数据 927 *pNewBuffer = pTempNewBuffer; 928 pTempNewBuffer = NULL; 929 return sizeOfFile; 930 } 931 932 //将上面得到的MemBuffer存盘到本地; 933 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile) 934 { 935 FILE* fp = NULL; 936 fp = fopen(lpszFile, "wb+"); 937 if (!fp) // 这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误 938 // if(fp == NULL) 可以这么写,没问题 939 { 940 fclose(fp); 941 return FALSE; 942 } 943 fwrite(pMemBuffer,size,1,fp); 944 fclose(fp); 945 fp = NULL; 946 return TRUE; 947 } 948 949 //RVA格式转换FOA --- RvaToFileOffset 950 DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva) 951 { 952 PIMAGE_DOS_HEADER pDosHeader = NULL; 953 PIMAGE_NT_HEADERS pNTHeader = NULL; 954 PIMAGE_FILE_HEADER pPEHeader = NULL; 955 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 956 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 957 DWORD numberOfSection = 0; 958 DWORD dwFOAValue = 0; 959 960 //判断指针是否有效 961 if (!pFileBuffer) 962 { 963 printf("pFileBuffer 指针无效 "); 964 return 0; 965 } 966 //判断是否是有效的MZ标志 967 if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) 968 { 969 printf("pFileBuffer不是有效的MZ标志 "); 970 return 0; 971 } 972 //判断是否是一个有效的PE标志 973 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 974 if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 975 { 976 printf("pFileBuffer不是一个有效的PE标志 "); 977 return 0; 978 } 979 980 printf("当前的Rva地址: %#X ",dwRva); 981 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); 982 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04); 983 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 984 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); 985 986 //定义个临时节表指针进行下面的计算操作 987 numberOfSection = pPEHeader->NumberOfSections; 988 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 989 990 991 //判断dwRva所处的节 992 if (dwRva <= pOptionHeader->SizeOfHeaders) 993 { 994 return (DWORD)dwRva; 995 } 996 //上面是判断如果rva地址所处的节在第一个节之前那么直接返回rva的地址; 997 //否则下面就是开始遍历查找节; 998 else 999 { 1000 for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++) 1001 {//下面是判断在哪个节的范围,然后根据rva所在的地址减去所在节的VirtualAddress得到的偏移值加上文件中对应节的偏移值PointerToRawData 1002 if ((dwRva >= pTempSectionHeader->VirtualAddress) && (dwRva < pTempSectionHeader->VirtualAddress + pTempSectionHeader->Misc.VirtualSize)) 1003 { 1004 dwFOAValue = dwRva - pTempSectionHeader->VirtualAddress + pTempSectionHeader->PointerToRawData; 1005 } 1006 else 1007 { 1008 printf("RvaToFoa 转换失败! "); 1009 return 0; 1010 } 1011 } 1012 } 1013 return dwFOAValue; 1014 } 1015 1016 //FOA格式转换RVA --- ImageOffset 1017 DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa) 1018 { 1019 PIMAGE_DOS_HEADER pDosHeader = NULL; 1020 PIMAGE_NT_HEADERS pNTHeader = NULL; 1021 PIMAGE_FILE_HEADER pPEHeader = NULL; 1022 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 1023 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 1024 DWORD numberOfSection = 0; 1025 DWORD dwRVAValue = 0; 1026 1027 //判断指针是否有效 1028 if (!pFileBuffer) 1029 { 1030 printf("pFileBuffer 指针无效 "); 1031 return 0; 1032 } 1033 //判断是否是有效的MZ标志 1034 if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) 1035 { 1036 printf("pFileBuffer不是有效的MZ标志 "); 1037 return 0; 1038 } 1039 //判断是否是一个有效的PE标志 1040 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 1041 if (*((PWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) 1042 { 1043 printf("pFileBuffer不是一个有效的PE标志 "); 1044 return 0; 1045 } 1046 1047 printf("当前的Foa地址: %#X ",dwFoa); 1048 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew); 1049 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+0x04); 1050 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); 1051 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader); 1052 1053 //定义个临时节表指针进行下面的计算操作 1054 numberOfSection = pPEHeader->NumberOfSections; 1055 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; 1056 1057 if (dwFoa <= pOptionHeader->SizeOfHeaders) 1058 { 1059 return (DWORD)dwFoa; 1060 } 1061 else 1062 { 1063 for (DWORD n = 0; n < numberOfSection; n++, pTempSectionHeader++) 1064 { 1065 if ((dwFoa >= pTempSectionHeader->PointerToRawData) && (dwFoa < pTempSectionHeader->SizeOfRawData)) 1066 { 1067 dwRVAValue = dwFoa - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress; 1068 } 1069 else 1070 { 1071 printf("FoaToRva 转换失败! "); 1072 return 0; 1073 } 1074 } 1075 } 1076 return dwRVAValue; 1077 } 1078 1079 //在原有的exe文件中开始操作添加ShellCode代码; 1080 1081 VOID AddCodeInCodeSec() 1082 { 1083 LPVOID pFileBuffer = NULL; 1084 LPVOID pImageBuffer = NULL; 1085 LPVOID pNewBuffer = NULL; 1086 PIMAGE_DOS_HEADER pDosHeader = NULL; 1087 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 1088 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 1089 PBYTE codeBegin = NULL; 1090 BOOL isOK = FALSE; 1091 DWORD size = 0; 1092 1093 //File-->FileBuffer 1094 ReadPEFile(FilePath_In,&pFileBuffer); 1095 if (!pFileBuffer) 1096 { 1097 printf("文件-->缓冲区失败 "); 1098 return ; 1099 } 1100 1101 //FileBuffer-->ImageBuffer 1102 CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer); 1103 if (!pImageBuffer) 1104 { 1105 printf("FileBuffer-->ImageBuffer失败 "); 1106 free(pFileBuffer); 1107 return ; 1108 } 1109 1110 //判断代码段空闲区域是否能够足够存储ShellCode代码 1111 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; 1112 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER); 1113 pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER); 1114 if (((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH) 1115 { 1116 printf("代码区域空闲空间不够 "); 1117 free(pFileBuffer); 1118 free(pImageBuffer); 1119 } 1120 1121 //将代码复制到空闲区域 1122 codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize); 1123 printf("pSectionHeader->VirtualAddress: %#010X ", pSectionHeader->VirtualAddress); 1124 printf("pSectionHeader->Misc.VirtualSize: %#010X ", pSectionHeader->Misc.VirtualSize); 1125 printf("codeBegin: %#010X ", codeBegin); 1126 1127 memcpy(codeBegin,ShellCode,SHELLCODELENGTH); 1128 1129 //修正E8-->call后面的代码区域 1130 DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer))); 1131 printf("callAddr ---> %#010X ",callAddr); 1132 *(PDWORD)(codeBegin + 0x09) = callAddr; 1133 printf("*(PWORD)(codeBegin + 0x09) ---> %#010X ",*(PDWORD)(codeBegin + 0x09)); 1134 /* 1135 关于修正E8的理解,公式:X = 要跳转的地址 - (E8当前的地址 + 5); 1136 要跳转的地址,这里是毋庸置疑的,就是我们要加入代码MessageBox的地址; 1137 然后要减去E8当前的地址+5的位置,这里不是太好理解; 1138 我们的目的是要将E8后面的4个字节计算出来,然后写入到E8后面,也就是公式中X; 1139 上面公式E8当前地址+5 ,而在此情况要定位到这个位置就要从代码的Dos开始通过指针相加; 1140 进行位置偏移到E8当前地址+5的位置; 1141 所以定位codeBegin的位置是:pImageBuffer指针最开始的位置(Dos头位置)通过内存中偏移的宽度移动到第一个节表的位置; 1142 也就是上面的pSectionHeader->VirtualAddress 操作形式; 1143 然后再偏移第一个节表在内存中对齐前实际的宽度(尺寸)pSectionHeader->Misc.VirtualSize; 1144 上述一番操作之后就到了第一个节表没有对齐前的位置,这个位置就是我们可以添加ShellCode代码的起始位置; 1145 到了添加ShellCode代码的起始位置之后,就要想办法添加E8位置后面的4个字节,此时根据ShellCode代码的宽度; 1146 进行计算,确认0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 刚好向后面数13个位置,按照十六进制看; 1147 就是0xD,所以在codeBegin偏移0xD个位置即可到达E9的位置,这也就是我们说的(E8当前的地址 + 5); 1148 到了上面的位置之后,由于我们最终是需要在程序运行之后在内存中添加ShellCode代码;所以这里一定要计算出; 1149 其准确的偏移地址,这样不管怎么拉伸到哪个位置,都能准确找到位置; 1150 注意:这里需要注意一点理解,上面说的pImageBuffer这个是我们加载程序到我们申请的内存中,绝不是程序在; 1151 运行中的那个内存,这里一定要理解清楚,她们是不一样的,理解了这个就能理解上面代码为什么要减去Dos头的; 1152 首地址,(DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer) 1153 */ 1154 1155 //修正E9-->jmp后面的代码区域 1156 DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pImageBuffer))); 1157 printf("jmpAddr ---> %#010X ",jmpAddr); 1158 *(PDWORD)(codeBegin + 0x0E) = jmpAddr; 1159 printf("*(PWORD)(codeBegin + 0x0E) ---> %#010X ",*(PDWORD)(codeBegin + 0x0E)); 1160 /* 1161 公式:X = 要跳转的地址 - (E9当前的地址 + 5) 1162 这里同样是要计算出E9后面4个字节的地址,我们的目的是在这里添加OEP的地址,让其执行完成MessageBox之后跳转; 1163 OEP的地址,那么这里就要先计算出OEP地址,就是pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint; 1164 再减去(E9当前的地址 + 5) 0x6A 00 0x6A 00 0x6A 00 0x6A 00 E8 00 00 00 00 E9 00 00 00 00; 1165 (DWORD)codeBegin + SHELLCODELENGTH 就是加上ShellCode总长度,偏移完成之后减去ImageBuffer首地址再加上ImageBase; 1166 */ 1167 1168 //修正OEP 1169 printf("pOptionHeader->AddressOfEntryPoint ---> %#010X ",pOptionHeader->AddressOfEntryPoint); 1170 printf("(DWORD)codeBegin ---> %#010X ",((DWORD)codeBegin - (DWORD)pImageBuffer)); 1171 pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer; 1172 printf("pOptionHeader->AddressOfEntryPoint ---> %#010X ",pOptionHeader->AddressOfEntryPoint); 1173 //修正OEP好理解,就是定位到OEP地址,然后直接通过codeBegin地址减去pImageBuffer的首地址即可; 1174 1175 //ImageBuffer-->NewBuffer 1176 size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer); 1177 if (size == 0 || !pNewBuffer) 1178 { 1179 printf("ImageBuffer-->NewBuffer失败 "); 1180 free(pFileBuffer); 1181 free(pImageBuffer); 1182 return ; 1183 } 1184 1185 //NewBuffer-->文件 1186 isOK = MemeryTOFile(pNewBuffer,size,FilePath_Out); 1187 if (isOK) 1188 { 1189 printf("修改代码添加SHELLCODE 存盘成功 "); 1190 return ; 1191 } 1192 1193 //释放内存 1194 free(pFileBuffer); 1195 free(pImageBuffer); 1196 free(pNewBuffer); 1197 } 1198 1199 //调用函数新增节表和节操作,成功之后并存盘到本地; 1200 VOID NewSectionsInCodeSec() 1201 { 1202 LPVOID pFileBuffer = NULL; 1203 LPVOID pNewImageBuffer = NULL; 1204 BOOL isOK = FALSE; 1205 DWORD size1 = 0; 1206 DWORD size2 = 0; 1207 1208 //File-->FileBuffer 1209 size1 = ReadPEFile(FilePath_In,&pFileBuffer); 1210 if (size1 == 0 || !pFileBuffer) 1211 { 1212 printf("文件-->缓冲区失败 "); 1213 return ; 1214 } 1215 printf("fileSize - Final: %#X ",size1); 1216 1217 //FileBuffer-->NewImageBuffer 1218 size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer); 1219 if (size2 == 0 || !pFileBuffer) 1220 { 1221 printf("FileBuffer-->NewImageBuffer失败 "); 1222 free(pFileBuffer); 1223 return ; 1224 } 1225 printf("sizeOfFile - Final: %#X ",size2); 1226 //NewImageBuffer-->文件 1227 isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out); 1228 if (isOK) 1229 { 1230 printf("新增节表和节存盘成功 "); 1231 return ; 1232 } 1233 1234 //释放内存 1235 free(pFileBuffer); 1236 free(pNewImageBuffer); 1237 } 1238 1239 //调用函数扩大一个节 1240 VOID ExtendLastSectionsInCodeSec() 1241 { 1242 //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewImageBuffer 1243 1244 LPVOID pFileBuffer = NULL; 1245 LPVOID pImageBuffer = NULL; 1246 LPVOID pNewImageBuffer = NULL; 1247 BOOL isOK = FALSE; 1248 DWORD FileBufferSize = 0; 1249 DWORD ImageBufferSize = 0; 1250 DWORD size = 0; 1251 1252 //File-->FileBuffer 1253 FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer); 1254 if (FileBufferSize == 0 || !pFileBuffer) 1255 { 1256 printf("文件-->缓冲区失败 "); 1257 return ; 1258 } 1259 printf("FileBufferSize - Final: %#X ",FileBufferSize); 1260 1261 //FileBuffer-->ImageBuffer 1262 ImageBufferSize = FileBufferToModifyImageBuffer(pFileBuffer,&pImageBuffer); 1263 if (ImageBufferSize == 0 || !pFileBuffer) 1264 { 1265 printf("FileBuffer-->ImageBuffer失败 "); 1266 free(pFileBuffer); 1267 return ; 1268 } 1269 printf("ImageBufferSize - Final: %#X ",ImageBufferSize); 1270 1271 size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewImageBuffer); 1272 if (size == 0 || !pImageBuffer) 1273 { 1274 printf("pImageBuffer-->pNewImageBuffer失败 "); 1275 free(pFileBuffer); 1276 return ; 1277 } 1278 //pNewImageBuffer-->文件 1279 isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out); 1280 if (isOK) 1281 { 1282 printf("扩大一个节成功,并存盘 "); 1283 return ; 1284 } 1285 1286 //释放内存 1287 free(pFileBuffer); 1288 free(pImageBuffer); 1289 free(pNewImageBuffer); 1290 } 1291 1292 1293 //调用函数扩大一个节 1294 VOID ModifySectionsOneInCodeSec() 1295 { 1296 //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile 1297 1298 LPVOID pFileBuffer = NULL; 1299 LPVOID pImageBuffer = NULL; 1300 LPVOID pNewImageBuffer = NULL; 1301 BOOL isOK = FALSE; 1302 DWORD FileBufferSize = 0; 1303 DWORD ImageBufferSize = 0; 1304 DWORD size = 0; 1305 1306 //File-->FileBuffer 1307 FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer); 1308 if (FileBufferSize == 0 || !pFileBuffer) 1309 { 1310 printf("文件-->缓冲区失败 "); 1311 return ; 1312 } 1313 printf("FileBufferSize ---> %#X ",FileBufferSize); 1314 1315 //FileBuffer-->ImageBuffer 1316 ImageBufferSize = CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer); 1317 if (ImageBufferSize == 0 || !pFileBuffer) 1318 { 1319 printf("FileBuffer-->ImageBuffer失败 "); 1320 free(pFileBuffer); 1321 return ; 1322 } 1323 printf("ImageBufferSize ---> %#X ",ImageBufferSize); 1324 1325 size = ImageBufferMergeSections(pImageBuffer,&pNewImageBuffer); 1326 if (size == 0 || !pImageBuffer) 1327 { 1328 printf("pImageBuffer-->pNewImageBuffer失败 "); 1329 free(pFileBuffer); 1330 return ; 1331 } 1332 //pNewImageBuffer-->文件 1333 isOK = MemeryTOFile(pNewImageBuffer,size,FilePath_Out); 1334 if (isOK) 1335 { 1336 printf("合并节完成,存盘成功 "); 1337 return ; 1338 } 1339 1340 //释放内存 1341 free(pFileBuffer); 1342 free(pImageBuffer); 1343 free(pNewImageBuffer); 1344 } 1345 1346 VOID RvaAndFoaConversion() 1347 { 1348 LPVOID pFileBuffer = NULL; 1349 DWORD FileBufferSize = 0; 1350 DWORD FoaFinalVaule = 0; 1351 DWORD RvaFinalVaule = 0; 1352 size_t pRVA = 1180; 1353 size_t pFOA = 2279; 1354 1355 //File-->FileBuffer 1356 FileBufferSize = ReadPEFile(FilePath_In,&pFileBuffer); 1357 if (FileBufferSize == 0 || !pFileBuffer) 1358 { 1359 printf("文件-->缓冲区失败 "); 1360 return ; 1361 } 1362 printf("FileBufferSize: %#X ",FileBufferSize); 1363 1364 FoaFinalVaule = RvaToFileOffset(pFileBuffer,pRVA); 1365 if (FoaFinalVaule == 0 || !pFileBuffer) 1366 { 1367 printf("pFileBuffer-->读取失败 "); 1368 free(pFileBuffer); 1369 return ; 1370 } 1371 printf("转换成功 --> FoaFinalVaule 传进来的pRVA值: : %#X %#X ",FoaFinalVaule,pRVA); 1372 1373 RvaFinalVaule = FoaToImageOffset(pFileBuffer,pFOA); 1374 if (RvaFinalVaule == 0 || !pFileBuffer) 1375 { 1376 printf("pFileBuffer-->读取失败 "); 1377 free(pFileBuffer); 1378 return ; 1379 } 1380 printf("转换成功 --> RvaFinalVaule 传进来的pFOA值 : %#X %#X ",RvaFinalVaule,pFOA); 1381 1382 1383 free(pFileBuffer); 1384 }
头文件代码
1 // gbpeall.h: interface for the gbpeall class. 2 // 3 ////////////////////////////////////////////////////////////////////// 4 5 #if !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_) 6 #define AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_ 7 8 #if _MSC_VER > 1000 9 #pragma once 10 #endif // _MSC_VER > 1000 11 12 #include <string.h> 13 #include <windows.h> 14 #include <stdlib.h> 15 16 #define debug 1 17 //#define FILEPATH_IN "C:\WINDOWS\system32\kernel32.dll" 18 // #define FilePath_In "C:\cntflx\notepad.exe" 19 #define FilePath_In "C:\cntflx\ipmsg.exe" 20 //#define FilePath_Out "C:\cntflx\notepadnewpes.exe" 21 //#define FilePath_Out "C:\cntflx\ipmsgnewpeaddcodes.exe" 22 //#define FilePath_Out "C:\cntflx\ipmsgnewaddsections.exe" 23 //#define FilePath_Out "C:\cntflx\ipmsgextendsections.exe" 24 #define FilePath_Out "C:\cntflx\ipmsg_cntf_merge.exe" 25 #define MESSAGEBOXADDR 0x77D5050B 26 #define SHELLCODELENGTH 0x12 //16进制的,转换为十进制就是18 27 28 extern BYTE ShellCode[]; 29 30 //读文件 --->FileBuffer 31 DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer); 32 33 //写到ImageBuffer,FileBuffer ---> ImageBuffer 34 DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer); 35 36 //写到NewImageBuffer, FileBuffer ---> NewImageBuffer 37 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer); 38 39 //写到NewImageBuffer, 这里供扩大节使用; 40 DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pNewImageBuffer); 41 42 //写入到NewBuffer,目的是将拉伸后的ImageBuffer再缩回来,为存盘准备 43 DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer); 44 45 //写入到NewImageBuffer,这里供合并节使用 46 DWORD ImageBufferMergeSections(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer); 47 48 //写到pNewBuffer里面,从pNewImageBuffer写入 ---> pNewBuffer 49 //DWORD ModifyImageBufferToNewBuffer(IN LPVOID pNewImageBuffer,OUT LPVOID* pNewBuffer); 50 51 //Rva转Foa 52 DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva); 53 54 //Foa转RVA 55 DWORD FoaToImageOffset(IN LPVOID pFileBuffer,IN DWORD dwFoa); 56 57 //对齐大小 58 DWORD AlignLength(DWORD Actuall_size,DWORD Align_size); 59 60 //另一种对齐计算方式 61 DWORD Alignment(DWORD alignment_value, DWORD addend, DWORD address); 62 63 //将MemBuffer写入到硬盘,这里就是将各种修改好的内存文件,存入到本地硬盘中; 64 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile); 65 66 //DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva); 67 68 //调用函数,添加ShellCode代码 69 VOID AddCodeInCodeSec(); //这个调用函数用到下面的4个函数 70 //ReadPEFile CopyFileBufferToImageBuffer CopyImageBufferToNewBuffer MemeryTOFile 71 72 //调用函数,新增节表和节操作; 73 VOID NewSectionsInCodeSec(); //这个调用函数用到下面的3个函数 74 //ReadPEFile CopyFileBufferToNewImageBuffer MemeryTOFile 75 76 //调用函数,扩大最后一个节 77 VOID ExtendLastSectionsInCodeSec(); //这个调用函数用到下面的4个函数 78 //ReadPEFile FileBufferToModifyImageBuffer CopyImageBufferToNewImageBuffer MemeryTOFile 79 80 //调用函数,合并节 81 VOID ModifySectionsOneInCodeSec(); //这个调用函数用到下面的4个函数 82 //ReadPEFile CopyFileBufferToImageBuffer FileBufferToModifyOneImageBuffer MemeryTOFile 83 84 //调用函数,Rva和Foa之间的相互转换; 85 VOID RvaAndFoaConversion(); //这个调用函数用到下面的3个函数 86 //ReadPEFile RvaToFileOffset FoaToImageOffset 87 88 #endif // !defined(AFX_GBPEALL_H__C24C6881_E003_41F7_BE14_24DDA1702CCD__INCLUDED_)
main函数入口处,这里根据调用的函数,直接找到对应合并节的代码即可
1 // allpelx.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include "gbpeall.h" 6 7 int main(int argc, char* argv[]) 8 { 9 //Fun(); 10 //AddCodeInCodeSec(); 11 //NewSectionsInCodeSec(); 12 //ExtendLastSectionsInCodeSec(); 13 ModifySectionsOneInCodeSec(); 14 //RvaAndFoaConversion(); 15 printf("Hello World! Cntf "); 16 system("pause"); 17 return 0; 18 }
执行结果
正常执行,并且可正常打开;
PE解析结果验证