注意:文章内容仅用于学习和技术交流,如有侵权请联系我删除。
学者应洁身自好,切勿做出违法的事情,旨在提供逆向思路。
➣➣欢迎关注本人信微公众号:Anonymous NoteBook➣➣
分享好玩有趣的网络资源&软件工具~
分享各种技术性PDF资源/付费查询PDF资源~
分享各种编程语言、开发技术、分布式事务、大数据与云计算技术~
分享有关网络爬虫(Web爬虫逆向 | 安卓逆向)案例、数据挖掘、技术心得等~
aHR0cHM6Ly93d3cubWlndS5jbi8=
登陆分析:
点击右上角登录按钮,弹出登录输入框:
【Ps: 手机号为随意填写。】
打开F12调试工具,点击登录按钮,查看登录接口:
会发现,每点击一次登录,都会出现两个接口。
第一个含有publickey的接口,顾名思义,应该是和公钥有关,想必登录加密为rsa,看下返回结果:
有过rsa加密经验的人一眼都能看出,返回的result结果中的参数正是rsa加密所需的参数,其中’modulus‘就是公钥。记好这两个参数,后面的所有加密都和result中的字段有关。
我们再看第二个接口,url中包含’authn‘, 顾名思义,这个接口即为登录认证接口,具体看下:
请求参数有四个加密参数:
既然前面分析中发现有公钥出现,这些参数确实为rsa加密。
返回结果:
分析总结:
1、首先在登录认证之前,程序会自动请求一个包含公钥的url,返回公钥以及其他参数。
2、通过上一步得到的参数,使用rsa进行对明文参数进行加密,得到加密参数。
3、请求登录认证接口,返回响应。
到此,我们把流程和加密捋了一遍,下面开始逆向分析:
逆向分析:
首先,既然我们知道加密手段为rsa,我们就先以RSA为关键词搜索下,看看是否有关键信息出现:
通过搜索发现,有两条重要信息"J_RsaPsd", "J_RsaAccout" ,点进去其中一条看下:
这里就是密码、账号的加密所在。
往下面翻,你又会发现一个重要的加密参数逻辑:
我们全局搜索下loginID加密参数,你会发现:
后面分析一下,就可以知道loginID的值其实就是账号加密后的值。
此时,我们打上几个关键的断点,进行下调试:
参数a为公钥接口的返回值:
另外,所有的加密函数x.excrypt 调用的都是gb函数,我们跟一下gb函数:
跳进来的这个文件就是该网站所有的加密逻辑所在,边执行、边调试,找到关键代码复制粘贴到本地js文件中。
此时到这里,我们就把loginID和enpassword 加密分析完成了。
下面分析指纹相关的参数:fingerPrint 和 fingerPrintDetail :
我们再次回到第一次进去的文件里:
可以直接看出, fingerPrint的值为变量b的result参数, fingerPrintDetail 的值为变量b的details参数。
变量b的结果是调用了加密函数q.page.rsaFingerprint得到,通过调试可知,q.page.rsaFingerprint调用的是rsaFingerprint(a,b)函数:
参数a和b分别为上一步请求得到的数据:
分析 到这里,心里想必对加密逻辑很清晰了吧。
跟进去rsaFingerprint函数,返回两个字段:
再次声明下:fingerPrint的值为变量b的result参数, fingerPrintDetail 的值为变量b的details参数。
走到这里,逆向完成度为95%。
接下来就是根据上面的分析,找到关键js函数,拷贝复制到本地,补全变量,运行调试:
完美运行。
但是我们仍需验证正确性,通过py文件进行模拟请求下:
结果与网页返回的结果一样。
本人注册了一个真实账号,再次模拟下:
登陆成功。
到此,逆向结束!!!!
var lb, mb, nb = "0123456789abcdefghijklmnopqrstuvwxyz", ob = new Array;
var navigator = {
appName: "Netscape",
}
var window = global;
function d(a, b, c) {
null != a && ("number" == typeof a ? this.fromNumber(a, b, c) : null == b && "string" != typeof a ? this.fromString(a, 256) : this.fromString(a, b))
}
function h(a, b, c, d, e, f) {
..................
//此处省略多行代码
return e
}
function E(a) {
this.m = a
}
function F(a) {
return a.s < 0 || a.compareTo(this.m) >= 0 ? a.mod(this.m) : a
}
function G(a) {
return a
}
function H(a) {
a.divRemTo(this.m, null, a)
}
function I(a, b, c) {
a.multiplyTo(b, c),
this.reduce(c)
}
function J(a, b) {
a.squareTo(b),
this.reduce(b)
}
function K() {
..................
//此处省略多行代码
}
function k(a) {
..................
//此处省略多行代码
}
function l(a) {
this.t = 1,
this.s = 0 > a ? -1 : 0,
a > 0 ? this[0] = a : -1 > a ? this[0] = a + this.DV : this.t = 0
}
function j(a, b) {
var c = ob[a.charCodeAt(b)];
return null == c ? -1 : c
}
function n(a, b) {
..................
//此处省略多行代码
}
function o() {
for (var a = this.s & this.DM; this.t > 0 && this[this.t - 1] == a;)
--this.t
}
function i(a) {
return nb.charAt(a)
}
function p(a) {
..................
//此处省略多行代码
return e ? f : "0"
}
function q() {
var a = e();
return d.ZERO.subTo(this, a),
a
}
function r() {
return this.s < 0 ? this.negate() : this
}
function s(a) {
..................
//此处省略多行代码
}
..................
//此处省略多个函数
..................
function db() {
..................
//此处省略多行代码
}
function eb(a, b) {
null != a && null != b && a.length > 0 && b.length > 0 ? (this.n = bb(a, 16),
this.e = parseInt(b, 16)) : alert("网络异常,请点击登录重试")
}
function fb(a) {
return a.modPowInt(this.e, this.n)
}
function gb(a) {
..................
//此处省略多行代码
}
ab.prototype.nextBytes = _,
db.prototype.doPublic = fb,
db.prototype.setPublic = eb,
db.prototype.encrypt = gb,
RSAKey = db
function rsaFingerprint(a, b) {
..................
//此处省略多行代码
g = new RSAKey;
g.setPublic(a, b);
for (var h = g.encrypt(d), i = 0; e > i; i += 117)
f += g.encrypt(c.substr(i, 117))
return {
details: f,
result: h
}
}
function FP(a) {
var b = rsaFingerprint(a.result.modulus, a.result.publicExponent);
return {
FingerPrint: b.result,
FingerPrintDetail: b.details,
}
// e.filter(".J_FingerPrint").val(b.result).end().filter(".J_FingerPrintDetail").val(b.details)
}
function rsaPWD(pwd){
var c = new RSAKey;
c.setPublic(resp.result.modulus, resp.result.publicExponent)
return c.encrypt(pwd)
}
function rsaloginID(account){
var c = new RSAKey;
c.setPublic(resp.result.modulus, resp.result.publicExponent)
return c.encrypt(account)
}
var resp = {
"status": 2000, "message": "", "header": {},
"result":
{
"publicExponent": "010001",
"modulus": "00833c4af965ff7a8409f8b5d5a83d87f2f19d7c1eb40dc59a98d2346cbb145046b2c6facc25b5cc363443f0f7ebd9524b7c1e1917bf7d849212339f6c1d3711b115ecb20f0c89fc2182a985ea28cbb4adf6a321ff7e715ba9b8d7261d1c140485df3b705247a70c28c9068caabbedbf9510dada6d13d99e57642b853a73406817"
}
}
function main(phone, pwd){
var FingerPrint = FP(resp).FingerPrint,
FingerPrintDetail = FP(resp).FingerPrintDetail
return {
fingerPrint:FingerPrint,
FingerPrintDetail: FingerPrintDetail,
rsaloginID: rsaloginID(phone),
enpassword: rsaPWD(pwd)
}
}
console.log(main('158xxxxxxxx','123456'))
// console.log('loginID: ',rsaloginID('158xxxxxxxx'))
// console.log('enpassword: ',rsaPWD('123456'))
// console.log('fingerPrint: ', FP(resp).FingerPrint)
// console.log('fingerPrintDetail: ', FP(resp).FingerPrintDetail)
import requests
import execjs
def get_encry_js():
with open(r'D:\xxxxx.js','r',encoding='utf-8') as f:
data = f.read()
return data
def get_resp(phone, pwd):
com_ = execjs.compile(get_encry_js())
result = com_.call('main',phone, pwd)
headers = {...}
data = {...}
response = requests.post('登陆认证url', headers=headers, data=data)
print(response.text)
if __name__ == '__main__':
get_resp('158xxxxxxxx','123456')
完事~~~~收工~~~~