(开始这段别人总结的比较好,我就拿来用了)
1.RVA2FOA
即我们现在知道内存状态下的偏移,需要找到文件状态下的偏移。
步骤如下图:
step1:内存中的地址减去内存基址得到偏移,即RVA。
step2:循环遍历节表中各个节的信息,判断在哪个节中。(需要满足:内存偏移+节数据没对齐的大小>image_panyi>内存偏移)
step3:找出在哪个节后,减去该节在内存中的偏移(VirturalAddress)得到在该节中的相对偏移。
step4:上一步得到的该节的相对偏移+该节在文件中的偏移(PointToRawData),即得到FOA
2.FOA2RVA
现在我们已经知道如何从内存中的偏移转化为文件中的偏移。现在是它的逆过程
step1:文件中的地址减去文件基址,得到在文件中的偏移,即FOA。
step2:循环遍历节表中各个节的信息,判断在哪个节中。(文件对齐+文件偏移>file_panyi>文件偏移)
step3:找出在哪个节后,减去该节在文件中的偏移(VirturalAddress)得到在该节中的相对偏移。
step4:上一步得到的该节的相对偏移+该节在内存中的偏移(VirtualAddress),即得到RVA。
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define size_shellcode 0x12
#define messagebox_add 0x76EE2030
DWORD ToLeaderPE(char* file_path, PVOID* pFileBuffer);
VOID ReadPEFile(IN LPVOID pFileBuffer);
DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer);
DWORD CopyImageBufferToNewBuffer(PVOID pImageBuffer, PVOID* pNewBuffer);
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile);
DWORD TestAddCodeInDataSec(PVOID pImageBuffer, PVOID* pNewFileBuffer, DWORD FileSize);
DWORD RvaToFileOffset(IN LPVOID pImageBuffer, IN LPVOID pFileBuffer, IN DWORD dwRva);
DWORD FoaToImageOffset(IN LPVOID pFileBuffer, IN LPVOID pImageBuffer, IN DWORD dwFoa);
BYTE shellcode[] = {
0x6A,00,0x6A,00,0x6A,00,0x6A,00,
0XE8,00,00,00,00,
0XE9,00,00,00,00
};
char file_path[] = "D:\\IPMSG2007\\IPMSG2007.exe";
char write_file_path[] = "D:\\Lib\\cp_XX.exe";
DWORD ToLeaderPE(char* file_path, PVOID* pFileBuffer)
{
FILE *pFile = NULL;
DWORD fileSize = 0;
LPVOID pFileBufferTemp = NULL;
pFile = fopen(file_path, "rb");
if (!pFile)
{
printf("can't open file1\n");
return 0;
}
fseek(pFile, 0, SEEK_END);
fileSize = ftell(pFile);
printf("FileBuffer: %x\n", fileSize);
fseek(pFile, 0, SEEK_SET);
pFileBufferTemp = malloc(fileSize);
if (!pFileBufferTemp)
{
printf("apply memory failed\n");
fclose(pFile);
return 0;
}
size_t n = fread(pFileBufferTemp, fileSize, 1, pFile);
if (!n)
{
printf("read data filed\n");
free(pFileBufferTemp);
fclose(pFile);
return 0;
}
*pFileBuffer = pFileBufferTemp;
pFileBufferTemp = NULL;
fclose(pFile);
return fileSize;
}
VOID ReadPEFile(IN LPVOID pFileBuffer)
{
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 (!pFileBuffer)
{
printf("文件读取失败\n");
return;
}
//判断是否是有效的MZ标志
if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不是有效的MZ标志\n");
free(pFileBuffer);
return;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//打印DOC头
printf("\n********************DOS头********************\n");
printf("MZ标志:%x\n", pDosHeader->e_magic);
printf("PE偏移:%x\n", pDosHeader->e_lfanew);
//判断是否是有效的PE标志
if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
free(pFileBuffer);
return;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//打印NT头
printf("********************NT头********************\n");
printf("NT:%x\n", pNTHeader->Signature);
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
//int NumberOfSections = pPEHeader->NumberOfSections;
//int SizeOfOptionalHeader = pPEHeader->SizeOfOptionalHeader;
printf("********************PE头********************\n");
printf("PE:%x\n", pPEHeader->Machine);
printf("节的数量:%x\n", pPEHeader->NumberOfSections);
printf("SizeOfOptionalHeader:%x\n", pPEHeader->SizeOfOptionalHeader);
//可选PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
printf("********************OPTIOIN_PE头********************\n");
printf("OPTION_PE:%x\n", pOptionHeader->Magic);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
for (int n = 0; n < pPEHeader->NumberOfSections; n++)
{
printf("********************SECTION %d********************\n", n + 1);
char name[9] = { 0 };
memcpy(name, pSectionHeader->Name, 8);
printf("SECTION NAME: %s\n", name);
printf("VirtualAddress: %x\n", pSectionHeader->VirtualAddress);
printf("SizeOfRawData: %x\n", pSectionHeader->SizeOfRawData);
printf("PointerToRawData: %x\n", pSectionHeader->PointerToRawData);
printf("Characteristics: %x\n", pSectionHeader->Characteristics);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER);
}
}
DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
{
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;
LPVOID pImageTemp = NULL;
if (!pFileBuffer)
{
printf("(CopyFileBufferToImageBuffer)FileBuffer open failed\n");
return 0;
}
if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("(CopyFileBufferToImageBuffer)不含MZ标志,不是exe文件!\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(CopyFileBufferToImageBuffer)不是有效的PE标志!\n");
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
pImageTemp = malloc(pOptionHeader->SizeOfImage);
if (!pImageTemp)
{
printf("(CopyFileBufferToImageBuffer)allocate dynamic memory failed!\n");
free(pImageTemp);
return 0;
}
memset(pImageTemp, 0, pOptionHeader->SizeOfImage);
memcpy(pImageTemp, pDosHeader, pOptionHeader->SizeOfHeaders);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
for (int n = 0; n < pPEHeader->NumberOfSections; n++, pSectionHeaderTemp++)
{
memcpy((PVOID)((DWORD)pImageTemp + pSectionHeaderTemp->VirtualAddress), (PVOID)((DWORD)pFileBuffer + pSectionHeaderTemp->PointerToRawData), pSectionHeaderTemp->SizeOfRawData);
printf("VirtualAddress%d: %10x PointerToRawData%d: %10x\n", n, (DWORD)pImageTemp + pSectionHeader->VirtualAddress, n, (DWORD)pFileBuffer + pSectionHeader->PointerToRawData);
}
*pImageBuffer = pImageTemp;
pImageTemp = NULL;
return pOptionHeader->SizeOfImage;
}
DWORD CopyImageBufferToNewBuffer(PVOID pImageBuffer, PVOID* pNewBuffer)
{
// 初始化PE头部结构体
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;
// 初始化NEW_BUFFER指针(temparay)
LPVOID pTempNewbuffer = NULL;
// 判断pImageBuffer是否有效
if (!pImageBuffer)
{
printf("(2pnewbuffer阶段)读取到内存的pimagebuffer无效!\n");
return 0;
}
//判断是不是exe文件
if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("(2pnewbuffer阶段)不含MZ标志,不是exe文件!\n");
return 0;
}
// 强制结构体类型转换
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(2pnewbuffer阶段)不是有效的PE标志!\n");
return 0;
}
// 强制结构体类型转换
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//获取new_buffer的大小
int new_buffer_size = pOptionHeader->SizeOfHeaders;
for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++)
{
new_buffer_size += pSectionHeader[i].SizeOfRawData; // pSectionHeader[i]另一种加法
}
// 分配内存(newbuffer)
pTempNewbuffer = malloc(new_buffer_size);
if (!pTempNewbuffer)
{
printf("(2pnewbuffer阶段)分配Newbuffer失败!\n");
return 0;
}
memset(pTempNewbuffer, 0, new_buffer_size);
// 拷贝头部
memcpy(pTempNewbuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
// 循环拷贝节区
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
for (DWORD j = 0; j < pPEHeader->NumberOfSections; j++, pTempSectionHeader++)
{ //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
memcpy((PDWORD)((DWORD)pTempNewbuffer + pTempSectionHeader->PointerToRawData), (PDWORD)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
}
//返回数据
*pNewBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
pTempNewbuffer = NULL;
return new_buffer_size; // 返回计算得到的分配内存的大小
}
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile)
{
FILE *fp;
fp = fopen(lpszFile, "wb");
if (fp != NULL)
{
fwrite(pMemBuffer, size, 1, fp);
}
fclose(fp);
return 1;
}
DWORD RvaToFileOffset(IN LPVOID pImageBuffer, IN LPVOID pFileBuffer, IN DWORD dwRva)
{
// 初始化PE头部结构体
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;
DWORD ImageOffset = dwRva;
//DWORD RelSectionOffset = 0;
// 判断pImageBuffer是否有效
if (!pImageBuffer)
{
printf("(RVA转换成FOA阶段)读取到内存的ImageBuffer无效!\n");
return 0;
}
//判断是不是exe文件
if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("(RVA转换成FOA阶段)不含MZ标志,不是exe文件!\n");
return 0;
}
// 强制结构体类型转换
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(RVA转换成FOA阶段)不是有效的PE标志!\n");
return 0;
}
printf("ImageOffset: %x\n", ImageOffset);
// 强制结构体类型转换
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionTemp = pSectionHeader;
if (ImageOffset <= pOptionHeader->SizeOfHeaders)
return (DWORD)pFileBuffer + ImageOffset;
else
{
for (int n = 0; n < pPEHeader->NumberOfSections; n++, pSectionTemp++)
{
if ((ImageOffset >= pSectionTemp[n].VirtualAddress) && (ImageOffset <= pSectionTemp[n].VirtualAddress + pSectionTemp[n].Misc.VirtualSize))
{
return ImageOffset - pSectionTemp[n].VirtualAddress + pSectionTemp[n].PointerToRawData;
}
}
}
printf("地址转换失败!\n");
return 0;
}
DWORD FoaToImageOffset(IN LPVOID pFileBuffer, IN LPVOID pImageBuffer, IN DWORD dwFoa)
{
// 初始化PE头部结构体
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;
DWORD FileOffset = dwFoa;
//DWORD RelSectionOffset = 0;
// 判断pImageBuffer是否有效
if (!pFileBuffer)
{
printf("(FOA转换RVA成阶段)读取到内存的ImageBuffer无效!\n");
return 0;
}
//判断是不是exe文件
if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("(FOA转换RVA成阶段)不含MZ标志,不是exe文件!\n");
return 0;
}
// 强制结构体类型转换
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(FOA转换RVA成阶段)不是有效的PE标志!\n");
return 0;
}
printf("FileOffset: %x\n", FileOffset);
// 强制结构体类型转换
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionTemp = pSectionHeader;
if (FileOffset <= pOptionHeader->SizeOfHeaders)
return (DWORD)pFileBuffer + FileOffset;
else
{
for (int n = 0; n < pPEHeader->NumberOfSections; n++, pSectionTemp++)
{ //判断 : 文件对齐+文件偏移>file_panyi>文件偏移 (即是在文件的哪个节中)
if ((FileOffset >= pSectionTemp->PointerToRawData) && (FileOffset < pSectionTemp->PointerToRawData + pSectionTemp->SizeOfRawData))
{
return FileOffset - pSectionTemp->PointerToRawData + pSectionTemp->VirtualAddress;
}
}
}
printf("地址转换失败!\n");
return 0;
}
DWORD TestAddCodeInDataSec(PVOID pImageBuffer, PVOID* pNewFileBuffer, DWORD FileSize)
{
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;
// 判断pImageBuffer是否有效
if (!pImageBuffer)
{
printf("(TestAddCodeInDataSec)ImageBuffer open failed\n");
return 0;
}
//判断是不是exe文件
if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("(TestAddCodeInDataSec)不含MZ标志,不是exe文件!\n");
return 0;
}
// 强制结构体类型转换
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(TestAddCodeInDataSec)不是有效的PE标志!\n");
return 0;
}
// 强制结构体类型转换
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//判断代码区空间够不够放shellcode
if (size_shellcode > (pSectionHeader->SizeOfRawData - pSectionHeader->Misc.VirtualSize))
{
printf("Data section sapce not enough to store shellcode\n");
free(pImageBuffer);
return 0;
}
printf("pSectionHeader->PointerToRawData:%x pSectionHeader->Misc.VirtualSize:%x\n", pSectionHeader->PointerToRawData, pSectionHeader->Misc.VirtualSize);
printf("pImageBuffer:%x\n", pImageBuffer);
//填充代码
PBYTE CodeAddLoc = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
printf("pSectionHeader->VirtualAddress:%X\n", pSectionHeader->VirtualAddress);
printf("CodeAddLoc:%x\n", CodeAddLoc);
memcpy(CodeAddLoc, shellcode, size_shellcode);
//修改E8跳转地址
DWORD callAddr = (messagebox_add - (pOptionHeader->ImageBase + ((DWORD)(CodeAddLoc + 0xD) - (DWORD)pImageBuffer)));
*(PDWORD)(CodeAddLoc + 0x09) = callAddr;
//修改E9跳转地址
DWORD jmpAddr = (pOptionHeader->AddressOfEntryPoint - ((DWORD)(CodeAddLoc + size_shellcode) - (DWORD)pImageBuffer));
*(PDWORD)(CodeAddLoc + 0x0E) = jmpAddr;
pOptionHeader->AddressOfEntryPoint = (DWORD)CodeAddLoc - (DWORD)pImageBuffer;
size_t size = CopyImageBufferToNewBuffer(pImageBuffer, pNewFileBuffer);
if (size = 0 || !pNewFileBuffer)
{
printf("imagebuffer->newfilebuffer失败!\n");
free(pImageBuffer);
free(pNewFileBuffer);
}
// 存盘
size_t ret4 = MemeryTOFile(*pNewFileBuffer, FileSize, write_file_path);
if (!ret4)
{
printf("store memory failed!\n");
return 0;
}
return 1;
}
int main()
{
LPVOID pFileBuffer = NULL;
LPVOID pNewFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
size_t ret1 = ToLeaderPE(file_path, &pFileBuffer); // &pFileBuffer(void**类型) 传递地址对其值可以进行修改
printf("exe->filebuffer 返回值为计算所得文件大小:%#x\n", ret1);
//ReadPEFile(pFileBuffer);
size_t ret2 = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
printf("filebuffer -> imagebuffer返回值为计算所得文件大小:%#x\n", ret2);
size_t ret3 = CopyImageBufferToNewBuffer(pImageBuffer, &pNewFileBuffer);
MemeryTOFile(pNewFileBuffer, ret3, write_file_path);
int pRVA = 0x00021178;
int pFOA = 0x00020450;
int ret_FOA1 = RvaToFileOffset(pImageBuffer, pFileBuffer, pRVA);
printf("内存偏移%#x 转换为文件中的偏移:%#x\n", pRVA, ret_FOA1);
int ret_RVA1 = FoaToImageOffset(pFileBuffer, pImageBuffer, pFOA);
printf("文件偏移%#x 转换为内存中的偏移:%#x\n", pFOA, ret_RVA1);
//size_t ret3 = TestAddCodeInDataSec(pImageBuffer, &pNewFileBuffer, ret1);
//printf("%d", ret3);
free(pFileBuffer);
free(pNewFileBuffer);
free(pImageBuffer);
return 0;
}
结果展示: