DEV Community

Cover image for Embedding Big Files in an Executable - Windows - Part 4
Gurigraphics
Gurigraphics

Posted on

Embedding Big Files in an Executable - Windows - Part 4

A file with this size 16515603 in hexadecimal is 0x1302FC. To store large values, up to 4 gigabytes, we will need 4 bytes:

0xFC, 0x02, 0x13, 0x00 
Enter fullscreen mode Exit fullscreen mode

We will use:

 bytFile.insert(bytFile.end(), { static_cast<char>((bytText.size() >> 24) & 0xFF), static_cast<char>((bytText.size() >> 16) & 0xFF), static_cast<char>((bytText.size() >> 8) & 0xFF), static_cast<char>((bytText.size() >> 0) & 0xFF) }); 
Enter fullscreen mode Exit fullscreen mode

1) Let's update the patch:

#include <fstream> #include <iostream> #include <string>  #include <vector> #include <sstream>  std::vector<char> file_read_bin(const std::string& fileName) { std::string filePath = fileName; std::ifstream file(filePath, std::ios::binary); if (file.fail()) { std::cerr << "Erro ao abrir o arquivo " << filePath << std::endl; } // Read bytes  std::vector<char> bytFile((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); file.close(); return bytFile; } void file_write_bin(const std::string& filePath, std::vector<char> bytFile) { // Write bytes std::ofstream outFile(filePath, std::ios::binary); if (outFile.fail()) { std::cerr << "Erro ao abrir o arquivo " << filePath << " para escrita" << std::endl; } outFile.write(bytFile.data(), bytFile.size()); outFile.close(); std::cout << "Arquivo alterado com sucesso" << std::endl; } int main(int argc, char *argv[]){ if (argc != 4) { std::cout << "Require 3 args: program.exe data.txt 163857\n"; return 1; } const char* program_file = argv[1]; const char* data_file = argv[2]; std::vector<char> bytFile = file_read_bin( program_file ); std::vector<char> bytText = file_read_bin( data_file ); int correctSize = std::stoi(argv[3]); int size = bytFile.size(); int diff = size - correctSize; // Logs std::cout << "size: " << size << "\n"; std::cout << "correctSize: " << correctSize << "\n"; // Remove old code if(size > correctSize ){ bytFile.erase(bytFile.end() - diff, bytFile.end() ); } // Add content bytFile.insert(bytFile.end(), bytText.begin(), bytText.end()); // Add content size bytFile.insert(bytFile.end(), { static_cast<char>((bytText.size() >> 24) & 0xFF), static_cast<char>((bytText.size() >> 16) & 0xFF), static_cast<char>((bytText.size() >> 8) & 0xFF), static_cast<char>((bytText.size() >> 0) & 0xFF) }); // Add file name std::string data_filename_str(data_file); data_filename_str+="\0"; bytFile.insert(bytFile.end(), data_filename_str.c_str(), data_filename_str.c_str() + data_filename_str.size() ); // Add name size bytFile.insert( bytFile.end(), data_filename_str.size() ); // Add symbol exist new file std::string symbol = "^"; bytFile.insert(bytFile.end(), symbol.c_str(), symbol.c_str() + symbol.size() ); // Rewrite  file_write_bin(program_file, bytFile); return 0; } 
Enter fullscreen mode Exit fullscreen mode

2) Compile

g++ patch.cpp -o patch 
Enter fullscreen mode Exit fullscreen mode

3) Update the program.cpp

As the function is getting too big with too many responsibilities, now let's refactor the code and separate these functions:

int getFileNamesize(std::vector<char> bytFile, int size) std::string getFileName(std::vector<char> bytFile, int size, int fileNameSize) int getContentSize(std::vector<char> bytFile, int size, int fileNameSize) std::string getContent(std::vector<char> bytFile, int size, int fileNameSize, int contentSize, int contentStart) int getContent(std::vector<char> bytFile, int size) 
Enter fullscreen mode Exit fullscreen mode

program.cpp

