滴水PE作业3

该代码实现读取PE文件,将导出表和重定位表的数据移到新节中,涉及内存分配、文件操作及PE结构解析。通过新增节、调整内存布局,并更新文件头信息来保存修改。

 实现目标: 开辟新的节并将导出表与重定位表的数据移到新的节中

代码如下

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<Windows.h>
FILE* OpenFile(char path[]);
char* GetMemory(FILE* file_point);
void FreeMemory(FILE* file_point, char* memory_point[], int memory_size);
void conversion(PIMAGE_SECTION_HEADER section);
PIMAGE_DOS_HEADER dos_ptr(char* memory);
PIMAGE_NT_HEADERS nt_ptr(char* memory);
PIMAGE_FILE_HEADER file_ptr(char* memory);
PIMAGE_OPTIONAL_HEADER optional_ptr(char* memory);
PIMAGE_SECTION_HEADER section_ptr(char* memory);
PIMAGE_SECTION_HEADER last_section_ptr(char* memory);
void export_file(char* memory);
char* transform_to_file(char* memory, char* first);
char* transform_to_memory(char* memory, char* first);
DWORD get_largest_size(DWORD virtual_size, DWORD file_size);
DWORD* data_directory(char* memory);

char* add_table(char* memory, FILE* file_point);
DWORD get_int(DWORD alignment, DWORD Size);
char* move_export(char* memory);
void move_reloc(char* space, char* memory);
void move_table(char path[]);
DWORD* table_address(char* memory);
DWORD need_space(char* memory);
void export_file(char* memory);

