Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
px-vm — Kit di reverse engineering per la VM bytecode di PerimeterX, con un disassemblatore basato su CFG, pipeline di decrittazione a 5 livelli, ricostruzione della tabella degli opcode e pulitore di emulazione stack per la ricerca sulla sicurezza nel fingerprinting del rilevamento bot. | Kitploit
Strumenti/GitHubGitHub/b9ph0met/px-vm
Analisi Dinamica (Sandboxing)Evasione IDS/IPSReverse EngineeringSicurezza WebAnalisi MalwareCrittografiaAnalisi di BinariPaper e RicercaApprendimento e FormazioneAnti-BotSpoofing dell'Impronta Digitale
55144 mesi faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
GitHub
b9ph0met/px-vm

px-vm

Kit di reverse engineering per la VM bytecode di PerimeterX, con un disassemblatore basato su CFG, pipeline di decrittazione a 5 livelli, ricostruzione della tabella degli opcode e pulitore di emulazione stack per la ricerca sulla sicurezza nel fingerprinting del rilevamento bot.

Vedi Repository

Analisi della VM di PerimeterX Auditor

Riepilogo

Questo repository documenta il reverse engineering di auditor.js di PerimeterX, una macchina virtuale basata su bytecode utilizzata come livello secondario di fingerprinting nella pipeline di rilevamento bot di PX. Questa analisi copre:

  • Estrazione del bytecode e pipeline di decrittazione a 5 livelli
  • Ricostruzione della tabella degli opcode (107 base + 40 honey + 24 padding + 16 gruppi di superistruzioni)
  • Decrittazione del pool di costanti (1230 voci, 1095 stringhe crittate)
  • Disassemblatore basato su CFG con risoluzione dei sotto-dispatch delle superistruzioni
  • Pulitore tramite emulazione dello stack che produce pseudo-codice leggibile
  • Tecniche anti-analisi: honey opcode, istruzioni sovrapposte, hashing dell'integrità del codice

Nota: Questo repository copre solo una versione (statica) della VM ed è inteso per scopi di ricerca sulla sicurezza e analisi. Non include solver dinamici o implementazioni di solver per produzione.

Contesto

Giovedì 2 aprile 2026, PerimeterX ha distribuito una nuova VM basata su bytecode come parte della loro pipeline di rilevamento bot.

Cosa contiene

auditor.js non assomiglia a un normale script sensore PX. Invece delle solite ricerche di proprietà offuscate e funzioni di raccolta:

  • 8 enormi stringhe base64 (_fg0 a _fg7), il programma VM crittato suddiviso tra variabili
  • Una funzione di decrittazione XOR (_dp) con una chiave per sito (_pk) che decomprime il JSON del programma
  • Un shuffle di Fisher-Yates che permuta la tabella degli opcode in modo che i valori del bytecode differiscano per build
  • Un ciclo di dispatch con 107+ gestori di caso, l'interprete della VM
  • Aritmetica BigInt per la crittografia RSA dell'output del fingerprint
  • Un hash di integrità del codice (_0x8df7) che esegue l'hash del codice sorgente della VM per derivare una chiave di decrittazione, in modo che qualsiasi modifica rompa silenziosamente la decrittazione del bytecode

Passo 1: Estrazione del bytecode

Il programma VM è suddiviso in 8 variabili, concatenate e poi decrittate tramite _dp() usando un cifrario XOR per sito con chiave _pk:

root@kitploit:~
var _pk = 893686289;
function _dp(_b) {
    var _r = atob(_b), _o = new Array(_r.length);
    for (var _i = 0; _i < _r.length; _i++) {
        _o[_i] = String.fromCharCode(
            _r.charCodeAt(_i) ^ (((_pk >>> (8 * (_i % 4))) ^ Math.imul(_i + 1, 0x6B8B4567)) & 0xFF)
        );
    }
    return _o.join("");
}

Il risultato è un oggetto JSON con nomi di chiave offuscati di due caratteri (es. "uo" per seed, "dk" per nonce). Una tabella di mappatura li converte in nomi standard.

root@kitploit:~
node extractor.js
# -> program.json

Struttura del programma

Passo 2: Decrittazione delle costanti

Tutte le 1095 stringhe costanti sono crittate con due livelli:

Livello 1: Murmur XOR statico con chiave 4008000571, dipendente dalla posizione.

Livello 2: XOR del flusso PRNG utilizzando un LCG di glibc, inizializzato combinando il seed del programma con l'indice di ogni costante tramite l'hash moltiplicativo di Knuth.

Prima della decrittazione, il seed viene XORato con un impronta ambientale (_0xaf48), una maschera di bit a 8 bit calcolata sondando le API del browser:

