文件从FileBuffer经过拉伸后成为ImageBuffer,此时还无法运行,但已经很接近运行的状态了。
代码实现从文件–FileBuffer–ImageBuffer–NewBuffer–硬盘的过程
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include <stdlib.h>
#include <malloc.h>
#include<windows.h>
#include<memory.h>
int GetFileszie(FILE* fptr);
char* ReadFilea(const char* Filepath);
void FileToImage() {
char* pFileBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头
PIMAGE_NT_HEADERS pNTHeader = NULL;//NT头
PIMAGE_FILE_HEADER pPEHeader = NULL;//PE头
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;//可选PE头
PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表头
pFileBuffer = ReadFilea("D:\\ipmsg\\IPMsg_2.exe");
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)(pFileBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)(pFileBuffer + pDosHeader->e_lfanew + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(pFileBuffer + pDosHeader->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER);
char* fptr = (pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
char* pImageBuffer = NULL;
pImageBuffer = (char*)malloc(pOptionHeader->SizeOfImage);
if(!pImageBuffer)
printf("申请空间失败!\n");
//申请空间的大小为SizeOfImage
memset(pImageBuffer, 0, pOptionHeader->SizeOfImage);
//一定要初始化
memcpy(pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);
//头部信息可以先直接全部复制
//注意复制的大小为SizeOfHeaders
for(size_t i = 0; i<pPEHeader->NumberOfSections; i++) {//size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
memcpy((void*)(pImageBuffer + pSectionHeader->VirtualAddress), (void*)(pFileBuffer + pSectionHeader->PointerToRawData), pSectionHeader->SizeOfRawData);
//将FileBuffer中从第一个节点开始,把SizeOfRawData大的节点复制到pImageBuffer+VirtualAddress处
pSectionHeader++;
}
//复制节点(拉伸)
//拉伸后存盘
FILE* nFp;
nFp = fopen("D:\\ipmsg\\IPMsg_new2.exe", "wb");//复制到指定位置
fwrite(pImageBuffer, pOptionHeader->SizeOfImage, 1, nFp);
fclose(nFp);
//还原后存盘
char* NewFileBuffer = NULL;
NewFileBuffer = (char*)malloc(0x22A600);//开辟一个空间,但是由于生成的文件不知道多大,所以不好计算,我就直接计算了未拉伸的文件长度
if(!NewFileBuffer)
printf("申请空间失败!\n");
memset(NewFileBuffer, 0, 0x22A600);
//不要忘记初始化
memcpy(NewFileBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);
//头部还是保持不变
fptr = (pFileBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
//让其重新指向第一个节点
for(size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
memcpy((void*)(NewFileBuffer + pSectionHeader->PointerToRawData), (void*)(pImageBuffer + pSectionHeader->VirtualAddress), pSectionHeader->SizeOfRawData);
pSectionHeader++;
}
FILE* nFp1;
nFp1 = fopen("D:\\ipmsg\\IPMsg_2.exe", "wb");
fwrite(NewFileBuffer, 0x22A600, 1, nFp1);
fclose(nFp1);
free(NewFileBuffer); NewFileBuffer = NULL;
free(pImageBuffer); pImageBuffer = NULL;
free(pFileBuffer); pFileBuffer = NULL;
}
char* ReadFilea(const char *Filepath ){
FILE* fptr = NULL;
fptr = fopen(Filepath,"rb");
if(!fptr) {
printf("打开失败");
return NULL;
}
int filesize = 0;
filesize = GetFileszie(fptr);
if (filesize == 0) {
printf("获取文件大小失败");
return NULL;
}
char* FileBuffer = (char*)malloc(filesize);
if(!FileBuffer) {
printf("开辟空间失败");
return NULL;
}
size_t n=fread(FileBuffer, 1, filesize, fptr);//将文件内容读到内存中
if(!n) {
printf("读取数据失败");
free(FileBuffer);
FileBuffer = NULL;
fclose(fptr);
return NULL;
}
fclose(fptr);
return FileBuffer;
}
int GetFileszie(FILE* fptr) {
int num = 0;
fseek(fptr, 0, SEEK_END);
num = ftell(fptr);
fseek(fptr, 0, SEEK_SET);
return num;
}
int main() {
//PrintNTHeaders();
FileToImage();
}
要注意执行完后生成的.exe程序还没法执行。
RVA和FOA互相转换
RVA:文件被装载到内存后相对基址的偏移地址。
FOA:文件偏移地址,即文件在硬盘上相对文件开头的偏移地址。
DWORD RvaToFileOffset(PVOID pBuffer, DWORD dwRva) {
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!pBuffer) {
printf("(RvaToFileOffset)Can't open file!\n");
return 0;
}
printf("ImageOffset: %#x\n", dwRva);
pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)(pBuffer + (pDosHeader->e_lfanew));
pPEHeader = (PIMAGE_FILE_HEADER)(pBuffer + (pDosHeader->e_lfanew) + 4);
pOptionHeader = PIMAGE_OPTIONAL_HEADER32(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(pBuffer + pPEHeader->SizeOfOptionalHeader);
char* fptr = (char *)(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
if(dwRva <= pOptionHeader->SizeOfHeaders) //先判断是否在头部
return (DWORD)dwRva;
else {
for(size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
//判断 : 文件对齐+文件偏移>file_offset>文件偏移 (即是在文件的哪个节中)
pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
if ((dwRva >= pSectionHeader->VirtualAddress) && (dwRva < pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize))
return dwRva - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
else
fptr = fptr + IMAGE_SIZEOF_SECTION_HEADER;
}
}
}
DWORD FoaToImageOffset(PVOID pBuffer, DWORD dwFoa) {
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!pBuffer) {
printf("(FoaToImageOffset)Can't open file!\n");
return 0;
}
printf("FileOffset: %#x\n", dwFoa);
pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)(pBuffer + (pDosHeader->e_lfanew));
pPEHeader = (PIMAGE_FILE_HEADER)(pBuffer + (pDosHeader->e_lfanew) + 4);
pOptionHeader = PIMAGE_OPTIONAL_HEADER32(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(pBuffer + pPEHeader->SizeOfOptionalHeader);
char* fptr = (char*)(pBuffer + (pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
if (dwFoa <= pOptionHeader->SizeOfHeaders)
return (DWORD)dwFoa;
else {
for (size_t i = 0; i < pPEHeader->NumberOfSections; i++) {
//判断 : 文件对齐+文件偏移>file_offset>文件偏移 (即是在文件的哪个节中)
pSectionHeader = PIMAGE_SECTION_HEADER(fptr);
if ((dwFoa >= pSectionHeader->PointerToRawData) && (dwFoa < pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData))
return dwFoa - pSectionHeader->PointerToRawData + pSectionHeader->VirtualAddress;
else
fptr = fptr + IMAGE_SIZEOF_SECTION_HEADER;
}
}
}
void operate() {
LPVOID pFileBuffer = NULL;
size_t pRVA = 0x12345;
size_t pFOA = 0x23456;
pFileBuffer = ReadFilea("C:\\Windows\\System32\\notepad.exe");
DWORD ret_FOA1 = RvaToFileOffset(pFileBuffer, pRVA);
printf("内存偏移%#x 转换为文件中的偏移: %#x\n", pRVA, ret_FOA1);
DWORD ret_RVA1 = FoaToImageOffset(pFileBuffer, pFOA);
printf("文件偏移%#x 转换为内存中的偏移: %#x\n", pFOA, ret_RVA1);
free(pFileBuffer);
}
int main() {
PrintNTHeaders();
operate();
}
在之前的输出PE头信息中添加代码即可。
滴水逆向——RVA与FOA相互转换_rva转foa_「已注销」的博客-CSDN博客
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com