Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
px-vm — Kit de ingeniería inversa para la máquina virtual de bytecode de PerimeterX, que incluye un desensamblador basado en CFG, un pipeline de descifrado de 5 capas, reconstrucción de tabla de códigos de operación y un limpiador de emulación de pila para la investigación de seguridad sobre la huella digital de detección de bots. | Kitploit
Herramientas/GitHubGitHub/b9ph0met/px-vm
Análisis Dinámico (Sandboxing)Evasión de IDS/IPSIngeniería InversaSeguridad WebAnálisis de MalwareCriptografíaAnálisis de BinariosPapers e InvestigaciónAprendizaje y EducaciónAnti-BotSuplantación de Huella Digital
5514hace 4 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
GitHub
b9ph0met/px-vm

px-vm

Ver Repositorio

Acerca de

Kit de ingeniería inversa para la máquina virtual de bytecode de PerimeterX, que incluye un desensamblador basado en CFG, un pipeline de descifrado de 5 capas, reconstrucción de tabla de códigos de operación y un limpiador de emulación de pila para la investigación de seguridad sobre la huella digital de detección de bots.

Compartir

Análisis de la VM de Auditor de PerimeterX

Resumen

Este repositorio documenta la ingeniería inversa de auditor.js de PerimeterX, una máquina virtual de bytecode utilizada como capa secundaria de huellas digitales en el pipeline de detección de bots de PX. Este análisis cubre:

  • Extracción de bytecode y pipeline de descifrado de 5 capas
  • Reconstrucción de tabla de opcodes (107 base + 40 honey + 24 padding + 16 grupos de superinstrucciones)
  • Descifrado del pool de constantes (1230 entradas, 1095 cadenas cifradas)
  • Desensamblador basado en CFG con resolución de sub-despacho de superinstrucciones
  • Limpiador de emulación de pila que produce pseudocódigo legible
  • Técnicas anti-análisis: opcodes honey, instrucciones superpuestas, hash de integridad de código

Nota: Este repositorio cubre solo una versión (estática) de la VM y está destinado a fines de investigación y análisis de seguridad. No incluye solucionadores dinámicos ni implementaciones de solucionadores de producción.

Antecedentes

El jueves 2 de abril de 2026, PerimeterX implementó una nueva VM de bytecode como parte de su pipeline de detección de bots.

Qué hay dentro

auditor.js no parece un script de sensor PX normal. En lugar de las habituales búsquedas de propiedades ofuscadas y funciones de recolección:

  • 8 cadenas base64 masivas (_fg0 a _fg7), el programa VM cifrado dividido en variables
  • Una función de descifrado XOR (_dp) con una clave por sitio (_pk) que desempaqueta el JSON del programa
  • Un barajado Fisher-Yates que permuta la tabla de opcodes para que los valores de bytecode difieran por compilación
  • Un bucle de despacho con más de 107 manejadores de casos, el intérprete de la VM
  • Aritmética BigInt para el cifrado RSA de la salida de huellas digitales
  • Un hash de integridad de código (_0x8df7) que hashea la propia fuente de la VM para derivar una clave de descifrado, de modo que cualquier modificación rompe silenciosamente el descifrado del bytecode

Paso 1: Extracción de bytecode

El programa VM está dividido en 8 variables, concatenado y luego descifrado mediante _dp() usando un cifrado XOR por sitio con clave _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("");
}

El resultado es un objeto JSON con nombres de clave de dos caracteres ofuscados (por ejemplo, "uo" para seed, "dk" para nonce). Una tabla de mapeo los convierte a nombres estándar.

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

Estructura del programa

Paso 2: Descifrado de constantes

Todas las 1095 constantes de cadena están cifradas con dos capas:

Capa 1: XOR murmur estático con clave 4008000571, dependiente de la posición.

Capa 2: XOR de flujo PRNG usando un LCG glibc, sembrado combinando la semilla del programa con el índice de cada constante mediante el hash multiplicativo de Knuth.

Antes del descifrado, la semilla se XOR con una huella digital del entorno (_0xaf48), una máscara de bits de 8 bits calculada probando APIs del navegador:

Para Chrome: _0xaf48 = 0b01111111 = 127, lo que da una semilla efectiva = 12755 ^ 127 = 12716.

Esto significa que el mismo programa produce diferentes resultados de descifrado en diferentes entornos. Ejecutarlo en Node.js vs Chrome vs Firefox produce diferentes semillas.

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

Lo que revelan las constantes

Las cadenas descifradas nos dicen exactamente qué huellas digitales recoge la VM:

Huellas digitales del navegador: screenWidth, screenHeight, innerWidth, innerHeight, devicePixelRatio, colorDepth, platform, userAgent, language, timezone, timezoneOffset, forcedColors, highContrast

Temporización de rendimiento: navigationStart, domComplete, domLoading, fetchStart, requestStart, responseEnd, secureConnectionStart, serverTiming

Criptografía RSA: BigInt, modPow, AQAB (65537 en base64), modulusLength, shiftLeft, shiftRight, getRandomValues

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

Nombres de campos PX: mtr, tst, mst, enc, sbx, fstec, pdc, prb, wvi, wva, pti, dis, los, cv, sc, jd, , ,

Referencias de endpoints: https://fst-ec.perimeterx.net/?id=

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

Paso 3: Tabla de opcodes

107 opcodes base que cubren todo el lenguaje JavaScript, más ruido generado dinámicamente:

40 opcodes honey son implementaciones alternativas de operaciones aritméticas/de comparación usando expresiones matemáticamente equivalentes pero sintácticamente diferentes. ADD puede aparecer como (a^b) + 2*(a&b) o -((-a)-b) o a-(-b). Cada opcode base puede tener hasta 3 variantes, generadas deterministicamente a partir de la semilla. Una simple instrucción ADD puede aparecer como 4 valores diferentes de bytecode dentro del mismo programa, rompiendo enfoques de coincidencia de patrones.

24 opcodes de relleno se asignan en la permutación pero no tienen manejadores y nunca se emiten. Existen para expandir el espacio de opcodes y hacer que el barajado sea más difícil de invertir.

16 grupos de superinstrucciones son la característica anti-análisis más importante. Cuando el bucle de despacho resuelve un opcode a un líder de superinstrucción, el manejador lee un byte adicional del flujo de bytecode y despacha a un sub-manejador. El sub-manejador puede ser una operación completamente diferente:

La tabla de opcodes se baraja mediante Fisher-Yates con semilla efectiva, por lo que los valores de bytecode difieren por compilación.

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

Paso 4: Constructor de CFG

El núcleo del kit de herramientas. cfg.js construye un grafo de flujo de control siguiendo todas las rutas de ejecución desde PC=0, decodificando cada instrucción con el contexto de cifrado correcto.

Por qué no un desensamblador lineal

PX usa instrucciones superpuestas en los límites de los bloques. Los mismos bytes se decodifican como operandos en una ruta de ejecución y como opcodes en otra, dependiendo del contexto de cifrado del bloque. Un escaneo lineal decodifica cada posición de byte una vez y pierde la ruta alternativa. El CFG sigue tanto los bordes de caída como los de salto, decodificando cada ruta de forma independiente.

Cifrado de bytecode de cinco capas

  1. Capa 1 (_0x3ca8): XOR murmur estático sobre bytes base64 crudos, con clave 4008000571
  2. Capa 2 (_0xece1): XOR por función con dos subcapas: clave estática dependiente de posición + clave de hash de integridad de código
  3. Capa 3 (_0x427d): XOR rodante por bloque. Cada bloque de cifrado (definido por los límites de fn.bl) obtiene un XOR adicional derivado de la clave de la función y el índice del bloque. El bloque 0 no está cifrado en el primer acceso; los bloques 1+ están cifrados. Por eso un desensamblador lineal funciona para el primer bloque pero produce basura para los bloques siguientes.
  4. Permutación de opcodes: Barajado Fisher-Yates + desplazamiento dependiente de posición + desplazamiento dependiente de bloque
  5. XOR de operandos por instrucción: Bytes de operando con XOR con una clave derivada de la posición de inicio de la instrucción