Per Chrome: _0xaf48 = 0b01111111 = 127, dando seed effettivo = 12755 ^ 127 = 12716.

Ciò significa che lo stesso programma produce risultati di decrittazione diversi in ambienti diversi. Eseguirlo in Node.js vs Chrome vs Firefox produce seed diversi.

root@kitploit:~
node decrypt_constants.js
# -> program_decrypted.json, constants_table.txt

Cosa rivelano le costanti

Le stringhe decrittate ci dicono esattamente cosa la VM sta raccogliendo come fingerprint:

Fingerprinting del browser: screenWidth, screenHeight, innerWidth, innerHeight, devicePixelRatio, colorDepth, platform, userAgent, language, timezone, timezoneOffset, forcedColors, highContrast

Tempi di performance: navigationStart, domComplete, domLoading, fetchStart, requestStart, responseEnd, secureConnectionStart, serverTiming

Crittografia RSA: BigInt, modPow, AQAB (65537 in base64), modulusLength, shiftLeft, shiftRight, getRandomValues

Sondaggio DOM/SVG: http://www.w3.org/2000/svg, createElementNS, getBoundingClientRect, getTotalLength, getBBox

Nomi dei campi PX: mtr, tst, mst, enc, sbx, fstec, pdc, prb, wvi, wva, pti, dis, los, cv, sc, jd, , ,

Riferimenti endpoint: https://fst-ec.perimeterx.net/?id=

Anti-debugger: _CMP_RCX_07;_JNZ_0x0A_EB_CC, CC|CD-04|BREAKPOINT-005

Passo 3: Tabella degli opcode

107 opcode base che coprono l'intero linguaggio JavaScript, più rumore generato dinamicamente:

40 honey opcode sono implementazioni alternative di operazioni aritmetiche/di confronto che utilizzano espressioni matematicamente equivalenti ma sintatticamente diverse. ADD potrebbe apparire come (a^b) + 2*(a&b) o -((-a)-b) o a-(-b). Ogni opcode base può avere fino a 3 varianti, generate deterministicamente dal seed. Una semplice istruzione ADD può apparire come 4 diversi valori di bytecode all'interno dello stesso programma, rompendo gli approcci di pattern-matching.

24 padding opcode sono allocati nella permutazione ma non hanno gestori e non vengono mai emessi. Esistono per espandere lo spazio degli opcode e rendere più difficile invertire lo shuffle.

16 gruppi di superistruzioni sono la caratteristica anti-analisi più importante. Quando il ciclo di dispatch risolve un opcode in un leader di superistruzione, il gestore legge un byte aggiuntivo dal flusso di bytecode e lo invia a un sotto-gestore. Il sotto-gestore può essere un'operazione completamente diversa:

La tabella degli opcode viene mescolata tramite Fisher-Yates inizializzato con il seed effettivo, quindi i valori del bytecode differiscono per build.

root@kitploit:~
node build_opcodes.js
# -> opcode_table.json, opcode_table.txt

Passo 4: Costruttore CFG

Il nucleo del toolkit. cfg.js costruisce un grafo di flusso di controllo seguendo tutti i percorsi di esecuzione da PC=0, decodificando ogni istruzione con il corretto contesto di crittazione.

Perché non un disassemblatore lineare

PX utilizza istruzioni sovrapposte ai confini dei blocchi. Gli stessi byte vengono decodificati come operandi su un percorso di esecuzione e come opcode su un altro, a seconda del contesto di crittazione del blocco. Una scansione lineare decodifica ogni posizione di byte una volta e perde il percorso alternativo. Il CFG segue sia i bordi di fall-through che quelli di salto, decodificando ogni percorso indipendentemente.

Crittografia del bytecode a cinque livelli

  1. Livello 1 (_0x3ca8): Murmur XOR statico sui byte raw base64, con chiave 4008000571
  2. Livello 2 (_0xece1): XOR per funzione con due sottolivelli: chiave statica dipendente dalla posizione + chiave dell'hash di integrità del codice
  3. Livello 3 (_0x427d): XOR rolling per blocco. Ogni blocco di crittazione (definito dai confini fn.bl) ottiene un XOR aggiuntivo derivato dalla chiave della funzione e dall'indice del blocco. Il blocco 0 non è crittato al primo accesso; i blocchi 1+ sono crittati. Questo è il motivo per cui un disassemblatore lineare funziona per il primo blocco ma produce spazzatura per i blocchi successivi.
  4. Permutazione degli opcode: Fisher-Yates shuffle + offset dipendente dalla posizione + offset dipendente dal blocco
  5. XOR degli operandi per istruzione: I byte degli operandi vengono XORati con una chiave derivata dalla posizione di inizio dell'istruzione

