下面是综合性相关代码中,关于新增一个节的代码
1 DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer) 2 { 3 //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展; 4 //啥也不干,即使理解成干,也是扩展成空白,这个是C++语法中允许的; 5 //LPSTR ----> typedef CHAR *LPSTR, *PSTR; 意思就是char* 指针;在WINNT.H头文件里面 6 FILE* pFile = NULL; 7 //定义一个FILE结构体指针,在标准的Stdio.h文件头里面 8 //可参考:https://blog.csdn.net/qq_15821725/article/details/78929344 9 DWORD fileSize = 0; 10 // typedef unsigned long DWORD; DWORD是无符号4个字节的整型 11 LPVOID pTempFileBuffer = NULL; 12 //LPVOID ----> typedef void far *LPVOID;在WINDEF.H头文件里面;别名的void指针类型 13 14 //打开文件 15 pFile = fopen(lpszFile,"rb"); //lpszFile是当作参数传递进来 16 if (!pFile) 17 { 18 printf("打开文件失败! "); 19 return 0; 20 } 21 /* 22 关于在指针类型中进行判断的操作,下面代码出现的情况和此一样,这里解释下: 23 1.因为指针判断都要跟NULL比较,相当于0,假值,其余都是真值 24 2.if(!pFile)和if(pFile == NULL), ----> 为空,就执行语句;这里是两个等于号不是一个等于号 25 3.if(pFile)就是if(pFile != NULL), 不为空,就执行语句; 26 */ 27 28 //读取文件内容后,获取文件的大小 29 fseek(pFile,0,SEEK_END); 30 fileSize = ftell(pFile); 31 fseek(pFile,0,SEEK_SET); 32 33 /* 34 fseek 通过使用二进制的方式打开文件,移动文件读写指针的位置,在stdio.h头文件里 35 36 int fseek(FILE * stream, long offset, int fromwhere); 37 38 上面是fseek的函数原型 39 第一个参数stream 为文件指针 40 第二个参数offset 为偏移量,整数表示正向偏移,负数表示负向偏移 41 第三个参数fromwhere 为指针的起始位置,设定从文件的哪里开始偏移,可能取值为:SEEK_CUR,SEEK_END,SEEK_SET 42 SEEK_SET 0 文件开头 43 SEEK_CUR 1 当前读写的位置 44 SEEK_END 2 文件尾部 45 46 下面是相关用法和例子: 47 fseek(fp,100L,0);把fp指针移动到离文件开头100字节处; 48 fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处; 49 fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。 50 fseek(fp,0,SEEK_SET);将读写位置移动到文件开头; 51 fseek(fp,0,SEEK_END);将读写位置移动到文件尾时; 52 fseek(fp,100L,SEEK_SET);将读写位置移动到离文件开头100字节处; 53 fseek(fp,100L,SEEK_CUR);将读写位置移动到离文件当前位置100字节处; 54 fseek(fp,-100L,SEEK_END);将读写指针退回到离文件结尾100字节处; 55 fseek(fp,1234L,SEEK_CUR);把读写位置从当前位置向后移动1234字节; 56 fseek(fp,0L,2);把读写位置移动到文件尾; 57 其中 ---> L后缀表示长整数 58 59 ftell()用于返回文件当前指针指向的位置,与fseek配合可以算出文件元素数据总数。 60 参考:http://c.biancheng.net/cpp/html/2519.html 61 62 ftell()函数用来获取文件读写指针的当前位置,其原型为:long ftell(FILE * stream); 同样在stdio.h头文件里 63 参数:stream 为已打开的文件指针。 64 */ 65 66 //动态申请内存空间 67 pTempFileBuffer = malloc(fileSize); 68 69 /* 70 参考:http://c.biancheng.net/cpp/html/137.html 71 原型:void* malloc (size_t size); 72 size_t ---> typedef unsigned int size_t; 无符号整型别名是size_t 73 void* ---> 函数的返回值类型是 void* ;void并不是说没有返回值或者返回空指针,而是返回的指针类型未知; 74 所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型; 75 例如:char *ptr = (char *)malloc(10); //分配10个字节的内存空间,用来存放字符 76 参数说明 ---> size 为需要分配的内存空间的大小,以字节(Byte)计。 77 函数说明 ---> malloc()在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化; 78 它们的值是未知的,所以分配完成内存之后需要初始化; 79 返回值:分配成功返回指向该内存的地址,失败则返回 NULL。 80 */ 81 82 if (!pTempFileBuffer) 83 { 84 printf("内存分配失败! "); 85 fclose(pFile); 86 return 0; 87 } 88 89 //根据申请到的内存空间,读取数据 90 91 size_t n = fread(pTempFileBuffer,fileSize,1,pFile); 92 if (!n) 93 { 94 printf("读取数据失败! "); 95 free(pTempFileBuffer); // 释放内存空间 96 fclose(pFile); // 关闭文件流 97 return 0; 98 } 99 100 //数据读取成功,关闭文件 101 *pFileBuffer = pTempFileBuffer; // 将读取成功的数据所在的内存空间的首地址放入指针类型pFileBuffer 102 pTempFileBuffer = NULL; // 初始化清空临时申请的内存空间 103 fclose(pFile); // 关闭文件 104 return fileSize; // 返回获取文件的大小 105 } 106 107 108 //通过复制FileBuffer并增加1000H到新的ImageBuffer里面 109 DWORD CopyFileBufferToNewImageBuffer(IN LPVOID pFileBuffer,IN size_t fileSize,OUT LPVOID* pNewImageBuffer) 110 { 111 PIMAGE_DOS_HEADER pDosHeader = NULL; 112 PIMAGE_NT_HEADERS pNTHeader = NULL; 113 PIMAGE_FILE_HEADER pPEHeder = NULL; 114 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; 115 PIMAGE_SECTION_HEADER pSectionHeader = NULL; 116 PIMAGE_SECTION_HEADER pLastSectionHeader = NULL; 117 LPVOID pTempNewImageBuffer = 0; 118 DWORD sizeOfFile = 0; 119 DWORD numberOfSection = 0; 120 DWORD okAddSections = 0; 121 122 123 //判断读取pFileBuffer读取是否成功 124 if (!pFileBuffer) 125 { 126 printf("缓冲区指针无效 "); 127 return 0; 128 } 129 130 //判断是否为MZ标志 131 132 if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ 133 { 134 printf("不是一个有效的MZ标志 "); 135 return 0; 136 } 137 138 //判断是否为PE标志 139 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; 140 if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // IMAGE_NT_SIGNATURE --> PE 141 { 142 printf("不是有效的PE标志 "); 143 return 0; 144 } 145 146 //*********************申请开辟内存空间***************************************************************** 147 148 sizeOfFile = fileSize+0x1000; 149 pTempNewImageBuffer = malloc(sizeOfFile); 150 151 //判断内存空间开辟是否成功 152 if (!pTempNewImageBuffer) 153 { 154 printf("pTempNewImageBuffer开辟内存空间失败 "); 155 return 0; 156 } 157 158 //初始化内存内容 159 memset(pTempNewImageBuffer,0,sizeOfFile); 160 161 //初始化完成之后,先把为修改的内存空间全部拷贝到新的内存空间 162 memcpy(pTempNewImageBuffer,pFileBuffer,fileSize); 163 164 //定位Dos头地址 165 pDosHeader = (PIMAGE_DOS_HEADER)(pTempNewImageBuffer); 166 167 //定位NT头的地址 168 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pTempNewImageBuffer+pDosHeader->e_lfanew); 169 170 //定位标志PE头地址 171 pPEHeder = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+0x04);//PE SIGNATURE 站4个字节 172 173 //定位可选PE头地址 174 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeder)+IMAGE_SIZEOF_FILE_HEADER);//IMAGE_SIZEOF_FILE_HEADER -> 20个字节 175 176 //定位第一个节表地址 177 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeder->SizeOfOptionalHeader); 178 179 //定位最后一个节表的地址 180 pLastSectionHeader = &pSectionHeader[pPEHeder->NumberOfSections-1]; 181 182 //判断是否有足够的空间添加一个节表 183 //判断条件: 184 /* 185 SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小 186 SizeOfHeader在可选PE头里面 187 */ 188 189 okAddSections = (DWORD)(pOptionHeader->SizeOfHeaders - (pDosHeader->e_lfanew + 0x04 + 190 sizeof(PIMAGE_FILE_HEADER) + pPEHeder->SizeOfOptionalHeader + sizeof(PIMAGE_SECTION_HEADER) 191 * pPEHeder->NumberOfSections)); 192 193 if (okAddSections < 2*sizeof(PIMAGE_SECTION_HEADER)) 194 { 195 printf("这个exe文件头不剩余空间不够 "); 196 free(pTempNewImageBuffer); 197 return 0; 198 } 199 200 //上面没问题,就开始修改内容了 201 //*************************修改内容******************************************************************* 202 203 //初始化新节表信息 204 PWORD pNumberOfSection = &pPEHeder->NumberOfSections; 205 PDWORD pSizeOfImage = &pOptionHeader->SizeOfImage; 206 207 numberOfSection = pPEHeder->NumberOfSections; 208 PVOID pSecName = &pSectionHeader[numberOfSection].Name; 209 PDWORD pSecMisc = &pSectionHeader[numberOfSection].Misc.VirtualSize; 210 PDWORD pSecVirtualAddress = &pSectionHeader[numberOfSection].VirtualAddress; 211 PDWORD pSecSizeOfRawData = &pSectionHeader[numberOfSection].SizeOfRawData; 212 PDWORD pSecPointToRawData = &pSectionHeader[numberOfSection].PointerToRawData; 213 PDWORD pSecCharacteristics = &pSectionHeader[numberOfSection].Characteristics; 214 215 //修改PE文件头里面的节数量信息 216 217 printf("*pNumberOfSection:%#X ",pPEHeder->NumberOfSections); 218 *pNumberOfSection = pPEHeder->NumberOfSections + 1; 219 printf("*pNumberOfSection:%#X ",pPEHeder->NumberOfSections); 220 221 //修改PE可选头里面SizeOfImage信息 222 printf("*pSizeOfImage:%#X ",pOptionHeader->SizeOfImage); 223 *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000; 224 printf("*pSizeOfImage:%#X ",pOptionHeader->SizeOfImage); 225 226 //向节表中添加数据 227 228 memcpy(pSecName,".newSec",8); 229 *pSecMisc = 0x1000; 230 //这里VirtualAddress的地址需要根据最后一个节表中对齐前内存中的实际大小? 231 //和文件中对齐后的大小,分别使用VirtualAddress加上她们的值,哪个大,就是 232 //哪个; 233 //VirtualAddress+max(VirtualSize,SizeOfRawData) 234 //就是上面的公式 235 236 //判断出要添加的值 237 DWORD add_size = pLastSectionHeader->Misc.VirtualSize > pLastSectionHeader->SizeOfRawData? 238 pLastSectionHeader->Misc.VirtualSize:pLastSectionHeader->SizeOfRawData; 239 //上面是个三目运算符 240 241 printf("pLastSectionHeader: %#X ",pLastSectionHeader); 242 printf("add_size: %#X ",add_size); 243 printf("numberOfSection: %#X ",pPEHeder->NumberOfSections); 244 printf("pLastSectionHeader->Misc.VirtualSize: %#X ",pLastSectionHeader->Misc.VirtualSize); 245 printf("pLastSectionHeader->SizeOfRawData: %#X ",pLastSectionHeader->SizeOfRawData); 246 printf("add_size: %#X ",add_size); 247 248 *pSecVirtualAddress = pLastSectionHeader->VirtualAddress + add_size; 249 250 //SectionAlignment对齐 251 252 if (*pSecVirtualAddress % pOptionHeader->SectionAlignment) 253 { 254 *pSecVirtualAddress = *pSecVirtualAddress / pOptionHeader->SectionAlignment * 255 pOptionHeader->SectionAlignment + pOptionHeader->SectionAlignment; 256 } 257 258 *pSecSizeOfRawData = 0x1000; 259 *pSecPointToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData; 260 261 //FileAlignment对齐 262 263 if (*pSecPointToRawData % pOptionHeader->FileAlignment) 264 { 265 *pSecPointToRawData = *pSecPointToRawData / pOptionHeader->FileAlignment * 266 pOptionHeader->FileAlignment + pOptionHeader->FileAlignment; 267 } 268 269 *pSecCharacteristics = 0xFFFFFFFF; 270 271 *pNewImageBuffer = pTempNewImageBuffer; 272 pTempNewImageBuffer = NULL; 273 274 return sizeOfFile; 275 } 276 277 BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile) 278 { 279 FILE* fp = NULL; 280 fp = fopen(lpszFile, "wb+"); 281 if (!fp) // 这里我刚开始写漏了一个等于号,变成复制NULL了,导致错误 282 // if(fp == NULL) 可以这么写,没问题 283 { 284 fclose(fp); 285 return FALSE; 286 } 287 fwrite(pMemBuffer,size,1,fp); 288 fclose(fp); 289 fp = NULL; 290 return TRUE; 291 }
调用上面代码的函数部分代码
1 VOID NewSectionsInCodeSec() 2 { 3 LPVOID pFileBuffer = NULL; 4 LPVOID pNewImageBuffer = NULL; 5 BOOL isOK = FALSE; 6 DWORD size1 = 0; 7 DWORD size2 = 0; 8 9 //File-->FileBuffer 10 size1 = ReadPEFile(FilePath_In,&pFileBuffer); 11 if (size1 == 0 || !pFileBuffer) 12 { 13 printf("文件-->缓冲区失败 "); 14 return ; 15 } 16 printf("fileSize - Final: %#X ",size1); 17 18 //FileBuffer-->NewImageBuffer 19 size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer); 20 if (size2 == 0 || !pFileBuffer) 21 { 22 printf("FileBuffer-->NewImageBuffer失败 "); 23 free(pFileBuffer); 24 return ; 25 } 26 printf("sizeOfFile - Final: %#X ",size2); 27 //NewImageBuffer-->文件 28 isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out); 29 if (isOK) 30 { 31 printf("新增节表和节存盘成功 "); 32 return ; 33 } 34 35 //释放内存 36 free(pFileBuffer); 37 free(pNewImageBuffer); 38 }
用户程序入口main执行代码部分
#include "stdafx.h" #include "gbpeall.h" int main(int argc, char* argv[]) { NewSectionsInCodeSec(); printf("Hello World! Cntf "); return 0; }
执行结果:
查看效果:
本次操作未添加ShellCode测试;