업데이트로 돌아가기
New releaseAug 12, 2026

TinyLoad v7.3

오픈소스 Windows x64 PE 패커 및 크립터. 커스텀 가상 머신으로 실행 파일을 압축·암호화하여 자체 추출 스텁(self-extracting stub)으로 만듭니다.

공유

github-social-preview

TinyLoad v7.4 - Windows용 PE 패커 및 크립터

build Mentioned in Awesome

TinyLoad는 x64 실행 파일용 PE 크립터/패커로, 입력된 exe를 다양한 보호 레이어로 패킹하여 리버스 엔지니어링을 방지합니다. 단일 .cpp 파일로 구성되어 있으며 외부 종속성이 없습니다.

작동 방식

TinyLoad는 페이로드를 자신의 복사본에 추가합니다. 패킹된 exe가 실행되면 페이로드를 추출하고, 복호화한 다음, 원본을 디스크에 기록하지 않고 메모리에서 직접 실행합니다. 패킹할 때마다 VM opcode가 무작위로 변경되어 4개의 독립적인 키를 가진 하위 테이블에 배치되므로 두 빌드가 동일하지 않습니다.

pack() 파이프라인
flowchart TD
    start["pack(in, out, vm, comp, veh, noconsole)"] --> load["loadFile(in) → orig"]
    load --> pe{"MZ + PE00 + Machine 0x8664 + NumberOfSections in 1..96?"}
    pe -->|fail| err["printf error / return false"]
    pe -->|ok| init["pay = orig    flags = 0"]
    
    init --> cdec{"--c ?"}
    cdec -->|yes| lz["flags |= 1<br/>lzPack: WINDOW=0xFFFF  MAXCHAIN=4096<br/>MAXMATCH=258  MINMATCH=3  HSIZE=65536<br/>hash4 = FNV-ish fold * 0x1000193<br/>lazy lookahead la = 1,2<br/>out = uint32le origSz + 8-token flag bytes<br/>match → varint dist, varint len-3"]
    cdec -->|no| vmq
    lz --> vmq{"--vm ?"}

    vmq -->|yes| scatter["flags |= 2<br/>Fisher-Yates 32 slots, scatter NUM_OPS=28<br/>into subtables 4x8, unused stay 0xFF<br/>opmap_enc op = tbl shl 6 OR idx"]
    scatter --> canary["canary corridor n=8, skip first 0x400 of pay<br/>canExp c = pay at off XOR prev"]
    canary --> mkvm["makeVmProgram opmap_enc, key1, key2, canary<br/>key1,key2 ← mt19937_64 TickCount64 XOR QPC<br/>opaque predicates + stream loop + canary mask"]
    mkvm --> venc["vmEncryptPayload  192-bit state<br/>k3 = 0x9E3779B97F4A7C15<br/>ks = uint8((k1 XOR k2) + k3)<br/>b = NOT(b XOR ks)<br/>k1 = rotl64(k1,11) XOR k2<br/>k2 = rotr64(k2,19) + k1 + k3<br/>k3 = k3 * phi XOR k1"]
    vmq -->|no| vehq
    venc --> vehq{"--veh ?"}

    vehq -->|yes| vflag["flags |= FLAG_VEH 4"]
    vehq -->|no| stub
    vflag --> stub["stub = loadFile GetModuleFileNameA self<br/>saveFile out, stub as host image"]

    stub --> skey["stubKey = 0x9E3779B97F4A7C15<br/>for i in 0x1000 .. min n, 0x2000:<br/>stubKey = (stubKey XOR stub i) * phi"]
    skey --> disp["prime vmRun dispKey=0 → fill g_off<br/>dispKey ← rng<br/>encOff j = uint64(g_off j) XOR dispKey"]

    disp --> tail["Tail: sig TINYLD60, origSz, packSz, flags,<br/>dispOff x28, subtables 4x8, vmCodeSz,<br/>dispKey, canary*, chunk*,<br/>payHash = SHA-256 orig first 8B"]
    tail --> hide["sig i XOR= stubKey shr 8i<br/>xorOpmap FNV-1a 0x811C9DC5 / 0x01000193<br/>feeds origSz, packSz, vmCodeSz + first 32B<br/>of vmCode and pay, per-table<br/>flags |= FLAG_CHUNK 8"]
    hide --> tenc["XOR-encode Tail fields with stubKey slices<br/>vmCode vi XOR= stubKey shr ((vi*3) and 63)"]

    tenc --> ovl["payload = vmCode || pay<br/>interleave: insert 0x00 after every 3 bytes"]
    ovl --> chunks["split into 4 chunks, shuffle physical order<br/>Tail placeholder TAIL_SERIALIZED_SZ = 419<br/>before each chunk: 128..640 RNG junk"]
    chunks --> tea["xxteaEncrypt bytes after Tail<br/>DELTA=0x9E3779B9  rounds=6+52/n<br/>remainder XOR pxKey0 xor pxKey1 xor pxKey2 xor pxKey3<br/>patch k i XOR FEEDF00D / CAFEBABE /<br/>DEADBEEF / 8BADF00D into _pxBlock<br/>between C0DE1337 and B007DEAD"]
    tea --> ser["XOR chunkOff / chunkSz / chunkOrder / chunkCnt<br/>serializeTail: 16 TLV records id + u16le sz + bytes<br/>Fisher-Yates order, LCG 1103515245+12345<br/>seed = stubKey XOR filesize<br/>append DWORD LE: tailOff XOR stubKey low 32"]

    ser --> fin{"--noconsole ?"}
    fin -->|yes| gui["OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI"]
    fin -->|no| scr
    gui --> scr["scrambleSections: cycle names<br/>.text .data .rdata .bss .idata"]
    scr --> done["saveFile out, result"]

