Embedding Files in an Executable - Windows - Part 2
Tags: cpp, programming, desktop
Published: 2023-03-19 00:16:09

**Why embed files inside an executable?**
**Why use a patch instead of a compiler and resources?**

1. To create a singleFile.exe, without folders and dependencies.
2. For the common user not to have access to the files.
3. To be able to use a "patch" instead of a "compiler" to create a program. And being able to do it on any operating system, without having to install anything.
4. For the "build" to be instantaneous.
5. For a server to be able to "compile everything", without needing hundreds gigs of memory.

This method is equivalent to using resources. The difference is that it does not require compilation to change the program content. The program can be updated on both Linux and Windows, without having to install libraries and dependencies and compilers. The program base works as a "template".

**1) Create the program template**

```cpp
#include <fstream>
#include <iostream>
#include <windows.h>
#include <sstream>
#include <string> 
#include <locale>
 
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 << "File open error " << 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 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(); 

    // Get content size in last byte
    std::string sizeHex = getHexValue(bytFile, size, 1); 
    int contentSize = hexToInt( sizeHex );

    // 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");

    // print content
    std::string content = "content: ";     
    for (int i = contentSize+1; i > 1; i--) { 
        std::string byteInStringFormat;
        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char
        content += byteInStringFormat;
    }     
    std::cout << content << std::endl; 

    return 0;
}
```
 
**2) Compile**

```cpp
g++ program.cpp -o program
```

**3) Exec and get file size**

```
program
```
```
file size: 163840
last byte: 00
int size : 0
content:
```
Or get file size by cmd
```
for %I in (program.exe) do @echo %~zI
163840
```

**4) Create the 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() );

  // Rewrite 
  file_write_bin(program_file, bytFile);

  return 0;
}
```

**5) Create content file: data.txt**
```cpp
1234567890Xkãj56
```

**6) Apply patch**
The correct file size was 163840;
This is used to split the file and not add patch over patch.
```
patch program.exe data.txt 163840
```

**7) Run program.exe**
```
program
```
```
file size: 163858
last byte: 11
int size : 17
content: 1234567890Xkãj56
```

**8) Change content file: data.txt**
```
123
```

**9) Apply patch**
```
patch program.exe data.txt 163840
```

**10) Run program.exe**
```
program
```
```
file size: 163844
last byte: 03
int size : 3
content: 123
```
One way to improve this would be to use a "linked list" to store more files in sequence. 


### Embedding Multiples Files in an Executable - Windows - Part 3
https://dev.to/gurigraphics/embedding-multiples-files-in-an-executable-windows-part-3-4pn8