Basic positioning skills of JS reverse

Limited space

Full content and source code: official account: ReverseCode, send punch

When we get a website, the first thing is the implementation of packet capture positioning encryption parameters. This paper will complete the analysis of encryption parameters through common positioning schemes combined with practical cases.

Search key parameters

This is the most common and simplest location scheme. After F12 opens the website console, Ctrl+Shift+F opens the search panel, such as searching the password parameter or submit function

password:`,`password=`,`password =`request url´╝îSearch method`var submit`perhaps`function submit`perhaps`submit:

to8to

There are too many search password locations, because the packet capture request is new_login.php

Search for new in the Element panel_ Login.php, ctrl+shift+f search loginCheck

In this method, jq('#rsa_userNum').val(rsaString(password));, Call the rsaString method to encrypt the password

function rsaString(str) {
    return encodeURIComponent(RSAUtilszb.encryptfun(str));
}

Enter the JS defined by encryptfun, and rsa encrypts at least 2000 lines, but the method is only 163 lines. Copy the JS, load the code through the JS debugging tool in the special tool for programming cat, and report an error. Reference error: window is not defined, add var window = this;, Error: reference error: JSEncrypt is not defined, add var JSEncrypt = JSEncryptExports.JSEncrypt; in the original JS;, Error reporting reference error: JSEncryptExports is undefined. Search var JSEncryptExports and VaR JSEncryptExports = {}; Added to JS debugging tool, error type error: JSEncrypt is not a constructor

Try to hit the breakpoint, but you can't enter the breakpoint every time, which means that it must be dynamically loaded js, and there will be a timestamp every time the js suffix is refreshed. Check Disable cache, open fiddler to capture packets, copy js to local to realize http spoofing, select the request, click autoresponder add rule drop-down, select Find a File, find the locally saved js and open the rule

Because the address of each JS request is different, regular matching regex:https://static\.to8to\.com/gb_js/to8torsaszb\.js\?_=\d + save the rule and reissue the request https://static.to8to.com/gb_js/to8torsaszb.js?_=1628128571412, spoofing network request JS using local JS

The error JSEncrypt is not a constructor is reported before formatting the entire js. Jsencrypt is export ed from the compressed js above

Add the above compressed code to the JS debugging tool of the programming cat, load the code, report the error reference error: navigator is not defined, add var navigator = {}, report the error reference error: window is not defined, add var window =this, because if you report the error ASN1 undefined with window = {}, and use this, you can get all the variable functions in the current JS.

dom element event listener

Exclude the Remove nodes of the buttons one by one through the Event Listeners in the Elements of the console until the last event listener invalidates the button and gets the js position where the button really takes effect.

China Tobacco New Business Alliance

The following is the implementation of this j function through dom element event listening_ Logical location analysis of mcmm encryption parameters.

In the above, set breakpoints in as many places as possible, listen to the element event, locate jsmain-9826b285f8fad5a5.js, format JS in the lower left corner, add breakpoints, and view all variable values by ctrl on the JS page

Hover over the mouse or print it out on the console, click to enter the method declaration, mark the breakpoint for the function in the same line, and press F8 for one-step debugging to complete the positioning of encryption parameters

xhr breakpoint

By locating the contracting function and stack, copy the URL request path to XHR/fetch Breakpoints under Sources to support regular.

Seven wheat data

Through the key encryption parameter analysis, the search is fruitless. Try to add XHR breakpoints in Sources and take the request path as the breakpoint content

Trace the call stack after the XHR breakpoint, and check whether the input and output parameters of each call stack contain encrypted analysis until they enter Promise asynchronous l.request, and debug to n.then(t.shift(), t.shift()),then as the asynchronous function of Promise, promise.then(onCompleted, onRejected);, Shift () calls the methods in t one by one. The parameter is the return value of the previous method. At the same time, deleting the method is equivalent to queue first in first out. Print t on the console, enter one method by one, and mark the breakpoint

In l.prototype.request, the analysis encryption parameter has not been generated yet. Enter the t method one by one

After executing r().interceptors.request.use, the generated a is analysis. Observe the logic in the code to complete encryption analysis. a=(0,n.cv)((0,n.oZ)(r, l)) is a comma expression. According to the analysis above, n.cv and n.oZ are functions, r and L are variables, which can be reduced to n.cv(n.oz(r,l)).

