Question

I am trying to understand how self-extracting PE files work. Can somebody explain why my code isn't working, or fix the main() part.

#include <iostream>
#include <Windows.h>

using namespace std;

void ExtractResource(const HINSTANCE hInstance, WORD resourceID, const char* outputFilename);

int main()
{
    HINSTANCE hInst = GetModuleHandle (0);
    ExtractResource(hInst, 101, "101.dll");
    ExtractResource(hInst, 102, "102.dll");
    ExtractResource(hInst, 103, "103.dll");
    ExtractResource(hInst, 104, "104.dll");
    cout << "Files are now extracted!";
    Sleep(INFINITE);
}


void ExtractResource(const HINSTANCE hInstance, WORD resourceID, const char* outputFilename){

        // First find and load the required resource          

        HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(resourceID), "BINARY");

        if(hResource==NULL)

                return;

        HGLOBAL hFileResource = LoadResource(hInstance, hResource);



        // Now open and map this to a disk file          

        LPVOID lpFile = LockResource(hFileResource);          

        DWORD dwSize = SizeofResource(hInstance, hResource);            



        // Open the file and filemap          

        HANDLE hFile = CreateFileA(outputFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW,

                FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY, NULL);          

        HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);            

        LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);            



        // Write the file

        CopyMemory(lpBaseAddress, lpFile, dwSize);            



        // Unmap the file and close the handles

        UnmapViewOfFile(lpBaseAddress);

        CloseHandle(hFilemap);

        CloseHandle(hFile);

}

I have 4 dll-files in resources, but I can't extract them using this. The resource ID´s should be correct, I checked it from resource header.

Is the problem in hInst or what else there could be wrong? I hope somebody could help me :) I have just a ~month ago started learning C & C++ so forgive me.

Was it helpful?

Solution

I do not see anything wrong with your code other than you not checking the return values of functions and printing appropriate messages when something goes wrong. Also note that you can replace the hInstance with nullptr and it still works.

Also note that if you are extracting to a location that requires extra permissions, you might have to run your program as administrator or add a manifest that forces it to ask for administrator privileges.

Personally, I use these in any of my resource applications:

    bool ExtractResource(std::uint16_t ResourceID, std::string OutputFileName, const char* ResType)
    {
        try
        {
            HRSRC hResource = FindResource(nullptr, MAKEINTRESOURCE(ResourceID), ResType);
            if (hResource == nullptr)
            {
                return false;
            }

            HGLOBAL hFileResource = LoadResource(nullptr, hResource);
            if (hFileResource == nullptr)
            {
                return false;
            }

            void* lpFile = LockResource(hFileResource);
            if (lpFile == nullptr)
            {
                return false;
            }

            std::uint32_t dwSize = SizeofResource(nullptr, hResource);
            if (dwSize == 0)
            {
                return false;
            }

            HANDLE hFile = CreateFile(OutputFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
            HANDLE hFilemap = CreateFileMapping(hFile, nullptr, PAGE_READWRITE, 0, dwSize, nullptr);
            if (hFilemap == nullptr)
            {
                return false;
            }

            void* lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);
            CopyMemory(lpBaseAddress, lpFile, dwSize);
            UnmapViewOfFile(lpBaseAddress);
            CloseHandle(hFilemap);
            CloseHandle(hFile);

            return true;
        }
        catch (...) {}
        return false;
    }

Main.cpp:

#include "Resource.h"

bool Extract(HWND WindowHandle) //WindowHandle for MessageBox parent.
{
    return ExtractResource(101,"101.dll", "BINARY");
}

int main()
{
    std::cout<<"Extracted Successfully: "<<std::boolalpha<<Extract(GetModuleHandle(0));
}

Again, be very wary that you are using a CONSOLE application which may or may not have a resource embedded in it.

OTHER TIPS

While the accepted answer works very well in most cases, it might fail when having very large files on x86 systems. MapViewOfFile in this case returns a NULL pointer and GetLastError returns ERROR_NOT_ENOUGH_MEMORY.

To overcome this issue, I changed the code to write the file in chunks and add it here in case anyone encounters the same issue:

bool ExtractResource(std::uint16_t ResourceID, std::wstring OutputFileName, LPCWSTR ResType)
{
    try
    {
        HRSRC hResource = FindResource(nullptr, MAKEINTRESOURCE(ResourceID), ResType);
        if (hResource == nullptr)
        {
            return false;
        }

        HGLOBAL hFileResource = LoadResource(nullptr, hResource);
        if (hFileResource == nullptr)
        {
            return false;
        }

        void* lpFile = LockResource(hFileResource);
        if (lpFile == nullptr)
        {
            return false;
        }

        std::uint32_t dwSize = SizeofResource(nullptr, hResource);
        if (dwSize == 0)
        {
            return false;
        }

        HANDLE hFile = CreateFile(OutputFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
        HANDLE hFilemap = CreateFileMapping(hFile, nullptr, PAGE_READWRITE, 0, dwSize, nullptr);
        if (hFilemap == nullptr)
        {
            return false;
        }
        
        ULONG ulChunkSize(65536);
        if (ULONG n = (ULONG)((dwSize + (ulChunkSize - 1)) / ulChunkSize))
        {
            LARGE_INTEGER offset = {};
            do
            {
                SIZE_T nBytes = (--n ? ulChunkSize : dwSize % ulChunkSize);
                void* lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, offset.HighPart, offset.LowPart, nBytes);
                if (lpBaseAddress != 0)
                {
                    CopyMemory(lpBaseAddress, lpFile, nBytes);
                    UnmapViewOfFile(lpBaseAddress);
                    lpFile = static_cast<char*>(lpFile) + nBytes;
                }
                else
                    return false;
            } while (offset.QuadPart += ulChunkSize, n);
            CloseHandle(hFilemap);
            CloseHandle(hFile);

            return true;

        }
    }
    catch (...) {}
    return false;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top