检测调试
- 键盘监听 F12
- 检测浏览器内外的高度差值
- 检测开发者人员工具变量是否为true
- 利用console 禁止使用console输出
- 利用代码运行时间差
- 利用toString 比如判断是否是"function Function() { [native code] }"
- 检测栈的层次caller
反调试
- debugger
- 非虚拟机:
- 在debugger那一行下断点,右键断点,edit breakpoint, 填写false; 在循环中无效
- 直接替换代码:
- 谷歌内核浏览器默认提供
- 浏览器插件 油猴
- 代理替换(中间人):fiddler、charles 可以通过正则匹配文件名
- 虚拟机:文件显示的是VMxxx
- 死循环:循环语句,无限递归,setInterval()不断调用、两个方法互调(断链)
- 引向错误的逻辑
常见的混淆
- eval
- 代码以字符串的形式传给eval进行执行
- 在虚拟机上执行
- AA混淆
- 最后一行代码有用,直接最后一行下断点,单步调试,进入虚拟机可看到源码
゚ω゚ノ = /`m´)ノ ~┻━┻ //*´∇`sojson.com*/
['_'];
o = (゚ー゚) = _ = 3;
c = (゚Θ゚) = (゚ー゚) - (゚ー゚);
(゚Д゚) = (゚Θ゚) = (o ^ _ ^ o) / (o ^ _ ^ o);
(゚Д゚) = {
゚Θ゚: '_',
゚ω゚ノ: ((゚ω゚ノ == 3) + '_')[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + '_')[o ^ _ ^ o - (゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + '_')[゚ー゚]
};
(゚Д゚)[゚Θ゚] = ((゚ω゚ノ == 3) + '_')[c ^ _ ^ o];
(゚Д゚)['c'] = ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚) - (゚Θ゚)];
(゚Д゚)['o'] = ((゚Д゚) + '_')[゚Θ゚];
(゚o゚) = (゚Д゚)['c'] + (゚Д゚)['o'] + (゚ω゚ノ + '_')[゚Θ゚] + ((゚ω゚ノ == 3) + '_')[゚ー゚] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚ == 3) + '_')[゚Θ゚] + ((゚ー゚ == 3) + '_')[(゚ー゚) - (゚Θ゚)] + (゚Д゚)['c'] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + (゚Д゚)['o'] + ((゚ー゚ == 3) + '_')[゚Θ゚];
(゚Д゚)['_'] = (o ^ _ ^ o)[゚o゚][゚o゚];
(゚ε゚) = ((゚ー゚ == 3) + '_')[゚Θ゚] + (゚Д゚).゚Д゚ノ + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚ == 3) + '_')[o ^ _ ^ o - ゚Θ゚] + ((゚ー゚ == 3) + '_')[゚Θ゚] + (゚ω゚ノ + '_')[゚Θ゚];
(゚ー゚) += (゚Θ゚);
(゚Д゚)[゚ε゚] = '\\';
(゚Д゚).゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ o - (゚Θ゚)];
(o゚ー゚o) = (゚ω゚ノ + '_')[c ^ _ ^ o];
(゚Д゚)[゚o゚] = '\"';
(゚Д゚)['_']((゚Д゚)['_'](゚ε゚ + (゚Д゚)[゚o゚] + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + (゚ー゚) + (゚Θ゚) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + ((o ^ _ ^ o) - (゚Θ゚)) + (゚Д゚)[゚ε゚] + (゚ー゚) + (c ^ _ ^ o) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + (c ^ _ ^ o) + (゚Д゚)[゚ε゚] + (゚Θ゚) + (゚ー゚) + ((゚ー゚) + (゚Θ゚)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + (゚ー゚) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + (゚ー゚) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + ((゚ー゚) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + (゚ー゚) + (c ^ _ ^ o) + (゚Д゚)[゚ε゚] + ((゚ー゚) + (o ^ _ ^ o)) + ((゚ー゚) + (゚Θ゚)) + (゚Д゚)[゚ε゚] + (゚ー゚) + (c ^ _ ^ o) + (゚Д゚)[゚ε゚] + (゚ー゚) + ((゚ー゚) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + ((゚ー゚) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + ((゚ー゚) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + ((o ^ _ ^ o) - (゚Θ゚)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + (゚ー゚) + (゚Д゚)[゚ε゚] + (゚Θ゚) + (゚ー゚) + (゚ー゚) + (゚Д゚)[゚ε゚] + (゚ー゚) + ((゚ー゚) + (o ^ _ ^ o)) + (゚Д゚)[゚ε゚] + ((゚ー゚) + (o ^ _ ^ o)) + (o ^ _ ^ o) + (゚Д゚)[゚o゚])(゚Θ゚))((゚Θ゚) + (゚Д゚)[゚ε゚] + ((゚ー゚) + (゚Θ゚)) + (゚Θ゚) + (゚Д゚)[゚o゚]);
```
- jj混淆
- 最后一行断点
- 对sojson.$_进行hook,然后在控制台通过arguments查看参数;
- 或者直接单步调试
- (sojson._)[sojson.$][sojson.$] 通过 ['constructor']['constructor']获取到Function,因此直接hook Function不起效果
sojson.$ = function(){debugger;}
sojson = ~[];
/*sojson.com*/
sojson = {
___: ++sojson,
/*sojson.com*/
$$$$: (![] + "")[sojson],
__$: ++sojson,
$_$_: (![] + "")[sojson],
_$_: ++sojson,
$_$$: ({} + "")[sojson],
$$_$: (sojson[sojson] + "")[sojson],
_$$: ++sojson,
$$$_: (!"" + "")[sojson],
$__: ++sojson,
$_$: ++sojson,
$$__: ({} + "")[sojson],
$$_: ++sojson,
$$$: ++sojson,
$___: ++sojson,
$__$: ++sojson
};
sojson.$_ = (sojson.$_ = sojson + "")[sojson.$_$] + (sojson._$ = sojson.$_[sojson.__$]) + (sojson.$$/*sojson.com*/
= (sojson.$ + "")[sojson.__$]) + ((!sojson) + "")[sojson._$$] + (sojson.__ = sojson.$_[sojson.$$_]) + (sojson.$ = (!"" + "")[sojson.__$]) + (sojson._ = (!"" + "")[sojson._$_]) + sojson.$_[sojson.$_$] + sojson.__ + sojson._$ + sojson.$;
/*sojson.com*/
sojson.$$ = sojson.$ + (!"" + "")[sojson._$$] + sojson.__ + sojson._ + sojson.$ + sojson.$$/*sojson.com*/
;
sojson.$ = (sojson.___)[sojson.$_][sojson.$_];
sojson.$(sojson.$(sojson.$$ + "\"" + "\\" + sojson.__$ + sojson.$$_ + sojson.$$_ + sojson.$_$_ + "\\" + sojson.__$ + sojson.$$_ + sojson._$_ + " \\" + sojson.__$ + sojson.$_$ + sojson.___ + sojson.$$$_ + (![] + "")[sojson._$_] + (![] + "")[sojson._$_] + sojson._$ + " \\" + sojson.$$$ + sojson.$_$ + " '\\" + sojson.__$ + sojson.$$_ + sojson.$$$ + sojson._$ + "\\" + sojson.__$ + sojson.$$_ + sojson._$_ + (![] + "")[sojson._$_] + sojson.$$_$ + "'\\" + sojson.$$$ + sojson._$$ + "\"")())(sojson = {
___: ++sojson,
$$$$: (![] + "")[sojson]
});
- FuckJs
js逆向的操作流程
- 抓包
- 调试
- 搜关键词:
- var xxx
- .xxx
- xxx:
- ['xxx']
- xhr断点
- 其他断点
- 抠取js
- 抠全了吗
- this是谁
- 尽量不修改源js
- 通过定义全局变量导出目标(函数,对象等)
- 改写
- 本地运行出值
- 提交服务器验证
常见加密类型
- 取盐校验,不可逆:md5 md4 md2 带密码的md5 sha1 sha256 sha512
- md5 16位 32位 40位 0123456789ABCDEF
- sha1 10位 sha256 64位 sha512 128位
- 对称加密: AES DES 3DES
key = CryptoJS.enc.Utf8.parse('十六位十六进制字符');
source_str = CryptoJS.enc.Utf8.parse('被加密的字符串');
CryptoJS.AES.encrypt(source_str, key, {各种配置参数信息});
其中各种配置参数可能会出现的关键词:
CryptoJS.mode.ECB CryptoJS.mode.CBC
CryptoJS.pad.Pkcs7 iv
- 非对称加密(私钥、公钥):RSA
setPublicKey(publicKey);
encrypt(原文);
- Base64 很有可能以=号结束
MTIzNDU25L2g5aW95ZWm5ZWm5ZWm44CC44CCYWJjZGZkbA==
window.btoa 对字符串进行 base64编码(注意不能编码中文);
winodw.atob 对 base64字符串 进行解码(对于包含中文的 base64编码,不能正确解码);
解决中文编码的办法:
// 编码
function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
// 解码
function b64_to_utf8(str) {
return decodeURIComponent(escape(window.atob(str)));
}
hook
function func() {
console.log("func");
}
// hook
func = function() {
console.log("hook func");
}
// hook 并执行原函数
var func_ = func;
func = function() {
console.log("hook func");
debugger();
func_();
}
- 通过Object.defineProperty替换一个对象属性(getter、setter)
(function(){
var value = "";
Object.defineProperty(document, 'cookie', {
set: function(val) {
console.log(val);
value = val;
debugger;
return val;
},
get: function() {
return value;
}
})
})();
hook的时机
- 最好在网页加载的第一个js文件的第一行下端点,然后在控制台手动注入hook,这种方式注入hook的时机还是可能会晚了。
- 利用浏览器中开发工具Sources下面的Overrides功能,对于js文件名变化的不好处理。
- 利用FD等中间人软件的替换响应功能注入hook,可以通过正则匹配js文件名
- 油猴,不推荐
抠代码
- 找到加载器,即加载模块的方法
- 找到需要调用的模块
- 构造一个自执行函数
- 定义一个全局变量,导出加密方法
- 编写自定义函数,按照网站实际加密流程进行加密
// 加载器
function(e) {
var t = {};
function n(r) {
if (t[r])
return t[r].exports;
var o = t[r] = {
exports: {}
};
return e[r].call(o.exports, o, o.exports, n),
o.exports
}
return 和可能是一个逗号表达式
}([
function(x1, x3, x3) {},
function(x1, x3, x3) {},
function(x1, x3, x3) {},
function(x1, x3, x3) {},
function(x1, x3, x3) {},
function(x1, x3, x3) {},
]) 传入数组 或者 对象 }({
a: function(x1, x3, x3) {},
b: function(x1, x3, x3) {},
...
})
RPC
资源
- JavaScript反调试技巧
- www.freebuf.com/articles/system/163579.html