www.sojson.com网站高级JS加密破解
在网上冲浪,看到了一个网站的JS加密,下面有一句话:

乍一看这句话吓一跳,我去这么猛,然后就很有兴趣想看看究竟是怎样一种加密算法。
对于破解JS加密算法的时候,都是先输入一个简单的语句然后分析加密后语句的规律,这里先输入一个简单的打印log:

代码拷出来格式化一下:
var __encode = 'sojson.com',
_0xb483 = ["\x5F\x64\x65\x63\x6F\x64\x65", "\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"]; (function(_0xd642x1) {
_0xd642x1[_0xb483[0]] = _0xb483[1]
})(window);
var _0xdc02 = ["\x6F\x6B", "\x6C\x6F\x67"];
console[_0xdc02[1]](_0xdc02[0])
这个时候规律已经挺明显了,不急先将十六进制、Unicode等转为易读形式:
<html>
<head>
<meta charset="UTF-8"/>
<title>JavaScript 16进制、Unicode解码</title>
</head>
<body>
<form action="#">
<textarea id="js-code" cols="100" rows="30"></textarea>
<button id="decode-btn" type="button">DECODE</button>
</form>
<script type="text/javascript">
!function () {
document.getElementById("decode-btn").addEventListener("click", event => {
const jsCodeBox = document.getElementById("js-code");
// 可能会有中文的unicode,要能够兼容
jsCodeBox.value = jsCodeBox.value.replace(/\\x..|\\u.{4}/g, hex => decode(hex));
});
function decode(hex) {
try {
const c = parseInt(hex.substring(2), 16);
return String.fromCharCode(c);
} catch (e) {
console.log("parse " + hex + " error.");
}
return hex;
}
}();
</script>
</body>
</html>
十六进制、Unicode解码之后:
var __encode = 'sojson.com',
_0xb483 = ["_decode", "http://www.sojson.com/javascriptobfuscator.html"]; (function(_0xd642x1) {
_0xd642x1[_0xb483[0]] = _0xb483[1]
})(window);
var _0xdc02 = ["ok", "log"];
console[_0xdc02[1]](_0xdc02[0])
这个时候规律已经超级明显了,就是将属性访问、字符串常量等乱七八糟的提取到一个字典中,然后再引用这个字典,可是这种既做不到不可逆(我下面会写一个专破工具),也做不到体积小,因为len("[_0xdc02[1]]")===12,而len(".log")===4,只在属性名超过11(12-1)并且被引用多次时才能够节省空间,这里的设计一大败笔就是字典名字出现频率极高,但是给的变量名字还是这么长,哈夫曼编码了解一下呗。至于运行速度没有差别,这点时间差别人当然是感觉不出来但多做了一次数组访问肯定是慢了。
下面是针对此网站的高级JS加密写的一个专破工具,基本能够实现还原:
<html>
<head>
<meta charset="UTF-8"/>
<title>sojson js高级加密专破工具, https://www.sojson.com/javascriptobfuscator.html</title>
</head>
<body>
<form action="#">
<textarea name="js-code" id="js-code" cols="100" rows="30"></textarea>
<button id="decode-btn" type="button">DECODE</button>
</form>
<script type="text/javascript">
!function () {
document.getElementById("decode-btn").addEventListener("click", event => {
const jsCodeBox = document.getElementById("js-code");
const rawJs = jsCodeBox.value;
let decodeJs = replaceDictionaryIndexReference(rawJs);
decodeJs = squareBracketsToDot(decodeJs);
decodeJs = dropSignature(decodeJs);
jsCodeBox.value = decodeJs;
/**
* 字典引用替换为字面值常量
*
* @param rawJs
* @returns {*}
*/
function replaceDictionaryIndexReference(rawJs) {
const dictionaryNameSet = extractDictionaryNames(rawJs);
let decodeJs = rawJs;
dictionaryNameSet.forEach(dicName => {
// 将字典声明于当前上下文环境
const dicCode = new RegExp("(var\\s+|)" + dicName + "\\s*=\\s*\\[.+?\\];").exec(decodeJs)[0];
eval(dicCode);
// 将访问到此变量的地方引用替换为字面值
let isChange = false;
decodeJs = decodeJs.replace(new RegExp(dicName + "\\[\\d+\\]", "g"), index => {
const dicIndex = parseInt(/\[(\d+)]/.exec(index)[1]);
let result = eval(dicName + "[" + dicIndex + "]");
// 对于文本,需要加上双引号
if (!result.match(/^\d+$/)) {
result = "\"" + result + "\"";
}
isChange = true;
return result;
});
// 如果此变量被使用过,则将其从原文中清除
if (isChange) {
decodeJs = decodeJs.replace(dicCode, "");
}
});
return decodeJs;
}
/**
* 抽取出所有字典名称
*
* @param rawJs
* @returns {Set}
*/
function extractDictionaryNames(rawJs) {
const re = /(_+\w+?)\s*=\s*\[.+?]/g;
// const re = /(_0x\w+?)\s*=/g;
const dictionaryNameSet = new Set();
while (dicName = re.exec(rawJs)) {
dictionaryNameSet.add(dicName[1]);
}
return dictionaryNameSet;
}
/**
* 方法调用尽量由["foo"]的形式转为点调用
*
* @param decodeJs
* @returns {string | void | *}
*/
function squareBracketsToDot(decodeJs) {
return decodeJs.replace(/\w+\["\w+"]/g, call => {
const nameAndAttr = call.replace("[\"", " ").replace("\"]", "").split(" ");
try {
// 只替换name在当前上下文中已存在并且attr的类型是function
if (typeof eval(nameAndAttr[0] + "." + nameAndAttr[1]) === "function") {
return nameAndAttr[0] + "." + nameAndAttr[1];
}
} catch (e) {
console.log("cannot replace: " + call);
}
return call;
});
}
/**
* 丢弃作者的签名
*
* @param encodeJs
* @returns {string | void | *}
*/
function dropSignature(encodeJs) {
return encodeJs.replace(/^var __encode.+?\(window\);/, "");
}
});
}();
</script>
</body>
</html>
效果演示:

