Simulación de Entorno RUIS 6: Cinco Estrategias Fundamentales para Construir una Cadena de Proxy DOM Robusta
Recientemente, mientras analizaba sitios web que emplean técnicas de seguridad dinámica, el mecanismo anti-rastreo de RUIS 6 representó un desafío significativo en el trabajo de igneniería inversa. A diferencia del ofuscamiento de código estático tradicional, RUIS 6 utiliza mecanismos de detección de entorno en tiempo de ejecución más complejos, especialmente una supervisión profunda de las API del DOM del navegador. Muchos principiantes que intentan construir entornos a menudo caen en un ciclo de "arreglado A pero falta B", resultando en un entorno extenso que aún no supera las detecciones. Este artículo no presenta fragmentos de código simples, sino un método sistemático para construir una cadena de proxy DOM completa, un método que he verificado en múltiples proyecots prácticos, que puede mejorar significativamente la tasa de éxito y estabilidad de la simulación del entorno.
1. Comprendiendo la Lógica de Detección de Entorno de RUIS 6
La detección de entorno de RUIS 6 no es una simple verificación de atributos, sino un proceso de verificación de llamadas en cadena. No solo verifica si document.createElement existe, sino que también comprueba si el elemento creado tiene la cadena de prototipos correcta, si las llamadas a métodos devuelven tipos de objetos esperados, e incluso realizará pruebas de acceso a propiedades en los objetos devueltos.
1.1 Multinivel de Detección
Las detecciones de RUIS 6 generalmente se dividen en tres niveles:
- Existencia de API básica - Verifica si los objetos globales como
window,document,navigatorexisten - Integridad funcional de la API - Comprueba si las llamadas a la API devuelven los tipos y estructuras de objetos correctos
- Detección de llamadas en cadena de objetos - Realiza acceso profundo a propiedades y llamadas a métodos en los objetos devueltos
// Ejemplo típico de detección en cadena
const elemento = document.createElement('div');
const elementosHijos = elemento.getElementsByTagName('i');
const longitud = elementosHijos.length;
// Aquí se detectará el valor devuelto por getElementsByTagName y la propiedad length
1.2 Puntos de Detección Comunes
Basado en mi experiencia, RUIS 6 presta especial atención a los siguientes aspectos de detección:
| Categoría de Detección | API Específica | Punto de Detección |
|---|---|---|
| Operaciones DOM | createElement |
Cadena de prototipos del objeto devuelto, propiedades enumerables |
| Operaciones DOM | getElementsByTagName |
Estructura similar a una matriz del valor devuelto, propiedad length |
| Operaciones DOM | appendChild/removeChild |
Contexto y parámetros durante la llamada al método |
| Características del Navegador | document.all |
Comportamiento especial similar a una matriz y propiedad length |
| Características del Navegador | navigator.webdriver |
Existencia y valor de la propiedad |
| Sistema de Eventos | addEventListener |
Llamada al método y manejo de eventos |
Nota: Las detecciones de RUIS 6 cambian dinámicamente, los puntos focales pueden variar entre diferentes sitios web y momentos. Por lo tanto, construir una cadena de proxy robusta es más importante que aplicar parches para puntos de detección específicos.
2. Construcción del Marco de Proxy Básico
El núcleo de la construcción de entornos es la apliacción del patrón proxy. Necesitamos crear un sistema que pueda interceptar todos los accesos a propiedades y llamadas a métodos, de modo que cuando RUIS 6 intente detectar una propiedad o método, podamos responder oportunamente con valores adecuados.
2.1 Creación de Función Proxy Genérica
Suelto comenzar creando una función proxy genérica que pueda manejar la mayoría de los escenarios de detección comunes:
class ProxyEntorno {
constructor(objetivo, nombre = 'desconocido') {
this._objetivo = objetivo;
this._nombre = nombre;
this._registroAcceso = new Set();
return new Proxy(objetivo, {
get: (obj, prop) => {
// Registrar acceso para depuración
this._registroAcceso.add(prop);
console.log(`[Proxy ${this._nombre}] Acceso a propiedad: ${String(prop)}`);
// Si el objeto tiene la propiedad, devolverla directamente
if (prop in obj) {
const valor = obj[prop];
// Si el valor es una función, enlazar el this correcto
if (typeof valor === 'function') {
return valor.bind(obj);
}
return valor;
}
// Manejar acceso a propiedades especiales
switch (prop) {
case 'length':
return 0;
case 'nodeType':
return 1;
case 'toString':
return () => `[object ${this._nombre}]`;
default:
// Para propiedades no definidas, devolver un nuevo proxy
// Esto soporta llamadas en cadena como a.b.c.d
const nuevoObj = {};
return new ProxyEntorno(nuevoObj, `${this._nombre}.${String(prop)}`);
}
},
set: (obj, prop, valor) => {
console.log(`[Proxy ${this._nombre}] Establecer propiedad: ${String(prop)} = ${valor}`);
obj[prop] = valor;
return true;
},
apply: (objetivo, thisArg, argumentos) => {
console.log(`[Proxy ${this._nombre}] Llamada a función, argumentos:`, argumentos);
// Manejar diferentes llamadas según el nombre de la función
if (objetivo.name === 'getElementsByTagName') {
return []; // Devolver array vacío
}
if (objetivo.name === 'addEventListener') {
return undefined; // Las escuchas de eventos generalmente no devuelven valor
}
// Por defecto devolver un objeto proxy
return new ProxyEntorno({}, `${this._nombre}()`);
}
});
}
// Obtener registro de acceso para analizar puntos de detección
obtenerRegistroAcceso() {
return Array.from(this._registroAcceso);
}
}
2.2 Inicialización de Proxies de Objetos Globales
Con la clase proxy base, necesitamos proxyizar los objetos globales clave:
// Crear proxy básico de window
const crearProxyWindow = () => {
const ventanaFalsa = {
// Propiedades básicas
innerWidth: 1920,
innerHeight: 1080,
outerWidth: 1936,
outerHeight: 1056,
// Marcadores de posición de objetos clave
document: null, // Se establecerá más tarde
navigator: null,
location: null,
// Propiedades de función
setTimeout: (fn, retraso) => {
console.log