首先声明,本人经过无数次摸爬滚打及翻阅各类资料,理论知识极其丰富,但是抠代码怎么都抠不会。

  无奈之下,只能承认:这个活,需要熟练度。

  本文仅对部分参数进行解析,有需要调用,请自行根据现实情况调整。

  第一步,首先要打开网站,假装输入公司名:111111,用户名:111111,密码:222222,点击登录,开始抓包。拿到数据包之后,对内部数据进行简单的梳理。

  

  headers里面没有什么特别的特别的,要注意的是content-type显示,参数是json格式;接下来看参数方面,这里面一共11个参数,经过多次抓包会发现,只有clientinfo/password/username三个参数在变化,而且很明显,这不是明文,是加密模式,那么模拟登录的关键点应该就是在与找这三个参数。

  第二步,通过全局搜索变量名来定位。变量赋值一般分两种,就是username= 和username:,先拿username=,发现没找到东西;拿username:搜索,结果如下图:

  

  明显发现,480/748处是一个函数处理username。分别看下这两个位置,对应函数,发现函数相同,在这一行函数上下浏览,发现480处有我们数据包里面所有参数,显然,这里就是处理参数的地方,做下断点,稍后进行调试。同时打开鬼鬼JS工具,定义一个函数,用于接收处理后username值,由于这里是处理输入值,我们需要给函数一个参数。