FILE* OpenFile(char path[]) {
	//打开文件
	FILE* file_point;
	int return1 = fopen_s(&file_point, path, "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);
	DWORD needed_size = sizeof(char) * file_size;
	char* enter_memory = (char*)malloc(needed_size);
	memset(enter_memory, 0, needed_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);
}

void conversion(PIMAGE_SECTION_HEADER section) {
	char* point = (char*)section;
	printf("节表: ");
	for (int i = 0; i < 8; i++) {
		printf("%c", *point);
		point++;
	}
}

PIMAGE_DOS_HEADER dos_ptr(char* memory) {
	return (PIMAGE_DOS_HEADER)(memory);
}
PIMAGE_NT_HEADERS nt_ptr(char* memory) {
	return (PIMAGE_NT_HEADERS)((DWORD)dos_ptr(memory) + dos_ptr(memory)->e_lfanew);
}
PIMAGE_FILE_HEADER file_ptr(char* memory) {
	return (PIMAGE_FILE_HEADER)((DWORD)nt_ptr(memory) + 4);
}
PIMAGE_OPTIONAL_HEADER optional_ptr(char* memory) {
	return (PIMAGE_OPTIONAL_HEADER)((DWORD)file_ptr(memory) + 20);
}
PIMAGE_SECTION_HEADER section_ptr(char* memory) {
	return (PIMAGE_SECTION_HEADER)(optional_ptr(memory) + 1);
}
PIMAGE_SECTION_HEADER last_section_ptr(char* memory) {
	PIMAGE_SECTION_HEADER section = section_ptr(memory);
	PIMAGE_FILE_HEADER file = file_ptr(memory);
	int circle_num = file->NumberOfSections;
	for (int i = 0; i < circle_num - 1; i++) {
		section++;
	}
	return section;
}
//导出文件
void export_file(char* memory) {
	FILE* win_file = NULL;
	fopen_s(&win_file, "D:\\Ddisk\\last_memory.exe", "wb");
	fseek(win_file, 0, SEEK_SET);
	PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
	//先导出头部数据
	int sizeofHeaders = optional->SizeOfHeaders;
	int fileAlignment = optional->FileAlignment;
	if ((sizeofHeaders % fileAlignment) > 0) {
		DWORD header_data = fileAlignment * ((sizeofHeaders / fileAlignment) + 1);
		fwrite(memory, 1, header_data, win_file);
	}
	else if ((sizeofHeaders % fileAlignment) == 0) {
		DWORD header_data2 = fileAlignment * (sizeofHeaders / fileAlignment);
		fwrite(memory, 1, header_data2, win_file);
	}
	//导出各个节
	int section_num = file_ptr(memory)->NumberOfSections;
	PIMAGE_SECTION_HEADER section = section_ptr(memory);
	for (int i = 0; i < section_num; i++) {
		fseek(win_file, section->PointerToRawData, SEEK_SET);
		fwrite((char*)(section->PointerToRawData + (DWORD)memory), 1, section->SizeOfRawData, win_file);
		section++;
	}
	fclose(win_file);
}
//将RVA转为FOA
char* transform_to_file(char* memory, char* first) {
	//定位file并获取节表数量
	PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)first;
	PIMAGE_FILE_HEADER file = (PIMAGE_FILE_HEADER)((DWORD)dos + dos->e_lfanew + 4);
	int table_num = file->NumberOfSections;
	//定位optional并获取内存基址与对齐
	PIMAGE_OPTIONAL_HEADER optional = (PIMAGE_OPTIONAL_HEADER)(DWORD(file) + 20);
	DWORD image_base = optional->ImageBase;
	DWORD align = optional->SectionAlignment;
	if ((int)(memory - first) >= (int)image_base) { memory = memory - image_base; }
	if ((int)memory < (int)align) { return memory; }
	PIMAGE_SECTION_HEADER section = NULL;
	section = (PIMAGE_SECTION_HEADER)(optional + 1);
	for (int i = 0; i < table_num; i++) {
		if ((section->VirtualAddress + get_largest_size(section->Misc.VirtualSize, section->SizeOfRawData)) >= (DWORD)memory && (DWORD)memory >= section->VirtualAddress) {
			return (char*)((DWORD)section->PointerToRawData + ((DWORD)memory - (DWORD)section->VirtualAddress));
			break;
		}
		section++;
	}
	return (char*)-1;
}
//将FOA转为RVA
char* transform_to_memory(char* memory, char* first) {
	//定位file并获取节表数量
	PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)first;
	PIMAGE_FILE_HEADER file = (PIMAGE_FILE_HEADER)((DWORD)dos + dos->e_lfanew + 4);
	int table_num = file->NumberOfSections;
	//定位optional并获取内存基址与对齐
	PIMAGE_OPTIONAL_HEADER optional = (PIMAGE_OPTIONAL_HEADER)(DWORD(file) + 20);
	DWORD image_base = optional->ImageBase;
	DWORD align = optional->SectionAlignment;
	if ((int)(memory - first) >= (int)image_base) { memory = memory - image_base; }
	if ((int)memory < (int)align) { return memory; }
	PIMAGE_SECTION_HEADER section = NULL;
	section = (PIMAGE_SECTION_HEADER)(optional + 1);
	for (int i = 0; i < table_num; i++) {
		if (section->PointerToRawData + get_largest_size(section->Misc.VirtualSize, section->SizeOfRawData) >= (DWORD)memory && (DWORD)memory >= section->PointerToRawData) {
			return (char*)((DWORD)section->VirtualAddress + ((DWORD)memory - (DWORD)section->PointerToRawData));
			break;
		}
		section++;
	}
	return (char*)-1;
}
//判断节表中的virtual_size与file_size的大小
DWORD get_largest_size(DWORD virtual_size, DWORD file_size) {
	if (virtual_size > file_size) {
		return virtual_size;
	}
	else {
		return file_size;
	}
	return 0;
}
//得到数据目录表中所有相关的数据
DWORD* data_directory(char* memory) {
	PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
	DWORD* data_directory = (DWORD*)&optional->DataDirectory;
	int directory_circle = optional->NumberOfRvaAndSizes;
	DWORD sum_arr[32] = { 0 };
	for (int i = 0; i < directory_circle; i++) {
		sum_arr[i + 16] = *data_directory;
		sum_arr[i] = (DWORD)(transform_to_file((char*)*data_directory, memory));
		data_directory = data_directory + 2;
	}
	return sum_arr;
}

