记一次好笑的逆向过程

2024-06-23 01:48
文章标签 逆向 好笑 一次 过程

本文主要是介绍记一次好笑的逆向过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为什么说是好笑,看到最后就明白了。

目标链接:url

打xhr断点并发起请求:

查看调用栈,发现了发起request的位置:

向上查看代码,发现了这个东西:

知道ajax请求里的signature参数和rs参数是从哪里来的。看一下这部分代码,可以知道构造url时的u,d,t来自哪里

u,d,t三个参数里,u和d很容易理解,主要是t参数如何获取,所以在这里重新开始打断点。s其实是一个函数,[u, d, l, window.couid, e, c, h["type" + e]].sort().join("")是将u,d等参数的列表变为一个字符串,作为s函数的参数。继续单步调试进入s函数:

这里的t就是前面说的字符串。继续调试,一顿调试后,找到最重要的一个函数doProcessBlock,然后基本就能知道如何获取加密后signature参数的值了。

整理了一下,获取加密后的链接,主要经过下面几个过程:

获取一个时间参数u:

import time
u = int(time.time()*1000)

获取参数d:

def get_d():un = '''function(t) {var n = "",e = false,r = undefined,i = t,a = ["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", "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"];e && (i = Math.round(Math.random() * (r - t)) + t);for (var o = 0; o < i; o++) {n += a[Math.round(Math.random() * (a.length - 1))]}return n;}'''t = 16return js2py.eval_js(un)(t)

下面的代码是还原:[u, d, l, window.couid, e, c, h["type" + e]].sort().join(""),最后得到一个字符

lis = [u, d, l, couid, e, c, h]
lis = [str(i) for i in lis]
lis.sort()
old = ''.join(lis)

除了u和d参数,其余参数实际为固定的参数,需要自行逆向获取。这个old就是前面提到的那一长串字符串t

整个加密过程就是对几个数组的操作,首先是得到一个8位初始数组:

def get_words():un = '''function f1() {
var f = [], s = [];
function jisuan() {function t(t) {for (var r = Math.sqrt(t), n = 2; n <= r; n++) if (! (t % n)) return ! 1;return ! 0}function r(e) {return 4294967296 * (e - (0 | e)) | 0}for (var n = 2,i = 0; i < 64;) t(n) && (i < 8 && (f[i] = r(Math.pow(n, .5))), s[i] = r(Math.pow(n, 1 / 3)), i++),n++
}
jisuan();
return f;
}'''return js2py.eval_js(un)()

通过old字符串得到16位的数组1:

def get_new_words(t):un = '''function(e) {for (var t = e.length,r = [], n = 0; n < t; n++) r[n >>> 2] |= (255 & e.charCodeAt(n)) << 24 - n % 4 * 8;return r;}'''r = js2py.eval_js(un)(t)return r

通过数组1得到32位的数组2:

def doFinalize(new_words):un = '''function(t){var r=t, n=496, i=496;r[i >>> 5] |= 128 << 24 - i % 32;r[14 + (i + 64 >>> 9 << 4)] = Math.floor(n / 4294967296);r[15 + (i + 64 >>> 9 << 4)] = n;sigBytes = 4 * r.length;h = r.splice(0, 32)return h;}'''result1 = js2py.eval_js(un)(new_words)return result1

使用最开始的8位数组和32位数组经过doProcessBlock函数得到新的8位数组,然后使用新的8位数组和32位数组又得到一个新的8位数组,doProcessBlock函数如下:

def doProcessBlock(e, t, words):un = '''function(e, t, words, s) {var c = [];for (var r = words,n = r[0], i = r[1], a = r[2], o = r[3], f = r[4], h = r[5], u = r[6], d = r[7], l = 0; l < 64; l++) {if (l < 16) c[l] = 0 | e[t + l];else {var p = c[l - 15],b = (p << 25 | p >>> 7) ^ (p << 14 | p >>> 18) ^ p >>> 3,y = c[l - 2],m = (y << 15 | y >>> 17) ^ (y << 13 | y >>> 19) ^ y >>> 10;c[l] = b + c[l - 7] + m + c[l - 16]}var v = n & i ^ n & a ^ i & a,g = (n << 30 | n >>> 2) ^ (n << 19 | n >>> 13) ^ (n << 10 | n >>> 22),_ = d + ((f << 26 | f >>> 6) ^ (f << 21 | f >>> 11) ^ (f << 7 | f >>> 25)) + (f & h ^ ~f & u) + s[l] + c[l];d = u,u = h,h = f,f = o + _ | 0,o = a,a = i,i = n,n = _ + (g + v) | 0}r[0] = r[0] + n | 0,r[1] = r[1] + i | 0,r[2] = r[2] + a | 0,r[3] = r[3] + o | 0,r[4] = r[4] + f | 0,r[5] = r[5] + h | 0,r[6] = r[6] + u | 0,r[7] = r[7] + d | 0return r;}'''s = get_s()result = js2py.eval_js(un)(e, t, words, s)return result

