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");
}
我似乎无法找到我在这里尝试做的事情的正确答案。
在我的 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");
}