TinyLoad v7.1 main.cpp

This commit is contained in:
iamsopotatoe
2026-06-16 16:16:30 +02:00
committed by GitHub
parent d4059294fb
commit 2ce6609abd
+315 -57
View File
@@ -1,4 +1,4 @@
// Tinyload v7.0, MIT license, https://github.com/iamsopotatoe-coder/TinyLoad/
// Tinyload v7.1, MIT license, https://github.com/iamsopotatoe-coder/TinyLoad/
#include <windows.h>
#include <vector>
#include <string>
@@ -83,16 +83,105 @@ __attribute__((noinline)) __attribute__((used)) static void noiseDecrypt() {
sdec2((char*)junk, g_noise[idx].enc, g_noise[idx].n, g_noise[idx].k);
}
__attribute__((noinline)) bool isDebugged() {
// go away windbg
if (IsDebuggerPresent()) {
return true;
//dual thread key recombination
struct PxTR_Context {
DWORD k[4]; // [0,1] from Thread A, [2,3] from Thread B
HANDLE fenceEvent;
BYTE* target;
SIZE_T length;
};
#define XXTEA_DELTA 0x9E3779B9
#define XXTEA_MX (((z>>5^y<<2)+(y>>3^z<<4))^((sum^y)+(ctx->k[(p&3)^e]^z)))
static void xxteaDecrypt(PxTR_Context* ctx, DWORD* v, int n) {
DWORD y = v[0], z, sum = (DWORD)((6 + 52/n) * (uint64_t)XXTEA_DELTA);
unsigned p, rounds = 6 + 52/n, e;
do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= XXTEA_MX;
}
z = v[n - 1];
y = v[0] -= XXTEA_MX;
sum -= XXTEA_DELTA;
} while (--rounds);
}
#undef XXTEA_MX
// Encrypt key is passed as explicit array
#define XXTEA_MX (((z>>5^y<<2)+(y>>3^z<<4))^((sum^y)+(key[(p&3)^e]^z)))
static void xxteaEncrypt(DWORD* v, int n, const DWORD key[4]) {
DWORD y, z, sum = 0;
unsigned p, rounds = 6 + 52/n, e;
z = v[n - 1];
do {
sum += XXTEA_DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = v[p + 1];
z = v[p] += XXTEA_MX;
}
y = v[0];
z = v[n - 1] += XXTEA_MX;
} while (--rounds);
}
#undef XXTEA_MX
#undef XXTEA_DELTA
// Encoded key words
__attribute__((section(".pxkey")))
static volatile struct {
DWORD guard1;
DWORD k0, k1, k2, k3;
DWORD guard2;
} _pxBlock = { 0xC0DE1337, 0xFEEDF00D, 0xCAFEBABE, 0xDEADBEEF, 0x8BADF00D, 0xB007DEAD }; //james bond reference :D
static DWORD _pxRead(int i) { volatile DWORD _keep = _pxBlock.guard2; return ((&_pxBlock.k0)[i]) ^ (_keep & 0); }
static DWORD WINAPI PxTR_ThreadA(LPVOID p) {
PxTR_Context* ctx = (PxTR_Context*)p;
// decode Thread A's key halves
DWORD k0 = _pxRead(0) ^ 0xFEEDF00D;
DWORD k1 = _pxRead(1) ^ 0xCAFEBABE;
WaitForSingleObject(ctx->fenceEvent, INFINITE);
// recombine transiently
ctx->k[0] = k0; ctx->k[1] = k1;
// fall back to XOR for short/remainder
SIZE_T nWords = ctx->length / 4;
if (nWords >= 2) {
xxteaDecrypt(ctx, (DWORD*)ctx->target, (int)nWords);
} else if (ctx->length > 0) {
DWORD tailKey = k0 ^ k1 ^ ctx->k[2] ^ ctx->k[3];
for (size_t i = 0; i < ctx->length; i++)
ctx->target[i] ^= (BYTE)(tailKey >> ((i & 3) * 8));
}
// scramble all key material
_pxBlock.k0 = 0; _pxBlock.k1 = 0;
ctx->k[0] = 0; ctx->k[1] = 0; ctx->k[2] = 0; ctx->k[3] = 0;
return 0;
}
static DWORD WINAPI PxTR_ThreadB(LPVOID p) {
PxTR_Context* ctx = (PxTR_Context*)p;
ctx->k[2] = _pxRead(2) ^ 0xDEADBEEF;
ctx->k[3] = _pxRead(3) ^ 0x8BADF00D;
_pxBlock.k2 = 0; _pxBlock.k3 = 0;
SetEvent(ctx->fenceEvent);
return 0;
}
__attribute__((noinline)) bool isDebugged() {
// PEB checks (x64)
BYTE* peb = (BYTE*)__readgsqword(0x60);
if (peb) {
if (*(peb + 2)) return true; // BeingDebugged
if (*(DWORD*)(peb + 0xBC) & 0x70) return true; // NtGlobalFlag
}
if (IsDebuggerPresent()) return true;
BOOL remote = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &remote);
if (remote) {
return true;
}
if (remote) return true;
return false;
}
@@ -126,6 +215,71 @@ struct Tail {
};
#pragma pack(pop)
#define TAIL_SERIALIZED_SZ (sizeof(Tail) + TF_COUNT * 3)
// Tail field table for shuffled serialization
enum { TF_SIG, TF_ORIGSZ, TF_PACKSZ, TF_FLAGS, TF_DISPOFF, TF_SUBTABLES,
TF_VMCODESZ, TF_DISPKEY, TF_CANARYOFF, TF_CANARYEXP, TF_CANARYCNT,
TF_CHUNKOFF, TF_CHUNKSZ, TF_CHUNKORDER, TF_CHUNKCNT, TF_COUNT };
struct TailField { uint8_t id; uint16_t off; uint16_t sz; };
static const TailField g_tailFields[TF_COUNT] = {
{TF_SIG, offsetof(Tail,sig), sizeof(((Tail*)0)->sig)},
{TF_ORIGSZ, offsetof(Tail,origSz), sizeof(((Tail*)0)->origSz)},
{TF_PACKSZ, offsetof(Tail,packSz), sizeof(((Tail*)0)->packSz)},
{TF_FLAGS, offsetof(Tail,flags), sizeof(((Tail*)0)->flags)},
{TF_DISPOFF, offsetof(Tail,dispOff), sizeof(((Tail*)0)->dispOff)},
{TF_SUBTABLES, offsetof(Tail,subtables), sizeof(((Tail*)0)->subtables)},
{TF_VMCODESZ, offsetof(Tail,vmCodeSz), sizeof(((Tail*)0)->vmCodeSz)},
{TF_DISPKEY, offsetof(Tail,dispKey), sizeof(((Tail*)0)->dispKey)},
{TF_CANARYOFF, offsetof(Tail,canaryOff), sizeof(((Tail*)0)->canaryOff)},
{TF_CANARYEXP, offsetof(Tail,canaryExp), sizeof(((Tail*)0)->canaryExp)},
{TF_CANARYCNT, offsetof(Tail,canaryCnt), sizeof(((Tail*)0)->canaryCnt)},
{TF_CHUNKOFF, offsetof(Tail,chunkOff), sizeof(((Tail*)0)->chunkOff)},
{TF_CHUNKSZ, offsetof(Tail,chunkSz), sizeof(((Tail*)0)->chunkSz)},
{TF_CHUNKORDER, offsetof(Tail,chunkOrder), sizeof(((Tail*)0)->chunkOrder)},
{TF_CHUNKCNT, offsetof(Tail,chunkCnt), sizeof(((Tail*)0)->chunkCnt)},
};
static Bytes serializeTail(const Tail& t, uint32_t seed) {
Bytes out;
out.reserve(512);
int order[TF_COUNT];
for (int i = 0; i < TF_COUNT; i++) order[i] = i;
// Fisher Yates
uint32_t s = seed;
for (int i = TF_COUNT - 1; i > 0; i--) {
s = s * 1103515245 + 12345;
int j = (int)(((uint64_t)s * (i + 1)) >> 32);
int tmp = order[i]; order[i] = order[j]; order[j] = tmp;
}
for (int fi = 0; fi < TF_COUNT; fi++) {
const auto& f = g_tailFields[order[fi]];
out.push_back(f.id);
out.push_back(f.sz & 0xFF);
out.push_back((f.sz >> 8) & 0xFF);
out.insert(out.end(), (BYTE*)&t + f.off, (BYTE*)&t + f.off + f.sz);
}
return out;
}
static bool parseTail(const Bytes& data, size_t pos, Tail& t, size_t endPos) {
memset(&t, 0, sizeof(t));
int fieldsFound = 0;
while (pos + 3 <= endPos && fieldsFound < TF_COUNT) {
uint8_t id = data[pos];
uint16_t sz = data[pos + 1] | ((uint16_t)data[pos + 2] << 8);
pos += 3;
if (pos + sz > endPos) return false;
if (id >= TF_COUNT) return false;
const auto& f = g_tailFields[id];
if (sz != f.sz) return false;
memcpy((BYTE*)&t + f.off, &data[pos], sz);
pos += sz;
fieldsFound++;
}
return fieldsFound == TF_COUNT;
}
// per-subtable keys
static void xorOpmap(BYTE* sub, const Tail& t, const BYTE* vmCode, const BYTE* pay) {
uint32_t baseH = 0x811C9DC5u;
@@ -710,7 +864,7 @@ Bytes makeVmProgram(const BYTE* enc, uint64_t key1, uint64_t key2,
int opqEnd = (int)bc.size();
{ int32_t off = opqEnd - (opqPatch + 4); memcpy(&bc[opqPatch], &off, 4); }
// xor-self -> 0
// xor self -> 0
eOp(bc,enc,LDI_I); eR(bc,6); e64(bc,0xDEADBEEFCAFEBABEull);
eOp(bc,enc,XOR_I); eR(bc,6); eR(bc,6);
eOp(bc,enc,LDI_I); eR(bc,7); e64(bc,1);
@@ -907,12 +1061,14 @@ static int sp_hdr() {
if (g_pe.data->size() < sizeof(IMAGE_DOS_HEADER)) return -2;
g_pe.dos = (IMAGE_DOS_HEADER*)g_pe.data->data();
if (g_pe.dos->e_magic != IMAGE_DOS_SIGNATURE) return -2;
if (g_pe.dos->e_lfanew <= 0) return -2;
if ((DWORD) g_pe.dos->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > g_pe.data->size()) return -2;
if (g_pe.dos->e_lfanew <= 0 || (DWORD)g_pe.dos->e_lfanew > g_pe.data->size() - sizeof(IMAGE_NT_HEADERS64)) return -2;
g_pe.nt = (IMAGE_NT_HEADERS64*)(g_pe.data->data() + g_pe.dos->e_lfanew);
if (g_pe.nt->Signature != IMAGE_NT_SIGNATURE) return -2;
if (g_pe.nt->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) return -2;
if (g_pe.nt->OptionalHeader.SizeOfImage > 0x40000000 || g_pe.nt->OptionalHeader.SizeOfImage == 0) return -2;
if (g_pe.nt->FileHeader.NumberOfSections > 96 || g_pe.nt->FileHeader.NumberOfSections == 0) return -2;
DWORD sio = g_pe.nt->OptionalHeader.SizeOfImage;
if (sio > 0x40000000 || sio == 0 || sio < g_pe.nt->OptionalHeader.SizeOfHeaders) return -2;
if (g_pe.nt->OptionalHeader.SizeOfHeaders > g_pe.data->size()) return -2;
return 1;
}
static int sp_map() {
@@ -924,15 +1080,17 @@ static int sp_map() {
}
memcpy(g_pe.base, g_pe.data->data(), hdrSize);
IMAGE_SECTION_HEADER* sect = IMAGE_FIRST_SECTION(g_pe.nt);
if (g_pe.nt->FileHeader.NumberOfSections > 96) return -2;
for (int i = 0; i < g_pe.nt->FileHeader.NumberOfSections; i++) {
if (sect[i].SizeOfRawData > 0) {
size_t srcOff = sect[i].PointerToRawData;
size_t dstOff = sect[i].VirtualAddress;
if (srcOff + sect[i].SizeOfRawData <= g_pe.data->size() && dstOff + sect[i].SizeOfRawData <= g_pe.nt->OptionalHeader.SizeOfImage) {
memcpy((BYTE*)g_pe.base + dstOff, g_pe.data->data() + srcOff, sect[i].SizeOfRawData);
}
}
int ns = g_pe.nt->FileHeader.NumberOfSections;
for (int i = 0; i < ns; i++) {
if (sect[i].SizeOfRawData == 0) continue;
DWORD srcOff = sect[i].PointerToRawData;
DWORD dstOff = sect[i].VirtualAddress;
DWORD sz = sect[i].SizeOfRawData;
if (srcOff + sz < srcOff) continue; // overflow
if (dstOff + sz < dstOff) continue;
if (srcOff + sz > g_pe.data->size()) continue;
if (dstOff + sz > g_pe.nt->OptionalHeader.SizeOfImage) continue;
memcpy((BYTE*)g_pe.base + dstOff, g_pe.data->data() + srcOff, sz);
}
return 2;
}
@@ -967,14 +1125,21 @@ static int sp_reloc() {
}
static int sp_import() {
auto* impDir = &g_pe.nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (impDir->Size > 0 && impDir->VirtualAddress < g_pe.nt->OptionalHeader.SizeOfImage) {
DWORD imgSz = g_pe.nt->OptionalHeader.SizeOfImage;
if (impDir->Size > 0 && impDir->VirtualAddress < imgSz) {
auto* imp = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)g_pe.base + impDir->VirtualAddress);
BYTE* impEnd = (BYTE*)g_pe.base + impDir->VirtualAddress + impDir->Size;
while ((BYTE*)(imp + 1) <= impEnd && imp->Name) {
int dllCount = 0;
while ((BYTE*)(imp + 1) <= impEnd && imp->Name && dllCount < 256) {
dllCount++;
if (imp->Name >= imgSz) { imp++; continue; }
HMODULE mod = LoadLibraryA((char*)((BYTE*)g_pe.base + imp->Name));
if (mod) {
if (imp->FirstThunk >= imgSz) { imp++; continue; }
auto* thunk = (IMAGE_THUNK_DATA64*)((BYTE*)g_pe.base + imp->FirstThunk);
auto* orig = (IMAGE_THUNK_DATA64*)((BYTE*)g_pe.base + (imp->OriginalFirstThunk ? imp->OriginalFirstThunk : imp->FirstThunk));
DWORD oth = imp->OriginalFirstThunk ? imp->OriginalFirstThunk : imp->FirstThunk;
if (oth >= imgSz) { imp++; continue; }
auto* orig = (IMAGE_THUNK_DATA64*)((BYTE*)g_pe.base + oth);
int impLimit = 10000;
while (orig->u1.AddressOfData && impLimit-- > 0) {
if (IMAGE_SNAP_BY_ORDINAL64(orig->u1.Ordinal)) {
@@ -1154,7 +1319,7 @@ static int sp_veh() {
g_vehProtCnt = 0;
IMAGE_SECTION_HEADER* sect = IMAGE_FIRST_SECTION(g_pe.nt);
int ns = g_pe.nt->FileHeader.NumberOfSections;
// std::clamp here?
// std::clamp here
if (ns < 0) ns = 0; if (ns > 96) ns = 96;
for (int i = 0; i < ns; i++) {
if (sect[i].SizeOfRawData == 0) continue;
@@ -1225,35 +1390,37 @@ static int s_chk() {
initStrings();
if (isDebugged()) return -2;
noiseDecrypt();
// Hide syscall here also?
// TODO: direct syscall for NtQueryInformationProcess to bypass IAT hooks
GetModuleFileNameA(NULL, g_st.self, MAX_PATH);
return 1;
}
static int s_ld() {
noiseDecrypt();
g_st.blob = loadFile(g_st.self);
if (g_st.blob.size() < sizeof(Tail) + 4) return -2;
if (g_st.blob.size() < TAIL_SERIALIZED_SZ + 4) return -2;
uint64_t sk = 0x9E3779B97F4A7C15ull;
for (size_t i = 0x1000; i < g_st.blob.size() && i < 0x2000; i++) {
sk = (sk ^ g_st.blob[i]) * 0x9E3779B97F4A7C15ull;
}
g_st.off = *(DWORD*)&g_st.blob[g_st.blob.size() - 4] ^ (DWORD)(sk & 0xFFFFFFFF);
if (g_st.off + sizeof(Tail) > g_st.blob.size()) return -2;
if (g_st.off + TAIL_SERIALIZED_SZ > g_st.blob.size()) return -2;
return 2;
}
static int s_prs() {
noiseDecrypt();
g_st.t = (Tail*)&g_st.blob[g_st.off];
static Tail _ts;
if (!parseTail(g_st.blob, g_st.off, _ts, g_st.off + TAIL_SERIALIZED_SZ)) return -2;
g_st.t = &_ts;
// derive key from stub (.text, skip headers)
uint64_t stubKey = 0x9E3779B97F4A7C15ull;
for (size_t i = 0x1000; i < g_st.blob.size() && i < 0x2000; i++) {
stubKey = (stubKey ^ g_st.blob[i]) * 0x9E3779B97F4A7C15ull;
}
// de-XOR metadata fields
// de XOR metadata fields
g_st.t->origSz ^= (DWORD)(stubKey & 0xFFFFFFFF);
g_st.t->packSz ^= (DWORD)((stubKey >> 32) & 0xFFFFFFFF);
g_st.t->flags ^= (BYTE)((stubKey >> 16) & 0xFF);
// de-XOR dispKey, canary, vmCodeSz
// de XOR dispKey, canary, vmCodeSz
uint64_t realDispKey = g_st.t->dispKey ^ stubKey;
g_st.t->vmCodeSz ^= (DWORD)((stubKey >> 8) & 0xFFFFFFFF);
g_st.t->canaryCnt ^= (BYTE)(stubKey & 0xFF);
@@ -1263,7 +1430,7 @@ static int s_prs() {
for (int si = 0; si < (int)sizeof(g_st.t->canaryExp); si++) {
g_st.t->canaryExp[si] ^= (BYTE)(stubKey >> ((si*11)&63));
}
// de-XOR sig with stubKey
// de XOR sig with stubKey
char sigBuf[8]; memcpy(sigBuf, g_st.t->sig, 8);
for (int si = 0; si < 8; si++) {
sigBuf[si] ^= (BYTE)(stubKey >> (si*8));
@@ -1286,13 +1453,33 @@ static int s_prs() {
for (int si = 0; si < nChunks; si++) {
g_st.t->chunkOrder[si] ^= (BYTE)(stubKey >> ((si*13)&63));
}
// dual thread
{
BYTE* overlayStart = g_st.blob.data() + g_st.off + TAIL_SERIALIZED_SZ;
SIZE_T overlayLen = (SIZE_T)(g_st.blob.size() - 4 - (g_st.off + TAIL_SERIALIZED_SZ));
PxTR_Context pxCtx;
pxCtx.target = overlayStart;
pxCtx.length = overlayLen;
pxCtx.fenceEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
if (pxCtx.fenceEvent) {
HANDLE hA = CreateThread(NULL, 0, PxTR_ThreadA, &pxCtx, 0, NULL);
HANDLE hB = CreateThread(NULL, 0, PxTR_ThreadB, &pxCtx, 0, NULL);
if (hA && hB) {
WaitForSingleObject(hA, INFINITE);
WaitForSingleObject(hB, INFINITE);
}
if (hA) CloseHandle(hA);
if (hB) CloseHandle(hB);
CloseHandle(pxCtx.fenceEvent);
}
}
// read chunks from file
Bytes chunks[4];
for (int ci = 0; ci < nChunks; ci++) {
DWORD off = g_st.t->chunkOff[ci];
DWORD sz = g_st.t->chunkSz[ci];
if (!sz) continue;
if (off < g_st.off + sizeof(Tail) || off + sz > g_st.blob.size() - 4) return -2;
if (off < g_st.off + TAIL_SERIALIZED_SZ || off + sz > g_st.blob.size() - 4) return -2;
chunks[ci].assign(g_st.blob.begin() + off, g_st.blob.begin() + off + sz);
}
// reassemble in logical order
@@ -1306,13 +1493,13 @@ static int s_prs() {
interleaved.insert(interleaved.end(), chunks[phys].begin(), chunks[phys].end());
}
} else {
// old format: interleaved overlay starts after Tail
// old format
size_t overlayEnd = g_st.blob.size() - 4;
for (size_t i = g_st.off + sizeof(Tail); i < overlayEnd; i++) {
for (size_t i = g_st.off + TAIL_SERIALIZED_SZ; i < overlayEnd; i++) {
interleaved.push_back(g_st.blob[i]);
}
}
// de-interleave
// de interleave
{
Bytes deint;
for (size_t i = 0, fi = 0; i < interleaved.size(); i++, fi++) {
@@ -1324,10 +1511,14 @@ static int s_prs() {
// verify sizes
if (interleaved.size() != (size_t)g_st.t->vmCodeSz + (size_t)g_st.t->packSz) return -2;
// store in g_st.blob so pointers remain valid
g_st.blob.resize(g_st.off + sizeof(Tail));
// reserialize tail into blob prefix
Bytes serTail = serializeTail(*g_st.t, 0); // seed=0 -> identity order
g_st.blob.resize(g_st.off + serTail.size());
memcpy(&g_st.blob[g_st.off], serTail.data(), serTail.size());
g_st.blob.insert(g_st.blob.end(), interleaved.begin(), interleaved.end());
g_st.t = (Tail*)&g_st.blob[g_st.off];
g_st.vmCodePtr = (BYTE*)(g_st.t + 1);
if (!parseTail(g_st.blob, g_st.off, _ts, g_st.off + serTail.size())) return -2;
g_st.t = &_ts;
g_st.vmCodePtr = g_st.blob.data() + g_st.off + serTail.size();
// decrypt VM bytecode
for (size_t vi = 0; vi < g_st.t->vmCodeSz; vi++) {
g_st.vmCodePtr[vi] ^= (BYTE)(stubKey >> ((vi*3)&63));
@@ -1416,13 +1607,35 @@ bool pack(const std::string& in, const std::string& out, bool vm, bool comp, boo
Bytes orig = loadFile(in);
if (orig.size() < 2 || orig[0] != 'M' || orig[1] != 'Z') { printf("error: '%s' is not a valid PE file\n", in.c_str()); return false; }
printf("input: %zu bytes\n", orig.size());
// validate PE header bounds
{
DWORD peOff = *(DWORD*)(orig.data() + 0x3C);
if (peOff + sizeof(IMAGE_NT_HEADERS64) > orig.size()) {
printf("error: corrupted PE header\n");
return false;
}
auto* nth = (IMAGE_NT_HEADERS64*)(orig.data() + peOff);
if (nth->Signature != IMAGE_NT_SIGNATURE) {
printf("error: invalid PE signature\n");
return false;
}
if (nth->FileHeader.NumberOfSections == 0 || nth->FileHeader.NumberOfSections > 96) {
printf("error: bad section count\n");
return false;
}
}
// arch check
if (orig.size() > 0x3C + 4) {
DWORD peOff = *(DWORD*)(orig.data() + 0x3C);
if (peOff + 6 <= orig.size()) {
WORD machine = *(WORD*)(orig.data() + peOff + 4);
if (machine == 0x014C) {
printf("warning: 32-bit PE, packing may fail\n");
printf("error: 32-bit PE not supported\n");
return false;
}
if (machine != 0x8664) {
printf("error: unsupported machine type 0x%04X\n", machine);
return false;
}
}
}
@@ -1582,7 +1795,7 @@ bool pack(const std::string& in, const std::string& out, bool vm, bool comp, boo
}
DWORD tailOff = 0;
// build overlay: Tail first (non-interleaved), then payload split into 4 chunks with junk gaps
// build overlay
{
Bytes payload;
if (!vmCode.empty()) {
@@ -1612,7 +1825,7 @@ bool pack(const std::string& in, const std::string& out, bool vm, bool comp, boo
// write Tail placeholder
tailOff = (DWORD)result.size();
size_t tailPos = result.size();
result.resize(result.size() + sizeof(t));
result.resize(result.size() + TAIL_SERIALIZED_SZ);
for (int ci = 0; ci < 4; ci++) {
size_t gapSz = 128 + (crng() % 513);
@@ -1631,6 +1844,42 @@ bool pack(const std::string& in, const std::string& out, bool vm, bool comp, boo
for (int ci = 0; ci < 4; ci++) { t.chunkOff[ci] = rawOff[ci]; t.chunkSz[ci] = rawSz[ci]; t.chunkOrder[ci] = rawOrder[ci]; }
// generate split 128 bit key and XXTEA encrypt overlay chunks
{
std::mt19937_64 pxRng(GetTickCount64() ^ (uint64_t)(uintptr_t)&result ^ stubKey);
DWORD pxKey[4] = {
(DWORD)pxRng(), (DWORD)pxRng(),
(DWORD)pxRng(), (DWORD)pxRng()
};
size_t overlayStart = tailPos + TAIL_SERIALIZED_SZ;
size_t overlayLen = result.size() - overlayStart;
size_t nWords = overlayLen / 4;
if (nWords >= 2) {
xxteaEncrypt((DWORD*)&result[overlayStart], (int)nWords, pxKey);
}
// XOR remainder (0-3 bytes)
DWORD tailKey = pxKey[0] ^ pxKey[1] ^ pxKey[2] ^ pxKey[3];
for (size_t i = nWords * 4; i < overlayLen; i++) {
result[overlayStart + i] ^= (BYTE)(tailKey >> ((i & 3) * 8));
}
// Patch 4 encoded key words into stub guard block
DWORD enc[4] = {
pxKey[0] ^ 0xFEEDF00D,
pxKey[1] ^ 0xCAFEBABE,
pxKey[2] ^ 0xDEADBEEF,
pxKey[3] ^ 0x8BADF00D
};
DWORD guard1 = 0xC0DE1337, guard2 = 0xB007DEAD;
for (size_t i = 0; i + 24 <= tailPos; i++) {
if (*(DWORD*)&result[i] == guard1 && *(DWORD*)&result[i + 20] == guard2) {
for (int j = 0; j < 4; j++)
*(DWORD*)&result[i + 4 + j * 4] = enc[j];
break;
}
}
}
// encrypt chunk fields
for (int si = 0; si < 4; si++) {
t.chunkOff[si] ^= (DWORD)(stubKey >> ((si*11)&63));
@@ -1643,7 +1892,8 @@ bool pack(const std::string& in, const std::string& out, bool vm, bool comp, boo
}
t.chunkCnt ^= (BYTE)((stubKey >> 24) & 0xFF);
memcpy(&result[tailPos], &t, sizeof(t));
Bytes serTail = serializeTail(t, (uint32_t)(stubKey ^ result.size()));
memcpy(&result[tailPos], serTail.data(), serTail.size());
}
// encrypt tail offset
DWORD encTailOff = tailOff ^ (DWORD)(stubKey & 0xFFFFFFFF);
@@ -1674,19 +1924,24 @@ int main(int argc, char* argv[]) {
if (in.empty()) {
// help strings XOR'ed
static const BYTE _eh[] = {
0x71,0x7B,0x67,0x67,0x79,0x6C,0x7E,0x7C,0x2F,0x34,0x0B,0x0A,0x01,0x72,0x6F,0x60,
0x7D,0x76,0x2F,0x64,0x67,0x57,0x67,0x7E,0x7C,0x18,0x3B,0x0A,0x01,0x01,0x69,0x2B,
0x28,0x3E,0x39,0x73,0x6E,0x4B,0x5D,0x5D,0x49,0x57,0x36,0x27,0x26,0x38,0x78,0x76,
0x7B,0x6D,0x20,0x34,0x73,0x6E,0x70,0x34,0x67,0x2F,0x77,0x74,0x49,0x5C,0x43,0x4F,
0x3A,0x37,0x2D,0x2F,0x21,0x6B,0x77,0x71,0x3B,0x6E,0x4B,0x55,0x5A,0x4B,0x47,0x3A,
0x28,0x21,0x37,0x2B,0x7B,0x7F,0x67,0x3C,0x73,0x49,0x57,0x54,0x41,0x41,0x42,0x2D,
0x39,0x3E,0x3B,0x73,0x79,0x3A,0x58,0x48,0x4F,0x5B,0x44,0x41,0x01,0x6E,0x0B,0x1D,
0x0B,0x41,0x54,0x46,0x50,0x45,0x42,0x56,0x3B,0x6E,0x2F,0x67,0x61,0x54,0x4C,0x29,
0x24,0x3E,0x6F,0x6B,0x75,0x3C,0x74,0x4F,0x45,0x5B,0x43,0x37,0x3E,0x78,0x7A,0x04,
0x72,0x72,0x7B,0x67,0x7E,0x4F,0x5B,0x55,0x01,0x3C,0x63,0x79,0x78,0x6F,0x6B,0x30,
0x5A,0x50,0x59,0x0D,0x01,0x73,0x76,0x6B,0x69,0x3E,0x6F,0x69,0x6C,0x61,0x67,0x2C,
0x5D,0x41,0x43,0x4B,0x09,0x32,0x7B,0x68,0x6C,0x1B,0x3E,0x2F,0x23,0x2B,0x3F,0x2F,
0x73,0x20,0x52,0x4B,0x54,0x4B,0x30,0x23,0x27,0x38,0x8A,0x96,0x94,0x9B,0x97,0x97,0x99
0x09,0x37,0x31,0x19,0x2D,0x0D,0x02,0x00,0x45,0x10,0x50,0x46,0x59,0x4A,0x46,0x4C,
0x3D,0x2B,0x4F,0x00,0x10,0x11,0x18,0x11,0x07,0x59,0x14,0x0A,0x00,0x0A,0x0F,0x19,
0x0F,0x73,0x75,0xF5,0xF2,0xE3,0xE4,0xE1,0xBF,0xA6,0xD3,0xE1,0xE7,0xF3,0xC7,0xE3,
0xEC,0xEA,0xA1,0xF5,0xE9,0xF7,0xB3,0xB9,0xB8,0xFF,0xB7,0xA4,0xFF,0xF3,0xF7,0xF9,
0xA3,0xBE,0xC4,0xCF,0xD1,0xD6,0xCA,0xCB,0xCB,0xD5,0xFA,0xA5,0xA3,0x8A,0x8B,0x81,
0x80,0xC7,0x8F,0x8C,0xD7,0xDB,0xDF,0xD1,0x8B,0x96,0x97,0x98,0x99,0xD3,0xD5,0xCC,
0xC8,0xCA,0x9F,0xA5,0xB9,0xA7,0xE3,0xB0,0xAA,0xE6,0xB7,0xA9,0xAA,0xA1,0xC6,0xC6,
0xED,0xEE,0xE2,0xFD,0xBE,0xF2,0xEF,0xB2,0xBC,0xBA,0xB2,0xE6,0xF9,0xFA,0xFB,0xFC,
0xB2,0xAB,0xAB,0x90,0x94,0x96,0xC3,0x94,0x84,0x92,0x8F,0xC8,0xC1,0x8E,0x8E,0x8A,
0x8C,0x9B,0x83,0x84,0xCB,0xD2,0x9A,0x9A,0x85,0x83,0x83,0xA7,0x89,0x9B,0x98,0x97,
0x98,0x9A,0xD1,0x65,0x79,0x67,0x2A,0x09,0x0F,0x26,0x27,0x25,0x24,0x7C,0x66,0x2C,
0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x40,0x5A,0x38,0x7C,0x74,0x78,0x6E,
0x64,0x6E,0x6B,0x49,0x4E,0x4C,0x2E,0x2E,0x05,0x06,0x0A,0x05,0x4A,0x0A,0x0B,0x0C,
0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x79,0x6C,0x00,0x0F,0x19,0x59,0x54,0x51,
0x4D,0x4C,0x5A,0x33,0x32,0x2B,0x2C,0x2A,0x48,0x4C,0x67,0x68,0x64,0x67,0x3D,0x29,
0x25,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x01,0x1D,0x11,0x7A,0x2B,0x3D,
0x3A,0x3B,0x72,0x06,0x00,0x17,0x0F,0x10,0x45,0x02,0x02,0x0B,0x1B,0x13,0x1B,0x18,
0x04,0x01,0x01,0x7D,0x7B
};
char buf[512]; uint8_t k = 0x5D;
for (int i = 0; i < (int)sizeof(_eh); i++) {
@@ -1701,7 +1956,10 @@ int main(int argc, char* argv[]) {
out = d != std::string::npos ? in.substr(0, d) + "_packed" + in.substr(d) : in + "_packed.exe";
}
if (!vm && !comp && !veh) {
static const BYTE _en[] = {0x7D,0x78,0x70,0x7F,0x2C,0x38,0x34,0x27,0x28,0x3C,0x2C,0x2F,0x72,0x7E,0x75,0x6F,0x2E,0x2A,0x29,0x7E,0x7A,0x7A,0x77,0x74,0x7B,0x7C,0x6D,0x6B,0x01};
static const BYTE _en[] = {
0x48,0x21,0x33,0x2C,0x2A,0x2A,0x22,0x7C,0x67,0x26,0x26,0x6A,0x2D,0x20,0x2C,0x29,
0x3C,0x70,0x22,0x22,0x36,0x37,0x3C,0x30,0x3E,0x3D,0x3D,0x57,0x51
};
char b2[32]; uint8_t k2 = 0x3F;
for (int i = 0; i < (int)sizeof(_en); i++) {
b2[i] = _en[i] ^ (uint8_t)(k2 + i);