【问题标题】:C# Extract Resource from Native PEC# 从原生 PE 中提取资源
【发布时间】:2017-08-10 22:48:53
【问题描述】:

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

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

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

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

【问题讨论】:

  • string exeContents = File.ReadAllText(exeFilePath, Encoding.GetEncoding(28591)); - 这就是你获取字节的方式,这就是你所需要的吗?还是需要帮助将字节显示为十六进制?还是像 ResourceHacker 那样组织字节?如果您想要所有内容,您必须向我们展示您的代码、到目前为止的内容以及遇到的问题。
  • @JeremyThompson 在上面的示例中,我需要资源本身的字节(2E373235)。我将字节转换为字符串等没有问题,但我需要一种解析 PE 文件并提取资源本身的方法。我目前正在尝试从 kernel32.dll 编组 FindResource 和其他函数,一旦我认为我取得了一些进展,我将添加一个 sn-p。
  • 你应该把它作为一个答案,人们会阅读所有这些并到最后找出它的解决方案。
  • 是的,当我很快得到某个答案时,正计划将其充实起来作为答案。 ;)

标签: c# resources portable-executable


【解决方案1】:

我最终编组代码并像处理 C++ 一样处理它。

关于FindResource() 需要注意的重要一点是,如果您将字符串而不是整数传递给它,它期望lpName 在前面加上#MSDN Page

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

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

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");

}

【讨论】:

  • 我会将其更改为 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);(可以从这里获取标志:pinvoke.net/default.aspx/Enums/LoadLibraryFlags.html?diff=y
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-17
  • 2018-01-25
相关资源
最近更新 更多