다운로드

releases에서 미리 컴파일된 바이너리를 받거나 직접 빌드하세요.

소스에서 빌드하기

MinGW(g++)가 필요합니다. 다음을 실행하세요:

g++ -o TinyLoad.exe TinyLoad.cpp -static -O2 -s

또는 build.bat을 사용하세요.

사용법

TinyLoad.exe --i <input> [--o <output>] [--vm] [--c] [--veh]
플래그기능
--i <file>패킹할 입력 exe
--o <file>출력 경로 (기본값: input_packed.exe)
--vmVM 암호화
--cLZ77 압축
--vehVEH 페이지 폴트 복호화
--noconsoleGUI 서브시스템

--vm, --c, --veh 중 최소 1개는 필요합니다.

예시

2026-08-1118-55-14-ezgif com-video-to-gif-converter

DIE 이미지

die-gui-packed die-gui-entropy

압축

해시 체인 매칭과 64KB 슬라이딩 윈도우를 사용하는 커스텀 LZ77 압축입니다. 압축이 먼저 실행된 다음 VM 암호화가 그 위에 적용되므로 압축된 데이터의 패턴도 숨겨집니다.

VM 암호화

스텁 내부에서 실행되는 커스텀 28 opcode 가상 머신입니다. opcode는 8개씩 4개의 하위 테이블에 무작위로 배치되며, 각 하위 테이블은 페이로드 데이터에서 파생된 서로 다른 키로 XOR 암호화됩니다. 1개의 하위 테이블을 크래킹해도 28개 중 최대 8개의 opcode만 드러납니다. 암호 자체는 rotl과 rotr 키 믹싱을 사용하는 128비트 스트림 암호로, 전적으로 VM 인터프리터 내부에서 실행됩니다. 페이로드는 XXTEA로 암호화됩니다.

VEH 페이지 폴트 복호화

--veh를 활성화하면 모든 PE 섹션 페이지가 PAGE_NOACCESS로 매핑됩니다. 프로그램이 페이지에 접근하려고 하면 예외가 발생하고, 벡터 예외 처리기가 해당 1개 페이지만 복호화한 후 올바른 보호를 설정합니다. 워치독 스레드가 백그라운드에서 실행되어 200ms 동안 접근되지 않은 페이지를 다시 암호화합니다. 어느 순간에도 프로그램의 대부분은 메모리에서 암호화된 상태로 유지되므로 메모리 덤프는 최근에 접근된 부분만 캡처할 수 있습니다.

안티 덤프

가장 중요한 4개의 API(GetModuleHandleA, GetProcAddress, ExitProcess, VirtualAlloc)가 스텁 내부의 래퍼 함수를 통해 리다이렉트됩니다. 페이로드가 로드된 후 전체 임포트 디렉토리가 0으로 초기화되어 메모리 덤프가 임포트 테이블을 재구성할 수 없습니다.

라이선스

MIT

참고 사항

  • readme에 넣지 않은 많은 기능이 있습니다. 코드를 직접 읽거나 changelog.md를 확인하세요.
  • 제가 테스트한 대부분의 파일에서 작동합니다. 만약 파일에서 오류가 발생하면 이슈를 열어주시면 확인하겠습니다.
  • 제안 및 기능 아이디어도 이슈로 올려주세요.
  • 사용하신다면 스타 하나가 큰 도움이 됩니다 <3
  • 네, AV가 패커를 플래그하는 것은 예상된 결과입니다. (현재 virustotal에서 9개 탐지가 있으며, 패킹하는 모든 파일은 콘텐츠와 무관하게 9개 탐지가 발생합니다)
  • 악성코드를 패킹하지 마세요. 이 도구는 합법적인 목적을 위한 것입니다.

카테고리