1 function test(username) {
2 var user = encryptedString(key, encodeURIComponent(username));
3 return user
4 }

  当逻辑处理完毕后,通过python调用该函数,该函数就应该返回user值,即对111111进行加密后的结果。encodeURIComponent()函数是自带函数,即进行urlencode编码处理,在上一层还有一个encryptedString函数,而且该函数除了username参数外,还有个key参数,发现key在上面一丢丢:key = new RSAKeyPair();复制过来,放在函数前面,同时发现上面还有一行函数调用【setMaxDigits(129)】,怀疑有用,但没证据~~~先记下,如果右面报错,就拿过来,加载代码,发现提示有函数未定义:

  

  继续通过全局查找,由于这个是函数,那么他定义的附近应该有function字符,很容易可以找到2个,点进去发现两个js文件一样,那就随意了,同时发现给该js文件不大,但是仔细看下,发现里面的内容都有用!把他全部复制过来,放在函数前面。
  

  然后继续用鬼鬼js工具加载代码,发现提示缺少对象,点击v8运行,发现biFromHex未定义,经查看,这也是个函数,缺啥补啥,继续到网页里面找。

  

  发现这俩定义文件也是有一样的,经对biFromHex函数内部查看,发现整个文件都是互相依赖函数,全部拿走,全部拿走。注意把后拿的内容(非同一文件内放在已有代码的最前方,防止因为变量定义问题造成代码错误),然后继续调用加载,发现还缺函数BarrettMu,重复上述步骤

  

  文件不大,也是相互依赖函数,直接拿走,放到最前面!然后继续加载,看是否缺少内容:这个时候鬼鬼JS工具一直报错,一直无法加载成功,把前面怀疑的那行代码拿过来,放到运行函数前面:加载成功了,没有提示缺少函数,这个时候调用函数,参数传入111111(注意加引号),发现调用成功,返回256长度的加密密文,格式与网页数据包一致,每次运行返回结果不同。至此,username加密逆向成功!

  

  接下来是password参数。同理password参数原行代码为:password: encryptedString(key, $('#password').val()),其中$('#password').val()是jQuery的语法,及获取网页输入的密码值,那就是222222,其他方法与username一样,直接在上面添加一个获取password参数的函数,测试调用发现成功~~~~

  最后就是clientinfo值,通过username出的代码发现该值已经产生了,这里仅仅是一个简单的赋值过程,那么产生数据。全局进行搜索,发现如下内容:

  

  这个地方疑似,进入源码,打下断点,准备调试(清除之前的断点),点击登录,发现没断,说明在这之前,该数据已经产生了,产生数据往往伴随着动作,在我们点击登录之前的网页动作,那就只有加载网页了。刷新网页发现断点触发。

  

  这里可以发现是通过base64encode函数处理一个info值,而info到这里是一个很长的字符串,上一行,对info进行了定义。我们尝试着进入dogetinfo函数,发现该函数大部分地方都是在定义值和获取值,并未看到什么调用函数处理值的地方,那么在他return的地方打下断点,再次刷新进入dogetinfo函数内部,查看返回内容,发现是很长的字符串,而且返回处代码为:eFlash.join("^^") + "^^" + eNavigator.join("^^");

  

  对应结果值来看,这个函数好像仅仅做了拼接动作,那么查看值,发现很多熟悉的字眼,例如navigator/screenDPI/appCodeName/appVersion/userAgent等等,这显然是本地信息,通过控制台将该内容取出,按照“^^”符号断开,发现确实是计算机信息,而且取的十分简单。经百度,这种获取浏览器主要信息的数据 指纹算法(这里信息很少,属于极为简单的指纹信息),服务器通过对该信息认证,发现同样指纹在同一时间内大量申请数据,会认为异常。如果要改,我们这里可以userAgent,伪装更改浏览器版本88.0.4324.190这个数据。到这里就很明白了 clientinfo = base64encode(info),而info 即上面的拼接后的字符串。但要注意的是,base64ecode不是JS内置函数,写入JS的话,需要找下该函数,否则直接python中使用base64库。

  至此,三个加密参数均被解析。

  具体代码在下方。

  具体分析步骤即操作步骤在代码注释部分,JS的文件拼接和复制在JS文件的最后

 1 '''
2 管家婆登录网址:http://login.wsgjp.com/
3 网站对userName、password、clientinfo 三个参数进行了加密
4 现在对这三个参数进行js逆向,抠代码:使用鬼鬼js调试工具
5
6 userName ----> 使用userName = 查找,找到的都是赋值的地方,不是生成参数的地方
7 使用 userName: 查找,发现代码 userName: encryptedString(key, encodeURIComponent(username)),
8 password ----> 进入代码所在进行定位 发现password也在这里产生
9 所以,一起操作了
10
11 以下转JS文件
12
13 clientinfo --> 对这个值进行解析,发现上面代码处,这个值只是赋值所在,说明在这一步之前,这个值就已经生成了
14 再次搜索该值,发现一处代码疑似: clientinfo = base64encode(info) 显然是对info值进行了base64编码
15 那么info是多少,上一行对info进行了定义:var info = doGetInfo();下一步就是寻找doGetInfo函数
16 查找后进入doGetInfo函数,发现该函数量不大,且没有参数,没参数意味着不受输入值的影响,初步检查改函数,
17 发现该函数前一半以定义为主,获取数据,我们直接在return的地方打断点。再次点击登录,发现没有断下来!
18 思考为什么中! 在登录之前就生成了,登录之前生成,生成数据是个动作行为,要伴随着网页动作,怀疑是打开网页、
19 即加载网页的时候生成的,直接刷新网页,成功!
20 获取该函数返回值如下:
21 flash:begin^^
22 navigator:begin^^
23 screenDPI:undefined^^
24 cookieEnabled:true^^
25 platform:Win32^^
26 appCodeName:Mozilla^^
27 appMinorVersion:undefined^^
28 appName:Netscape^^
29 appVersion:5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36^^
30 browserLanguage:undefined^^
31 cpuClass:undefined^^
32 systemLanguage:undefined^^
33 userAgent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36^^
34 userLanguage:undefined^^
35 language:zh-CN^^
36 language:zh-CN^^
37 oscpu:undefined
38
39 结合eFlash.join("^^") + "^^" + eNavigator.join("^^")这行代码,没学过js都应该猜得到,是用^^对数据进行拼接,
40 断开后,发现很多很熟悉的东西,这些都是浏览器信息,undefined即未获取到,那么有效信息即appVersion、userAgent
41 这里基本上就是固定值了。
42 经百度,这种获取浏览器主要信息的数据 指纹算法(这里信息很少,属于极为简单的指纹信息),
43 服务器通过对该信息认证,发现同样指纹在同一时间内大量申请数据,会认为异常。如果要改,我们这里可以userAgent,
44 伪装更改浏览器版本88.0.4324.190这个数据。
45 那么 clientinfo = base64encode(info),而info 即上面的拼接后的字符串
46
47 注意:将函数直接写进JS的话,请把base64encode函数也复制进去,不能少参数,注意调试,否则请直接在python中
48 调用base64方法
49
50
51 '''
52
53 import execjs
54
55 def read_js(file):
56 with open(file, 'r', encoding='utf8') as f:
57 js_data = f.read()
58 return js_data
59
60
61
62
63 if __name__ == '__main__':
64 # 先读取js文件
65 js_r = read_js('getsome.js')
66 # 使用execjs方法获取js文件内容
67 js_o = execjs.compile(js_r)
68 # call方法调用函数,参数:函数名, 参数值
69 _username = js_o.call('getusername','111111')
70 print(_username)
71 print(len(_username))
72 _password = js_o.call('getpwd', '222222')
73 print(_password)
74 print(len(_password))
75
76 _clientinfo = js_o.call('getCL')
77 print(_clientinfo)

  JS 代码如下,这里就折叠了,因为行数太多。

