自解压可执行C ++

时间:2013-09-21 00:34:29

标签: c++ resources extract hinstance

我试图了解自解压PE文件的工作原理。有人可以解释为什么我的代码不起作用,或修复main()部分。

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

}

我在资源中有4个dll文件,但是我无法使用它来提取它们。资源ID应该是正确的,我从资源标题中检查了它。

hInst中的问题或其他可能出错的问题是什么?我希望有人可以帮助我:)我只有一个月前开始学习C&amp; C ++原谅我。

2 个答案:

答案 0 :(得分:2)

除了没有检查函数的返回值并在出现错误时打印相应的消息之外,我没有看到您的代码有任何问题。另请注意,您可以使用nullptr替换hInstance,它仍然有效。

另请注意,如果要解压缩到需要额外权限的位置,则可能必须以管理员身份运行程序或添加强制它要求管理员权限的清单。

就个人而言,我在任何资源应用程序中使用这些:

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

同样,要非常谨慎地使用CONSOLE应用程序,该应用程序可能包含或不包含资源。

答案 1 :(得分:0)

虽然接受的答案在大多数情况下效果很好,但在 x86 系统上具有非常大的文件时可能会失败。在这种情况下,MapViewOfFile 返回 NULL 指针,GetLastError 返回 ERROR_NOT_ENOUGH_MEMORY

为了克服这个问题,我更改了代码以分块写入文件并将其添加到此处,以防有人遇到相同的问题:

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;
}