结论:
只是很简单的变量名混淆+字典压缩,而且字典变量名长度是个很严重的瑕疵,关于字典压缩可以参考JS Packer,我之前也写过一篇关于JS Packer的文章。
.
www.sojson.com网站高级JS加密破解的更多相关文章
- python爬虫-有道翻译-js加密破解
有道翻译-js加密破解 这是本地爬取的网址:http://fanyi.youdao.com/ 一.分析请求 我们在页面中输入:水果,翻译后的英文就是:fruit.请求携带的参数有很多,先将参数数据保存 ...
- Python 爬虫js加密破解(四) 360云盘登录password加密
登录链接:https://yunpan.360.cn/mindex/login 这是一个md5 加密算法,直接使用 md5加密即可实现 本文讲解的是如何抠出js,运行代码 第一部:抓包 如图 第二步: ...
- Python 爬虫js加密破解(三) 百度翻译 sign
第一步: 模拟抓包分析加密参数 第二步: 找到加密字段 调试出来的sign和抓取得到的数据一致,都是 275626.55195 第三部: 分析js加密方法 第四部:运行js代码: 仅供交流学习使用
- 码农代理免费代理ip端口字段js加密破解
起因 之前挖过爬取免费代理ip的坑,一个比较帅的同事热心发我有免费代理ip的网站,遂研究了下:https://proxy.coderbusy.com/. 解密 因为之前爬过类似的网站有了些经验,大概知 ...
- web主题公园版权信息破解:script.js加密文件
很多人会使用web主题公园网站的免费worldpress主题,但它的主题又都被加了版权信息,故意让人找不到版权信息的修改位置. 你如果去footer.php里面删除版权信息(技术支持:web主题公园) ...
- Python爬虫—破解JS加密的Cookie
前言 在GitHub上维护了一个代理池的项目,代理来源是抓取一些免费的代理发布网站.上午有个小哥告诉我说有个代理抓取接口不能用了,返回状态521.抱着帮人解决问题的心态去跑了一遍代码.发现果真是这样. ...
- 使用selenium进行密码破解(绕过账号密码JS加密)
经常碰到网站,账号密码通过js加密后进行提交.通过burp拦截抓到的账号密码是加密后的,所以无法通过burp instruder进行破解.只能模拟浏览器填写表单并点击登录按钮进行破解.于是想到了自动化 ...
- Python破解js加密实例(有道在线翻译)
在爬虫爬取网站的时候,经常遇到一些反爬虫技术,比如: 加cookie,身份验证UserAgent 图形验证,还有很难破解的滑动验证 js签名验证,对传输数据进行加密处理 对于js加密经过加密传输的就是 ...
- 爬虫破解js加密(一) 有道词典js加密参数 sign破解
在爬虫过程中,经常给服务器造成压力(比如耗尽CPU,内存,带宽等),为了减少不必要的访问(比如爬虫),网页开发者就发明了反爬虫技术. 常见的反爬虫技术有封ip,user_agent,字体库,js加密, ...
随机推荐
- Jquery 中 $.getJSON的用法
之前类似的方法用过 $.post, $.get,$.ajax,还是第一次用这个 $.getJSON. 前三个都是用作异步请求的,那么最后一个呢?其实也是异步请求的,和 $.get 最类似,因为他也是将 ...
- linux 负载均衡配置 keepalive lvs 使用nginx转发 CentOS7 搭建LVS+keepalived负载均衡
最近希望能够配置一下负载均衡,在虚拟机上面,但是网上找了很多资料很零散,对于不了解的人,很多不够详细,最近终于做好了,把具体的步骤写下来,方便各位网友查阅学习 这个实验需要安装nginx如果没有安装过 ...
- Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future)
这一系列的文章暂不涉及Java多线程开发中的底层原理以及JMM.JVM部分的解析(将另文总结),主要关注实际编码中Java并发编程的核心知识点和应知应会部分. 说在前面,Java并发编程的实质,是线程 ...
- Embarcadero Delphi 7 Enterprise 7.0.4.453 中文版
在 win7下可能报错请大家按下面的方式 delphi7运行不正常的提示unable to rename'c:\program files\Borland\delphi7\Bin\delphi32.$ ...
- 基于c的简易计算器二
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> ...
- 【大数据】Spark基础解析
第1章 Spark概述 1.1 什么是Spark 1.2 Spark内置模块 Spark Core:实现了Spark的基本功能,包含任务调度.内存管理.错误恢复.与存储系统交互等模块.Spark Co ...
- svmrank 的误差惩罚因子c选择 经验
C是一个由用户去指定的系数,表示对分错的点加入多少的惩罚,当C很大的时候,分错的点就会更少,但是过拟合的情况可能会比较严重,当C很小的时候,分错的点可能会很多,不过可能由此得到的模型也会不太正确,所以 ...
- Rotting Oranges - LeetCode
目录 题目链接 注意点 解法 小结 题目链接 Rotting Oranges - LeetCode 注意点 解法 解法一:bfs.首先先统计所有新鲜的橘子数目fresh,如果fresh大于0则一直执行 ...
- python之插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2).是稳定的排序方法.插入算法把要排序的数组分成两部 ...
- 洛谷 P3942 将军令 解题报告
P3942 将军令 题目描述 又想起了四月. 如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房. 凭君莫话封侯事,一将功成万骨枯. 梦里,小\(F\)成了一个给将军 ...