1、移动各种表的目的
(1)在程序启动时,系统会根据导入导出表等进行初始化工作。为了保护程序,一般会对exe程序的二进制进行加密等工作,但是一旦将这些表也进行了加密,那么系统在初始化的时候没办法找到这些表,也无法启动程序。
(2)在对程序加密之前,需要对一些关键的表进行移动后,再对原来的数据进行加密,这样才不能破坏原来的程序。
(3)学会移动各种表,是对程序加密/破解的基础。
2、如何移动导出表
上一篇文章,提到了如何对导出表进行解析,导出表的结构如图下。
导出表的位置是在可选PE头的第一项,如图,我们可以通过PE头找到其在所在地址,但是注意的是该地址是在内存(RVA)中的偏移,需要将其转为文件偏移(FOA)
移动过程
注意点:
(1)需要将原来的数据目录项指向新的位置,存的是RVA
(2)导出函数地址表,名称表和序号表都指向的是RVA
(3)导出名称表里存的名称也是RVA。以上都需要将存在文件中的位置转为RVA,然后修复以上地址
4、代码如下
第一部分将文件读到内存中
LPVOID ReadFileBuffer(LPCSTR siFilename) {
int file_size = 0;
FILE* fp = NULL;
fopen_s(&fp,siFilename, "rb");
if (fp == NULL) {
printf("%d", GetLastError());
return NULL;
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
LPVOID file_buffer_addr = (LPVOID)malloc(file_size);
if (file_buffer_addr == NULL) {
return NULL;
}
memset(file_buffer_addr, 0, file_size);
if (file_buffer_addr != NULL) {
fread(file_buffer_addr, sizeof(char), file_size, fp);
fclose(fp);
return file_buffer_addr;
}
else {
fclose(fp);
free(file_buffer_addr);
file_buffer_addr = NULL;
return NULL;
}
}
第二部分:RVA转FOA
DWORD RVAtoFOA(DWORD dwROAAddress,char * FileBuffer){
PIMAGE_DOS_HEADER dos = NULL;
PIMAGE_NT_HEADERS nt = NULL;
PIMAGE_FILE_HEADER file_header = NULL;
PIMAGE_SECTION_HEADER section_header = NULL;
PIMAGE_OPTIONAL_HEADER option_header = NULL;
DWORD dwNumberofSections = NULL;
//DWORD dwSizeofImage = NULL;
//DWORD dwSizeofHeaders = NULL;
DWORD dwSizeofOptionHeader = NULL;
DWORD dwVirtualAddress = NULL;
DWORD dwSizeofRawData = NULL;
DWORD dwPointerRawData = NULL;
//DWORD dwVirtualAddress = NULL;
DWORD dwImageBase = NULL;
DWORD dwFOAaddress = NULL;
dos = (PIMAGE_DOS_HEADER)FileBuffer;
nt = (PIMAGE_NT_HEADERS)(FileBuffer + dos->e_lfanew);
file_header = (PIMAGE_FILE_HEADER)(&(nt->FileHeader));
option_header = (PIMAGE_OPTIONAL_HEADER)(&(nt->OptionalHeader));
dwImageBase = option_header->ImageBase;
dwNumberofSections = file_header->NumberOfSections;
//dwSizeofImage = option_header->SizeOfImage;
//dwSizeofHeaders = option_header->SizeOfHeaders;
dwSizeofOptionHeader = file_header->SizeOfOptionalHeader;
section_header = (PIMAGE_SECTION_HEADER)((char*)option_header + dwSizeofOptionHeader);
if (dwROAAddress <= section_header->VirtualAddress) {
//如果小于第一个节的virtualAddress,说明在头部。
dwFOAaddress = dwROAAddress;
return dwFOAaddress;
}
//dwVirtualAddress = section_header->VirtualAddress;
for (int i = 0; i < dwNumberofSections; i++) {
//printf("%x", ((PIMAGE_SECTION_HEADER)((char*)section_header + 40))->VirtualAddress);
if (dwROAAddress >= section_header->VirtualAddress && dwROAAddress < ((PIMAGE_SECTION_HEADER