Descifrado de paquete web inverso JS

Descargo de responsabilidad: este artículo es solo para estudio e investigación, y está prohibido usarlo con fines ilegales, de lo contrario, usted será responsable de las consecuencias. Si hay alguna infracción, informe y elimine, ¡gracias!

Prólogo: Puede que mi tecnología no sea muy buena, pero soy muy perezoso, cómo hacerlo de la manera más simple posible, así que si hay un mejor método de descifrado, puede comentar en el área de comentarios ~

Sitio web de destino: este sitio web es muy pobre, no se puede encontrar el campo de verificación y no se puede romper el punto de interrupción XHR.Es muy extraño, pero me atrevo a escribir este artículo, lo que significa que lo he pasado.

Aquí está el sitio web:

aHR0cHM6Ly90b29scy5taWt1LmFjL25vdmVsYWkv

En cuanto a la ingeniería inversa JS, no es más que:

        1. Encuentra parámetros

        2. La ubicación donde se genera el parámetro de posicionamiento

        3. Analizar la lógica de encriptación de los parámetros

        4. Llamada de código de deducción

En cuanto a webpack, si no lo entiendes, puedes leer el siguiente artículo:

https://app.yinxiang.com/fx/970ae39c-9964-4aae-aa96-7e81fee4ef8f

         En pocas palabras, después de ser empaquetados por webpack, todos los recursos se convierten en módulos, que se llaman a través del "cargador (distribuidor)".

Comencemos el proceso inverso:

Abra el sitio web de destino, haga clic en el botón "Iniciar generación" del sitio web de destino más veces y espere a que la generación tenga éxito.Después de comparar varias solicitudes, se puede encontrar que los parámetros de solicitud son los mismos, pero el authsign en la solicitud el encabezado es diferente cada vez, así que juzgue el El parámetro es el parámetro de validación (en realidad es esto).

El primer paso, las reglas antiguas primero buscan globalmente,

Parece que no hay asignación, lo cual es muy extraño,

El segundo paso es localizar la posición del parámetro. En resumen, primero mire la ubicación donde se inició la solicitud (encuéntrela en el iniciador) (de hecho, hay otro método: Js Hook, que se discutirá más adelante)

 Salta aquí, alcanza un punto de interrupción aquí.

 Haga clic en "Iniciar compilación" nuevamente

 Se puede encontrar que hay una t aquí, y los encabezados dentro no saben qué es (los encabezados generales son encabezados de solicitud, por lo que esto es muy sospechoso, recuerde esta t primero), en resumen, presione F10 para omitir la función y continuar ejecutar.

e es una matriz, parece estar atravesando esta matriz, no me importa, no puedo entenderlo de todos modos, luego presione F10 para omitir.

Después de llegar aquí, puede encontrar los parámetros de solicitud aquí, pero no hay ningún "authsign" que queramos, luego presione F10 para saltar hasta que vea los parámetros que necesitamos (Authsign).

Se puede encontrar que la t aparece aquí nuevamente, y los encabezados dentro siguen siendo esos valores. Presione F10 para saltar la función

Bueno, después de saltar, puede encontrar que hay un Authsign adicional en los encabezados de este t aquí. Entonces este Authsign se genera aquí.

Establecemos un punto de interrupción aquí, cancelamos otros puntos de interrupción y hacemos clic en "Iniciar generación" nuevamente,

Después de detenernos aquí, presionamos F9 para ejecutar paso a paso (F10 es para ejecutar a través de funciones),

Ejecución paso a paso aquí, imprímalo, puede encontrar que este es el lugar donde se generan los parámetros de cifrado, y ahora se ha ubicado.

Hablemos de otro método: JS Hook

Necesita instalar una extensión  en el navegador : oil monkey (Violentmonkey)

        Abra el complemento para crear un nuevo script: la función de este script es ingresar al estado del depurador cuando se establece el encabezado de solicitud especificado.

        Más guiones: ( https://www.jb51.net/article/241736.htm )

// ==UserScript==
// @name        tools.miku
// @namespace   Violentmonkey Scripts
// @match       https://*/*
// @grant       none
// @version     1.0
// @author      -
// @description 2022/11/4 08:39:59
// ==/UserScript==
var code = function(){
var org = window.XMLHttpRequest.prototype.setRequestHeader;
window.XMLHttpRequest.prototype.setRequestHeader = function(key,value){
    if(key=='Authsign'){
        debugger;
    }
    return org.apply(this,arguments);
}
}
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

Luego actualice la página e inicie el script. Haga clic en "Iniciar generación" nuevamente y verá que se detendrá aquí, lo que indica que "Authsign está configurado en Encabezado" en este momento.

 Luego comenzamos a rastrear la pila. El propósito del rastreo de la pila también es encontrar la ubicación donde se generan los parámetros cifrados.

La pila de llamadas es la persona que llama del código actual y la persona que llama de la persona que llama . Para decirlo sin rodeos, el programa ejecuta todas las operaciones anteriores aquí, y el valor "Authsign" se establece aquí, y la pila se rastrea de arriba a abajo. La parte superior es la posición actual y la parte inferior es la posición de la llamada anterior. Si no sabe cómo hacerlo, solo puede encontrar un tutorial sobre la búsqueda de pilas por su cuenta.

Finalmente, después de perseguir este h.request, es el mismo que ingresó el lanzador. Presione F10 para ver paso a paso, donde se agrega "Authsign", sígalo y ubique la posición del parámetro encriptado.

Luego, como dije hace un momento, ubique después de los parámetros de encriptación.

A través de la observación, se puede encontrar que este es un paquete webpack. El packaging de webpack es muy característico, y hay un distribuidor.

f es , y y se define arriba,  y = nn(f), bien.

A continuación, comenzamos a ajustar el código, primero establecemos un punto de interrupción aquí en y=nn(f) y actualizamos la página (los módulos se cargan al principio, por lo que actualizamos la página en lugar de hacer clic en "Iniciar generación")

Después de romperlo, salta a n. Puede pasar el mouse sobre n y saltar a este método, o puede imprimir n directamente en la consola y luego hacer doble clic para saltar a este método.

 

 Puede ver que este es el llamado cargador (distribuidor) de webpack

Copiamos directamente todo el archivo js. Algunos tutoriales pueden decir que solo copiar el cargador es suficiente. De hecho, no es el caso. Podemos encontrar que nuestro y = nn (f) es nn, y n es la función o, que es equivalente a on (f), buscamos este archivo js, ​​podemos encontrar que on se define a continuación, por lo que necesitamos copiarlos todos en lugar de solo copiar el cargador.

 Cree un nuevo archivo js y péguelo aquí.

Defina un señor de variable global. Cambie la última d() a lorder=o, la última d() es una función de entrada, no la necesitamos, así que podemos usar lorder para hacer o afuera. Luego cambiamos la forma de matriz a forma de objeto y construimos dos métodos para probarla.

 Algo salió mal. la ventana no está definida. la ventana no está definida, definamos una var window={} al principio; 

 Luego, ejecútelo nuevamente y salga con éxito, lo que indica que no hay ningún problema con nuestro cargador.

Bien, copiemos el método que necesitamos, f=n(267), y=nn(f), lo mismo, actualice la página para saltar y luego copie el método. Podemos ver que n(267) no es un método.

 En este momento, saltamos a n, que es el cargador, alcanzamos un punto de interrupción, actualizamos la página y luego imprimimos la función con el subíndice 267 en la consola, e es la matriz de funciones, es decir, e[267].

Después de saltar, descubrí que todo el módulo js en el interior es diferente de los demás (esto tiene la forma de una matriz), y hay un montón de funciones llamadas en él. No me importan en este momento. Copiar uno por uno es demasiado agotador. Por supuesto, si te gusta una copia también está bien, pero recuerda cambiar la forma del objeto al subíndice correspondiente, eso es todo.

No lo demostraré aquí, usamos el método perezoso para escupirlo con un solo clic. Primero ubique el comienzo de js donde se encuentra e[267] Todos los módulos que comienzan con this son archivos de módulos empaquetados en webpack.

También copiamos el módulo js y lo colocamos en nuestro cargador (tenga en cuenta que nuestro cargador js debe copiarse nuevamente desde el navegador, debe estar sin cambios, es decir, sin Lorder).

 Entonces necesitas usar el reverso rápido del pescador. Esta es la dirección del proyecto del tipo grande.

Documentos · maestro · pescado / webpack_ast · GitCode

Falta de dependencias para complementar las dependencias , creé un archivo a.js en esta carpeta ast y luego copié el js que escribimos (cargador y módulo de matriz) a a.js.

Luego abra cmd para ingresar a la carpeta ast y ejecute el comando:

nodo webpack_mixer.js -l a.js -o webpack_out.js

 Si se informa un error, se complementará la falta de dependencias y, después de la operación exitosa, habrá un archivo extra webpack_out.js, que es un módulo en forma de objeto.

Luego copie el js nuevamente a nuestro propio js, ​​y el jefe también nos ayudó cuidadosamente a generar variables globales para que las llamemos (export_function = o;), aquí hay otro visto bueno para el jefe.

 La n en el código es equivalente a la función o, y o está asignada a la variable global export_function, es decir, n(267)=o(267)=export_function(267), ahí está el método 267, y luego mira abajo,

También definimos n(267), y y,

Luego está la función m, que está definida arriba, y la copiamos, en resumen, es para compensar lo que falta.

Después de ejecutar, hay una excepción nuevamente. Cuando vemos esta excepción, sabemos que falta una función y no sabemos qué función falta, por lo que agregamos el código console.log(c) al cargador, donde c es el subíndice, y se puede decir que es el nombre del objeto, para que sepa en qué función informó un error y qué función falta. 

 emmm, funcion 51

Las viejas reglas, ingrese el decorador y establezca un punto de interrupción 

Luego salte al método No. 51 y copie todo el módulo js en el cargador. Tenga en cuenta que nuestro cargador js debe copiarse nuevamente en el navegador. Al igual que el anterior, también es cmd para ingresar a la carpeta ast y ejecutar el comando:

 nodo webpack_mixer.js -l a.js -o webpack_out.js

 Luego, simplemente copie los módulos en el archivo js de salida a nuestro propio módulo js loader.

 ¡Recuerde separar los métodos con comas!

 Después de guardarlo, guárdelo y ejecútelo, y vuelva a informar de un error. e no está definido, 

 Averigüemos de dónde viene e. Mirando hacia arriba, puede encontrar que e está aquí, que es el parámetro del método.

 

 Luego miramos de dónde vienen los parámetros de este método, mirando hacia atrás, podemos encontrar que es .call(this, n(262), n(51)), es decir, e es n(262), o es n(51).

Bien, entonces también definimos un e=n(262), lo guardamos y lo ejecutamos de nuevo, y reportamos un error nuevamente, r no está definido, lo mismo, encuentra dónde está definido r

 Encontrado justo al principio,

También definamos r, r=n(56), guardemos y ejecutemos e informemos un error, o no está definido, o es el n(51) justo ahora, definámoslo y luego guardemos y ejecutemos e informemos un error. .

En e = decodeURIComponent(l); aquí se reporta un error, URIError: URI malformed, esto es muy extraño, mira si falta algo. Bueno, podemos ver que, de hecho, hay algunas definiciones de parámetros por encima de esta m, no la tenemos, así que agréguela.

 Bueno, después de agregarlo, todavía guarda y ejecuta e informa un error, pero no es el error de ahora, esta vez es d(...)(...)[m(...)] no es una función , vea dónde d es ¿Qué definición? ¿Hay alguna operación redundante?

Entonces puedes ver que hay una operación después de la definición de d, daextend(_.a), y _ = nn(m), m = n(568),

También agregamos estas definiciones, todavía guardar y ejecutar e informar un error, el documento no está definido,

 Esta excepción es diferente de la ventana, y no funciona si se definió anteriormente. En resumen, intentemos definir arriba, var document={}, puede ver que se imprime f, pero aún hay un problema, lo que indica que el atributo "words" no está definido, y words es un atributo de f,

 En resumen, imprímalo y compárelo con el navegador, m("8", "fUV&") es dominio, que es el nombre de dominio, es decir, la salida de documento[dominio] no está definida,

 Mira el navegador,

 Por lo tanto, dado que nuestro programa no puede obtener el nombre de dominio del documento del navegador, podemos usar el valor muerto directamente. Después de cambiarlo, guárdelo y ejecútelo, y vuelva a informar un error. Hay un problema con el módulo de cifrado.

 Imprimamos para ver qué es el cifrado, y podemos ver que es el método de cifrado AES,

Los parámetros ya existen, nos referimos a la biblioteca de cifrado de nodejs,

var CryptoJS = require("crypto-js");

Crypto-js se instala solo, y luego también se cambia el siguiente cifrado, guardar y ejecutar 

 ¡El arduo trabajo valió la pena y finalmente el cifrado fue exitoso! Ponlo en apipost y pruébalo.Es raro que no haya datos.¿Hay algún problema con los datos cifrados?

 Después de incansables esfuerzos, finalmente se encontró que

 Hay un problema con el documento[m("3", "jx9[")] de esta f. Dije antes que nuestro programa no puede acceder al documento del sitio web, así que imprimámoslo para ver qué valor se necesita.

Se puede ver que también es un nombre de dominio, por lo que nuestro documento [m ("3", "jx9 [")] también debe reemplazarse con 'tools.miku.ac', guarde y ejecute,

Vuelva a colocar los datos cifrados en Apipost, esta vez la solicitud es más larga (gran alegría),

Podéis ver que la web devuelve la imagen en formato base64, ¡y por fin es todo un éxito!

Pego el código de descifrado del núcleo, pero los módulos intermedios no se pegarán (demasiados),

var CryptoJS = require("crypto-js");
var document = {}
var export_function;
!function (e) {
    //这里是加载器代码
}({
    //这里是模块代码
});
module.exports = export_function;
e = export_function(262)
o = export_function(51)
r = export_function(56)
f = export_function(267)
y = export_function.n(f)
h = (export_function(37), export_function(91), export_function(92), export_function(25), export_function(123), export_function(49))
d = export_function.n(h)
m = export_function(568)
_ = export_function.n(m)
d.a.extend(_.a)
var n, l, h = ["jsjiami.com.v6", "jsjSiamtirN.coEmh.Fulv6YWfbWzOB==", "bALCr8KoHEA=", "w7BQDcKBPMO7", "wqw8W8OFT1XDnw==", "TcKFbsOIw7oTwqnDrQ==", "wqM3w7c=", "w6TCqsKDw6PCsMOaRA==", "wq9Qw7rDpcKRZg==", "w7Msw5zDtsORCsOJIw==", "OlPDoQ==", "IsOIWMOowpvCtHdD"];
n = h,
    l = 448,
    function (e, t, o, r) {
        if ((t >>= 8) < e) {
            for (; --e;)
                r = n.shift(),
                    t === e ? (t = r,
                        o = n.shift()) : o.replace(/[StrNEhFulYWfbWzOB=]/g, "") === t && n.push(r);
            n.push(n.shift())
        }
    }(++l, 114688);
var m = function t(n, c) {
    n = ~~"0x".concat(n);
    var l = h[n];
    if (void 0 === t.RVAulw) {
        !function () {
            var t = "undefined" != typeof window ? window : "object" === (void 0 === e ? "undefined" : Object(r.a)(e)) && "object" === (void 0 === o ? "undefined" : Object(r.a)(o)) ? o : this;
            t.atob || (t.atob = function (e) {
                for (var t, n, o = String(e).replace(/=+$/, ""), r = 0, c = 0, l = ""; n = o.charAt(c++); ~n && (t = r % 4 ? 64 * t + n : n,
                    r++ % 4) ? l += String.fromCharCode(255 & t >> (-2 * r & 6)) : 0)
                    n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(n);
                return l
            }
            )
        }();
        t.hRdDHj = function (e, t) {
            for (var n, o = [], r = 0, c = "", l = "", h = 0, d = (e = atob(e)).length; h < d; h++)
                l += "%" + ("00" + e.charCodeAt(h).toString(16)).slice(-2);
            e = decodeURIComponent(l);
            for (var m = 0; m < 256; m++)
                o[m] = m;
            for (m = 0; m < 256; m++)
                r = (r + o[m] + t.charCodeAt(m % t.length)) % 256,
                    n = o[m],
                    o[m] = o[r],
                    o[r] = n;
            m = 0,
                r = 0;
            for (var _ = 0; _ < e.length; _++)
                r = (r + o[m = (m + 1) % 256]) % 256,
                    n = o[m],
                    o[m] = o[r],
                    o[r] = n,
                    c += String.fromCharCode(e.charCodeAt(_) ^ o[(o[m] + o[r]) % 256]);
            return c
        }
            ,
            t.gjhasZ = {},
            t.RVAulw = !0
    }
    var d = t.gjhasZ[n];
    return void 0 === d ? (void 0 === t.PPSXqK && (t.PPSXqK = !0),
        l = t.hRdDHj(l, c),
        t.gjhasZ[n] = l) : l = d,
        l
}
_ = d()()[m("0", "ZLEd")]()[m("1", "1)V^")]()
f = y.a[m("2", "ise7")]("" + _ + 'tools.miku.ac');
authsign=f + "." + CryptoJS.AES.encrypt(_, 'tools.miku.ac')[m("9", "6lDQ")]()
console.log(authsign)

Este artículo es para hacer un registro para mí y, por supuesto, todos son bienvenidos a aprender y comunicarse.

Supongo que te gusta

Origin blog.csdn.net/qq_51502150/article/details/127879654
Recomendado
Clasificación