0

0

Javascript逆向与反逆向

小云云

小云云

发布时间:2017-12-05 10:25:51

|

6969人浏览过

|

来源于php中文网

原创

popunderjs 原来在 github 上是有开源代码的,但后来估计作者发现这个需求巨大的商业价值,索性不开源了,直接收费。所以现在要研究它的实现方案,只能上官网扒它源码了。

文件结构

script.js 是功能主体,实现了 popunder 的所有功能以及定义了多个 API 方法

license.demo.js 是授权文件,有这个文件你才能顺利调用 script.js 里的方法

防止被逆向

这么具有商业价值的代码,就这么公开地给你们用,肯定要考虑好被逆向的问题。我们来看看它是怎么反逆向的。

首先,打开控制台,发现2个问题:

立即学习Java免费学习笔记(深入)”;

  1. 控制台所有内容都被反复清空,只输出了这么一句话: Console was cleared script.js?0.5309098417125133:1

  2. 无法断点调试,因为一旦启用断点调试功能,就会被定向到一个匿名函数 (function() {debugger})

也就是说,常用的断点调试方法已经无法使用了,我们只能看看源代码,看能不能理解它的逻辑了。但是,它源代码是这样的:

var a = typeof window === S[0] && typeof window[S[1]] !== S[2] ? window : global;
try {
a[S[3]](S[4]);
return function() {}
;
} catch (a) {
try {
(function() {}
[S[11]](S[12])());
return function() {}
;
} catch (a) {
if (/TypeError/[S[15]](a + S[16])) {
return function() {}
;
}
}
}

 

可见源代码是根本不可能阅读的,所以还是得想办法破掉它的反逆向措施。

利用工具巧妙破解反逆向

首先在断点调试模式一步步查看它都执行了哪些操作,突然就发现了这么一段代码:

(function() {
(function a() {
try {
(function b(i) {
if (('' + (i / i)).length !== 1 || i % 20 === 0) {
(function() {}
).constructor('debugger')();
} else {
debugger ;
}
b(++i);
}
)(0);
} catch (e) {
setTimeout(a, 5000);
}
}
)()
}
)();

 

这段代码主要有2部分,一是通过 try {} 块内的 b() 函数来判断是否打开了控制台,如果是的话就进行自我调用,反复进入 debugger 这个断点,从而达到干扰我们调试的目的。如果没有打开控制台,那调用 debugger 就会抛出异常,这时就在 catch {} 块内设置定时器,5秒后再调用一下 b() 函数。

这么说来其实一切的一切都始于 setTimeout 这个函数(因为 b() 函数全是闭包调用,无法从外界破掉),所以只要在 setTimeout 被调用的时候,不让它执行就可以破解掉这个死循环了。

所以我们只需要简单地覆盖掉 setTimeout 就可以了……比如:

window._setTimeout = window.setTimeout;
window.setTimeout = function () {};

 

但是!这个操作无法在控制台里面做!因为当你打开控制台的时候,你就必然会被吸入到 b() 函数的死循环中。这时再来覆盖 setTimeout 已经没有意义了。

这时我们的工具 TamperMonkey 就上场了,把代码写到 TM 的脚本里,就算不打开控制台也能执行了。

TM 脚本写好之后,刷新页面,等它完全加载完,再打开控制台,这时 debugger 已经不会再出现了!

接下来就轮到控制台刷新代码了

通过 Console was cleared 右侧的链接点进去定位到具体的代码,点击 {} 美化一下被压缩过的代码,发现其实就是用 setInterval 反复调用 console.clear() 清空控制台并输出了

Console was cleared

信息,但是注意了,不能直接覆盖 setInterval 因为这个函数在其他地方也有重要的用途。

所以我们可以通过覆盖 console.clear() 函数和过滤 log 信息来阻止它的清屏行为。

同样写入到 TamperMonkey 的脚本中,代码:

window.console.clear = function() {};
window.console._log = window.console.log;
window.console.log = function (e) {
if (e['nodeName'] && e['nodeName'] == 'p') {
return ;
}
return window.console.error.apply(window.console._log, arguments);
};

 

