目标如上图: 将文件放入内存后拉伸再拉回去存盘
代码如下, 写的比较乱, 没怎么整理, 大佬勿怪
发现一些问题, 节的数据没有存盘, 所以导出来的文件无法运行( ̄▽  ̄)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<Windows.h>
//存入内存
//开始拉伸
//拉回来
//存回硬盘
//存入内存
//1. 打开文件
//2. 开辟空间
// 2.1获取开辟空间的大小
//3. 载入
FILE* OpenFile() {
//打开文件
FILE* file_point;
int return1 = fopen_s(&file_point, "C:\\Windows\\System32\\notepad.exe","rb");
if (return1 != 0) {
printf("获取文件指针错误\n");
}
return file_point;
}
char* GetMemory(FILE* file_point) {
//开辟空间
fseek(file_point, 0, SEEK_END);
int file_size = ftell(file_point);
fseek(file_point, 0, SEEK_SET);
char* enter_memory = (char*)malloc(sizeof(char) * file_size);
fread(enter_memory, file_size, 1, file_point);
return enter_memory;
}
void FreeMemory(FILE* file_point, char* memory_point[], int memory_size) {
for (int i = 0; i < memory_size; i++) {
free(memory_point[i]);
}
fclose(file_point);
}
//将16进制转成字符, 检测用, 一般没什么用
void conversion(int data) {
char* point = (char*)&data;
for (int i = 0; i < 4; i++) {
printf("%c", *point);
point++;
}
}
//开始拉伸
// 1.根据可选PE头里sizofImage的大小申请空间, 将空间全部用0覆盖
// 2. 申请完后根据sizeofHeaders的值将headers的数据加入新的空间
// 3. 根据标准pe头里的numberofSection遍历节表,
// 4.根据节表中的PointertoRawData与SizeOfRawData将数据填入VisualAddress所指向的内存
char* BeginStretch(char* memory) {
PIMAGE_DOS_HEADER dos_header = NULL;
dos_header = (PIMAGE_DOS_HEADER)memory;
//创建nt头并根据dos头的数据设置nt头的起始地址
PIMAGE_NT_HEADERS nt_header = NULL;
nt_header = (PIMAGE_NT_HEADERS)((DWORD)dos_header + dos_header->e_lfanew);
//创建PE标准头并从中获得NumberOfSections
PIMAGE_FILE_HEADER file_header = NULL;
file_header = &(nt_header->FileHeader);
int section_num = file_header->NumberOfSections;
//从标准PE头转到可选PE头并获取SizeOfImage
PIMAGE_OPTIONAL_HEADER optional_header = NULL;
optional_header = (PIMAGE_OPTIONAL_HEADER)((DWORD)file_header + IMAGE_SIZEOF_FILE_HEADER);
int stretch_size = optional_header->SizeOfImage;
//创建新的空间清零并复制headers至新的空间
char* new_memory = (char*)malloc(sizeof(char)*stretch_size);
memset(new_memory, 0, stretch_size);
memcpy(new_memory, memory, optional_header->SizeOfHeaders);
//获取memory的节表
PIMAGE_SECTION_HEADER section_header = NULL;
section_header = (PIMAGE_SECTION_HEADER)((DWORD)optional_header + file_header->SizeOfOptionalHeader);
//创建新的dos头并根据dos头的e_lfanew创建nt头
PIMAGE_DOS_HEADER new_dos = NULL;
new_dos = (PIMAGE_DOS_HEADER)new_memory;
PIMAGE_NT_HEADERS new_nt_header = NULL;
new_nt_header = (PIMAGE_NT_HEADERS)((DWORD)new_dos + new_dos->e_lfanew);
//获取new_memory的节表, 寻找到了速度较快的写法
PIMAGE_SECTION_HEADER new_section = NULL;
new_section = (PIMAGE_SECTION_HEADER)((DWORD)(new_nt_header + 1));
//遍历节表, 根据memory节表中的PointertoRawData与SizeOfRawData将数据填入new_memory的VisualAddress所指向的内存
//偏移需要加上memory才是正确的地址
for (int i = 0; i < section_num; i++) {
memcpy((char*)(new_memory+new_section->VirtualAddress), (char*)(memory+section_header->PointerToRawData), section_header->SizeOfRawData);
section_header++;
new_section++;
}
return new_memory;
}
//拉回来
//先确定需要申请多大的空间后申请空间后清零
// 1.根据file_header中的number_of_section确定节表的数量
// 2. 根据节表中最后一个节的pointer_to_raw_data+Visual_size的起始地址确定需要的大小
//根据optional_header中的size_of_headers将headers加入新的内存
//根据节表中的visual_address+memory起始地址确定节的位置
//根据节表中的visual_size确定每个节要复制的大小
//将上面的节根据新节表中的PointeToRawData复制到last_memory
char* Back_Origin(char* new_memory){
//新建nt头
PIMAGE_DOS_HEADER new2_dos = NULL;
new2_dos = (PIMAGE_DOS_HEADER)new_memory;
PIMAGE_NT_HEADERS new2_nt = NULL;
new2_nt = (PIMAGE_NT_HEADERS)((DWORD)new2_dos + new2_dos->e_lfanew);
//根据file_header中的number_of_section确定节表的数量
PIMAGE_FILE_HEADER new2_file = (PIMAGE_FILE_HEADER)((DWORD)new2_nt+4);
int new2_section_num = new2_file->NumberOfSections;
//找到第一个节表的位置
PIMAGE_SECTION_HEADER new2_section = NULL;
new2_section = (PIMAGE_SECTION_HEADER)((DWORD)(new2_nt + 1));
//定位到最后一个节
for (int i = 0; i < new2_section_num-1; i++) {
new2_section++;
}
//根据节表中最后一个节的pointer_to_raw_data+Visual_size确定需要的大小
DWORD size = (DWORD)(new2_section->PointerToRawData + new2_section->Misc.VirtualSize);
//申请空间
char* last_memory = (char*)malloc(sizeof(char) * size);
memset(last_memory, 0, size);
//获取headers的大小并复制到last_memory
PIMAGE_OPTIONAL_HEADER new2_optional = (PIMAGE_OPTIONAL_HEADER)((DWORD)new2_file + 20);
DWORD last_headers_size = new2_optional->SizeOfHeaders;
memcpy(last_memory, new_memory, last_headers_size);
//定位到last_memory的起始节表
PIMAGE_DOS_HEADER last_dos = NULL;
last_dos = (PIMAGE_DOS_HEADER)last_memory;
PIMAGE_NT_HEADERS last_nt = NULL;
last_nt = (PIMAGE_NT_HEADERS)((DWORD)last_dos + last_dos->e_lfanew);
PIMAGE_SECTION_HEADER last_section = NULL;
last_section = (PIMAGE_SECTION_HEADER)((DWORD)(last_nt + 1));
for (int i = 0; i < new2_section_num; i++) {
memcpy((char*)(last_memory + last_section->PointerToRawData), (char*)(new_memory + new2_section->VirtualAddress), new2_section->Misc.VirtualSize);
last_section++;
new2_section++;
}
return last_memory;
}
// 存回硬盘
//确定last_memory的容量
//使用fwrite函数
void Back_Rom(char* last_memory) {
//新建nt头
PIMAGE_DOS_HEADER new2_dos = NULL;
new2_dos = (PIMAGE_DOS_HEADER)last_memory;
PIMAGE_NT_HEADERS new2_nt = NULL;
new2_nt = (PIMAGE_NT_HEADERS)((DWORD)new2_dos + new2_dos->e_lfanew);
//根据file_header中的number_of_section确定节表的数量
PIMAGE_FILE_HEADER new2_file = (PIMAGE_FILE_HEADER)((DWORD)new2_nt + 4);
int new2_section_num = new2_file->NumberOfSections;
//找到第一个节表的位置
PIMAGE_SECTION_HEADER new2_section = NULL;
new2_section = (PIMAGE_SECTION_HEADER)((DWORD)(new2_nt + 1));
//定位到最后一个节
for (int i = 0; i < new2_section_num - 1; i++) {
new2_section++;
}
//根据节表中最后一个节的pointer_to_raw_data+Visual_size确定需要的大小
DWORD size = (DWORD)(new2_section->PointerToRawData + new2_section->Misc.VirtualSize);
FILE* last_one_file = NULL;
fopen_s(&last_one_file, "D:\\Ddisk\\last_memory.exe", "wb");
fwrite(last_memory, 1, size, last_one_file);
fclose(last_one_file);
}
void main() {
FILE* file_point = OpenFile();
char* memory_point = GetMemory(file_point);
char* new_memory = BeginStretch(memory_point);
char* last_memory = Back_Origin(new_memory);
Back_Rom(last_memory);
//conversion(0x7865742e);
char* memory[] = { memory_point,new_memory, last_memory};
int num = (sizeof(memory)) / 4;
FreeMemory(file_point, memory, num);
}