代码里的s其实就是get_words函数里那个s,修改get_words函数中js代码的返回值即可。

使用得到新的8位数组,就能获取最后的signature参数的值了:

def get_str(l, count):un = '''function(words, sigBytes) {for (var t = words,r = sigBytes,n = [], i = 0; i < r; i++) {var a = t[i >>> 2] >>> 24 - i % 4 * 8 & 255;n.push((a >>> 4).toString(16)),n.push((15 & a).toString(16))}return n.join("")}'''count = 32return js2py.eval_js(un)(l, count)

以上,就是整个逆向过程。

最后说一下为什么好笑,因为对js还是了解的不深,所以经过了漫长的调试才获取到最后的signature参数。但实际上对js足够了解的人,或者js逆向经验老到的人,看到signature参数的值基本就能猜到,signature参数是经过sha256加密后得到。。。。。。

费劲巴累的,最后把人家加密代码抠出来才解决问题。。。。。。

这篇关于记一次好笑的逆向过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085987

相关文章

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

剑指offer(C++)--数组中只出现一次的数字

题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 class Solution {public:void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {int len = data.size();if(len<2)return;int one = 0;for(int i

剑指offer(C++)--第一个只出现一次的字符

题目 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写). class Solution {public:int FirstNotRepeatingChar(string str) {map<char, int> mp;for(int i = 0; i < str.size(); ++i)m

逆向学习汇编篇:内存管理与寻址方式

本节课在线学习视频(网盘地址,保存后即可免费观看): ​​https://pan.quark.cn/s/3ceeb9ae6d98​​ 在汇编语言的世界中,内存管理和寻址方式是构建程序的基础。理解这些概念不仅对于编写高效的汇编代码至关重要,也是进行逆向工程分析的关键技能。本文将深入探讨内存管理的基本原则和多种寻址方式,并通过代码案例来展示它们的实际应用。 1. 内存管理 内存管理涉及如何分配

LeetCode —— 只出现一次的数字

只出现一次的数字 I  本题依靠异或运算符的特性,两个相同数据异或等于0,数字与0异或为本身即可解答。代码如下: class Solution {public:int singleNumber(vector<int>& nums) {int ret = 0;for (auto e : nums){ret ^= e;}return ret;}};  只出现一次的数字 II

mysql中存储过过程和游标的联合使用

1.SQL如下: DELIMITER //DROP PROCEDURE IF EXISTS PrintAllEmployeeNames5;CREATE PROCEDURE PrintAllEmployeeNames5()BEGINDECLARE error_count INT DEFAULT 0;DECLARE num INT ;DECLARE done INT DEFAULT

Class 对象在执行引擎中的初始化过程

一个 class 文件被加载到内存中需要经过 3 大步:装载、链接、初始化。 装载 装载是指 Java 虚拟机查找 .class 文件并生成字节流,然后根据字节流创建 java.lang.Class 对象的过程。 链接 链接过程分为 3 步:验证、准备、解析。 验证: 初始化 这是 class 加载的最后一步,这一阶段是执行类构造器方法的过程,并真正初始化类变量。 1.文件格式检验:检

绿联nas折腾过程中遇到的问题

绿联nas折腾过程中遇到的问题 目录 ssh权限问题超级用户 ssh 权限问题 使用chmod -R 777 目录/ 给指定目录及其所有子目录和文件设置最大的权限,权限设置为 rwxrwxrwx(读、写、执行权限给所有用户)。这个命令会将目录和文件的权限设置为非常宽松,允许所有用户对它们进行任何操作。 700只有所有者有读和写以及执行的权限 查看访问权限:ls -l 当前文件夹下所有用

一次OOM引起的优化

一次OOM引发的优化 最近在自己研究一个应用,功能简单,所以就想在ui上面下些功夫。 关于界面的想法: 页面A对某一类型的数据项进行增删改,存入数据库中。页面B对数据库中现存的数据项放入自定义View中进行显示(一条数据和一个view是对应的),从而实现一种类似Metro风格的布局。 实施 自定义View不是很难,算是初学,所以在数据适配显示、尺寸计算方面耽误了一些时间。原来的想法

对递归执行过程的简单描述

1. 分析代码 #include <stdio.h>void fun(int n){printf("1th - Level: %d Address: %d\n", n, &n);if(n < 3)fun(n+1);printf("2th - Level: %d Address: %d\n", n, &n);}int main(){fun(1);return 0;} 输出结果为: