最近需要参考下易企秀H5的json配置文件,发现已经做了加密,其实前端的加密分析起来只是麻烦点。

抓包分析

先看一个H5: https://h5.eqxiu.com/s/XvEn30op

F12可以看到,配置json地址是:https://s1-cdn.eqxiu.com/eqs/page/142626394?code=XvEn30op&time=1542972816000

对应的json:

{"success":true,"code":200,"msg":"操作成功","obj":"加密后的字符串"}

obj对应的是正式的配置信息

解码分析

需要对加密信息进行解密,首先可以定位到解密代码

function _0x230bc7(_0x2fb175) {
return _0x3c31('0xee') == typeof _0x2fb175[_0x3c31('0x25')] && _0x2fb175['\x6f\x62\x6a'][_0x3c31('0xe')] > 0x64 ? _0x54c90c[_0x3c31('0x31f')]()['\x74\x68\x65\x6e'](function() {
_0x249a60();
var _0x5ab652 = null
, _0x2cf0a4 = null
, _0x4d1175 = null;
try {
var _0x3dbfaa = _0x2fb175[_0x3c31('0x25')]['\x73\x75\x62\x73\x74\x72\x69\x6e\x67'](0x0, 0x13)
, _0x360e25 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](0x13 + 0x10);
_0x2cf0a4 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](0x13, 0x13 + 0x10),
_0x4d1175 = _0x2cf0a4,
_0x5ab652 = _0x3dbfaa + _0x360e25,
_0x2cf0a4 = CryptoJS['\x65\x6e\x63'][_0x3c31('0x320')][_0x3c31('0x6b')](_0x2cf0a4),
_0x4d1175 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')]['\x70\x61\x72\x73\x65'](_0x4d1175);
var _0x57e61a = CryptoJS[_0x3c31('0x322')][_0x3c31('0x323')](_0x5ab652, _0x2cf0a4, {
'\x69\x76': _0x4d1175,
'\x6d\x6f\x64\x65': CryptoJS[_0x3c31('0x324')][_0x3c31('0x325')],
'\x70\x61\x64\x64\x69\x6e\x67': CryptoJS[_0x3c31('0x326')][_0x3c31('0x327')]
});
return _0x2fb175[_0x3c31('0x36')] = JSON[_0x3c31('0x6b')](CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x267')](_0x57e61a)),
_0x2fb175;
} catch (_0x36fffe) {
_0x5ab652 = _0x2fb175[_0x3c31('0x25')]['\x73\x75\x62\x73\x74\x72\x69\x6e\x67'](0x0, _0x2fb175[_0x3c31('0x25')][_0x3c31('0xe')] - 0x10),
_0x2cf0a4 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](_0x2fb175[_0x3c31('0x25')][_0x3c31('0xe')] - 0x10),
_0x4d1175 = _0x2cf0a4,
_0x2cf0a4 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x6b')](_0x2cf0a4),
_0x4d1175 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x6b')](_0x4d1175);
var _0x4ff7de = CryptoJS[_0x3c31('0x322')][_0x3c31('0x323')](_0x5ab652, _0x2cf0a4, {
'\x69\x76': _0x4d1175,
'\x6d\x6f\x64\x65': CryptoJS['\x6d\x6f\x64\x65'][_0x3c31('0x325')],
'\x70\x61\x64\x64\x69\x6e\x67': CryptoJS[_0x3c31('0x326')][_0x3c31('0x327')]
});
return _0x2fb175[_0x3c31('0x36')] = JSON[_0x3c31('0x6b')](CryptoJS[_0x3c31('0x321')]['\x55\x74\x66\x38'][_0x3c31('0x267')](_0x4ff7de)),
_0x2fb175;
}
}) : Promise[_0x3c31('0x1e')](_0x2fb175);

这个代码基本不可读,简单分析下可以发现,_0x3c31('0x321')对应一个字符串,'\x6f\x62\x6a'等也可以转义:

先转义:

function decode(xData) {
return xData.replace(/\\x(\w{2})/g, function (_, $1) { return String.fromCharCode(parseInt($1, 16)) });
}

然后替换下:

Function.prototype.getMultiLine = function () {
var lines = new String(this);
lines = lines.substring(lines.indexOf("/*") + 3, lines.lastIndexOf("*/"));
return lines;
} function decode(xData) {
return xData.replace(/\\x(\w{2})/g, function (_, $1) { return String.fromCharCode(parseInt($1, 16)) });
} var str1 = function () {
/*
var _0x5ab652 = _0x50019d(_0x3c31('0x30c'))
, _0x2cf0a4 = _0x50019d('\x63\x6f\x6d\x70\x4b\x65\x79')
, _0x5cba8a = {
'\x74\x79\x70\x65': _0x3c31('0x16c'),
'\x75\x72\x6c': _0x8aa6f1()
}
, _0xfca4af = {
'\x74\x79\x70\x65': _0x3c31('0x16c'),
'\x75\x72\x6c': _0xefaeb()
};
_0x31f1b8 && (_0x5cba8a[_0x3c31('0x2cb')] = {
'\x70\x61\x73\x73\x77\x6f\x72\x64': _0x31f1b8
});
var _0x11871b = null
, _0x170c7e = Promise[_0x3c31('0x1e')](null); var _0x256cd0 = _0x2cf0a4(0x16)
, _0x36150e = _0x2cf0a4(0x15)
, _0x42a8d9 = _0x36150e['\x61\x6a\x61\x78']
, _0xdc46dc = _0x36150e[_0x3c31('0x1ef')]
, _0xcca797 = _0x2cf0a4(0x18)
, _0x50019d = _0xcca797[_0x3c31('0x5f')]
, _0x5c77e3 = _0xcca797['\x70\x61\x72\x73\x65\x55\x72\x6c']
, _0x36d54a = _0x2cf0a4(0x3a)['\x70\x65\x72\x66\x65\x63\x74\x4d\x65\x74\x61']
, _0x4c6a9e = _0x2cf0a4(0x2c)[_0x3c31('0x328')]
, _0x296a9b = _0x2cf0a4(0x2c)[_0x3c31('0x329')]
, _0x54c90c = _0x2cf0a4(0x17)
, _0x50f238 = _0x2cf0a4(0x3d)[_0x3c31('0x32a')]
, 0x13 = 0x13
, 0x0 = 0x0
, 0x10 = 0x10
, CryptoJS = null;
function _0x230bc7(_0x2fb175) {
return _0x3c31('0xee') == typeof _0x2fb175[_0x3c31('0x25')] && _0x2fb175['\x6f\x62\x6a'][_0x3c31('0xe')] > 0x64 ? _0x54c90c[_0x3c31('0x31f')]()['\x74\x68\x65\x6e'](function() {
_0x249a60();
var _0x5ab652 = null
, _0x2cf0a4 = null
, _0x4d1175 = null;
try {
var _0x3dbfaa = _0x2fb175[_0x3c31('0x25')]['\x73\x75\x62\x73\x74\x72\x69\x6e\x67'](0x0, 0x13)
, _0x360e25 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](0x13 + 0x10);
_0x2cf0a4 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](0x13, 0x13 + 0x10),
_0x4d1175 = _0x2cf0a4,
_0x5ab652 = _0x3dbfaa + _0x360e25,
_0x2cf0a4 = CryptoJS['\x65\x6e\x63'][_0x3c31('0x320')][_0x3c31('0x6b')](_0x2cf0a4),
_0x4d1175 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')]['\x70\x61\x72\x73\x65'](_0x4d1175);
var _0x57e61a = CryptoJS[_0x3c31('0x322')][_0x3c31('0x323')](_0x5ab652, _0x2cf0a4, {
'\x69\x76': _0x4d1175,
'\x6d\x6f\x64\x65': CryptoJS[_0x3c31('0x324')][_0x3c31('0x325')],
'\x70\x61\x64\x64\x69\x6e\x67': CryptoJS[_0x3c31('0x326')][_0x3c31('0x327')]
});
return _0x2fb175[_0x3c31('0x36')] = JSON[_0x3c31('0x6b')](CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x267')](_0x57e61a)),
_0x2fb175;
} catch (_0x36fffe) {
_0x5ab652 = _0x2fb175[_0x3c31('0x25')]['\x73\x75\x62\x73\x74\x72\x69\x6e\x67'](0x0, _0x2fb175[_0x3c31('0x25')][_0x3c31('0xe')] - 0x10),
_0x2cf0a4 = _0x2fb175[_0x3c31('0x25')][_0x3c31('0xeb')](_0x2fb175[_0x3c31('0x25')][_0x3c31('0xe')] - 0x10),
_0x4d1175 = _0x2cf0a4,
_0x2cf0a4 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x6b')](_0x2cf0a4),
_0x4d1175 = CryptoJS[_0x3c31('0x321')][_0x3c31('0x320')][_0x3c31('0x6b')](_0x4d1175);
var _0x4ff7de = CryptoJS[_0x3c31('0x322')][_0x3c31('0x323')](_0x5ab652, _0x2cf0a4, {
'\x69\x76': _0x4d1175,
'\x6d\x6f\x64\x65': CryptoJS['\x6d\x6f\x64\x65'][_0x3c31('0x325')],
'\x70\x61\x64\x64\x69\x6e\x67': CryptoJS[_0x3c31('0x326')][_0x3c31('0x327')]
});
return _0x2fb175[_0x3c31('0x36')] = JSON[_0x3c31('0x6b')](CryptoJS[_0x3c31('0x321')]['\x55\x74\x66\x38'][_0x3c31('0x267')](_0x4ff7de)),
_0x2fb175;
}
}) : Promise[_0x3c31('0x1e')](_0x2fb175);
}"
*/
}
var js1 = decode(str1.getMultiLine());
js1 = js1.replace(/_0x3c31\('([^\']+)'\)/g, function ($v, $g) { return _0x3c31($g); })

