Skip to content

Instantly share code, notes, and snippets.

@AltimorTASDK
Created November 1, 2022 19:13
Show Gist options
  • Save AltimorTASDK/48d198c10033830c0aca1ef7a8e542de to your computer and use it in GitHub Desktop.
Save AltimorTASDK/48d198c10033830c0aca1ef7a8e542de to your computer and use it in GitHub Desktop.
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <Windows.h>
char *rva_to_pointer(char *data, uint32_t rva)
{
const auto &dos = *(IMAGE_DOS_HEADER*)data;
const auto &pe = *(IMAGE_NT_HEADERS64*)&data[dos.e_lfanew];
// After the end of _IMAGE_OPTIONAL_HEADER
const auto &opt = pe.OptionalHeader;
const auto *sections = (IMAGE_SECTION_HEADER*)&opt.DataDirectory[opt.NumberOfRvaAndSizes];
for (auto i = 0; i < pe.FileHeader.NumberOfSections; i++) {
const auto start = sections[i].VirtualAddress;
const auto end = start + sections[i].Misc.VirtualSize;
if (rva >= start && rva < end)
return &data[rva - start + sections[i].PointerToRawData];
}
throw std::out_of_range("RVA not in section bounds");
}
uint64_t xtea_next()
{
static constexpr uint32_t key[] = { 0x6DEAC50E, 0x5703A8A5, 0x3A2D6F68, 0xFF8E988E };
static constinit uint32_t v0 = 0x1AE1DA57;
static constinit uint32_t v1 = 0x66808190;
uint32_t sum = 0;
for (auto i = 0; i < 64; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += 0x9E3779B9;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
}
return ((uint64_t)v1 << 32) | v0;
}
uint32_t decode_7bit(const char **stream)
{
char byte;
uint32_t shift = 0;
uint32_t value = 0;
do {
byte = *(*stream)++;
value += (uint32_t)(byte & 0x7F) << shift;
shift += 7;
} while (byte & 0x80);
return value;
}
void unpack(char *data, const char *rva_stream)
{
uint32_t rva = 0;
uint32_t size = 0;
while (true) {
const auto xor_key = xtea_next();
for (auto shift = 0; shift < 64; shift += 8) {
while (size == 0) {
rva += decode_7bit(&rva_stream);
if (rva == (uint32_t)-1)
return;
size = decode_7bit(&rva_stream);
}
*rva_to_pointer(data, rva++) ^= xor_key >> shift;
size--;
}
}
}
int main(int argc, const char *argv[])
{
if (argc < 3) {
std::cerr << "Usage: unpacker <cod.exe> <unpacked.exe>\n";
return 1;
}
const auto *in_path = argv[1];
const auto *out_path = argv[2];
auto in_file = std::ifstream(in_path, std::ios::binary | std::ios::ate);
if (!in_file.is_open()) {
std::cerr << "Failed to open \"" << in_path << "\"\n";
return 1;
}
const auto length = in_file.tellg();
const auto data = std::make_unique<char[]>(length);
in_file.seekg(0);
in_file.read(data.get(), length);
in_file.close();
auto out_file = std::ofstream(out_path, std::ios::binary);
if (!out_file.is_open()) {
std::cerr << "Failed to open \"" << out_path << "\"\n";
return 1;
}
static constexpr char rva_pattern[] = "\x80\x20\xBB\xC1\x01\x05\xBB\xC1";
const auto *rva_stream = std::search(data.get(), data.get() + length,
rva_pattern, rva_pattern + sizeof(rva_pattern) - 1);
if (rva_stream == data.get() + length) {
std::cerr << "Failed to find RVA stream\n";
return 1;
}
unpack(data.get(), rva_stream);
out_file.write(data.get(), length);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment