前言
目前盈包,我們?nèi)粘g覽的網(wǎng)站中,日常會(huì)有防止網(wǎng)站被黑客克隆網(wǎng)站醇王、爬取網(wǎng)站呢燥、壓縮代碼等的需求,都會(huì)使用一些方法對(duì)源碼進(jìn)行處理寓娩。其中叛氨,有的使用Webpack對(duì)JavaScript代碼進(jìn)行打包,也有使用js代碼加密的方法棘伴。因此寞埠,本篇文章將會(huì)對(duì)js代碼加密進(jìn)行一個(gè)簡(jiǎn)單的分析,并主要針對(duì)不可逆加密提供一些常用的近似解密思路焊夸。
JavaScript加密分析
首先仁连,我們能確定的一件事是,無(wú)論加密與否阱穗,加載的js文件都能夠在瀏覽器其中執(zhí)行怖糊,并得到對(duì)應(yīng)的結(jié)果帅容。
有的思路是根據(jù)一些參數(shù)特殊處理進(jìn)行加密,也有的是跟后端達(dá)成協(xié)議伍伤,進(jìn)行加解密的方式得出結(jié)果并執(zhí)行。但是遣钳,后者的方案會(huì)對(duì)我們的服務(wù)造成額外的壓力扰魂,因此使用前者更為主流。因此本篇文章只討論前者這種的方案蕴茴。
近似解密的方案是基于代碼邏輯正確劝评、提高可讀性的方向進(jìn)行的。
這里列舉了一些加密方式(可逆的):
- 最簡(jiǎn)單的加密解密
- 轉(zhuǎn)義字符""的妙用
- 使用Microsoft出品的腳本編碼器Script Encoder來(lái)進(jìn)行編碼
- 任意添加NUL空字符(十六進(jìn)制00H)
- 無(wú)用內(nèi)容混亂以及換行空格TAB大法
- 自寫解密函數(shù)法
對(duì)應(yīng)的加解密思路可以看這里倦淀,我就不一一列舉了
不可逆的加密方式:
根據(jù)各種指定的參數(shù)混淆+不可逆的算法進(jìn)行加密https://www.jsjiami.com/
但是蒋畜,即使是不可逆加密過(guò)后,得出的結(jié)果也是能正常執(zhí)行的撞叽,符合JavaScript的語(yǔ)法的姻成,因此,我們就可以就此對(duì)源碼進(jìn)行翻譯愿棋。
舉個(gè)栗子并分享一個(gè)思路
舉個(gè)栗子
var __encode = 'jsjiami.com', _a = {}, _0xb483 = ["\x5F\x64\x65\x63\x6F\x64\x65", "\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"]; (function (_0xd642x1) { _0xd642x1[_0xb483[0]] = _0xb483[1] })(_a); var __Oxb24bc = ["\x6C\x69\x74\x65\x2D\x61\x6E\x64\x72\x6F\x69\x64\x26", "\x73\x74\x72\x69\x6E\x67\x69\x66\x79", "\x26\x61\x6E\x64\x72\x6F\x69\x64\x26\x33\x2E\x31\x2E\x30\x26", "\x26", "\x26\x38\x34\x36\x63\x34\x63\x33\x32\x64\x61\x65\x39\x31\x30\x65\x66", "\x31\x32\x61\x65\x61\x36\x35\x38\x66\x37\x36\x65\x34\x35\x33\x66\x61\x66\x38\x30\x33\x64\x31\x35\x63\x34\x30\x61\x37\x32\x65\x30", "\x69\x73\x4E\x6F\x64\x65", "\x63\x72\x79\x70\x74\x6F\x2D\x6A\x73", "", "\x61\x70\x69\x3F\x66\x75\x6E\x63\x74\x69\x6F\x6E\x49\x64\x3D", "\x26\x62\x6F\x64\x79\x3D", "\x26\x61\x70\x70\x69\x64\x3D\x6C\x69\x74\x65\x2D\x61\x6E\x64\x72\x6F\x69\x64\x26\x63\x6C\x69\x65\x6E\x74\x3D\x61\x6E\x64\x72\x6F\x69\x64\x26\x75\x75\x69\x64\x3D\x38\x34\x36\x63\x34\x63\x33\x32\x64\x61\x65\x39\x31\x30\x65\x66\x26\x63\x6C\x69\x65\x6E\x74\x56\x65\x72\x73\x69\x6F\x6E\x3D\x33\x2E\x31\x2E\x30\x26\x74\x3D", "\x26\x73\x69\x67\x6E\x3D", "\x61\x70\x69\x2E\x6D\x2E\x6A\x64\x2E\x63\x6F\x6D", "\x2A\x2F\x2A", "\x52\x4E", "\x4A\x44\x4D\x6F\x62\x69\x6C\x65\x4C\x69\x74\x65\x2F\x33\x2E\x31\x2E\x30\x20\x28\x69\x50\x61\x64\x3B\x20\x69\x4F\x53\x20\x31\x34\x2E\x34\x3B\x20\x53\x63\x61\x6C\x65\x2F\x32\x2E\x30\x30\x29", "\x7A\x68\x2D\x48\x61\x6E\x73\x2D\x43\x4E\x3B\x71\x3D\x31\x2C\x20\x6A\x61\x2D\x43\x4E\x3B\x71\x3D\x30\x2E\x39", "\x75\x6E\x64\x65\x66\x69\x6E\x65\x64", "\x6C\x6F\x67", "\u5220\u9664", "\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A", "\u671F\u5F39\u7A97\uFF0C", "\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C", "\x6A\x73\x6A\x69\x61", "\x6D\x69\x2E\x63\x6F\x6D"]; function taskUrl(_0x7683x2, _0x7683x3 = {}) { let _0x7683x4 = + new Date(); let _0x7683x5 = `${__Oxb24bc[0x0]}${JSON[__Oxb24bc[0x1]](_0x7683x3)}${__Oxb24bc[0x2]}${_0x7683x2}${__Oxb24bc[0x3]}${_0x7683x4}${__Oxb24bc[0x4]}`; let _0x7683x6 = __Oxb24bc[0x5]; const _0x7683x7 = $[__Oxb24bc[0x6]]() ? require(__Oxb24bc[0x7]) : CryptoJS; let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString(); return { url: `${__Oxb24bc[0x8]}${JD_API_HOST}${__Oxb24bc[0x9]}${_0x7683x2}${__Oxb24bc[0xa]}${escape(JSON[__Oxb24bc[0x1]](_0x7683x3))}${__Oxb24bc[0xb]}${_0x7683x4}${__Oxb24bc[0xc]}${_0x7683x8}${__Oxb24bc[0x8]}`, headers: { '\x48\x6F\x73\x74': __Oxb24bc[0xd], '\x61\x63\x63\x65\x70\x74': __Oxb24bc[0xe], '\x6B\x65\x72\x6E\x65\x6C\x70\x6C\x61\x74\x66\x6F\x72\x6D': __Oxb24bc[0xf], '\x75\x73\x65\x72\x2D\x61\x67\x65\x6E\x74': __Oxb24bc[0x10], '\x61\x63\x63\x65\x70\x74\x2D\x6C\x61\x6E\x67\x75\x61\x67\x65': __Oxb24bc[0x11], '\x43\x6F\x6F\x6B\x69\x65': cookie } } } (function (_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) { _0x7683xe = __Oxb24bc[0x12]; _0x7683xc = function (_0x7683xf) { if (typeof alert !== _0x7683xe) { alert(_0x7683xf) }; if (typeof console !== _0x7683xe) { console[__Oxb24bc[0x13]](_0x7683xf) } }; _0x7683xb = function (_0x7683x7, _0x7683x9) { return _0x7683x7 + _0x7683x9 }; _0x7683xd = _0x7683xb(__Oxb24bc[0x14], _0x7683xb(_0x7683xb(__Oxb24bc[0x15], __Oxb24bc[0x16]), __Oxb24bc[0x17])); try { _0x7683x9 = __encode; if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb(__Oxb24bc[0x18], __Oxb24bc[0x19]))) { _0x7683xc(_0x7683xd) } } catch (e) { _0x7683xc(_0x7683xd) } })({})
首先
看到上面的內(nèi)容科展,分析得出里面包含著\x5F\x64\x65\x63\x6F\x64\x65
、\u5220\u9664
這些特殊字符串糠雨,我們可以得出才睹,里面的混淆會(huì)是進(jìn)行過(guò)unicode和16進(jìn)制的轉(zhuǎn)換得出的,因此甘邀,我們可以先對(duì)此先進(jìn)行一次轉(zhuǎn)換琅攘,最終得出的結(jié)果是
var __encode = 'jsjiami.com',
_a = {},
_0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function(_0xd642x1) {
_0xd642x1[_0xb483[0]] = _0xb483[1]
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "刪除", "版本號(hào),js會(huì)定", "期彈窗松邪,", "還請(qǐng)支持我們的工作", "jsjia", "mi.com"];
function taskUrl(_0x7683x2, _0x7683x3 = {}) {
let _0x7683x4 = +new Date();
let _0x7683x5 = `${__Oxb24bc[0x0]}${JSON[__Oxb24bc[0x1]](_0x7683x3)}${__Oxb24bc[0x2]}${_0x7683x2}${__Oxb24bc[0x3]}${_0x7683x4}${__Oxb24bc[0x4]}`;
let _0x7683x6 = __Oxb24bc[0x5];
const _0x7683x7 = $[__Oxb24bc[0x6]]() ? require(__Oxb24bc[0x7]) : CryptoJS;
let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
return {
url: `${__Oxb24bc[0x8]}${JD_API_HOST}${__Oxb24bc[0x9]}${_0x7683x2}${__Oxb24bc[0xa]}${escape(JSON[__Oxb24bc[0x1]](_0x7683x3))}${__Oxb24bc[0xb]}${_0x7683x4}${__Oxb24bc[0xc]}${_0x7683x8}${__Oxb24bc[0x8]}`,
headers: {
'Host': __Oxb24bc[0xd],
'accept': __Oxb24bc[0xe],
'kernelplatform': __Oxb24bc[0xf],
'user-agent': __Oxb24bc[0x10],
'accept-language': __Oxb24bc[0x11],
'Cookie': cookie
}
}
}(function(_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) {
_0x7683xe = __Oxb24bc[0x12];
_0x7683xc = function(_0x7683xf) {
if (typeof alert !== _0x7683xe) {
alert(_0x7683xf)
};
if (typeof console !== _0x7683xe) {
console[__Oxb24bc[0x13]](_0x7683xf)
}
};
_0x7683xb = function(_0x7683x7, _0x7683x9) {
return _0x7683x7 + _0x7683x9
};
_0x7683xd = _0x7683xb(__Oxb24bc[0x14], _0x7683xb(_0x7683xb(__Oxb24bc[0x15], __Oxb24bc[0x16]), __Oxb24bc[0x17]));
try {
_0x7683x9 = __encode;
if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb(__Oxb24bc[0x18], __Oxb24bc[0x19]))) {
_0x7683xc(_0x7683xd)
}
} catch (e) {
_0x7683xc(_0x7683xd)
}
})({})
到此
我們大致上已把對(duì)應(yīng)的內(nèi)容簡(jiǎn)單地解密出來(lái)了坞琴。但是,目前而言测摔,源碼的可讀性比較差置济,我們可以再觀察一下》姘耍可以發(fā)現(xiàn)浙于,在開頭已定義了__Oxb24bc
這個(gè)數(shù)組變量,文中的部分變量也使用到數(shù)組中的內(nèi)容挟纱,因此羞酗,我們可以根據(jù)這樣轉(zhuǎn)化一波∥煞可以得出一下:
var __encode = 'jsjiami.com',
_a = {},
_0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
_0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "刪除", "版本號(hào)檀轨,js會(huì)定", "期彈窗胸竞,", "還請(qǐng)支持我們的工作", "jsjia", "mi.com"];
function taskUrl(_0x7683x2, _0x7683x3 = {}) {
let _0x7683x4 = +new Date();
let _0x7683x5 = `lite-android&${JSON.stringify(_0x7683x3)}&android&3.1.0&${_0x7683x2}&${_0x7683x4}&846c4c32dae910ef`;
let _0x7683x6 = "12aea658f76e453faf803d15c40a72e0";
const _0x7683x7 = $.isNode() ? require("crypto-js") : CryptoJS;
let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
return {
url: ""+`${JD_API_HOST}api?functionId=${_0x7683x2}&body=${escape(JSON.stringify(_0x7683x3))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${_0x7683x4}&sign=${_0x7683x8}`+"",
headers: {
'Host': 'api.m.jd.com',
'accept': '*/*',
'kernelplatform': 'RN',
'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
'Cookie': cookie
}
}
}
(function (_0x7683x9, _0x7683xa, _0x7683xb, _0x7683xc, _0x7683xd, _0x7683xe) {
_0x7683xe = 'undefined';
_0x7683xc = function (_0x7683xf) {
if (typeof alert !== _0x7683xe) {
alert(_0x7683xf)
};
console.log(console)
if (typeof console !== _0x7683xe) {
console.log(_0x7683xf)
}
};
_0x7683xb = function (_0x7683x7, _0x7683x9) {
return _0x7683x7 + _0x7683x9
};
_0x7683xd = _0x7683xb('刪除', _0x7683xb(_0x7683xb('版本號(hào),js會(huì)定', '期彈窗参萄,'), '還請(qǐng)支持我們的工作'));
try {
_0x7683x9 = __encode;
if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === _0x7683xb('jsjia', 'mi.com'))) {
_0x7683xc(_0x7683xd)
}
} catch (e) {
_0x7683xc(_0x7683xd)
}
})({})
其中卫枝,我們可以看到_0x7683xb
這個(gè)方法,其實(shí)實(shí)際上處理的操作是在做字符串拼接讹挎,對(duì)此可以簡(jiǎn)化整理一下校赤,并得出:
var __encode = 'jsjiami.com',
_a = {},
_0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"];
(function (_0xd642x1) {
_0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "刪除", "版本號(hào),js會(huì)定", "期彈窗筒溃,", "還請(qǐng)支持我們的工作", "jsjia", "mi.com"];
function taskUrl(_0x7683x2, _0x7683x3 = {}) {
let _0x7683x4 = +new Date();
let _0x7683x5 = `lite-android&${JSON.stringify(_0x7683x3)}&android&3.1.0&${_0x7683x2}&${_0x7683x4}&846c4c32dae910ef`;
let _0x7683x6 = "12aea658f76e453faf803d15c40a72e0";
const _0x7683x7 = $.isNode() ? require("crypto-js") : CryptoJS;
let _0x7683x8 = _0x7683x7.HmacSHA256(_0x7683x5, _0x7683x6).toString();
return {
url: ""+`${JD_API_HOST}api?functionId=${_0x7683x2}&body=${escape(JSON.stringify(_0x7683x3))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${_0x7683x4}&sign=${_0x7683x8}`+"",
headers: {
'Host': 'api.m.jd.com',
'accept': '*/*',
'kernelplatform': 'RN',
'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
'Cookie': cookie
}
}
}
(function (_0x7683x9, _0x7683xa, _0x7683xc, _0x7683xd, _0x7683xe) {
_0x7683xe = 'undefined';
_0x7683xc = function (_0x7683xf) {
if (typeof alert !== _0x7683xe) {
alert(_0x7683xf)
};
console.log(console)
if (typeof console !== _0x7683xe) {
console.log(_0x7683xf)
}
};
_0x7683xd = '刪除版本號(hào)马篮,js會(huì)定期彈窗,還請(qǐng)支持我們的工作';
try {
_0x7683x9 = __encode;
if (!(typeof _0x7683x9 !== _0x7683xe && _0x7683x9 === 'jsjiami.com')) {
_0x7683xc(_0x7683xd)
}
} catch (e) {
_0x7683xc(_0x7683xd)
}
})({})
對(duì)此怜奖,基本已經(jīng)翻譯完成浑测,剩下的給這些_0x7683
開頭的變量換個(gè)名字,讓他看起來(lái)更加舒服歪玲,在這里迁央,我就大致根據(jù)這些變量定義的數(shù)據(jù)起個(gè)名字,并簡(jiǎn)化一些累贅的代碼~
Magic~
var __encode = 'jsjiami.com',
_a = {};
(function (_0xd642x1) {
_0xd642x1["_decode"] = "http://www.sojson.com/javascriptobfuscator.html"
})(_a);
var __Oxb24bc = ["lite-android&", "stringify", "&android&3.1.0&", "&", "&846c4c32dae910ef", "12aea658f76e453faf803d15c40a72e0", "isNode", "crypto-js", "", "api?functionId=", "&body=", "&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=", "&sign=", "api.m.jd.com", "*/*", "RN", "JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)", "zh-Hans-CN;q=1, ja-CN;q=0.9", "undefined", "log", "刪除", "版本號(hào)读慎,js會(huì)定", "期彈窗漱贱,", "還請(qǐng)支持我們的工作", "jsjia", "mi.com"];
function taskUrl(id, data = {}) {
let time = +new Date();
let form = `lite-android&${JSON.stringify(data)}&android&3.1.0&${id}&${time}&846c4c32dae910ef`;
let code = "12aea658f76e453faf803d15c40a72e0";
const sha = $.isNode() ? require("crypto-js") : CryptoJS;
let sign = sha.HmacSHA256(form, code).toString();
return {
url: ""+`${JD_API_HOST}api?functionId=${id}&body=${escape(JSON.stringify(data))}&appid=lite-android&client=android&uuid=846c4c32dae910ef&clientVersion=3.1.0&t=${time}&sign=${sign}`+"",
headers: {
'Host': 'api.m.jd.com',
'accept': '*/*',
'kernelplatform': 'RN',
'user-agent': 'JDMobileLite/3.1.0 (iPad; iOS 14.4; Scale/2.00)',
'accept-language': 'zh-Hans-CN;q=1, ja-CN;q=0.9',
'Cookie': cookie
}
}
}
(function (encode, alarm) {
alarm = function (msg) {
if (typeof alert !== 'undefined') {
alert(msg)
};
if (typeof console !== 'undefined') {
console.log(msg)
}
};
try {
encode = __encode;
if (!(typeof encode !== 'undefined' && encode === 'jsjiami.com')) {
alarm('刪除版本號(hào),js會(huì)定期彈窗夭委,還請(qǐng)支持我們的工作')
}
} catch (e) {
alarm('刪除版本號(hào)幅狮,js會(huì)定期彈窗,還請(qǐng)支持我們的工作')
}
})({})
就此株灸,解密已經(jīng)處理好了
或許崇摄,寫到這里,會(huì)有很多朋友會(huì)問(wèn)
Q:為什么_0x7683
開頭的變量沒(méi)不能直接解析出他具體的變量名是什么呢慌烧?
A:首先逐抑,這個(gè)變量的生成具體是根據(jù)哪些參數(shù)算出來(lái)的,我們不清楚屹蚊,想要去解開他需要嘗試各種組合厕氨,有可能有朋友說(shuō),一看就知道是進(jìn)制轉(zhuǎn)換出來(lái)的汹粤。這么想命斧,沒(méi)錯(cuò),但是嘱兼,具體是哪個(gè)進(jìn)制国葬,你還要不斷的嘗試,而且,其實(shí)這只是一個(gè)變量名汇四,到最后也不會(huì)影響里面的邏輯接奈。因此,為了高效而言通孽,還是直接起一個(gè)新的名字就好了序宦。(只是審查源碼的邏輯,不要太糾結(jié))
工具方法(網(wǎng)上)
下面這個(gè)方法可以直接把數(shù)組的內(nèi)容在文中替換利虫,并且挨厚,把xxx["yyy"]的格式轉(zhuǎn)為xxx.yyy的格式。其中糠惫,__Oxb7f82
需要根據(jù)實(shí)際情況下的字符串?dāng)?shù)組對(duì)應(yīng)的變量進(jìn)行替換,以本文的栗子為例是__Oxb24bc
,其中code
的數(shù)據(jù)是對(duì)應(yīng)需要解碼的js數(shù)據(jù)钉疫。
console.log(code.replace(/__Oxb7f82\[0x[\da-f]+\]/g,a=>{
a=`"${eval(a).replace(/"/g,"\"")}"`;
console.log(a);
return a
}).replace(/\[s*['"][^"']+['"]\s*\]/g,a=>{
a=a.trim();
a=a.substring(2,a.length-2)
console.log(a);
return "."+a
}))
寫到最后硼讽,這篇文章僅做技術(shù)分享,若涉及版權(quán)和信息安全問(wèn)題牲阁,請(qǐng)聯(lián)系小編會(huì)馬上處理~