var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function base64encode(str) {
try {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
out += base64EncodeChars.charAt(c3 & 0x3F);
} } catch (e) {
}
return out;
} function BarrettMu(m)
{
this.modulus = biCopy(m);
this.k = biHighIndex(this.modulus) + 1;
var b2k = new BigInt();
b2k.digits[2 * this.k] = 1; // b2k = b^(2k)
this.mu = biDivide(b2k, this.modulus);
this.bkplus1 = new BigInt();
this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1)
this.modulo = BarrettMu_modulo;
this.multiplyMod = BarrettMu_multiplyMod;
this.powMod = BarrettMu_powMod;
} function BarrettMu_modulo(x)
{
var q1 = biDivideByRadixPower(x, this.k - 1);
var q2 = biMultiply(q1, this.mu);
var q3 = biDivideByRadixPower(q2, this.k + 1);
var r1 = biModuloByRadixPower(x, this.k + 1);
var r2term = biMultiply(q3, this.modulus);
var r2 = biModuloByRadixPower(r2term, this.k + 1);
var r = biSubtract(r1, r2);
if (r.isNeg) {
r = biAdd(r, this.bkplus1);
}
var rgtem = biCompare(r, this.modulus) >= 0;
while (rgtem) {
r = biSubtract(r, this.modulus);
rgtem = biCompare(r, this.modulus) >= 0;
}
return r;
} function BarrettMu_multiplyMod(x, y)
{
/*
x = this.modulo(x);
y = this.modulo(y);
*/
var xy = biMultiply(x, y);
return this.modulo(xy);
} function BarrettMu_powMod(x, y)
{
var result = new BigInt();
result.digits[0] = 1;
var a = x;
var k = y;
while (true) {
if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a);
k = biShiftRight(k, 1);
if (k.digits[0] == 0 && biHighIndex(k) == 0) break;
a = this.multiplyMod(a, a);
}
return result;
} var biRadixBase = 2;
var biRadixBits = 16;
var bitsPerDigit = biRadixBits;
var biRadix = 1 << 16; // = 2^16 = 65536
var biHalfRadix = biRadix >>> 1;
var biRadixSquared = biRadix * biRadix;
var maxDigitVal = biRadix - 1;
var maxInteger = 9999999999999998; // maxDigits:
// Change this to accommodate your largest number size. Use setMaxDigits()
// to change it!
//
// In general, if you're working with numbers of size N bits, you'll need 2*N
// bits of storage. Each digit holds 16 bits. So, a 1024-bit key will need
//
// 1024 * 2 / 16 = 128 digits of storage.
// var maxDigits;
var ZERO_ARRAY;
var bigZero, bigOne; function setMaxDigits(value)
{
maxDigits = value;
ZERO_ARRAY = new Array(maxDigits);
for (var iza = 0; iza < ZERO_ARRAY.length; iza++) ZERO_ARRAY[iza] = 0;
bigZero = new BigInt();
bigOne = new BigInt();
bigOne.digits[0] = 1;
} setMaxDigits(20); // The maximum number of digits in base 10 you can convert to an
// integer without JavaScript throwing up on you.
var dpl10 = 15;
// lr10 = 10 ^ dpl10
var lr10 = biFromNumber(1000000000000000); function BigInt(flag)
{
if (typeof flag == "boolean" && flag == true) {
this.digits = null;
}
else {
this.digits = ZERO_ARRAY.slice(0);
}
this.isNeg = false;
} function biFromDecimal(s)
{
var isNeg = s.charAt(0) == '-';
var i = isNeg ? 1 : 0;
var result;
// Skip leading zeros.
while (i < s.length && s.charAt(i) == '0') ++i;
if (i == s.length) {
result = new BigInt();
}
else {
var digitCount = s.length - i;
var fgl = digitCount % dpl10;
if (fgl == 0) fgl = dpl10;
result = biFromNumber(Number(s.substr(i, fgl)));
i += fgl;
while (i < s.length) {
result = biAdd(biMultiply(result, lr10),
biFromNumber(Number(s.substr(i, dpl10))));
i += dpl10;
}
result.isNeg = isNeg;
}
return result;
} function biCopy(bi)
{
var result = new BigInt(true);
result.digits = bi.digits.slice(0);
result.isNeg = bi.isNeg;
return result;
} function biFromNumber(i)
{
var result = new BigInt();
result.isNeg = i < 0;
i = Math.abs(i);
var j = 0;
while (i > 0) {
result.digits[j++] = i & maxDigitVal;
i = Math.floor(i / biRadix);
}
return result;
} function reverseStr(s)
{
var result = "";
for (var i = s.length - 1; i > -1; --i) {
result += s.charAt(i);
}
return result;
} var hexatrigesimalToChar = new Array(
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
); function biToString(x, radix)
// 2 <= radix <= 36
{
var b = new BigInt();
b.digits[0] = radix;
var qr = biDivideModulo(x, b);
var result = hexatrigesimalToChar[qr[1].digits[0]];
while (biCompare(qr[0], bigZero) == 1) {
qr = biDivideModulo(qr[0], b);
digit = qr[1].digits[0];
result += hexatrigesimalToChar[qr[1].digits[0]];
}
return (x.isNeg ? "-" : "") + reverseStr(result);
} function biToDecimal(x)
{
var b = new BigInt();
b.digits[0] = 10;
var qr = biDivideModulo(x, b);
var result = String(qr[1].digits[0]);
while (biCompare(qr[0], bigZero) == 1) {
qr = biDivideModulo(qr[0], b);
result += String(qr[1].digits[0]);
}
return (x.isNeg ? "-" : "") + reverseStr(result);
} var hexToChar = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'); function digitToHex(n)
{
var mask = 0xf;
var result = "";
for (i = 0; i < 4; ++i) {
result += hexToChar[n & mask];
n >>>= 4;
}
return reverseStr(result);
} function biToHex(x)
{
var result = "";
var n = biHighIndex(x);
for (var i = biHighIndex(x); i > -1; --i) {
result += digitToHex(x.digits[i]);
}
return result;
} function charToHex(c)
{
var ZERO = 48;
var NINE = ZERO + 9;
var littleA = 97;
var littleZ = littleA + 25;
var bigA = 65;
var bigZ = 65 + 25;
var result; if (c >= ZERO && c <= NINE) {
result = c - ZERO;
} else if (c >= bigA && c <= bigZ) {
result = 10 + c - bigA;
} else if (c >= littleA && c <= littleZ) {
result = 10 + c - littleA;
} else {
result = 0;
}
return result;
} function hexToDigit(s)
{
var result = 0;
var sl = Math.min(s.length, 4);
for (var i = 0; i < sl; ++i) {
result <<= 4;
result |= charToHex(s.charCodeAt(i))
}
return result;
} function biFromHex(s)
{
var result = new BigInt();
var sl = s.length;
for (var i = sl, j = 0; i > 0; i -= 4, ++j) {
result.digits[j] = hexToDigit(s.substr(Math.max(i - 4, 0), Math.min(i, 4)));
}
return result;
} function biFromString(s, radix)
{
var isNeg = s.charAt(0) == '-';
var istop = isNeg ? 1 : 0;
var result = new BigInt();
var place = new BigInt();
place.digits[0] = 1; // radix^0
for (var i = s.length - 1; i >= istop; i--) {
var c = s.charCodeAt(i);
var digit = charToHex(c);
var biDigit = biMultiplyDigit(place, digit);
result = biAdd(result, biDigit);
place = biMultiplyDigit(place, radix);
}
result.isNeg = isNeg;
return result;
} function biDump(b)
{
return (b.isNeg ? "-" : "") + b.digits.join(" ");
} function biAdd(x, y)
{
var result; if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = biSubtract(x, y);
y.isNeg = !y.isNeg;
}
else {
result = new BigInt();
var c = 0;
var n;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] + y.digits[i] + c;
result.digits[i] = n % biRadix;
c = Number(n >= biRadix);
}
result.isNeg = x.isNeg;
}
return result;
} function biSubtract(x, y)
{
var result;
if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = biAdd(x, y);
y.isNeg = !y.isNeg;
} else {
result = new BigInt();
var n, c;
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] - y.digits[i] + c;
result.digits[i] = n % biRadix;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += biRadix;
c = 0 - Number(n < 0);
}
// Fix up the negative sign, if any.
if (c == -1) {
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = 0 - result.digits[i] + c;
result.digits[i] = n % biRadix;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += biRadix;
c = 0 - Number(n < 0);
}
// Result is opposite sign of arguments.
result.isNeg = !x.isNeg;
} else {
// Result is same sign.
result.isNeg = x.isNeg;
}
}
return result;
} function biHighIndex(x)
{
var result = x.digits.length - 1;
while (result > 0 && x.digits[result] == 0) --result;
return result;
} function biNumBits(x)
{
var n = biHighIndex(x);
var d = x.digits[n];
var m = (n + 1) * bitsPerDigit;
var result;
for (result = m; result > m - bitsPerDigit; --result) {
if ((d & 0x8000) != 0) break;
d <<= 1;
}
return result;
} function biMultiply(x, y)
{
var result = new BigInt();
var c;
var n = biHighIndex(x);
var t = biHighIndex(y);
var u, uv, k; for (var i = 0; i <= t; ++i) {
c = 0;
k = i;
for (j = 0; j <= n; ++j, ++k) {
uv = result.digits[k] + x.digits[j] * y.digits[i] + c;
result.digits[k] = uv & maxDigitVal;
c = uv >>> biRadixBits;
//c = Math.floor(uv / biRadix);
}
result.digits[i + n + 1] = c;
}
// Someone give me a logical xor, please.
result.isNeg = x.isNeg != y.isNeg;
return result;
} function biMultiplyDigit(x, y)
{
var n, c, uv; result = new BigInt();
n = biHighIndex(x);
c = 0;
for (var j = 0; j <= n; ++j) {
uv = result.digits[j] + x.digits[j] * y + c;
result.digits[j] = uv & maxDigitVal;
c = uv >>> biRadixBits;
//c = Math.floor(uv / biRadix);
}
result.digits[1 + n] = c;
return result;
} function arrayCopy(src, srcStart, dest, destStart, n)
{
var m = Math.min(srcStart + n, src.length);
for (var i = srcStart, j = destStart; i < m; ++i, ++j) {
dest[j] = src[i];
}
} var highBitMasks = new Array(0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,
0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF); function biShiftLeft(x, n)
{
var digitCount = Math.floor(n / bitsPerDigit);
var result = new BigInt();
arrayCopy(x.digits, 0, result.digits, digitCount,
result.digits.length - digitCount);
var bits = n % bitsPerDigit;
var rightBits = bitsPerDigit - bits;
for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) {
result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) |
((result.digits[i1] & highBitMasks[bits]) >>>
(rightBits));
}
result.digits[0] = ((result.digits[i] << bits) & maxDigitVal);
result.isNeg = x.isNeg;
return result;
} var lowBitMasks = new Array(0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF); function biShiftRight(x, n)
{
var digitCount = Math.floor(n / bitsPerDigit);
var result = new BigInt();
arrayCopy(x.digits, digitCount, result.digits, 0,
x.digits.length - digitCount);
var bits = n % bitsPerDigit;
var leftBits = bitsPerDigit - bits;
for (var i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) {
result.digits[i] = (result.digits[i] >>> bits) |
((result.digits[i1] & lowBitMasks[bits]) << leftBits);
}
result.digits[result.digits.length - 1] >>>= bits;
result.isNeg = x.isNeg;
return result;
} function biMultiplyByRadixPower(x, n)
{
var result = new BigInt();
arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n);
return result;
} function biDivideByRadixPower(x, n)
{
var result = new BigInt();
arrayCopy(x.digits, n, result.digits, 0, result.digits.length - n);
return result;
} function biModuloByRadixPower(x, n)
{
var result = new BigInt();
arrayCopy(x.digits, 0, result.digits, 0, n);
return result;
} function biCompare(x, y)
{
if (x.isNeg != y.isNeg) {
return 1 - 2 * Number(x.isNeg);
}
for (var i = x.digits.length - 1; i >= 0; --i) {
if (x.digits[i] != y.digits[i]) {
if (x.isNeg) {
return 1 - 2 * Number(x.digits[i] > y.digits[i]);
} else {
return 1 - 2 * Number(x.digits[i] < y.digits[i]);
}
}
}
return 0;
} function biDivideModulo(x, y)
{
var nb = biNumBits(x);
var tb = biNumBits(y);
var origYIsNeg = y.isNeg;
var q, r;
if (nb < tb) {
// |x| < |y|
if (x.isNeg) {
q = biCopy(bigOne);
q.isNeg = !y.isNeg;
x.isNeg = false;
y.isNeg = false;
r = biSubtract(y, x);
// Restore signs, 'cause they're references.
x.isNeg = true;
y.isNeg = origYIsNeg;
} else {
q = new BigInt();
r = biCopy(x);
}
return new Array(q, r);
} q = new BigInt();
r = x; // Normalize Y.
var t = Math.ceil(tb / bitsPerDigit) - 1;
var lambda = 0;
while (y.digits[t] < biHalfRadix) {
y = biShiftLeft(y, 1);
++lambda;
++tb;
t = Math.ceil(tb / bitsPerDigit) - 1;
}
// Shift r over to keep the quotient constant. We'll shift the
// remainder back at the end.
r = biShiftLeft(r, lambda);
nb += lambda; // Update the bit count for x.
var n = Math.ceil(nb / bitsPerDigit) - 1; var b = biMultiplyByRadixPower(y, n - t);
while (biCompare(r, b) != -1) {
++q.digits[n - t];
r = biSubtract(r, b);
}
for (var i = n; i > t; --i) {
var ri = (i >= r.digits.length) ? 0 : r.digits[i];
var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1];
var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2];
var yt = (t >= y.digits.length) ? 0 : y.digits[t];
var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1];
if (ri == yt) {
q.digits[i - t - 1] = maxDigitVal;
} else {
q.digits[i - t - 1] = Math.floor((ri * biRadix + ri1) / yt);
} var c1 = q.digits[i - t - 1] * ((yt * biRadix) + yt1);
var c2 = (ri * biRadixSquared) + ((ri1 * biRadix) + ri2);
while (c1 > c2) {
--q.digits[i - t - 1];
c1 = q.digits[i - t - 1] * ((yt * biRadix) | yt1);
c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2);
} b = biMultiplyByRadixPower(y, i - t - 1);
r = biSubtract(r, biMultiplyDigit(b, q.digits[i - t - 1]));
if (r.isNeg) {
r = biAdd(r, b);
--q.digits[i - t - 1];
}
}
r = biShiftRight(r, lambda);
// Fiddle with the signs and stuff to make sure that 0 <= r < y.
q.isNeg = x.isNeg != origYIsNeg;
if (x.isNeg) {
if (origYIsNeg) {
q = biAdd(q, bigOne);
} else {
q = biSubtract(q, bigOne);
}
y = biShiftRight(y, lambda);
r = biSubtract(y, r);
}
// Check for the unbelievably stupid degenerate case of r == -0.
if (r.digits[0] == 0 && biHighIndex(r) == 0) r.isNeg = false; return new Array(q, r);
} function biDivide(x, y)
{
return biDivideModulo(x, y)[0];
} function biModulo(x, y)
{
return biDivideModulo(x, y)[1];
} function biMultiplyMod(x, y, m)
{
return biModulo(biMultiply(x, y), m);
} function biPow(x, y)
{
var result = bigOne;
var a = x;
while (true) {
if ((y & 1) != 0) result = biMultiply(result, a);
y >>= 1;
if (y == 0) break;
a = biMultiply(a, a);
}
return result;
} function biPowMod(x, y, m)
{
var result = bigOne;
var a = x;
var k = y;
while (true) {
if ((k.digits[0] & 1) != 0) result = biMultiplyMod(result, a, m);
k = biShiftRight(k, 1);
if (k.digits[0] == 0 && biHighIndex(k) == 0) break;
a = biMultiplyMod(a, a, m);
}
return result;
} function RSAKeyPair() {
var encryptionExponent = "010001";
var decryptionExponent = "";
var modulus = "9A568982EE4BF010C38B5195A6F2DC7D66D5E6C02098CF25044CDD031AC08C6569D7063BB8959CB3FCB5AF572DE355AFA684AF7187948744E673275B494F394AF7F158841CA8B63BF65F185883F8D773A57ED731EDCD1AF2E0E57CD45F5F3CB4EBDD38F4A267E5ED02E7B44B93EDFFDADBDC8368019CD496BEC735BAF9E57125";
this.e = biFromHex(encryptionExponent);
this.d = biFromHex(decryptionExponent);
this.m = biFromHex(modulus);
this.digitSize = 2 * biHighIndex(this.m) + 2;
this.chunkSize = this.digitSize - 11;
this.radix = 16;
this.barrett = new BarrettMu(this.m);
} function twoDigit(n) {
return (n < 10 ? "0" : "") + String(n);
} function encryptedString(key, s) {
if (key.chunkSize > key.digitSize - 11) {
return "Error";
}
var a = new Array();
var sl = s.length; var i = 0;
while (i < sl) {
a[i] = s.charCodeAt(i);
i++;
}
var al = a.length;
var result = "";
var j, k, block;
for (i = 0; i < al; i += key.chunkSize) {
block = new BigInt();
j = 0;
var x;
var msgLength = (i + key.chunkSize) > al ? al % key.chunkSize : key.chunkSize;
var b = new Array();
for (x = 0; x < msgLength; x++) {
b[x] = a[i + msgLength - 1 - x];
}
b[msgLength] = 0; // marker
var paddedSize = Math.max(8, key.digitSize - 3 - msgLength); for (x = 0; x < paddedSize; x++) {
b[msgLength + 1 + x] = Math.floor(Math.random() * 254) + 1;
} b[key.digitSize - 2] = 2; // marker
b[key.digitSize - 1] = 0; // marker for (k = 0; k < key.digitSize; ++j) {
block.digits[j] = b[k++];
block.digits[j] += b[k++] << 8;
}
var crypt = key.barrett.powMod(block, key.e);
var text = key.radix == 16 ? biToHex(crypt) : biToString(crypt, key.radix);
result += text + " ";
}
return result.substring(0, result.length - 1); // Remove last space.
} setMaxDigits(129);
var key = new RSAKeyPair();
// 第一步在这里创建函数,username,必然是获取到的,所以需要传个值,
// 同理,处理password function getusername(username) {
// 很明显,username是被urlencode处理过的,直接使用方法
var user = encryptedString(key, encodeURIComponent(username));
return user
} function getpwd(password) {
// 原文中的 $('#password').val() jquery写法,它的意思是,从password标签中获取value值,
// val的()中没有对象,即为取值,有东西即为赋值
var pwd = encryptedString(key, password);
return pwd
}
var info = 'flash:begin^^navigator:begin^^screenDPI:undefined^^cookieEnabled:true^^platform:Win32^^appCodeName:Mozilla^^appMinorVersion:undefined^^appName:Netscape^^appVersion:5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36^^browserLanguage:undefined^^cpuClass:undefined^^systemLanguage:undefined^^userAgent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36^^userLanguage:undefined^^language:zh-CN^^language:zh-CN^^oscpu:undefined'
function getCL() {
var cl = base64encode(info);
return cl
} // 经对这俩函数初步解析(眼睛看),发现这个是个函数encryptedString 可以直接搜索这个函数
// 即 function encryptedString的地方,也可以通过打断点进入函数,
// 将函数整体复制过来,发现文件不大,检查下文件内部数据,基本都是有用数据,
// 就全部拿过来,放置到自定义函数前面
// 调用后,发现key未定义,再看源码,发现就在上面,复制过来,
// 他的上一行setMaxDigits(129);看起来是个单独调用,也取过来
// 继续调用自定义函数,发现函数setMaxDigits不存,将改行注释掉后,发现biFromHex函数不存在,
// 经查找,这俩函数在一起,干脆全拿来放在前面,恢复注释
// 继续调用(鬼鬼JS 直接点加载也会提醒,但有时不会提醒详细,需要点V8运行)发现BarrettMu未定义,继续找
// 发现这个文件很小,内部代码均为关联代码,全复制过来
// 至此,鬼鬼JS工具提示完成,工具中调用函数可以得到与浏览器类似结果
// 我们回到py文件中,利用execJS工具调用试试

JS逆向-抠代码的第一天【手把手学会抠代码】的更多相关文章

  1. JS逆向-抠代码的第二天【手把手学会抠代码】

    今天的学习项目:沃支付:https://epay.10010.com/auth/login 清空浏览器缓存后,打开网页,输入手机号,密码222222,按照网站要求填入验证码(sorry,我没有账号密码 ...

  2. JS逆向-抠代码的第四天【手把手学会抠代码】

    今天是md5巩固项目,该项目比昨天的复杂一些,但方法思路是一样的. 今天的目标:https://www.webportal.top/ 打开网站,填入账号密码(密码项目以123456做测试).点击登录抓 ...

  3. 兄弟,你爬虫基础这么好,需要研究js逆向了,一起吧(有完整JS代码)

    这几天的确有空了,看更新多快,专门研究了一下几个网站登录中密码加密方法,比起滑块验证码来说都相对简单,适合新手js逆向入门,大家可以自己试一下,试不出来了再参考我的js代码.篇幅有限,完整的js代码在 ...

  4. 网络爬虫之记一次js逆向解密经历

    1 引言 数月前写过某网站(请原谅我的掩耳盗铃)的爬虫,这两天需要重新采集一次,用的是scrapy-redis框架,本以为二次爬取可以轻松完成的,可没想到爬虫启动没几秒,出现了大堆的重试提示,心里顿时 ...

  5. 这个爬虫JS逆向加密任务,你还不来试试?逆向入门级,适合一定爬虫基础的人

    友情提示:在博客园更新比较慢,有兴趣的关注知识图谱与大数据公众号吧.这次选择苏宁易购登录密码加密,如能调试出来代表你具备了一定的JS逆向能力,初学者建议跟着内容调试一波,尽量独自将JS代码抠出来,实在 ...

  6. 爬虫必看,每日JS逆向之爱奇艺密码加密,今天你练了吗?

    友情提示:优先在公众号更新,在博客园更新较慢,有兴趣的关注一下知识图谱与大数据公众号,本次目标是抠出爱奇艺passwd加密JS代码,如果你看到了这一篇,说明你对JS逆向感兴趣,如果是初学者,那不妨再看 ...

  7. 淘宝的sign参数js逆向

    前言:现在网站都有很强的反爬机制,都是非常常见的是用js前端加密参数,所以不得不去分析和逆向js混淆后的代码 一. 打开天猫或淘宝,shift+ctrl+F12全局搜索sign参数. 这里发现很多地方 ...

  8. python爬虫之JS逆向

    Python爬虫之JS逆向案例 由于在爬取数据时,遇到请求头限制属性为动态生成,现将解决方式整理如下: JS逆向有两种思路: 一种是整理出js文件在Python中直接使用execjs调用js文件(可见 ...

  9. python爬虫之JS逆向某易云音乐

    Python爬虫之JS逆向采集某易云音乐网站 在获取音乐的详情信息时,遇到请求参数全为加密的情况,现解解决方案整理如下: JS逆向有两种思路: 一种是整理出js文件在Python中直接使用execjs ...

随机推荐

  1. UML类图设计神器 AmaterasUML 的配置及使用

    最近写论文需要用到UML类图,但是自己画又太复杂,干脆找了个插件,是Eclipse的,也有IDEA的,在这里我简单说下Eclipse的插件AmaterasUML 的配置与使用吧. 点击这里下载Amat ...

  2. Gym 101480F Frightful Formula(待定系数)题解

    #include<cmath> #include<set> #include<map> #include<queue> #include<cstd ...

  3. MOOC学习成果认证及对高等教育变革路径的影响

    MOOC是网络开放教育创新发展的产物,也是备受人们欢迎的网络学习途径.当前制约MOOC能否可持续深入发展的问题聚焦于MOOC学习成果能否得到合理的认证.MOOC学习成果认证分为非学分认证和学分认证.M ...

  4. Github access token

    Github access token https://github.com/settings/tokens https://docs.github.com/en/free-pro-team@late ...

  5. window resize & resize observer

    window resize & resize observer https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_e ...

  6. babel 常用操作

    astexplorer babel-types code to ast const { parse } = babel; const code = ` for (let k in ${data}) { ...

  7. Dart: puppeteer库

    和node的差不多,只有写API不一样 puppeteer 地址 安装依赖 dependencies: puppeteer: ^1.7.1 下载 chrome-win 到 <project_ro ...

  8. go-admin在线开发平台学习-3[细节解析]

    本章节主要的内容是对go-admin中的一些有趣编码进行分析,为自己以后提供一些借鉴 使用cli方式启动项目 使用cobra[眼镜蛇]完成强壮cli的工具,确保稳定. 使用cli的方式启动项目的好处显 ...

  9. 【PY从0到1】 一文掌握Pandas量化基础

    # 2[PY从0到1] 一文掌握Pandas量化基础 # Numpy和pandas是什么关系呢? # 在我看来,np偏向于数据细节处理,pd更偏向于表格整体的处理. # 要记住的pd内部的数据结构采用 ...

  10. 5分钟入门websocket

    5 个步骤快速掌握消息发送和接收 获取您的 appkey 先注册一个irealtime账号,然后登录到后台管理端,创建一个免费应用,就能得到您的 appkey.点击注册 各种前端生态端集成 ireal ...