Reputation: 796
I seem to be failing to find the correct answer to what I am trying to do here.
In my C# code, I would like to extract resources from another executable that would be passed by user prompt. The other executable would be a native PE file.
As an example, I need to pull the KDATA\106
resource from this PE file (sample.exe
). This is what it looks like in ResourceHacker.
I seem to be only able to find info on how to extract from my program, or parsing from another project.
Upvotes: 4
Views: 2315
Reputation: 796
I ended up marshalling the code and handling this as if it was C++.
One important thing to note about FindResource()
is that it expects the lpName
to be prepended with #
if you pass it a string instead of an integer. 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.
First I marshal out all of the important functions from kernel32.dll in a separate class, then call the resource by name and type. (I grabbed most of this class from a blog that I cannot find again, will link if I locate it again.) Note that I have marshaled the parameters of FindResource
as strings and not integers, for simplicity in C# (no need for hacks with 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");
}
Upvotes: 6