Самораспаковывающийся исполняемый файл C++
Я пытаюсь понять, как работают самораспаковывающиеся 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-файла в ресурсах, но я не могу извлечь их используя это. Идентификаторы ресурса должны быть правильными, я проверил это из заголовка ресурса.
Проблема в hInst
или что там еще может быть не так? Я надеюсь, что кто-нибудь может мне помочь:) Я всего лишь ~ месяц назад начал изучать C & C++, так что простите меня.
2 ответа
Я не вижу ничего плохого в вашем коде, кроме того, что вы не проверяете возвращаемые значения функций и не печатаете соответствующие сообщения, когда что-то идет не так. Также обратите внимание, что вы можете заменить 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, которое может иметь или не иметь встроенный ресурс.
Хотя принятый ответ в большинстве случаев работает очень хорошо, он может дать сбой при наличии очень больших файлов в системах 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;
}