
例1
URL:https://www.gm99.com/
对登录界面的password进行逆向分析。
在这个例子中直接搜索"password:"就可以定位到关键代码,当然也可用其它方法进行定位:
password就是o,o是通过a.encode(t.password, s)方法产生的,打上断点重新登录,查看参数具体值,其中t.password就是输入的密码,s是时间戳:
查看encode具体代码,发现代码在3模块中:
可以看到使用了 jsencrypt,并且有 setPublicKey 设置公钥方法,很明显采用的加密方法是RSA加密。在进行逆向分析时需要了解常见加密方法加密过后的密文长度,这样有利于对代码的快速定位。MD5加密后的密文长度是16位或是32位;SHA1加密后的密文长度是40位;如果是其它长度的大概率是RSA加密,但是也有可能是其它加密方法或者编码。在没有混淆代码的情况下,大部分的RSA加密是通过三个步骤进行的:
var o = new JSEncrypt;
o.setPublicKey(""),
o.encrypt();
所以本例子可以通过搜索encrypt,setPublicKey进行快速定位。打上断点继续跟踪encrypt具体代码,该方法是在4模块中:
这就是password加密的的大致过程,了解加密过程后就是扒取代码了,先去看JS代码最开始的一部分,发现是代码是模块化的,通过一个加载器加载。call()
或者 apply()
方法的就是模块加载器,可以通过它们调用模块的方法:
直接复制加载器的相关代码:
然后用到哪个模块就复制该模块到后面的大括号中,encode是在3模块中,在3模块中又调用了4模块,所以要复制两个模块。这里的i就是函数加载器,这里的模块是数字,不需要加双引号,如果是字母等形式需要加上,如var r = i("a"):
直接复制两个模块,然后创建一个全局变量en导出自执行函数中的方法:
然后创建一个自定义函数进行调用:
补全window和navigator不然会报错:
补全之后运行,报错ASN1 is not defined:
ASN1是一个JS解码器,一般浏览器内置的,大部分js调试器是没有的。在浏览器里面 window 其实就是 nodejs中的global,在 nodejs 里没有 window,所以在 nodejs 环境中可以将 window 定义为 global,如果定义为空,可能会报错。所以在这里将var window = this改为var window = global,再次运行就不会报错了:
例2
URL:https://ec.minmetals.com.cn/open/home/purchase-info
刷新页面(采购信息)就可看到param:
可以看到加密过后的数据很长,大概率是RSA加密,尝试搜索setPublicKey定位关键代码:
给代码尾部打上断点(方便定位代码和观察各个对象的值),重新刷新界面,断点生效,可以判断搜到的代码就是加密代码:
在console输出t.encryptLong(JSON.stringify(a)),可以看到每次的结果都是不一样的,输出的值就是密文值:
t.encryptLong(JSON.stringify(a))中有两个未对象t和a,这时候需要跟踪t和a是怎么来的,其中t涉及两步:
t = new v["a"]
t.setPublicKey(r)
t.setPublicKey(r)是设置公钥,r就是公钥的值,可以在console中输出,需要的时候直接复制:
t是由v产生,而v= t("9816"):
a是由m方法产生,可以在console输出m方法,点击代码快速定位到m方法:
其中m方法中需要解决e、sign、timeStamp的来源,直接在console中输出e,发现e是一个对象,需要用的时候直接复制即可:
Sign是由f()(JSON.stringify(e))产生的,JSON.stringify()就是将对象转换成一个字符串,在控制台查看f()(JSON.stringify(e))具体是什么,可以发现是一个32位长度的密文,很可能是一个MD5加密:
随便去网上找一个MD5加密方法对JSON.stringify(e)进行加密,发现加密结果和上面一样,可以确定方法就是一个MD5加密:
timeStamp就是一个时间戳,可以在console中输出:
接下来需要扒取代码,给t打上断点,刷新页面,选中t直接跟进去:
发现是一个加载器,很明显是一个webpack,通过加载器加载9816模块:
查看9816模块的具体代码,发现9816模块又使用到a524模块:
首先把加载器所在的方法复制下来,然后补全模块代码,通过一个全局变量gb导出自执行方法中的方法:
然后在创建一个自定义方法模拟加密过程,其中e是一个对象可以直接从console复制;r是公钥也可以从console复制;f方法是MD5加密方法;这里的gb相当于加载器;然后在复制关键步骤代码:
运行之后报错显示m方法未定义,复制m方法到自定义方法中:
m方法调用了d方法和b方法需要继续补全:
运行过后显示encryptLong方法未定义,定位到encryptLong方法后继续补全:
encryptLong方法中又调用了w方法,继续补全w方法,成功运行:
总体代码:
window = this;
var gb;
(function(A){}({
a524: function(e) {},
9816: function(e, t, n) {}
})
function getparem(){
e ={
"inviteMethod": "",
"businessClassfication": "",
"mc": "",
"lx": "ZBGG",
"dwmc": "",
"pageIndex": 1
};
r = '';
function f(string,bit) {}
function b(A, e, t) {}
function w(A) {}
function d(A, e) {}
function m(A) {}
v = gb("9816");
t = new v["a"];
v["a"].prototype.encryptLong = function(A) {}
t.setPublicKey(r);
a = m(m({}, e), {}, {
sign: f(JSON.stringify(e),32),
timeStamp: +new Date
});
s = t.encryptLong(JSON.stringify(a));
return s;
}
a=getparem();
console.log(a)
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)