JS逆向实战:扣代码时如何快速定位结果不对的问题?

大家好,今天分享一个在扣代码的时候如何快速定位数据问题的方法。

扣代码

不知道有没有小伙伴遇到过类似的问题,在扣代码的时候,一般都是缺啥补啥,遇到了报错就补上对应的函数,缺失什么就补什么。但是在补完所有缺失函数后,发现运行加密函数,返回的结果不对,和在网页上面计算的不一致,这个时候要如何解决呢?

我们来想一下,在运行扣完的代码后,正常来说执行这些代码会运行正确的计算逻辑,得到正确的结果。但是结果是错误的,反推一下,那执行逻辑应该也是错误的。会有什么问题导致执行逻辑发生错误呢?做过后端开发的小伙伴应该知道,大概率就是两种方法:

  1. if 判断、逻辑运算符、三元运算符
  2. 报错捕获

if 判断

先说 if 判断,代码中可以使用 if 判断是否为浏览器环境来让正常的逻辑分叉,进而执行错误的逻辑。逻辑运算符和三元运算符也是一样的,通过判断环境检测的结果来让变量初始化成正确的值或者错误的值。

image-20250410204330320

例如这里执行了一段混淆后的代码,里面检测了一些环境和函数,通过执行结果和三元运算符来判断浏览器环境,从而让 b 变量的某些属性赋值为不同的值,可能会导致计算结果出错。

报错捕获

报错捕获也是常见的检测方式,一般会在 try 关键字中执行一些本来不报错的指令,例如浏览器中存在的函数,但是在 nodejs 中不存在,执行后就会报错。但是在报错后使用 catch 捕获然后继续执行,会导致 try 中的部分语句没有执行到,从而让计算过程缺失部分步骤,导致计算结果出现错误。

当然了,也有反过来的,在浏览器中执行只有 nodejs 中存在的函数,本来应该报错的但在 nodejs 中就不报错了,也会导致执行了错误的逻辑导致错误。

image-20250410204013628

例如这里,使用 eval 执行 CanvasCaptureMediaStreamTrack 函数但不调用,在浏览器中会正常执行不报错,但是在 nodejs 中会报错,从而被 catch 捕获,让 cb 变量和 cu 变量初始化为错误的值,进而影响后续的计算结果。

如何快速定位

那么对于以上两种情况,如何快速定位问题呢?

代理之环境自吐

对于第一种不会报错的情况,可以使用代理的方式让代码将环境自己吐出来,简称环境自吐。原理就是使用代理,封装对于特定对象的 getset 方法,有点类似于 Java 的 gettersetter 注解哈哈。

以下代码仅供参考,代码来源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function setProxy(proxyObjs) {
for (let i = 0; i < proxyObjs.length; i++) {
const handler = `{
get: function(target, property, receiver) {
if (property!="Math" && property!="isNaN"){
if (target[property] && typeof target[property] !="string" && Object.keys(target[property]).length>3){
}else{
console.log("方法:", "get ", "对象:", "${proxyObjs[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", target[property]);}}
return target[property];
},
set: function(target, property, value, receiver) {
console.log("方法:", "set ", "对象:", "${proxyObjs[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]);
return Reflect.set(...arguments);
}
}`;
eval(`try {
${proxyObjs[i]};
${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler});
} catch (e) {
${proxyObjs[i]} = {};
${proxyObjs[i]} = new Proxy(${proxyObjs[i]}, ${handler});
}`);
}
}

setProxy(['window', 'document', ' navigator', 'screen', 'localStorage'])

通过监控某些对象的 setget 方法,可以将代码在运行时对这些对象所做的操作都打印出来, 后续可以从日志中看到代码都访问了哪些环境,然后将对应的属性放到浏览器获取正确的值后,就可以补上对应的环境,再次运行代码就不会报错了。

image-20250410211509173

nodejs 中运行后,可以看到好多的属性获取的时候返回值都是 undefined,这都是要补的环境。

image-20250410211814204

补环境这里多说一句,除了写代码也可以使用 v_jstools 插件来输出对应的环境,只需要勾选对应的对象,不用写一行代码即可获取大量的环境信息,大大节省补环境的时间。

补环境还有更多好用的工具和方法就不多讲了(其实我不会哈哈),留给大家慢慢探索。

报错检测

报错检测会稍微简单一些,既然报错的时候会使用 trycatch,那执行报错了肯定会输出错误信息。但是在混淆后的代码中 catch 一般都会被置空,我们手动补上输出语句不就好了。

image-20250410212724696

以猿人学的第 14 题为例,扣完代码后发现运行的结果不对,但是也不缺失任何函数,说明肯定有环境检测或者在哪里报错了但是没有提示出来,环境检测可以使用上面的方法来检测。

image-20250410213726174
image-20250410213749182

image-20250410213801888

我们将所有的 catch 都搜索出来并且补上打印语句,将错误都打印出来看看。

image-20250410212946077

再次运行,会发现在打印结果之前打印出来很多错误堆栈,按照报错堆栈将所有问题一一解决以后,重新运行,发现结果正确了,至此扣代码完成,可以本地运行或者远程调用了。

总结

上面所说的所有方法并不是唯一,还有更多的大佬开发了很多的好用的工具,大家可以多多试用,可以在逆向的时候事半功倍,感谢大家的阅读。

本文章首发于个人博客 LLLibra146’s blog

本文作者:LLLibra146

更多文章请关注公众号 (LLLibra146):LLLibra146

版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!

本文链接
https://blog.d77.xyz/archives/942db7c9.html