signed

QiShunwang

“诚信为本、客户至上”

PE文件从硬盘到内存再到硬盘

2021/3/21 11:14:32   来源:
#pragma warning(suppress : 4996)
#include "ImageBuffer.h"
char inputPath[] = "C:\\ipmsg\\Feige\\Feige.exe";
char outputPath[] = "C:\\ipmsg\\Feige\\Feige2.exe";
LPSTR FILEPATH = inputPath;
LPSTR OUT_FILEPATH = outputPath;

int main(void)
{
    LPVOID pFileBuffer;
    LPVOID pImageBuffer;
    LPVOID pNewBuffer;
    int size = 0;
    ReadPEFile(FILEPATH,&pFileBuffer);
    CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
    MemeryTOFile(pNewBuffer, size, OUT_FILEPATH);
    free(pFileBuffer);
    free(pImageBuffer);
    free(pNewBuffer);
    return 0;
}

//**************************************************************************
//ReadPEFile:将文件读取到缓冲区
//参数说明:
//lpszFile 文件路径 //pFileBuffer 缓冲区指针
//返回值说明:
//读取失败返回0  否则返回实际读取的大小
//************************************************************************** 
DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
{
    FILE* pFile = NULL;
    DWORD fileSize = 0;

   // LPVOID pFileBuf = NULL;
    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;
    char tableName[9] = { 0 };

    //打开文件
    pFile = fopen(lpszFile, "rb");
    if (!pFile)
    {
        printf("无法打开EXE文件\n");
        return NULL;
    }
    //读取文件大小
    fseek(pFile, 0, SEEK_END);
    fileSize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
    //分配缓冲区
    *pFileBuffer = (LPVOID)malloc(fileSize);
    if (!(*pFileBuffer) )
    {
        printf("空间分配失败!\n");
        fclose(pFile);
        return NULL;
    }
    memset(*pFileBuffer,0, fileSize);
    //讲文件数据读取到缓冲区
    size_t n = fread(*pFileBuffer, fileSize, 1, pFile);
    if (!n)
    {
        printf("读取数据失败!\n");
        free(*pFileBuffer);
        fclose(pFile);
        return NULL;
    }
    //关闭文件
    fclose(pFile);

    if (*((PWORD)(*pFileBuffer)) != IMAGE_DOS_SIGNATURE)
    {
        printf("不是有效地MZ标志\n");
        free(*pFileBuffer);
        return 0;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)(*pFileBuffer);
    //打印dos头
    //printf("--------------------------------------DOC------------------------------------------\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 0;
    }
    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);
    //printf("--------------------------------------PE------------------------------------------\n");
    //printf("PE类型10B→32位    20B→64位:%x\n", pPEHeader->Machine);
    //printf("文件存在的节的总数:%x\n", pPEHeader->NumberOfSections);
    //printf("可选PE头的大小,32位默认E0h  64位默认F0h:%x\n", pPEHeader->SizeOfOptionalHeader);
    //printf("PE属性:%x\n", pPEHeader->Characteristics);
    //可选PE头	
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    //printf("********************OPTIOIN_PE头********************\n");
    //printf("OPTION_PE 类型:10B→32位    20B→64位:%x\n", pOptionHeader->Magic);
    //printf("所有代码节的和:%x\n", pOptionHeader->SizeOfCode);
    //printf("已初始化数据大小的和:%x\n", pOptionHeader->SizeOfInitializedData);
    //printf("未初始化数据大小的和:%x\n", pOptionHeader->SizeOfUninitializedData);
    //printf("程序入口:%x\n", pOptionHeader->AddressOfEntryPoint);
    //printf("代码开始的基址:%x\n", pOptionHeader->BaseOfCode);
    //printf("数据开始的基址:%x\n", pOptionHeader->BaseOfData);
    //printf("内存镜像基址:%x\n", pOptionHeader->ImageBase);
    //printf("内存对齐:%x\n", pOptionHeader->SectionAlignment);
    //printf("文件对齐:%x\n", pOptionHeader->FileAlignment);
    //printf("内存中整个PE文件的映射的尺寸:%x\n", pOptionHeader->SizeOfImage);
    //printf("所有头+节表按照文件对齐后的大小:%x\n", pOptionHeader->SizeOfHeaders);
    //printf("初始化时保留的栈大小:%x\n", pOptionHeader->SizeOfStackReserve);
    //printf("初始化时栈实际提交的大小:%x\n", pOptionHeader->SizeOfStackCommit);
    //printf("初始化时保留的堆大小:%x\n", pOptionHeader->SizeOfHeapReserve);
    //printf("初始化时堆实际提交的大小:%x\n", pOptionHeader->SizeOfHeapCommit);
    //printf("目录项数目:%x\n", pOptionHeader->NumberOfRvaAndSizes);

    //printf("+++++++++++++++++++++++++++++++++++++++\n");
    //printf("pOptionHeader->SizeOfImage:%x\n", pOptionHeader->SizeOfImage);
    //printf("+++++++++++++++++++++++++++++++++++++++\n");

    pSectionHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + (pPEHeader->SizeOfOptionalHeader));
    for (int i = 0; i < (pPEHeader->NumberOfSections); i++)
    {
        char* c = (char*)pSectionHeader;
        for (int n = 0; n < 8; n++)
        {
            tableName[n] = *c;
            c++;
        }
        //printf("第%d个节的名字:%s\n", i, tableName);
        //printf("第%d个节的大小:%x\n", i, pSectionHeader->Misc.VirtualSize);
        //printf("第%d个节的内存偏移:%x\n", i, pSectionHeader->VirtualAddress);
        //printf("第%d个节在文件中对齐的大小:%x\n", i, pSectionHeader->SizeOfRawData);
        //printf("第%d个节的文件偏移:%x\n", i, pSectionHeader->PointerToRawData);
        //printf("第%d个节的属性:%x\n", i, pSectionHeader->Characteristics);
        pSectionHeader++;
    }
    printf("****************************************\n");
    //printf("%x\n", fileSize);
    return fileSize;
    //return (pOptionHeader->SizeOfImage);
}