El CFG aplica las cinco capas de forma no destructiva (el XOR de operandos se calcula sobre la marcha, no en el lugar) para que las regiones de instrucciones superpuestas no se corrompan entre sí.

Resolución de superinstrucciones

Para cada líder de superinstrucción, el CFG lee el sub-byte, busca el manejador real en super_groups.json y decodifica el operando para el opcode real. Los destinos de salto de opcodes de salto fusionados (por ejemplo, lo que parece ASSIGN_OP_VAR pero en realidad es JMP) se siguen correctamente.

root@kitploit:~
node cfg.js        # all functions -> cfg_output/
node cfg.js 79     # single function to stdout

Verificado contra trazas de ejecución del navegador: 600 instrucciones trazadas en 14 funciones, 0 discrepancias en deltas de pila. Los 34 opcodes únicos validados. El despacho de superinstrucciones confirmado correcto para los 10 grupos líderes que se ejecutaron durante la inicialización.

Paso 5: Limpiador

Toma la salida del CFG y ejecuta emulación de pila para producir comentarios de expresiones. Convierte el bytecode crudo en pseudocódigo legible.

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

Recorre las instrucciones en orden, rastreando una pila virtual. Cada push/pop/call construye una cadena de expresión:

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 se suprime el ruido puramente aritmético/de comparación en una pila vacía. Todo lo demás se mantiene ya que el CFG ya filtró honey y padding.

112 funciones, 5435 instrucciones mantenidas, 207 ruidos suprimidos. fn79 (el recolector de huellas digitales, 1109 instrucciones) tiene un 85% de cobertura de comentarios de expresiones.

Arquitectura de la VM

VM basada en pila con pila de 256 ranuras, cadena de ámbito, cadena de manejadores try/catch y pila de iteradores for-in. El bucle de despacho lee opcodes de 2 bytes en little-endian, resuelve mediante permutación + XOR de posición + desplazamiento de bloque, descifra operandos en el lugar, ejecuta el manejador y luego vuelve a cifrar operandos para que el bytecode nunca se descifre completamente en memoria.

Hallazgos clave

  • Cifrado RSA de la salida de huellas digitales usando BigInt, modPow, exponente 65537
  • Huellas digitales de renderizado SVG mediante getTotalLength() y getBBox() en rutas construidas
  • Recopilación completa de cascada performance.timing
  • Marcadores de detección anti-depurador (CC|CD-04|BREAKPOINT-005)
  • La función 79 es el recolector principal de huellas digitales (8361 bytes, ~1200 instrucciones)

Notas

Se ha utilizado IA para ayudar a documentar el código, escribir herramientas y redactar este readme.

Descargo de responsabilidad

Puramente con fines educativos/de investigación en seguridad. Sin solucionadores ni bypasses, solo documentando cómo funciona la VM porque es genuinamente interesante.

Si alguien de PerimeterX/HUMAN Security tiene inquietudes sobre este repositorio, no dude en contactar: [email protected]

Descargar herramienta
CampoDescripción
sSemilla (12755), impulsa todas las operaciones criptográficas
nNonce (1603730985), aleatorización por programa
gIndicador de generador, habilita la capa de descifrado de hash de integridad
xIndicador cifrado, las constantes están cifradas con XOR
cPool de constantes, 1230 entradas
fFunciones, 112 entradas con bytecode cifrado
ePunto de entrada, índice de función 0
BitPruebaChrome
0typeof window.matchMedia === "function"1
1document.elementFromPoint existe1
2typeof window.requestAnimationFrame === "function"1
3typeof window.getComputedStyle === "function"1
4CSS.supports existe1
5navigator.sendBeacon existe1
6document.execCommand existe1
7process.versions.node existe (Node.js)0
ads
enve
init
El líder se resuelve comoSub-byteRealmente ejecuta
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