#include <fstream> #include <iostream> #include <windows.h> #include <sstream> #include <string>  #include <locale>  int assetsCount = 0; std::vector<char> file_read_bin(const std::string& fileName) { std::string filePath = fileName; std::ifstream file(filePath, std::ios::binary); if (file.fail()) { std::cerr << "Erro ao abrir o arquivo " << filePath << std::endl; } // Read bytes  std::vector<char> bytFile((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); file.close(); return bytFile; } std::string getHexValue(const std::vector<char>& bytFile, int size, int byteCount) { std::stringstream ss; ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(bytFile[size - byteCount])); return ss.str(); } int hexToInt(std::string hexStr) { return std::stoi(hexStr, nullptr, 16); } int getFileNamesize(std::vector<char> bytFile, int size){ std::string sizeHex = getHexValue(bytFile, size, 2); return hexToInt( sizeHex ); } std::string getFileName(std::vector<char> bytFile, int size, int fileNameSize){ std::string fileName = ""; int startfileName = fileNameSize + 2; for (int i = startfileName; i > 2; i--) { std::string byteInStringFormat; byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char fileName += byteInStringFormat; } return fileName; } int getContentSize(std::vector<char> bytFile, int size, int fileNameSize){ std::string byte_24 = getHexValue(bytFile, size, fileNameSize + 3); std::string byte_16 = getHexValue(bytFile, size, fileNameSize + 4); std::string byte_08 = getHexValue(bytFile, size, fileNameSize + 5); std::string byte_00 = getHexValue(bytFile, size, fileNameSize + 6); std::stringstream ss; ss << std::hex << byte_00 << byte_08 << byte_16 << byte_24; int contentSize; ss >> contentSize; return contentSize; } std::string getContent(std::vector<char> bytFile, int size, int fileNameSize, int contentSize, int contentStart){ std::string content = ""; for (int i = contentStart; i > fileNameSize+3+3; i--) { std::string byteInStringFormat; byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char  content += byteInStringFormat; } return content; } int getContent(std::vector<char> bytFile, int size) { if( bytFile[size - 1] != '^') { // Exist new file? std::cout << "end" << "\n"; return 0; } assetsCount+=1; std::cout << assetsCount << "-----------------" << "\n"; // Get file name size in last byte  int fileNameSize = getFileNamesize(bytFile, size); std::cout << "content name size: " << fileNameSize << "\n"; // Get file name in last byte  std::string fileName = getFileName(bytFile, size, fileNameSize); std::cout << "content name: " << fileName << "\n"; // Get content size in 4 bytes int contentSize = getContentSize(bytFile, size, fileNameSize); std::cout << "content size: " << contentSize << "\n"; // Get content int contentStart = contentSize+fileNameSize+3+3; std::string content = getContent(bytFile, size, fileNameSize, contentSize, contentStart); // Print big string int stringSize = content.size(); int maxLineSize = 80; for (int i = 0; i < stringSize; i += maxLineSize) { int lineSize = std::min(stringSize - i, maxLineSize); std::cout << content.substr(i, lineSize) << std::endl; } // End int final = size - (contentStart + 1); std::cout << "-----------------" << "\n"; getContent(bytFile, final+1); // get new file return 0; } int main(int argc, char *argv[]){ // Read file std::string filename = std::string(argv[0]) + ".exe"; std::vector<char> bytFile = file_read_bin( filename ); int size = bytFile.size(); // Logs std::cout << "file size: " << size << std::endl; std::cout << "last byte: " << getHexValue(bytFile, size, 1) << std::endl; //std::cout << "int size : " << contentSize << std::endl;  // console "pt-BR" accentuation errors system("chcp 1252 > nul"); setlocale(LC_ALL, "pt_BR.UTF-8"); getContent(bytFile, size); return 0; } 
Enter fullscreen mode Exit fullscreen mode

4) Compile

g++ program.cpp -o program 
Enter fullscreen mode Exit fullscreen mode

5) Exec and get "file size"

program 
Enter fullscreen mode Exit fullscreen mode
file size: 172032 last byte: 00 end 
Enter fullscreen mode Exit fullscreen mode

6) Create um big content data3.txt

Create the file "data3.txt" and add this content:

https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js

To make it easier to verify that everything went right, you can add a "ã" at the beginning and end of this file:

ã/*! jQuery v3.6.4 | 
Enter fullscreen mode Exit fullscreen mode
(C.jQuery=C.$=S),S});ã 
Enter fullscreen mode Exit fullscreen mode

7) Apply pacth

patch program.exe data3.txt 172032 
Enter fullscreen mode Exit fullscreen mode

8) Run program.exe

program 
Enter fullscreen mode Exit fullscreen mode
file size: 261846 last byte: 5e 1----------------- content name size: 9 content name: data3.txt content size: 89799 ã/*! jQuery v3.6.4 (...) ned"==typeof e&&(C.jQuery=C.$=S),S});ã ----------------- end 
Enter fullscreen mode Exit fullscreen mode

8) Apply a new patch with new size

patch program.exe data3.txt 261846 
Enter fullscreen mode Exit fullscreen mode

9) Run program.exe

First clear console

cls 
Enter fullscreen mode Exit fullscreen mode
program 
Enter fullscreen mode Exit fullscreen mode

Result

file size: 351660 last byte: 5e 1----------------- content name size: 9 content name: data3.txt content size: 89799 ã/*! jQuery v3.6.4 | (...) ned"==typeof e&&(C.jQuery=C.$=S),S});ã ----------------- 2----------------- content name size: 9 content name: data3.txt content size: 89799 ã/*! jQuery v3.6.4 | (...) ned"==typeof e&&(C.jQuery=C.$=S),S});ã ----------------- end 
Enter fullscreen mode Exit fullscreen mode

Embedding Files in an Executable - SDL/Windows - Part 5

https://dev.to/gurigraphics/embedding-files-in-an-executable-sdlwindows-part-5-2he4

Top comments (0)