得到

var _0x5ab652 = _0x50019d(userKey)
, _0x2cf0a4 = _0x50019d('compKey')
, _0x5cba8a = {
'type': GET,
'url': _0x8aa6f1()
}
, _0xfca4af = {
'type': GET,
'url': _0xefaeb()
};
_0x31f1b8 && (_0x5cba8a[data] = {
'password': _0x31f1b8
});
var _0x11871b = null
, _0x170c7e = Promise[resolve](null); var _0x256cd0 = _0x2cf0a4(0x16)
, _0x36150e = _0x2cf0a4(0x15)
, _0x42a8d9 = _0x36150e['ajax']
, _0xdc46dc = _0x36150e[$ajax]
, _0xcca797 = _0x2cf0a4(0x18)
, _0x50019d = _0xcca797[getUrlParam]
, _0x5c77e3 = _0xcca797['parseUrl']
, _0x36d54a = _0x2cf0a4(0x3a)['perfectMeta']
, _0x4c6a9e = _0x2cf0a4(0x2c)[isVipScene]
, _0x296a9b = _0x2cf0a4(0x2c)[isTgScene]
, _0x54c90c = _0x2cf0a4(0x17)
, _0x50f238 = _0x2cf0a4(0x3d)[setJsCrypto]
, 0x13 = 0x13
, 0x0 = 0x0
, 0x10 = 0x10
, CryptoJS = null;
function _0x230bc7(_0x2fb175) {
return string == typeof _0x2fb175[obj] && _0x2fb175['obj'][length] > 0x64 ? _0x54c90c[$loadCryptoJS]()['then'](function() {
_0x249a60();
var _0x5ab652 = null
, _0x2cf0a4 = null
, _0x4d1175 = null;
try {
var _0x3dbfaa = _0x2fb175[obj]['substring'](0x0, 0x13)
, _0x360e25 = _0x2fb175[obj][substring](0x13 + 0x10);
_0x2cf0a4 = _0x2fb175[obj][substring](0x13, 0x13 + 0x10),
_0x4d1175 = _0x2cf0a4,
_0x5ab652 = _0x3dbfaa + _0x360e25,
_0x2cf0a4 = CryptoJS['enc'][Utf8][parse](_0x2cf0a4),
_0x4d1175 = CryptoJS[enc][Utf8]['parse'](_0x4d1175);
var _0x57e61a = CryptoJS[AES][decrypt](_0x5ab652, _0x2cf0a4, {
'iv': _0x4d1175,
'mode': CryptoJS[mode][CFB],
'padding': CryptoJS[pad][NoPadding]
});
return _0x2fb175[list] = JSON[parse](CryptoJS[enc][Utf8][stringify](_0x57e61a)),
_0x2fb175;
} catch (_0x36fffe) {
_0x5ab652 = _0x2fb175[obj]['substring'](0x0, _0x2fb175[obj][length] - 0x10),
_0x2cf0a4 = _0x2fb175[obj][substring](_0x2fb175[obj][length] - 0x10),
_0x4d1175 = _0x2cf0a4,
_0x2cf0a4 = CryptoJS[enc][Utf8][parse](_0x2cf0a4),
_0x4d1175 = CryptoJS[enc][Utf8][parse](_0x4d1175);
var _0x4ff7de = CryptoJS[AES][decrypt](_0x5ab652, _0x2cf0a4, {
'iv': _0x4d1175,
'mode': CryptoJS['mode'][CFB],
'padding': CryptoJS[pad][NoPadding]
});
return _0x2fb175[list] = JSON[parse](CryptoJS[enc]['Utf8'][stringify](_0x4ff7de)),
_0x2fb175;
}
}) : Promise[resolve](_0x2fb175);
}"

