C# 从本机 PE 中提取资源

Dem*_*335 4 c# resources portable-executable

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

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

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

ResourceHacker显示PE资源

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

Dem*_*335 6

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

需要注意的一件重要事情FindResource()是,如果您向其传递字符串而不是整数,则它希望lpName在前面加上。MSDN 页面#

如果字符串的第一个字符是井号 (#),则其余字符表示十进制数,用于指定资源名称或类型的整数标识符。例如,字符串“#258”代表整数标识符258。

首先,我将 kernel32.dll 中的所有重要函数编组到一个单独的类中,然后按名称和类型调用资源。(我从一个我无法再次找到的博客中获取了此类的大部分内容,如果我再次找到它,将链接到它。)请注意,为了在 C# 中简单起见,我已将 的参数编组为字符串而FindResource不是整数(无需使用 进行修改MAKEINTRESOURCE) 。

资源管理器.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;
    }
}
Run Code Online (Sandbox Code Playgroud)

主程序.cs

public Main(){

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

}
Run Code Online (Sandbox Code Playgroud)

  • 我会将其更改为“LoadLibraryEx(lpFileName, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);”以支持 32\64 位文件。签名:`[DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);`(可以从这里获取标志:http://pinvoke.net/ default.aspx/Enums/LoadLibraryFlags.html?diff=y) (3认同)