Get the functions in n through the console

window = global;
window.document = {
    cookie: ''  // Bring your own cookie s here
}
function i(e) {
    var t, a = (t = "",
        ["66", "72", "6f", "6d", "43", "68", "61", "72", "43", "6f", "64", "65"].forEach((function (e) {
                t += unescape("%u00" + e)
            }
        )),
        t);
    return String[a](e)
}
function s() {
    return unescape("861831832863830866861836861862839831831839862863839830865834861863837837830830837839836861835833".replace(/8/g, "%u00"))
}
var n = {
    oZ: function g(e, t) {
        t || (t = s());
        for (var a = (e = e.split("")).length, n = t.length, o = "charCodeAt", r = 0; r < a; r++)
            e[r] = i(e[r][o](0) ^ t[(r + 10) % n][o](0));
        return e.join("")
    },
    cv: function h(e) {
        return function (e) {
            try {
                return btoa(e)
            } catch (t) {
                return Buffer.from(e).toString("base64")
            }
        }(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (function (e, t) {
                return i("0x" + t)
            }
        )))
    },
    ej: function u(e) {
        var t, a = new RegExp("(^| )" + e + "=([^;]*)(;|$)");
        return (t = document.cookie.match(a)) ? unescape(t[2]) : null
    }
}

Since btoa is essentially base64 encryption, after introducing CryptoJS.pad.js

function base64(data) {
 var wordArray = CryptoJS.enc.Utf8.parse(data);
 var base64_data = CryptoJS.enc.Base64.stringify(wordArray);
 return base64_data
}
var n = {
    oZ: function g(e, t) {
        t || (t = s());
        for (var a = (e = e.split("")).length, n = t.length, o = "charCodeAt", r = 0; r < a; r++)
            e[r] = i(e[r][o](0) ^ t[(r + 10) % n][o](0));
        return e.join("")
    },
    cv: function h(e) {
        return function (e) {
            try {
                return base64(e)
            } catch (t) {
                return Buffer.from(e).toString("base64")
            }
        }(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (function (e, t) {
                return i("0x" + t)
            }
        )))
    },
    ej: function u(e) {
        var t, a = new RegExp("(^| )" + e + "=([^;]*)(;|$)");
        return (t = document.cookie.match(a)) ? unescape(t[2]) : null
    }
}

Restore the logic in try/catch

var l = "00000008d78d46a"
var d = "@#"
var e = {
    // url: "/rank/indexPlus/brand_id/1",
    url: "/rank/indexPlus/brand_id/" + pg,    // 1. Free list 0. Paid list 2. Best seller list
    baseURL: "https://api.qimai.cn",
}
var c = {
    default: function On(e) {
        this._init(e)
    }
}
var u = "synct"
var t = (0, n.ej)(u);
var m = "syncd"
var f = f = c.default.prototype.difftime = -(0, n.ej)(m) || +new Date - 1e3 * t
var o = +new Date - (f || 0) - 1515125653845
var r = []
r = r.sort().join(""), r = (0, n.cv)(r), r += d + e.url.replace(e.baseURL, ""), r += d + o, r += d + 1,
a_ = (0, n.cv)((0, n.oZ)(r, l))
return a_

Initiator stack trace

The Initiator of the contract request under the Network, such as the top-level breakpoint of the jquery stack (it may be requested many times to find the breakpoint entered when the contract request is found), re request to find the js formatting breakpoint belonging to the target website in the stack.

e-netcom

Log in to capture packets, open the Initiator, and enter the code line located at the top of the stack

Set the breakpoint, check the call stack on the right, and call the bottom layer method by method until the react library js finds the preLogin, finds the location where the password appears, and sets the breakpoint

When logging in again, enter the breakpoint and find the password

Enter the encryption method, aes encryption

Open the Crypto class in WT-JS, copy key and iv, and output in HEX format. The comparison result is standard AES encryption.

See aes.js for the implementation of AES encryption and decryption based on base64 or hexadecimal

Changfang Group

Search J_ After password, interrupt and log in again

Enter desEncrypt, and the approximate encryption completion logic is in this function