基板上可以读了,使用CryptoJS做的前端解密,然后直接给最后的代码:


// 依赖: https://lib.eqh5.com/CryptoJS/1.0.1/cryptoJs.js
function decrypt(result) {
var ciphertext = null
, key = null
, iv = null;
try {
var part0 = result.obj.substring(0x0, 0x13)
, part1 = result.obj.substring(0x13 + 0x10);
key = result.obj.substring(0x13, 0x13 + 0x10),
iv = key,
ciphertext = part0 + part1,
key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv);
var decryptData = CryptoJS.AES.decrypt(ciphertext, key, {
'iv': iv,
'mode': CryptoJS.mode.CFB,
'padding': CryptoJS.pad.NoPadding
});
return CryptoJS.enc.Utf8.stringify(decryptData);
} catch (_0x36fffe) {
ciphertext = result[obj]['substring'](0x0, result.obj.length - 0x10),
key = result[obj][substring](result.obj.length - 0x10),
iv = key,
key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv);
var decryptData = CryptoJS.AES.decrypt(ciphertext, key, {
'iv': iv,
'mode': CryptoJS.mode.CFB,
'padding': CryptoJS.pad.NoPadding
});
return CryptoJS.enc.Utf8.stringify(decryptData)
}
}

易企秀H5 json配置文件解密分析的更多相关文章

  1. 如何搭建易企秀H5平台?

    导读 易企秀如何开启伪静态支持? 一秀如何开启伪静态? 下载易企秀源码 oschina: http://git.oschina.net/jsper/html5Editor Windows下搭建环境 安 ...

  2. H5类似易企秀/编辑器/页面制作/开发/生成工具/软件/源码/授权

    代码地址如下:http://www.demodashi.com/demo/14960.html 项目简介 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具. ...

  3. 易企秀 we+ Maka 兔展 四大H5页面制作工具

    H5这个由HTML5简化而来的词汇,正通过微信广泛传播.H5是集文字.图片.音乐.视频.链接等多种形式的展示页面,丰富的控件.灵活的动画特效.强大的交互应用和数据分析,高速低价的实现信息传播,非常适合 ...

  4. H5易企秀

    周末被领导叫回来加班,说要做一个易企秀一样的页面,然后就有这篇笔记 原计划用几百个计时器去执行,后面放弃了,太难改了,还是选择了animate.css插件,这是一个纯css的插件,只需要引入css就行 ...

  5. 易企秀微场景2016最新完整版V10.5,小编亲测修复众多错误

    易企秀V10.5更新说明1.修复拨号英文错误2.修复转送场景问题3.修复设置场景密码乱码问题4.修复前台批量删除客户图片5.修复数据收集分页问题6.修复图片分类错乱问题7.修复音乐和特效冲突问题8.修 ...

  6. 【krpano】加密XML手动解密分析

    krpano允许对XML文件进行加密,对XML进行相应的保护.加密分为两种,第一种为公共加密,即允许其他krpano全景读取该XML,而另一种为私有加密,仅允许加密的用户读取XML.两种加密方式的算法 ...

  7. .Net Core Linux centos7行—.net core json 配置文件

    .net core 对配置系统做出了大幅度更新,不在局限于之前的*.xml配置方式.现在支持json,xml,ini,in memory,环境变量等等.毫无疑问的是,现在的json配置文件是.net ...

  8. [.NET Core] 简单读取 json 配置文件

    简单读取 json 配置文件 背景 目前发现网上的 .NET Core 读取配置文件有点麻烦,自己想搞个简单点的. .NET Core 已经不使用之前的诸如 app.config 和 web.conf ...

  9. Asp .Net Core 读取appsettings.json配置文件

         Asp .Net Core 如何读取appsettings.json配置文件?最近也有学习到如何读取配置文件的,主要是通过 IConfiguration,以及在Program中初始化完成的. ...

随机推荐

  1. 题解-Atcoder_agc005D ~K Perm Counting

    Problem AtCoder-agc005D 题意概要:给出\(n,k\),求合法的排列个数,其中合法定义为任何数字所在位置与自身值差的绝对值不为\(k\)(即求排列\(\{A_i\}\),使得\( ...

  2. CodeForces 937C Save Energy! 水题

    题意: 一个炉子烤鸡,炉子打开的时候一共$T$分钟可以烤完,关闭的时候一共$2T$分钟可以烤完,炉子每$K$分钟自动关闭,厨师每$D$分钟回来检查,打开炉子 问多长时间烤完.. 题解: 用整数写比较稳 ...

  3. C#委托delegate、Action、Func、predicate 对比用法

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递.事件是一种特殊的委托. 一.委托的声明   (1) delegate delegate我们常用到的一种声明 Delega ...

  4. 码云 Git No network connection

    背景 git,好久没用了都.心血来潮还是赶紧熟悉下吧.果不其然,每次要熟悉或开始一个东西,立马就出现问题.本来好好的环境竟然不行了,搞定后感觉应该是换了网络环境的事.这倒次要,主要让我想起了最初学习g ...

  5. URLConnection和HttpURLConnection

    URLConnection和HttpURLConnection使用的都是java.net中的类,属于标准的java接口. HttpURLConnection继承自URLConnection,差别在与H ...

  6. VUE 密码验证与提示

    1. 概述 1.1 说明 vue项目中,为了较为明了的让用户看到所输入的密码信息的长度与复杂度是否满足要求,开发一个组件来满足此需求(当密码输入时进行密码验证操作,当密码的长度在8到24位之间,密码中 ...

  7. 学了这么久,vue和微信小程序到底有什么样的区别?

    前言 写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别.相比之下,小程序的钩子函数要简单得多. 一.生命周期 先贴两张图: vue生命周期 小程序生命周期   相比之下 ...

  8. deepin 桌面突然卡死

    deepin桌面突然卡死 使用快捷键Ctrl+alt+F2 重启systemctl

  9. MySQL数据库之安装

    一.基础部分 1.数据库是什么 之前所学,数据要永久保存,比如用户注册的用户信息,都是保存于文件中,而文件只能存在于某一台机器上. 如果我们不考虑从文件中读取数据的效率问题,并且假设我们的程序所有的组 ...

  10. WinHex数据恢复笔记(一)

    WinHex数据恢复功能强大,可以从硬件簇上扇区进行数据扫描恢复.首先对winhex的各个功能介绍.之后对实例记录一个Word文档删除后进行恢复. 1.WinHex数据恢复软件的编辑区输入与其他普通文 ...