Demonslay335
Demonslay335

Reputation: 796

C# Extract Resource from Native PE

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.

ResourceHacker display of PE resources

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

Answers (1)

Demonslay335
Demonslay335

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

Related Questions