js逆向之ast还原—某招聘网站2024/4/29新版token生成分析
转载于–酷酷妖
最近好多人来问我招聘网站的__zp_stoken__有什么思路,平常的vmp直接打日志,可是碰到平坦流就一点思路都没有
平坦流的难点在于流程控制,除了单步跟就是ast还原
大家对与ast的评价都是褒贬不一 但是你看那个大佬不会ast的 我的建议是能学就学
很多人倒在ast这一步 那我详细来讲讲最新版zp_stoken ast还原
而新版zp_stoken的难度在于流程控制更加复杂了 之前都是if—else
由于文章和公开性的限制 一些细节不便于展示
我会录制完整视频版 有手就行
现在的平坦流都是大站才会有
那以前的混淆不也是大站才有 现在遍地的ob 所以ast才有学习的必要
============正文分割线=
zp_的入口在html中 而这个html是动态加载的 每次都会变
可以使用hook cookie的方式但是会有很多的干扰项
为什么别人说要搜索ABC 就是在这里 通过hook之后就能看到入口
hook的步骤就不在细说 网上一搜一堆
第一次知道入口是这个东西之后就能清空网站缓存在脚本断点就能比较快速的定位到代码的位置
有些网站加载的动态html可以先尝试开发者工具中的替换来固定html 让动态的html变成静态的 更有便于跟踪定位
进入ABC函数就能看到,平坦流了
在入口处打上断点 然后将整份代码 复制到编辑器中更又便于分析
这玩意如果不借助ast的话,那怎么办,纯纯黑奴单步跟也吃不消啊
平坦流都是代码自动生成的所以在结构上都大差不差
先从外层逐步往里面开始分析,第一层的switch是G,G又通过D&3得到0,进入case 0看看
G:case 0 里面就一个函数 和一个if判断
而函数里面有一个switch 条件分支的值是T 看到上面图可以知道T是 D左移2位
在&3 结果还是0 ·····下面同理 第一层算出的结果是0-0-3-3 按照结果进入分支内看看
可以看到最后 判断的是Z 而Z的内部就是代码的本体,当然还有干扰项
在按照上面的步骤 把最开始的D=240替换为21重新计算节点
第二次的步骤为1-1-1-0
发现还是有干扰项 那么在按照之前的步骤重新计算 下一个位置
第三次的步骤为1-2-3-2
这回结果不一样了 发现n={};
说明我们之前的步骤是正确的,如果不放心还可拿到网站上单步跟检验一下
到这一步整个代码结构,节点规律都明了
// G->T->U->Z 先从G进入到T在进入U在进入Z 计算下节点这一步比较简单
function Switch_discriminant(D) {
let G = D & 3;
let T = D >> 2 & 3;
let U = D >> 4 & 3;
let Z = D >> 6 & 3;
return {'G': G, 'T': T, 'U': U, 'Z': Z}
}
//由于D是动态变化的所以使用传参的方式传递 返回值是一个对象在函数外面接收的时候比较清晰K:V
节点的位置拿到了,下一步就是 G->T->U->Z最终拿到Z的值
//由于文章和公开性的限制 此处只讲思路
//case_ :遍历到的G的case
//D :第一次number常量D
function 节点计算(case_,D) {
//先计算出第一次 G->T->U->Z 的值
let indx = Switch_discriminant(D)
//从indx中一次从case_ 节点中取出T、U、Z所代表的节点
xxxx(case_,switch_Z)
}
//case_ :遍历到的G的case
//switch_Z: 取出来的最内层节点
function xxxx(case_,switch_Z) {
//这个函数就是整个还原的关键函数
//判断switch_Z的类型 如果还是D = xxx 那么就递归调用节点计算函数
//如果是普通的复制 例如上面找到的 n={};就直接保存这个节点最后在进行整体替换
//难点在于三元表达式,需要先还原三元表达式 让后在根据if里面的值和else里面的值进行单独的替换
//本来还应该判断一下当前的节点是否被多次应用 zp_stoken的都是单次的可以直接合并
//如果碰到函数的话先直接不管 最后在单独还原函数的代码
}
原本有800多行代码最终还原后 只有50来行,一眼就能看到整个加密逻辑
第一个try最终的还原效果
还原了之后的难度甚至不足原来的十分之一 这就是ast的魅力