Il CFG applica tutti e cinque i livelli in modo non distruttivo (lo XOR degli operandi viene calcolato al volo, non in-place) in modo che le regioni di istruzioni sovrapposte non si corrompano a vicenda.

Risoluzione delle superistruzioni

Per ogni leader di superistruzione, il CFG legge il sotto-byte, cerca il gestore effettivo in super_groups.json e decodifica l'operando per il vero opcode. I target di salto da opcode di salto fusi (es. ciò che sembra ASSIGN_OP_VAR ma è in realtà JMP) vengono seguiti correttamente.

root@kitploit:~
node cfg.js        # tutte le funzioni -> cfg_output/
node cfg.js 79     # singola funzione su stdout

Verificato rispetto a tracce di esecuzione del browser: 600 istruzioni tracciate in 14 funzioni, 0 discrepanze nei delta dello stack. Tutti i 34 opcode unici validati. Il dispatch delle superistruzioni confermato corretto per tutti i 10 gruppi leader eseguiti durante l'inizializzazione.

Passo 5: Pulitore

Prende l'output del CFG ed esegue l'emulazione dello stack per produrre commenti di espressione. Trasforma il bytecode grezzo in pseudo-codice leggibile.

root@kitploit:~
node cleaner.js 79     # fn79 su stdout

Scorre le istruzioni in ordine, tracciando uno stack virtuale. Ogni push/pop/call costruisce una stringa di espressione:

root@kitploit:~
  0018  GET_VAR                 ; 0.0001
  001e  GET_VAR                 ; or
  0024  PUSH_CONST              ; "_0x166"
  002b  CALL_METHOD_C           ; 0.0001._0x88(or, "_0x166")
  ...
  0114  PUSH_CONST              ; "fontSize"
  011b  PUSH_CONST              ; "pdc"
  0122  CALL_METHOD_C           ; _0x18c.getHours("fontSize", "pdc")

Solo il rumore puramente aritmetico/di confronto su uno stack vuoto viene soppresso. Tutto il resto viene mantenuto poiché il CFG ha già filtrato honey e padding.

112 funzioni, 5435 istruzioni mantenute, 207 rumori soppressi. fn79 (il raccoglitore di fingerprint, 1109 istruzioni) ha l'85% di copertura dei commenti di espressione.

Architettura della VM

VM basata su stack con stack a 256 slot, catena di scope, catena di gestori try/catch e stack di iteratori for-in. Il ciclo di dispatch legge opcode LE a 2 byte, risolve tramite permutazione + XOR di posizione + offset di blocco, decritta gli operandi in-place, esegue il gestore, poi ricritta gli operandi in modo che il bytecode non sia mai completamente decrittato in memoria.

Risultati principali

  • Crittografia RSA dell'output del fingerprint utilizzando BigInt, modPow, esponente 65537
  • Fingerprinting del rendering SVG tramite getTotalLength() e getBBox() su percorsi costruiti
  • Raccolta completa della cascata performance.timing
  • Marcatori di rilevamento anti-debugger (CC|CD-04|BREAKPOINT-005)
  • La funzione 79 è il raccoglitore principale di fingerprint (8361 byte, ~1200 istruzioni)

Note

L'IA è stata utilizzata per aiutare a documentare il codice, scrivere strumenti e redigere questo readme.

Disclaimer

Puramente per scopi educativi/ricerca sulla sicurezza. Nessun solver o bypass, solo documentazione di come funziona la VM perché è genuinamente interessante.

Se qualcuno di PerimeterX/HUMAN Security ha preoccupazioni riguardo a questo repo, non esiti a contattarmi: [email protected]

Scarica lo strumento
CampoDescrizione
sSeed (12755), guida tutte le operazioni crittografiche
nNonce (1603730985), randomizzazione per programma
gFlag generatore, abilita il livello di decrittazione con hash di integrità
xFlag crittato, le costanti sono crittate con XOR
cPool di costanti, 1230 voci
fFunzioni, 112 voci con bytecode crittato
ePunto di ingresso, indice funzione 0
BitTestChrome
0typeof window.matchMedia === "function"1
1document.elementFromPoint esiste1
2typeof window.requestAnimationFrame === "function"1
3typeof window.getComputedStyle === "function"1
4CSS.supports esiste1
5navigator.sendBeacon esiste1
6document.execCommand esiste1
7process.versions.node esiste (Node.js)0
ads
enve
init
Leader si risolve comeSotto-byteEffettivamente esegue
FOR_IN_NEXT74FOR_IN_NEXT
FOR_IN_NEXT100MAKE_CLOSURE
ASSIGN_OP_VAR165ASSIGN_OP_VAR
ASSIGN_OP_VAR37JMP
GET_VAR_PROP_C143SET_VAR_POP
GET_VAR_PROP_C23JMP_NULLISH