C# 从原生 PE 中提取资源

C# Extract Resource from Native PE

我似乎无法找到我在这里尝试做的事情的正确答案。

在我的 C# 代码中,我想从 另一个 可执行文件中提取资源,该可执行文件将由用户提示传递。另一个可执行文件将是本机 PE 文件。

例如,我需要从这个 PE 文件 (sample.exe) 中提取 KDATA6 资源。这就是它在 ResourceHacker 中的样子。

我似乎只能找到有关如何从 my 程序中提取或从另一个项目中解析的信息。

我最终整理了代码并像处理 C++ 一样处理它。

关于 FindResource() 需要注意的一件重要事情是,如果您将字符串而不是整数传递给它,它希望 lpName# 为前缀。 MSDN Page

If the first character of the string is a pound sign (#), the remaining characters represent a decimal number that specifies the integer identifier of the resource's name or type. For example, the string "#258" represents the integer identifier 258.

首先,我将 kernel32.dll 中的所有重要函数整理到单独的 class 中,然后按名称和类型调用资源。 (我从一个我找不到的博客中抓取了大部分 class,如果我再次找到它,将会 link。)请注意,我已将 FindResource 的参数编组为 strings 而不是整数,为了 C# 中的简单性(不需要使用 MAKEINTRESOURCE 进行 hack)。

ResourceManager.cs

class ResourceManager
{    
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
    //  public static extern IntPtr FindResource(IntPtr hModule, int lpName, uint lpType);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LockResource(IntPtr hResData);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool EnumResourceNames(IntPtr hModule, string lpType, IntPtr lpEnumFunc, IntPtr lParam);

    public static byte[] GetResourceFromExecutable(string lpFileName, string lpName, string lpType)
    {
        IntPtr hModule = LoadLibrary(lpFileName);
        if (hModule != IntPtr.Zero)
        {
            IntPtr hResource = FindResource(hModule, lpName, lpType);
            if (hResource != IntPtr.Zero)
            {
                uint resSize = SizeofResource(hModule, hResource);
                IntPtr resData = LoadResource(hModule, hResource);
                if (resData != IntPtr.Zero)
                {
                    byte[] uiBytes = new byte[resSize];
                    IntPtr ipMemorySource = LockResource(resData);
                    Marshal.Copy(ipMemorySource, uiBytes, 0, (int)resSize);
                    return uiBytes;
                }
            }
        }
        return null;
    }
}

Main.cs

public Main(){

    string path = @"C:\sample.exe";
    // Get the raw bytes of the resource
    byte[] resource = ResourceManager.GetResourceFromExecutable(path, "#106", "KDATA");

}