之所以用 error 来输出信息,是为了查看它的调用栈,对理解程序逻辑有帮助。

基本上,做完这些的工作之后,这段代码就可以跟普通程序一样正常调试了。但还有个问题,它主要代码是经常混淆加密的,所以调试起来很有难度。下面简单讲讲过程。

混淆加密方法一:隐藏方法调用,降低可读性

从 license.demo.js 可以看到开头有一段代码是这样的:

慧博商城系统HuiboShop2011
慧博商城系统HuiboShop2011

慧博商城系统HuiboShop2011系统特色:1、上百套模板随意下载切换、模板定时更新;2、csv数据导入、数据定向读取,一键导入商品信息,省时、省力; 3、多会员等级管理,一站搞定零售、批发、代销;4、可集成网站分销功能模块,缔造庞大的代理业务链,代理客户一键铺货;5、代码严谨,防SQL注入;前后台用户分开管理,密码不可逆加密;6、简单易操作、只需几分钟搞定一个商城网站;商城后台帐号admin

下载
var zBCa = function T(f) {
for (var U = 0, V = 0, W, X, Y = (X = decodeURI("+TR4W%17%7F@%17.....省略若干"),
W = '',
'D68Q4cYfvoqAveD2D8Kb0jTsQCf2uvgs'); U < X.length; U++,
V++) {
if (V === Y.length) {
V = 0;
}
W += String["fromCharCode"](X["charCodeAt"](U) ^ Y["charCodeAt"](V));
}
var S = W.split("&&");

 

通过跟踪执行,可以发现 S 变量的内容其实是本程序所有要用到的类名、函数名的集合,类似于 var S = ['console', 'clear', 'console', 'log'] 。如果要调用 console.clear() 和 console.log() 函数的话,就这样

var a = window;
a[S[0]][S[1]]();
a[S[2]][S[3]]();

 

混淆加密方法二:将函数定义加入到证书验证流程

license.demo.js 中有多处这样的代码:

a['RegExp']('/R[\S]{4}p.c\wn[\D]{5}t\wr/','g')['test'](T + '')

 

这里的 a 代表 window,T 代表某个函数, T + '' 的作用是把 T 函数的定义转成字符串,所以这段代码的意思其实是,验证 T 函数的定义中是否包含某些字符。

每次成功的验证,都会返回一个特定的值,这些个特定的值就是解密核心证书的参数。

可能是因为我重新整理了代码格式,所以在重新运行的时候,这个证书一直运行不成功,所以后来就放弃了通过证书来突破的方案。

逆向思路:输出所有函数调用和参数

通过断点调试,我们可以发现,想一步一步深入地搞清楚这整个程序的逻辑,是十分困难,因为它大部分函数之间都是相互调用的关系,只是参数的不同,结果就不同。

所以我后来想了个办法,就是只查看它的系统函数的调用,通过对调用顺序的研究,也可以大致知道它执行了哪些操作。

要想输出所有系统函数的调用,需要解决以下问题:

  1. 覆盖所有内置变量及类的函数,我们既要覆盖 window.console.clear() 这样的依附在实例上的函数,也要覆盖依附在类定义上的函数,如 window.HTMLAnchorElement.__proto__.click()

  2. 需要正确区分内置函数和自定义函数

经过搜索后,找到了区分内置函数的代码:

// Used to resolve the internal `[[Class]]` of values
var toString = Object.prototype.toString;

// Used to resolve the decompiled source of functions
var fnToString = Function.prototype.toString;

// Used to detect host constructors (Safari > 4; really typed array specific)
var reHostCtor = /^\[object .+?Constructor\]$/;

// Compile a regexp using a common native method as a template.
// We chose `Object#toString` because there's a good chance it is not being mucked with.
var reNative = RegExp('^' +
// Coerce `Object#toString` to a string
String(toString)
// Escape any special regexp characters
.replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')
// Replace mentions of `toString` with `.*?` to keep the template generic.
// Replace thing like `for ...` to support environments like Rhino which add extra info
// such as method arity.
.replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);

function isNative(value) {
var type = typeof value;
return type == 'function'
// Use `Function#toString` to bypass the value's own `toString` method
// and avoid being faked out.
? reNative.test(fnToString.call(value))
// Fallback to a host object check because some environments will represent
// things like typed arrays as DOM methods which may not conform to the
// normal native pattern.
: (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;
}

 

然后结合网上的资料,写出了递归覆盖内置函数的代码:

function wrapit(e) {
if (e.__proto__) {
wrapit(e.__proto__);
}
for (var a in e) {
try {
e[a];
} catch (e) {
// pass
continue;
}
var prop = e[a];
if (!prop || prop._w) continue;

prop = e[a];
if (typeof prop == 'function' && isNative(prop)) {
e[a] = (function (name, func) {
return function () {
var args = [].splice.call(arguments,0); // convert arguments to array
if (false && name == 'getElementsByTagName' && args[0] == 'iframe') {
} else {
console.error((new Date).toISOString(), [this], name, args);
}
if (name == 'querySelectorAll') {
//alert('querySelectorAll');
}
return func.apply(this, args);
};
})(a, prop);
e[a]._w = true;
};
}
}

 

使用的时候只需要:

wrapit(window);
wrapit(document);

 

然后模拟一下正常的操作,触发 PopUnder 就可以看到它的调用过程了。

参考资料:

A Beginners’ Guide to Obfuscation Detect if function is native to browser Detect if a Function is Native Code with JavaScript

以上内容就是Javascript逆向与反逆向的教程,希望能帮助到大家。

相关推荐:

JavaScript中undefined与null的区别详解

JavaScript中confirm()方法的使用介绍

JavaScript中的后退与刷新的实例详解

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

11

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

4

2026.01.21

无人机驾驶证报考 uom民用无人机综合管理平台官网
无人机驾驶证报考 uom民用无人机综合管理平台官网

无人机驾驶证(CAAC执照)报考需年满16周岁,初中以上学历,身体健康(矫正视力1.0以上,无严重疾病),且无犯罪记录。个人需通过民航局授权的训练机构报名,经理论(法规、原理)、模拟飞行、实操(GPS/姿态模式)及地面站训练后考试合格,通常15-25天拿证。

16

2026.01.21

Python多线程合集
Python多线程合集

本专题整合了Python多线程相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.21

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

4

2026.01.21

windows激活码分享 windows一键激活教程指南
windows激活码分享 windows一键激活教程指南

Windows 10/11一键激活可以通过PowerShell脚本或KMS工具实现永久或长期激活。最推荐的简便方法是打开PowerShell(管理员),运行 irm https://get.activated.win | iex 脚本,按提示选择数字激活(选项1)。其他方法包括使用HEU KMS Activator工具进行智能激活。

2

2026.01.21

excel表格操作技巧大全 表格制作excel教程
excel表格操作技巧大全 表格制作excel教程

Excel表格操作的核心技巧在于 熟练使用快捷键、数据处理函数及视图工具,如Ctrl+C/V(复制粘贴)、Alt+=(自动求和)、条件格式、数据验证及数据透视表。掌握这些可大幅提升数据分析与办公效率,实现快速录入、查找、筛选和汇总。

6

2026.01.21

毒蘑菇显卡测试网站入口 毒蘑菇测试官网volumeshader_bm
毒蘑菇显卡测试网站入口 毒蘑菇测试官网volumeshader_bm

毒蘑菇VOLUMESHADER_BM测试网站网址为https://toolwa.com/vsbm/,该平台基于WebGL技术通过渲染高复杂度三维分形图形评估设备图形处理能力,用户可通过拖动彩色物体观察画面流畅度判断GPU与CPU协同性能;测试兼容多种设备,但中低端手机易卡顿或崩溃,高端机型可能因发热降频影响表现,桌面端需启用独立显卡并使用支持WebGL的主流浏览器以确保准确结果

25

2026.01.21

github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

7

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.9万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号