Last updated on October 7, 2023 pm
PE练习,FileBuffer–ImageBuffer–FileBuffer
回顾
目前我们已经知道PE文件结构大致组成部分,即
实际上这些部分就已经可以决定一个PE文件的全部的东西了,可以通过头找到节表,由节表找到每一个节区,每一个节区就存放了运行时的信息。
练习
要求
将一个EXE文件从文件形式拉伸成内存形式,再由内存形式压缩回文件形式,存盘后能运行
note:这里的内存是指由malloc分配的堆空间地址,不是程序ImageBase的地址
需要解决的问题
Q1:要拷贝的数据在哪
A1:各种头的数据在FileBuffer最前面,而且紧紧相连,中间没有空,同时大小由SizeOfHeaders决定;节区地址可以由节表中的PointerToRawData找到
Q2:要分配多少空间来存储copy数据
A2:在可选PE头中有一个SizeOfImage
成员,它决定了在内存中PE文件的大小,因此分配SizeOfImage
空间即可
Q3:要把数据copy去哪里
A3:各种头的数据可以直接copy到ImageBuffer的前面,节区地址可以由节表中每一个结构体的VirtualAddress
决定
同理从ImageBuffer拷贝到FileBuffer时,头部数据也不变,节区地址则可由节表中的PointerToRawData
决定
Q4:节区大小如何确定
A4:节区大小可与节表两个成员相关,第一个是Misc,第二个是SizeOfRawData。从图中可能会觉得SizeOfRawData一定大于Misc,其实并不一定。考虑这个情形,在编写程序时,仅声明一个全部变量char ch[1000]
而并不初始化,那么在文件中就不会为这个变量分配空间存储,只有在内存中时才会分配。而Misc所指的大小就是在内存中的大小,那么这时候Misc就有可能大于SizeOfRawData
那么是不是谁大用谁呢?也不是,还是以刚刚为例,如果执意使用Misc作为要copy的节区大小,由于在文件中并没有为其分配大小,那么这时候就有可能会把下一个节区数据也copy进来,这就乱套了。
所以最终答案就是,用小的,或者只用SizeOfRawData,这样能保证精确地把该节区数据全部正确copy,即使还要需要内存,那么也是紧跟已copy数据之后,而且下一个节区地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 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
| #include<stdio.h> #include<windows.h> #include<malloc.h>
DWORD Size(FILE* fp){ DWORD size = 0; fseek(fp,0,SEEK_END); size = ftell(fp); fseek(fp,0,SEEK_SET); return size; }
char* FileToImage(char* filebuffer){
PIMAGE_DOS_HEADER DosHeader = NULL; PIMAGE_NT_HEADERS NTHeader = NULL; PIMAGE_FILE_HEADER FileHeader = NULL; PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL; PIMAGE_SECTION_HEADER SectionHeader = NULL; char* TemBuffer = NULL;
if (!filebuffer) { printf("Invalid buffer!\n"); return 0; }
if (*(PWORD)filebuffer != IMAGE_DOS_SIGNATURE) { printf("not a PE file!\n"); return 0; }
DosHeader = (PIMAGE_DOS_HEADER)filebuffer; NTHeader = (PIMAGE_NT_HEADERS) (filebuffer + DosHeader->e_lfanew); FileHeader = (PIMAGE_FILE_HEADER)(filebuffer + DosHeader->e_lfanew + 4); OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER); SectionHeader = (PIMAGE_SECTION_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);
TemBuffer = (char*)malloc(OptionalHeader->SizeOfImage);
memset(TemBuffer,0,OptionalHeader->SizeOfImage); memcpy(TemBuffer,DosHeader,OptionalHeader->SizeOfHeaders);
for(int i=0;i<FileHeader->NumberOfSections;i++){ memcpy((TemBuffer + SectionHeader->VirtualAddress),(filebuffer + SectionHeader->PointerToRawData),SectionHeader->SizeOfRawData); SectionHeader = (PIMAGE_SECTION_HEADER)(filebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader + 40 * (i + 1));
}
return TemBuffer; }
char* ImageToFile(char* imagebuffer){ PIMAGE_DOS_HEADER DosHeader = NULL; PIMAGE_NT_HEADERS NTHeader = NULL; PIMAGE_FILE_HEADER FileHeader = NULL; PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL; PIMAGE_SECTION_HEADER SectionHeader = NULL; char* TemBuffer = NULL;
if (!imagebuffer) { printf("Invalid buffer!\n"); return 0; }
if (*(PWORD)imagebuffer != IMAGE_DOS_SIGNATURE) { printf("not a PE file!\n"); return 0; }
DosHeader = (PIMAGE_DOS_HEADER)imagebuffer; NTHeader = (PIMAGE_NT_HEADERS)(imagebuffer + DosHeader->e_lfanew); FileHeader = (PIMAGE_FILE_HEADER)(imagebuffer + DosHeader->e_lfanew + 4); OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(imagebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER); SectionHeader = (PIMAGE_SECTION_HEADER)(imagebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader);
DWORD new_size = OptionalHeader->SizeOfHeaders; for (int i = 0; i < FileHeader->NumberOfSections; i++) { new_size += (SectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i)->SizeOfRawData; }
TemBuffer = (char*)malloc(new_size);
memset(TemBuffer, 0, new_size); memcpy(TemBuffer, imagebuffer, OptionalHeader->SizeOfHeaders);
for (int i = 0; i < FileHeader->NumberOfSections; i++) { memcpy((TemBuffer + SectionHeader->PointerToRawData), (imagebuffer + SectionHeader->VirtualAddress), SectionHeader->SizeOfRawData); SectionHeader = (PIMAGE_SECTION_HEADER)(imagebuffer + DosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + FileHeader->SizeOfOptionalHeader + 40 * (i + 1)); }
return TemBuffer; }
int main(){ char* buffer;
FILE* fp1 = NULL; FILE* fp2 = NULL; errno_t err_1 = fopen_s(&fp1, "C:\\Users\\yongrin\\Desktop\\PE_info.exe", "rb"); errno_t err_2 = fopen_s(&fp2, "C:\\Users\\yongrin\\Desktop\\PE_info_changed.exe", "wb"); DWORD size = Size(fp1); buffer = (char*)malloc(size); fread(buffer,size,1,fp1);
char* newbuffer; newbuffer = FileToImage(buffer); newbuffer = ImageToFile(newbuffer);
fwrite(newbuffer,size,1,fp2);
return 0; }
|