js逆向--技巧
检测调试
- 键盘监听 F12
- 检测浏览器内外的高度差值
- 检测开发者人员工具变量是否为true
- 利用console 禁止使用console输出
- 利用代码运行时间差
- 利用toString 比如判断是否是"function Function() { [native code] }"
- 检测栈的层次caller
反调试
- debugger
- 非虚拟机:
- 在debugger那一行下断点,右键断点,edit breakpoint, 填写false; 在循环中无效
- 直接替换代码:
- 谷歌内核浏览器默认提供
- 浏览器插件 油猴
- 代理替换(中间人):fiddler、charles 可以通过正则匹配文件名
- 虚拟机:文件显示的是VMxxx
- eval
- Function
- Function.prototype.constructor = function(x) {}
Function.prototype.constructor_ = Function.prototype.constructor; Function.prototype.constructor = function(x) { if (x != "debugger") { return Function.prototype.constructor_(x); } return function() {}; }
- Function.prototype.constructor = function(x) {}
- 非虚拟机:
- 死循环:循环语句,无限递归,setInterval()不断调用、两个方法互调(断链)
- 引向错误的逻辑
- 通过hook,输出正确调用堆栈
常见的混淆
- 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
- AES
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
- 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;
}
})
})();
- new Proxy
hook的时机
- 最好在网页加载的第一个js文件的第一行下端点,然后在控制台手动注入hook,这种方式注入hook的时机还是可能会晚了。
- 利用浏览器中开发工具Sources下面的Overrides功能,对于js文件名变化的不好处理。
- 利用FD等中间人软件的替换响应功能注入hook,可以通过正则匹配js文件名
- 油猴,不推荐
抠代码
- webpack
- 找到加载器,即加载模块的方法
- 找到需要调用的模块
- 构造一个自执行函数
- 定义一个全局变量,导出加密方法
- 编写自定义函数,按照网站实际加密流程进行加密
// 加载器
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
- 使用websocket
- 使用javascript编写webscoket代码
- 将代码注入在目标js中合适的位置
- 可以使用chrome浏览器自带的override功能,将目标js保存在本地
- 然后把webscoket代码复制到合适位置
!(function(){ windows.my_var = 目标对象或者方法; var ws = new WebSocket("ws或者wss://host:post"); ws.onopen = function(event) { xxx } ws.onmessage = function(event) { // 假设要调用目标网站的加密函数 result = window.my_var.encrypt(event.data); ws.send(result); // 发回服务器 } })();
- 手动运行目标网站,触发注入的webscoket代码执行,完成于服务器的连接
- 这样服务器与注入代码就可以进行通信了
资源
- JavaScript反调试技巧
- www.freebuf.com/articles/system/163579.html
分类:
JavaScript
, 逆向
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探