//**************************************************************************
//CopyFileBufferToImageBuffer:将文件从FileBuffer复制到ImageBuffer
//参数说明:
//pFileBuffer  FileBuffer指针
//pImageBuffer ImageBuffer指针
//返回值说明: //读取失败返回0  否则返回复制的大小 
//************************************************************************** 
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer, OUT LPVOID* pImageBuffer)
{
    DWORD ImageSize = 0;
    char* dest = NULL;
    char* src = NULL;
    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;
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    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)((char*)pOptionHeader + (pPEHeader->SizeOfOptionalHeader));

    ImageSize = (pOptionHeader->SizeOfImage);
    //printf("+++++++++++++++++++++++++++++++++++++++\n");
    //printf("CopyFileBufferToImageBuffer:%x\n", ImageSize);
    //printf("pOptionHeader->SizeOfImage:%x\n", pOptionHeader->SizeOfImage);
    //printf("+++++++++++++++++++++++++++++++++++++++\n");
    //分配缓冲区
    *pImageBuffer = malloc(ImageSize);
    if (!(*pImageBuffer))
    {
        printf("空间分配失败!\n");
        return 0;
    }
    memset(*pImageBuffer, 0, ImageSize);
    //拷贝各个头
    dest = (char*)*pImageBuffer;
    src = (char*)pFileBuffer;
    memcpy(dest,src,(pOptionHeader->SizeOfHeaders));

    //拷贝各个节
    for (int i = 0; i < (pPEHeader->NumberOfSections); i++)
    {
        dest = NULL;
        src = NULL;
        src = (char*)((char*)pFileBuffer + pSectionHeader->PointerToRawData);
        dest = (char*)((char*)*pImageBuffer + pSectionHeader->VirtualAddress);
        memcpy(dest, src, (pSectionHeader->SizeOfRawData));
        pSectionHeader++;
    }
    printf("****************************************\n");
    printf("%x\n", ImageSize);
    return ImageSize;
}

//**************************************************************************
//CopyImageBufferToNewBuffer:将ImageBuffer中的数据复制到新的缓冲区
//参数说明:
//pImageBuffer ImageBuffer指针
//pNewBuffer NewBuffer指针
//返回值说明:
//读取失败返回0  否则返回复制的大小
//************************************************************************** 
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer, OUT LPVOID* pNewBuffer)
{
    DWORD NewSize = 0;
    char* dest = NULL;
    char* src = NULL;
    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;
    PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
    pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    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)((char*)pOptionHeader + (pPEHeader->SizeOfOptionalHeader));

    //计算NewBuffer要多少空间 = 最后一个节在文件中的偏移 + 在文件中对齐后的大小
    pLastSectionHeader = pSectionHeader + ((pPEHeader->NumberOfSections) - 1);
    NewSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
    //分配缓冲区
    *pNewBuffer = malloc(NewSize);
    if (!(*pNewBuffer))
    {
        printf("空间分配失败!\n");
        return 0;
    }
    memset(*pNewBuffer, 0, NewSize);
    //拷贝各个头
    dest = (char*)*pNewBuffer;
    src = (char*)pImageBuffer;
    memcpy(dest, src, (pOptionHeader->SizeOfHeaders));

    //拷贝各个节
    for (int i = 0; i < (pPEHeader->NumberOfSections); i++)
    {
        dest = NULL;
        src = NULL;
        src = (char*)((char*)pImageBuffer + pSectionHeader->VirtualAddress);
        dest = (char*)((char*)*pNewBuffer + pSectionHeader->PointerToRawData);
        memcpy(dest, src, (pSectionHeader->SizeOfRawData));
        //printf("第%d个节的大小:%x\n", i, pSectionHeader->Misc.VirtualSize);
        //printf("第%d个节的内存偏移:%x\n", i, pSectionHeader->VirtualAddress);
        //printf("第%d个节在文件中对齐的大小:%x\n", i, pSectionHeader->SizeOfRawData);
        //printf("第%d个节的文件偏移:%x\n", i, pSectionHeader->PointerToRawData);
        pSectionHeader++;
    }
    printf("****************************************\n");
    printf("%x\n", NewSize);
    return NewSize;
}

//**************************************************************************
//MemeryTOFile:将内存中的数据复制到文件
//参数说明:
//pMemBuffer 内存中数据的指针
//size 要复制的大小
//lpszFile 要存储的文件路径
//返回值说明:
//失败返回0  否则返回1
//************************************************************************** 
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile)
{
    FILE* p  = NULL;
    int i = 0;
    p = fopen(lpszFile,"wb+");
    if (!p)
    {
        printf("无法创建文件\n");
        return 0;
    }
    i = fwrite(pMemBuffer,size, 1,p);
    printf("****************************************\n");
    printf("%x\n", i);
    fclose(p);
    return i;
}