Embedding Multiples Files in an Executable - Windows - Part 3

gurigraphics

Gurigraphics

Posted on March 19, 2023

Embedding Multiples Files in an Executable - Windows - Part 3

This example deals with multiple files. Is now also stored:

content name size: 8
content name: data.txt
content size: 10
content: 1234567890
Enter fullscreen mode Exit fullscreen mode

This symbol is used to signal that a new file exists

std::string symbol = "^";
Enter fullscreen mode Exit fullscreen mode

1) Create 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 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    
    std::cout << "content name size: ";    
    std::string sizeHex = getHexValue(bytFile, size, 2); 
    int fileNameSize = hexToInt( sizeHex );
    std::cout << fileNameSize << "\n";

    // Get file name in last byte 
    std::string fileName = "content name: ";     
    for (int i = fileNameSize+2; i > 1; i--) { 
        std::string byteInStringFormat;
        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char
        fileName += byteInStringFormat;
    } 
    std::cout << fileName << std::endl;

    // Get content size in last byte    
    std::cout << "content size: ";    
    std::string contentSizeHex = getHexValue(bytFile, size, fileNameSize + 3); 
    int contentSize = hexToInt( contentSizeHex );
    std::cout << contentSize << "\n";

    // Print content
    std::string content = "content: ";
    int contentStart = contentSize+fileNameSize+3;   //9   5 
    for (int i = contentStart; i > fileNameSize+3; i--) { 
        std::string byteInStringFormat;
        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char 
        content += byteInStringFormat;
    }  
    std::cout << content << "\n"; 

    // 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

2) Compile

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

3) Exec and get "file size"

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

Or get file size by cmd

for %I in (program.exe) do @echo %~zI
168960
Enter fullscreen mode Exit fullscreen mode

4) Create patch.cpp

#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(), bytText.size() );

  // 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

5) Create content file: data.txt

1234567890Xkãj56
Enter fullscreen mode Exit fullscreen mode

6) Apply patch

patch program.exe data.txt 168960
Enter fullscreen mode Exit fullscreen mode

7) Run program.exe and get new size

program
Enter fullscreen mode Exit fullscreen mode
file size: 168988
last byte: 5e
1-----------------
content name size: 8
content name: data.txt
content size: 17
content: 1234567890Xkãj56
-----------------
end
Enter fullscreen mode Exit fullscreen mode

8) Create new content file: data2.txt

1234567890Xkãj56888
Enter fullscreen mode Exit fullscreen mode

9) Apply patch with new size

patch program.exe data2.txt 168988
Enter fullscreen mode Exit fullscreen mode

10) Run program.exe

program
Enter fullscreen mode Exit fullscreen mode
file size: 169020
last byte: 5e
1-----------------
content name size: 9
content name: data2.txt
content size: 20
content: 1234567890Xkãj56888
-----------------
2-----------------
content name size: 8
content name: data.txt
content size: 17
content: 1234567890Xkãj56
-----------------
end
Enter fullscreen mode Exit fullscreen mode

Embedding Big Files in an Executable - Windows - Part 4

https://dev.to/gurigraphics/embedding-big-files-in-an-executable-windows-part-4-25hf

💖 💪 🙅 🚩
gurigraphics
Gurigraphics

Posted on March 19, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related