Chrome开发工具与js加密
观察当前数据流的请求情况恢复直接执行当前函数进入当前函数跳出当前函数Step直接进入下一个局部函数内部, 比较少用禁止debugger模式下的所有断点在所有抛出异常点的位置暂停, 比较少用Watch监控变量值的变化断点作用域Global全局变量Local局部变量Closure闭包(自由变量)调用栈, 用来了解当前结果产生所经历的函数调用过程.我们在Call Stack上跳转函数的时候, 可以看到堆
Chrome开发工具与js加密
chrome开发者工具
-
Network
观察当前数据流的请求情况
- Search按钮进行关键词的一些搜索
- Filter按钮进行当前请求的过滤, 屏蔽不必要的请求
- Preserve log保存当前所有请求日志, 如果不勾选, 刷新页面会丢失历史日志
- Disable cache关闭浏览器缓存
-
Source
-
debugger console
-
Resume
恢复
-
Step over
直接执行当前函数
-
Step into
进入当前函数
-
Step out
跳出当前函数
-
Step
直接进入下一个局部函数内部, 比较少用
-
Deactive breakpoint
禁止debugger模式下的所有断点
-
Pause on exceptions
在所有抛出异常点的位置暂停, 比较少用
-
-
-
Watch
监控变量值的变化
-
Breakpoints
断点
-
Scope
作用域
-
Global
全局变量
-
Local
局部变量
-
Closure
闭包(自由变量)
-
-
Call Stack
调用栈, 用来了解当前结果产生所经历的函数调用过程.
我们在Call Stack上跳转函数的时候, 可以看到堆栈环境, 但是当前堆栈环境不一定准确.
-
XHR/fetch Breakpoints
监听请求中的关键字, 在请求发送前暂停
-
DOM Breakpoints
监听DOM的变化
-
Global Listeners
全局监听器
-
Event Listeners Breakpoints
事件监听器
- Mouse
- Keyboard
分析流程
- 分析要抓取的数据来自哪个请求
- 尽量使用Fiddler, Charles抓包工具, chrome开发者工具也可以, 但是分析起来没有抓包工具方便
- 观察请求的组成
- headers尽量拼全, 之后再逐步减少不必要的字段
还原被混淆的变量名
-
eval
eval可以将字符串转换为可执行语句
eval('n("0x155", "uYFB")')
-
通过正则还远混淆的代码
const n = require('./anti_confuse.js').n restoreJs = function(jsContent){ // 使用正则表达式匹配所有混淆函数 let matchArray = jsContent.match(/n\("[^\"]+", "[^\"]+"\)/g) for(let i=0; i<matchArray.length; i++){ let tmp = matchArray[i] try{ while (jsContent.indexOf(tmp) !== -1){ // 注意最后需要添加单引号表示字符串 jsContent = jsContent.replace(tmp, "\"" + eval(tmp) + "\"") } }catch (e){ console.log(e); console.log(tmp) } } return jsContent }
JS模块的导入和导出
-
导出模块exports
module.exports = { n: d }
-
导入模块require
const anti_confuse = require('./anti_confuse.js'); const n = anti_confuse.n
JS文件的写入和写出
-
导入文件处理模块
const file = require("fs");
-
文件读取
readFileSync返回的是二进制数组, 需要调用toString来转变为字符串
let jsContent = file.readFileSync("./react_pdd_20210513.js").toString();
-
文件写入
let newJsContent = restoreJs(jsContent) file.writeFile( "react_pdd_20210513.restore.js", // 文件名 newJsContent, // 写入内容 {encoding: "utf-8", flag: "w"}, // 参数 function (e){ if (e){ console.log("文件写入失败") }else{ console.log("文件写入成功") } } )
-
三元运算符
true?console.log("true"): console.log("false")
加密流程
我们定位到了加密函数, 调用后产生了加密结果anti_content, 接下来就是要找齐加密所需要的参数和加密的具体函数
-
将多个参数加密成多个小数组, 最终合并为大数组
a = (t = [])[K].apply(t, [s[o](), Wt[o](), pt[o](), mt[o](), vt[o](), bt[o](), gt[o](), kt[o](), _t[o](), yt[o](), wt[o]()].concat(function(t) { if (Array.isArray(t)) { for (var n = 0, e = Array(t.length); n < t.length; n++) e[n] = t[n]; return e } return Array.from(t) }(Ct[o]()), [St[o](), Ot[o](), Rt[o](), Pt[o](), jt[o](), Dt[o]()]));
-
生成了大数组
a
的长度为16的二进制信息u
for (var u = a[E][g](2)[p](""), f = 0; r["ZIIDs"](u[E], 16); f += 1) u[r["XjWuA"]]("0"); u = u[x]("");
-
通过
u
生成了W
参数列表中的l
l[H](et[k](u[O](0, 8), 2), et[k](u[O](8, 16), 2))
-
合并了
a
和l
a = [][K]([3], [1, 0, 0], l, a);
-
压缩了大数组
a
h = i['deflate'](a)
-
将
h
Uint8Array中的元素值转变为String, 产生了W
W = [][b]["call"](h, (function(t) { return String[S](t) } ));
-
W
通过encode
函数加密W
和tt
后的结果和定值0ap
相加生成了anti_contentr["yrFVy"](r["ZRscj"], c[r["wSNTe"]](r["yrFVy"](W[x](""), tt[x]("")), c["budget"]))
tt
是验证函数dt
和At
是否被修改的字段.
更多推荐
所有评论(0)