上一次写博客都是4年前了,现在重新学习又是感慨万千。
以前要是没去浪费时间干其他事情,可能在这个领域也能有所建树了吧,虽然每次安慰自己多了很多人生阅历,但谁不想有个happy ending呢?
/*FileToFileBuffer,将文件读到内存里,只需要计算出需要分配多少内存接下来按照普通函数传参就行了,
可能需要注意fopen的最后一个参数,需要选择二进制,也就是b,不是t,默认给的是t*/
PVOID FileToFileBuffer(BYTE* fileName) {
FILE* pFile;
DWORD fSize = 0;
PVOID fileBuffer;
pFile = fopen(fileName, "rb");
if (!pFile) {
printf("open failed 1 \n");
return FALSE;
}
if (fseek(pFile, 0, SEEK_END)) {
printf("fseek failed\n");
return FALSE;
}
fSize = ftell(pFile);
fileBuffer = (PVOID)malloc(fSize);
if (!fileBuffer) {
printf("malloc failed\n");
return FALSE;
}
memset(fileBuffer, 0, fSize);
fseek(pFile, 0, SEEK_SET);
fread(fileBuffer, 1, fSize, pFile);
fclose(pFile);
pFile = 0;
return fileBuffer;
}```
/*将内存里的文件拉伸到一块新的内存里,先根据optional头里的数据申请足够大小的内存,再遍历节表就能
得出,记得memset整块内存为0,这样写到硬盘才不会是一堆cc*/
```c
PVOID FileBufferToImageBuffer(PVOID pFileBuffer) {
PIMAGE_DOS_HEADER pDosHeader = pFileBuffer;
PIMAGE_NT_HEADERS pNTHeader = (DWORD)pDosHeader + pDosHeader->e_lfanew;
PIMAGE_FILE_HEADER pFileHeader = &pNTHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = (DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER);
PIMAGE_SECTION_HEADER pSecHeader = (DWORD)pOptHeader + pFileHeader->SizeOfOptionalHeader;
PVOID pImageBuffer = (PVOID)malloc(pOptHeader->SizeOfImage);
if (!pImageBuffer) {
printf("malloc failed\n");
return FALSE;
}
memset(pImageBuffer, 0, pOptHeader->SizeOfImage);
memcpy(pImageBuffer, pFileBuffer, pOptHeader->SizeOfHeaders);
for (size_t i = 0; i < pFileHeader->NumberOfSections; i++) {
memcpy((DWORD)pImageBuffer + pSecHeader->VirtualAddress, (DWORD)pFileBuffer + pSecHeader->PointerToRawData,
pSecHeader->SizeOfRawData);
pSecHeader++;
}
free(pFileBuffer);
return pImageBuffer;
}
```c
/*将内存里拉伸过的文件重新写回硬盘里 根据视频里的内容无法完美实现 会导致PE结构完整但是后面的数据没有
写入硬盘,当然本身读到内存里的东西就不足以构造出整个文件可能以前知道为啥,现在忘了*/
/*如果上面的函数能完成那么这个基本上也能,需要注意的点是如何计算大小要写入的大小,我的建议是最后一个
节的偏移+大小,也能遍历一遍节表,加上所有的sizeOfRawData*/
PVOID ImageBufferToFileBuffer(BYTE* fileName, PVOID pImageBuffer) {
//寻找头节点
PIMAGE_DOS_HEADER pDosHeader = pImageBuffer;
PIMAGE_NT_HEADERS pNTHeader = (DWORD)pDosHeader + pDosHeader->e_lfanew;
PIMAGE_FILE_HEADER pFileHeader = &pNTHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = (DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER);
PIMAGE_SECTION_HEADER pSecHeader = (DWORD)pOptHeader + pFileHeader->SizeOfOptionalHeader;
PIMAGE_SECTION_HEADER pLastSecHeader = pSecHeader + pFileHeader->NumberOfSections - 1;
//计算文件大小
DWORD sizeOfRawData = pLastSecHeader->PointerToRawData + pLastSecHeader->SizeOfRawData;
PVOID pFileBuffer = (PVOID)malloc(sizeOfRawData);
if (!pFileBuffer) {
printf("malloc failed\n");
return FALSE;
}
memset(pFileBuffer, 0, sizeOfRawData);
//储存数据到内存
memcpy(pFileBuffer, pImageBuffer, pOptHeader->SizeOfHeaders);
for (size_t i = 0; i < pFileHeader->NumberOfSections; i++) {
printf("RVA:%p FOA:%p\n", pSecHeader, RVAToFOA(pSecHeader, pImageBuffer));
memcpy((DWORD)pFileBuffer + pSecHeader->PointerToRawData, (DWORD)pImageBuffer + pSecHeader->VirtualAddress,
pSecHeader->SizeOfRawData);
pSecHeader++;
}
free(pImageBuffer);
//储存数据到硬盘
FILE* pFile;
pFile = fopen(fileName, "wb");
if (!pFile) {
printf("fopen failed\n");
return FALSE;
}
fwrite(pFileBuffer, sizeOfRawData, 1, pFile);
fclose(pFile);
return pFileBuffer;
}
/*转换内存里的虚拟地址对应到文件里的地址
我的思路是1.获得Virtual address,就是在内存种的偏移,方便计算,这个需要传入pImageBuffer,也就是
开辟的imageBuffer的指针,RVA - pImageBuffer 就获得了va
2.判断在不在headers里注意只需要判断是否小于sizeOfHeaders
3.遍历节表找到在VA在哪个节表里,然后计算
*/
PVOID RVAToFOA(PVOID RVA,PVOID pImageBuffer) {
//寻找头节点
PIMAGE_DOS_HEADER pDosHeader = pImageBuffer;
PIMAGE_NT_HEADERS pNTHeader = (DWORD)pDosHeader + pDosHeader->e_lfanew;
PIMAGE_FILE_HEADER pFileHeader = &pNTHeader->FileHeader;
PIMAGE_OPTIONAL_HEADER pOptHeader = (DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER);
PIMAGE_SECTION_HEADER pSecHeader = (DWORD)pOptHeader + pFileHeader->SizeOfOptionalHeader;
//计算VA
PVOID virtualAddr = (DWORD)RVA - (DWORD)pImageBuffer;
//定位是否在Headers里
if (virtualAddr < pOptHeader->SizeOfHeaders) {
return virtualAddr;
}
//定位在哪一个节里
for (size_t i = 0; i < pFileHeader->NumberOfSections - 1; i++) {
PIMAGE_SECTION_HEADER pNextSecHeader = pSecHeader + 1;
if (virtualAddr >= pSecHeader->VirtualAddress && virtualAddr < pNextSecHeader->VirtualAddress) {
return (DWORD)virtualAddr - pSecHeader->VirtualAddress + pSecHeader->PointerToRawData;
}
pSecHeader++;
}
return FALSE;
}
本文介绍了如何使用C语言实现将文件读取到内存(FileToFileBuffer),内存中文件结构的处理(如FileBufferToImageBuffer和ImageBufferToFileBuffer),以及虚拟地址到文件物理地址的转换(RVAToFOA)过程。
1516

被折叠的 条评论
为什么被折叠?



