下面是综合性相关代码中,关于新增一个节的代码 1 DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer) 2 { 3 //下面有个IN和OUT,大致意思就是参数的类型传入进来之后不进行宏扩展; 4 //啥也
下面是综合性相关代码中,关于新增一个节的代码
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 //可参考
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("打开文件失败!\r\n");
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("内存分配失败!\r\n");
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("读取数据失败!\r\n");
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("缓冲区指针无效\r\n");
127 return 0;
128 }
129
130 //判断是否为MZ标志
131
132 if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE --> MZ
133 {
134 printf("不是一个有效的MZ标志\r\n");
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标志\r\n");
143 return 0;
144 }
145
146 //*********************申请开辟内存空间*****************************************************************
147
148 sizeOfFile = fileSize+0x1000;
149 pTempNewImageBuffer = malloc(sizeOfFile);
150
151 //判断内存空间开辟是否成功
152 if (!pTempNewImageBuffer)
153 {
154 printf("pTempNewImageBuffer开辟内存空间失败\r\n");
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文件头不剩余空间不够\r\n");
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 \r\n",pPEHeder->NumberOfSections);
218 *pNumberOfSection = pPEHeder->NumberOfSections + 1;
219 printf("*pNumberOfSection:%#X \r\n",pPEHeder->NumberOfSections);
220
221 //修改PE可选头里面SizeOfImage信息
222 printf("*pSizeOfImage:%#X \r\n",pOptionHeader->SizeOfImage);
223 *pSizeOfImage = pOptionHeader->SizeOfImage + 0x1000;
224 printf("*pSizeOfImage:%#X \r\n",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 \r\n",pLastSectionHeader);
242 printf("add_size: %#X \r\n",add_size);
243 printf("numberOfSection: %#X \r\n",pPEHeder->NumberOfSections);
244 printf("pLastSectionHeader->Misc.VirtualSize: %#X \r\n",pLastSectionHeader->Misc.VirtualSize);
245 printf("pLastSectionHeader->SizeOfRawData: %#X \r\n",pLastSectionHeader->SizeOfRawData);
246 printf("add_size: %#X \r\n",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("文件-->缓冲区失败\r\n");
14 return ;
15 }
16 printf("fileSize - Final: %#X \r\n",size1);
17
18 //FileBuffer-->NewImageBuffer
19 size2 = CopyFileBufferToNewImageBuffer(pFileBuffer,size1,&pNewImageBuffer);
20 if (size2 == 0 || !pFileBuffer)
21 {
22 printf("FileBuffer-->NewImageBuffer失败\r\n");
23 free(pFileBuffer);
24 return ;
25 }
26 printf("sizeOfFile - Final: %#X \r\n",size2);
27 //NewImageBuffer-->文件
28 isOK = MemeryTOFile(pNewImageBuffer,size2,FilePath_Out);
29 if (isOK)
30 {
31 printf("新增节表和节存盘成功\r\n");
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\r\n");
return 0;
}
执行结果:
查看效果:
本次操作未添加ShellCode测试;
迷茫的人生,需要不断努力,才能看清远方模糊的志向!