In the encryption logic, first get the key according to SECURITYKEY.get(), first get the str through the back end of the request, judge whether the encryption type is aes, then intercept the string and convert it to hexadecimal through toHexString to get the key, iv and security

After sorting out the logic deduction JS and reporting an error, CryptoJS is not defined. Click to enter the CryptoJS.AES.encrypt deduction aes.js source code

function getdes(encodeType) {
    // Request "/ resource / JS / session. JSP? = 1628210376229" to return
    var str = "E55A433905551AC39DB3165591D9CD74";
    if (encodeType == null || encodeType == 'aes') {
        if (str.length < 32) {
            str += "abcdefghijklmnopqrstuvwxyz1234567890"
        }
        str = str.toUpperCase();
        var key = {};
        key.key = str.substring(0, 16);
        key.iv = str.substring(16, 32);
        key.security = "\u4435\u5320\u4d35"
    } else {
        if (str.length < 16) {
            str += "abcdefghijklmnopqrstuvwxyz"
        }
        str = str.toUpperCase();
        var key = {};
        key.key = toHexString(str.substring(0, 8));
        key.iv = toHexString(str.substring(8, 16));
        key.security = "\u4445\u5320\u4d45"
    }
    return key
}
function getPwd(value, type) {
    var keyObj = {};
    if (type == null || "aes" == type.toLowerCase()) {
        keyObj = getdes()
        value = CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(keyObj.key), {
            iv: CryptoJS.enc.Utf8.parse(keyObj.iv)
        }).toString()
    } else {
        keyObj = getdes()('des');
        value = CryptoJS.DES.encrypt(value, CryptoJS.enc.Hex.parse(keyObj.key), {
            iv: CryptoJS.enc.Hex.parse(keyObj.iv)
        })
    }
    return keyObj.security + value
}

Install the programming cat plug-in

  • Fiddler version must be > = v4.6.3. Copy the special plug-in for Fiddler programming cat to the Scripts directory under the fiddler program directory. Example: C: \ program files (x86) \ fiddle2 \ Scripts

Iqiyi

  1. Covering primitive function
  function xxx(){
      console.log("1111")
  }
  var xxx_ = xxx;
  xxx = function(){
      console.log("2222")
  }
  window.alert = function(){console.log("?")}
  console.clear = function(){console.log("?")}
  setInterval = function(){}
  1. Object.defineProperty replaces object property (getter.setter)
  (function () {
      var a = "";
      Object.defineProperty(document, 'cookie', {
          set: function (val) {
              console.log('Hook Capture cookie set up->', val);
              a = val;
              return val;
          },
          get: function(){
              return a;
          }
      });
  })();
  document.cookie = "1"  // set up
  document.cookie  // obtain
  1. The opportunity of hook is to inject a hook into the console and refresh the web page. Filter the js of the Network and find the first loaded js. Right click Open in Sources panel to format the first line of breakpoints. However, some cookies may be generated asynchronously in html. Inject more than one hook into the console, clear the cookies and inject hook manually, Find the VM virtual machine in the console, find the js of our hook, and mark the breakpoint. Each hook will pass through the set. You can view the call stack on the right and trace the source and encryption method of the cookie. (it is possible to inject hook later than some asynchronous requests or js in html)

  1. fiddler is used to replace all requests and responses, and the special tool for programming cat is used to inject hook

(function () {
    'use strict';
    Object.defineProperty(document, 'cookie', {
        set: function (val) {
            if (val.indexOf("__dfp") != -1) {
                debugger;
            }
            console.log('Hook Capture cookie set up->', val);
            return val;
        }
    });
})();

Next, check the call stack and finally save it to window.name.

(function () {
    'use strict';
    var a = "";
    Object.defineProperty(window, 'name', {
        set: function (val) {
            debugger;
            a = val;
            console.log('Hook Capture cookie set up->', val);
            return val;
        }, 
        get: function(){
            return a;
        }
    });
})();

After entering iqiyi again, the breakpoint completes the hook location, so that the cookie generation logic can be analyzed according to the call stack.

This paper is based on the operation tool platform of blog group sending one article and multiple sending OpenWrite release

Tags: frida

Posted on Sun, 05 Dec 2021 01:50:37 -0500 by happypete