【问题标题】:Self-Extracting Executable C++自解压可执行 C++
【发布时间】:2013-09-26 11:43:05
【问题描述】:

我正在尝试了解自解压 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 和 C++,所以请原谅我。

【问题讨论】:

  • 定义“不能”。究竟哪个 API 调用因哪个错误而失败?使用调试器找出答案。
  • 它构建得很好,但它不会提取资源。我正在使用 VS2012。
  • 所以,调试你的程序找出原因。
  • 当我尝试调试它时,调试器不会说/做任何事情。似乎它正在工作,但唯一的问题是它并没有真正提取文件。它们应该被提取到同一个文件夹中,但没有任何反应。
  • 在调试器下单步执行程序时,检查每个 API 调用的返回值。找出失败的那个。

标签: c++ resources extract hinstance


【解决方案1】:

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

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

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

    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 应用程序可能嵌入也可能没有嵌入资源。

【讨论】:

  • 这对我来说似乎很复杂,就像我说的只是一个初学者 :) 有没有任何 简单 方法可以使我在 OP 中发布的代码工作?该项目目前只有资源中的文件,只有 main.cpp 文件。我还需要其他东西吗?不,我没有在任何需要管理员权限的地方提取文件,只是尝试在桌面上运行它,但没有任何反应。如果有人能帮我一个大忙,从哪里学习并修复原始代码,我将非常感激。也感谢您提到 nullptr 的事情,不知道。
  • 呃.. 一秒钟。我会尝试简化我所拥有的。它应该和你的差不多:l
  • 另请注意,如果我简化它可能不起作用,因为您似乎正在使用可能会或可能不会允许资源的控制台应用程序。通常当我们谈到资源时,我们指的是 GUI 程序而不是控制台。但是,我会假设您已经将资源嵌入到您的程序中,因此我将根据这个假设简化答案。
  • 我看到你编辑了你的帖子,很好。 :) 我会在几个小时内试试这个。我希望它对我有用。但如果没有,我可以只创建一个空项目,将代码粘贴到那里并将入口点从 int main 更改为 Win32 WinMain 吗?走着瞧。无论如何,谢谢,我会尽快测试。
  • 谢谢!几乎没有变化,它就像一个魅力。我将所有“uint32_t”都更改为整数,它就像我想要的那样工作。好的。把它改成 int 不好吗?
【解决方案2】:

虽然接受的答案在大多数情况下效果很好,但在 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 2015-01-06
    • 1970-01-01
    相关资源
    最近更新 更多