使用FindResource和内存缓冲区

Using FindResource with a memory buffer

本文关键字:缓冲区 内存 FindResource 使用      更新时间:2023-10-16

我有一个内存缓冲区,其中包含一个有效的exe文件图像,我想从中提取一些资源。
为此,我使用FindResource函数,但该函数期望一个HMODULE,并在使用exe提供内存缓冲区时崩溃。

是否有一种方法可以使它与内存缓冲区一起工作,而不是将exe写入临时文件,使用LoadLibrary加载它,然后做所需的工作?

我有一个内存缓冲区,其中包含一个有效的文件图像

是哪种形式?我猜比原始版本(如磁盘)要好。但是你需要'mapped as image'内存来使用FindResource。不是硬映射你的原始图像的自我(如果你只想访问资源,但不执行它从内存)的代码示例:

PVOID MapImage(PIMAGE_DOS_HEADER pvRawData, ULONG cbRawData)
{
    if (cbRawData < sizeof(IMAGE_DOS_HEADER))
    {
        return 0;
    }
    if (pvRawData->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return 0;
    }
    ULONG e_lfanew = pvRawData->e_lfanew, s = e_lfanew + sizeof(IMAGE_NT_HEADERS);
    if (e_lfanew >= s || s > cbRawData)
    {
        return 0;
    }
    PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)RtlOffsetToPointer(pvRawData, e_lfanew);
    if (pinth->Signature != IMAGE_NT_SIGNATURE)
    {
        return 0;
    }
    ULONG SizeOfImage = pinth->OptionalHeader.SizeOfImage, SizeOfHeaders = pinth->OptionalHeader.SizeOfHeaders;
    s = e_lfanew + SizeOfHeaders;
    if (SizeOfHeaders > SizeOfImage || SizeOfHeaders >= s || s > cbRawData)
    {
        return 0;
    }
    s = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pinth->FileHeader.SizeOfOptionalHeader;
    if (s > SizeOfHeaders)
    {
        return 0;
    }
    ULONG NumberOfSections = pinth->FileHeader.NumberOfSections;
    PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)RtlOffsetToPointer(pinth, s);
    ULONG Size;
    if (NumberOfSections)
    {
        if (e_lfanew + s + NumberOfSections * sizeof(IMAGE_SECTION_HEADER) > SizeOfHeaders)
        {
            return 0;
        }
        do 
        {
            if (Size = min(pish->Misc.VirtualSize, pish->SizeOfRawData))
            {
                union {
                    ULONG VirtualAddress, PointerToRawData;
                };
                VirtualAddress = pish->VirtualAddress, s = VirtualAddress + Size;
                if (VirtualAddress > s || s > SizeOfImage)
                {
                    return 0;
                }
                PointerToRawData = pish->PointerToRawData, s = PointerToRawData + Size;
                if (PointerToRawData > s || s > cbRawData)
                {
                    return 0;
                }
            }
        } while (pish++, --NumberOfSections);
    }
    PVOID ImageBase = VirtualAlloc(0, SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
    if (!ImageBase)
    {
        return 0;
    }
    memcpy(ImageBase, pvRawData, SizeOfHeaders);
    if (NumberOfSections = pinth->FileHeader.NumberOfSections)
    {
        do 
        {
            --pish;
            if (Size = min(pish->Misc.VirtualSize, pish->SizeOfRawData))
            {
                memcpy(RtlOffsetToPointer(ImageBase, pish->VirtualAddress),
                    RtlOffsetToPointer(pvRawData, pish->PointerToRawData), Size);
            }
        } while (--NumberOfSections);
    }
    return ImageBase;
}
void Test(PVOID pvRawData, ULONG cbRawData, PCWSTR lpType, PCWSTR lpName)
{
    if (HMODULE ImageBase = (HMODULE)MapImage((PIMAGE_DOS_HEADER)pvRawData, cbRawData))
    {
        if (HRSRC hResInfo = FindResource(ImageBase, lpName, lpType))
        {
            if (HGLOBAL hg = LoadResource(ImageBase, hResInfo))
            {
                __nop();
            }
        }
        VirtualFree(ImageBase, 0, MEM_RELEASE);
    }
}

MapImage包含有效数据大小的检查。然而,如果你确定(pvRawData, cbRawData)是100%正确的-你可以跳过这个检查和简化代码

//i编辑Test函数基于@IInspectable注释-删除__try/__except -这里不需要

您的选择:

  1. 保存到临时文件并加载LoadLibraryEx
  2. 解析PE文件并自己定位资源。
  3. 复制必要的操作,以各种内存模块库之一的方式从内存中加载模块。