//新增一个节
// 不拉伸, 使用file_buffer
// 1. 修改numberOfSection
// 2. 修改SizeOfImage=原来的sizeofImage+节对齐后的长度
// 3. 向节表中添加信息
//	(1)判断sizeofHeaders-最后一个节表位置判断是否足够添加节(是否够40字节))
//	(2)够的话添加, 不够的话将节表的数据向前移,修改e_lfanew的值, 继续添加, 还不够的话添加失败(或将两个节表合并, 空出一个节表)
//	(3)判断加多少: 遍历导出表与导入表的数据, 根据其结果得到大小
DWORD get_int(DWORD alignment, DWORD Size) {
	if (Size % alignment == 0) {
		return alignment * (Size / alignment);
	}
	else {
		return ((Size / alignment) * alignment) + alignment;
	}
}
//得到数据目录表存储的各个表的数据
DWORD* table_address(char* memory) {
	PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
	DWORD* data_directory = (DWORD*)&optional->DataDirectory;
	int directory_circle = optional->NumberOfRvaAndSizes;
	DWORD sum_arr[32] = { 0 };
	for (int i = 0; i < directory_circle; i++) {
		sum_arr[i + 16] = *data_directory;
		sum_arr[i] = (DWORD)(transform_to_file((char*)*data_directory, memory));
		data_directory = data_directory + 2;
	}
	return sum_arr;
}
//计算开辟新的节表所需要的空间
DWORD need_space(char* memory) {
	//求出节需要的空间, 目前需要的空间为导出表的数据+重定位表的数据
	//使用数组存储所有表的地址
	DWORD* ptr_one = table_address(memory);
	DWORD directory_arr[32] = { 0 };
	for (int i = 0; i < 32; i++) {
		directory_arr[i] = *ptr_one;
		ptr_one++;
	}
	PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
	//得到导出表需要的空间
	DWORD export_sum_space = 0;
	if (directory_arr[0] != 0) {
		PIMAGE_EXPORT_DIRECTORY export_table2 = (PIMAGE_EXPORT_DIRECTORY)(directory_arr[0] + (DWORD)memory);
		char* name_base = (char*)(transform_to_file((char*)export_table2->Name, memory) + (DWORD)memory);
		//得到导出表需要的空间
		DWORD function_space = 4 * export_table2->NumberOfFunctions;
		DWORD name_order_space = (strlen(name_base)) + (6 * export_table2->NumberOfNames);
		DWORD export_space = ((DWORD)(export_table2 + 1) - (DWORD)(export_table2));
		export_sum_space = function_space + name_order_space + export_space;

	}
	DWORD reloc_size = 0;
	//得到重定位表需要的空间
	if (directory_arr[5] != 0) {
		PIMAGE_BASE_RELOCATION reloc_table = (PIMAGE_BASE_RELOCATION)(directory_arr[5] + (DWORD)memory);
		while (reloc_table->SizeOfBlock != 0 && reloc_table->VirtualAddress != 0) {
			reloc_size = reloc_size + reloc_table->SizeOfBlock;
			reloc_table = (PIMAGE_BASE_RELOCATION)((DWORD)reloc_table + reloc_table->SizeOfBlock);
		}
	}
	return reloc_size + export_sum_space;
}
//添加新的节表
char* add_table(char* memory, FILE* file_point) {
	//得到各个头的指针
	PIMAGE_DOS_HEADER dos = dos_ptr(memory);
	PIMAGE_NT_HEADERS nt = nt_ptr(memory);
	PIMAGE_FILE_HEADER file = file_ptr(memory);
	PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
	PIMAGE_SECTION_HEADER section = section_ptr(memory);

	int section_num = file->NumberOfSections;
	int size_of_header = optional->SizeOfHeaders;
	PIMAGE_SECTION_HEADER last_site = section;
	for (int i = 0; i < section_num; i++) {
		last_site++;
	}
	//将第一个节表的数据复制到要添加的最后一个节表中
	if ((size_of_header - ((DWORD)(last_site)-(DWORD)(memory))) >= 80 && *(char*)last_site == 0x00) {
		DWORD add_data = (DWORD)(section + 1) - (DWORD)(section);
		char* first_site = (char*)section;
		char* last_site2 = (char*)last_site;
		for (int i = 0; i < add_data; i++) {
			*last_site2 = *first_site;
			first_site++;
			last_site2++;
		}
		//更改节表的名称
		char* correct_added_data = (char*)last_site;
		char myName[] = "BruceLi";
		for (int i = 0; i < 8; i++) {
			*correct_added_data = myName[i];
			correct_added_data++;
		}
		//修改新的节表的起始地址, 大小属性
		PIMAGE_SECTION_HEADER dao2_last_site = last_site - 1;
		last_site->PointerToRawData = (dao2_last_site->PointerToRawData + get_int(optional->FileAlignment, dao2_last_site->SizeOfRawData));
		last_site->VirtualAddress = (dao2_last_site->VirtualAddress + get_int(optional->SectionAlignment, dao2_last_site->Misc.VirtualSize));
		DWORD last_size = get_int(optional->SectionAlignment, need_space(memory));
		last_site->SizeOfRawData = last_size;
		last_site->Misc.VirtualSize = last_size;
		//修改Number of section,修改SizeOfImage
		file->NumberOfSections = file->NumberOfSections + 1;
		optional->SizeOfImage = optional->SizeOfImage + last_size;
		//开辟新的空间
		fseek(file_point, 0, SEEK_END);
		int file_size = ftell(file_point);
		char* ptr = memory;
		ptr = (char*)realloc(memory, (file_size + last_size) * sizeof(char));
		return ptr;
	}
	else {
		if (((size_of_header - ((DWORD)last_site - (DWORD)memory)) + (dos->e_lfanew - 0x40)) >= 80) {
			//空间不够但将节表的数据向前移>=40字节, 修改e_lfanew的值
			dos->e_lfanew = 0x40;
			int circle_times = (DWORD)last_site - (DWORD)nt;
			char* correct_ptr = (char*)nt;
			char* correct_ptr2 = (char*)(memory + 64);
			for (int i = 0; i < circle_times; i++) {
				*correct_ptr2 = *correct_ptr;
				*correct_ptr = 0;
				correct_ptr2++;
				correct_ptr++;
			}
			printf("Error\n");
			return 0;
		}
		else {
			printf("Error\n");
			return 0;
		}

	}
	return 0;
}
//将file_address转为virtual_address

//移动导出表
char* move_export(char* memory) {
	//得到数据目录表与需要填充数据的空间
	PIMAGE_SECTION_HEADER last_section = last_section_ptr(memory);
	char* space_site = (char*)last_section->PointerToRawData;
	DWORD arr[32] = { 0 };
	DWORD* ptr = table_address(memory);
	for (int i = 0; i < 32; i++) {
		arr[i] = *ptr;
		ptr++;
	}
	//填充名称表的数据
	char* space2 = space_site + (DWORD)memory;
	if (arr[0] != 0) {
		//根据得到的名称表的大小将名称表移至地址处
		//得到导出表的地址
		PIMAGE_EXPORT_DIRECTORY export_table = (PIMAGE_EXPORT_DIRECTORY)(memory + arr[0]);
		int numberOfNames = export_table->NumberOfNames;
		//得到导出表→ 名称表的地址
		char* addressOfNames_address = transform_to_file((char*)export_table->AddressOfNames, memory) + (DWORD)memory;
		//得到名称表存储名称的真实的值
		char* addressOfNames = (char*)(transform_to_file((char*)*(DWORD*)addressOfNames_address, memory) + (DWORD)memory);
		DWORD* name_address = (DWORD*)addressOfNames_address;

		for (int i = 0; i < numberOfNames; i++) {
			char* address_name = (char*)(transform_to_file((char*)*(DWORD*)name_address, memory) + (DWORD)memory);
			*name_address = (DWORD)transform_to_memory((char*)(space2 - (DWORD)memory), memory);
			for (int i = 0; i < strlen((char*)addressOfNames) + 1; i++) {
				if (i == strlen((char*)(addressOfNames))) {
					*space2 = 0;
					space2++;
					break;
				}
				*space2 = *address_name;
				space2++;
				address_name++;
			}
			name_address++;
		}
		//修改导出表名称表的地址的指针
		export_table->AddressOfNames = (DWORD)transform_to_memory((char*)((DWORD)space2 - (DWORD)memory), memory);
		//将名称表复制到新的空间
		DWORD* space3 = (DWORD*)space2;
		DWORD* need_copy_name = (DWORD*)addressOfNames_address;
		for (int i = 0; i < numberOfNames; i++) {
			*space3 = *need_copy_name;
			space3++;
			need_copy_name++;
		}
		//根据名称表的space3将序号表中的数据遍历至新的地址
		short* space4 = (short*)space3;
		int order_num = export_table->NumberOfNames;
		short* order_site = (short*)(transform_to_file((char*)export_table->AddressOfNameOrdinals, memory) + (DWORD)memory);
		//修改导出表->序号表的地址的指针
		export_table->AddressOfNameOrdinals = (DWORD)transform_to_memory((char*)((DWORD)space3 - (DWORD)memory), memory);
		for (int i = 0; i < order_num; i++) {
			*space4 = *order_site;
			space4++;
			order_site++;
		}
		//根据名称表的space4将函数表中的数据遍历至新的地址
		DWORD* space5 = (DWORD*)space4;
		int function_num = export_table->NumberOfFunctions;
		DWORD* function_site = (DWORD*)(transform_to_file((char*)export_table->AddressOfFunctions, memory) + (DWORD)memory);
		//修改导出表->函数表的地址的指针
		export_table->AddressOfFunctions = (DWORD)transform_to_memory((char*)((DWORD)space4 - (DWORD)memory), memory);
		for (int i = 0; i < function_num; i++) {
			*space5 = *function_site;
			space5++;
			function_site++;
		}
		//根据返回的space5将导出表的名称导至新的空间, 返回space6
		DWORD* space6 = space5;
		DWORD* function_name_site = (DWORD*)(transform_to_file((char*)export_table->Name, memory) + (DWORD)memory);
		export_table->Name = (DWORD)transform_to_memory((char*)((DWORD)space5 - (DWORD)memory), memory);
		*space6 = *function_name_site;
		space6++;
		//将导出表的数据根据space6移至新的空间
		char* export_data_move = (char*)export_table;
		PIMAGE_OPTIONAL_HEADER optional_last = optional_ptr(memory);
		char* transform_export_address = (char*)optional_last->DataDirectory;
		DWORD* export_table_site = (DWORD*)(transform_to_file((char*)*transform_export_address, memory) + (DWORD)memory);
		*export_table_site = (DWORD)space6;
		char* space7 = (char*)space6;
		for (int i = 0; i < ((DWORD)(export_table + 1) - (DWORD)(export_table)); i++) {
			*space7 = *export_data_move;
			space7++;
			export_data_move++;
		}
		return space7;
	}
	else {
		printf("不存在导出表, 无法移动\n");
		return 0;
	}
	return 0;
}
//移动重定位表
void move_reloc(char* space, char* memory) {
	if (space != 0) {
		//找到重定位表的位置
		PIMAGE_OPTIONAL_HEADER optional = optional_ptr(memory);
		DWORD* reloc = (DWORD*)optional->DataDirectory;
		int circle_times = optional->NumberOfRvaAndSizes;
		for (int i = 0; i < circle_times; i++) {
			if (i == 5) {
				break;
			}
			reloc = reloc + 2;
		}
		DWORD* reloc2 = (DWORD*)*reloc;
		*reloc = (DWORD)transform_to_memory((char*)(space - memory), memory);
		char* new_space = (char*)space;
		PIMAGE_BASE_RELOCATION reloc3 = (PIMAGE_BASE_RELOCATION)(transform_to_file((char*)reloc2, memory) + (DWORD)memory);
		char* reloc4 = NULL;
		while (reloc3->SizeOfBlock != 0 && reloc3->VirtualAddress != 0) {
			reloc4 = (char*)reloc3;
			for (int i = 0; i < reloc3->SizeOfBlock; i++) {
				*new_space = *reloc4;
				new_space++;
				reloc4++;
			}
			reloc3 = (PIMAGE_BASE_RELOCATION)((reloc3->SizeOfBlock) + (DWORD)reloc3);
		}
		for (int i = 0; i < 8; i++) {
			*new_space = 0;
			new_space++;
		}
		printf("移动重定位表成功\n");
	}
	else{
		printf("导出表未移动成功, 重定位表移动失败\n");
	}
}
void move_table(char path[]) {
	FILE* file_point = OpenFile(path);
	char* memory_point = GetMemory(file_point);
	char* added_memory = add_table(memory_point, file_point);
	char* space = move_export(added_memory);
	move_reloc(space, added_memory);
	export_file(added_memory);
	char* memory[] = { added_memory };
	int num = (sizeof(memory)) / 4;
	FreeMemory(file_point, memory, num);
}
int main() {
    char dll[] = "D:\\Ddisk\\逆向\\AutoUpdateUtil.dll";
    char last_memory[] = "D:\\Ddisk\\last_memory.exe";
    char notepad[] = "C:\\Windows\\System32\\notepad.exe";
    char crack[] = "D:\\Ddisk\\逆向\\CrackMe.exe";
	move_table(dll);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值