jsvmp某书x-s算法分析还原

1.前沿

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

2.网址

aHR0cHM6Ly93d3cueGlhb2hvbmdzaHUuY29tL2V4cGxvcmU/Y2hhbm5lbF9pZD1ob21lZmVlZF9yZWNvbW1lbmQ=

3.加密参数定位

3.1:搜索定位

全局搜索加密参数X-S在图中位置下断点

可以看出X-S的值来自l["X-s"]

l = (a && void 0 !== window._webmsxyw ? window._webmsxyw : encrypt_sign)(c, i) || {};

l是一个三元表达式

这段代码简化就是window._webmsxyw(c,i)

传入两个参数分别是c和i,如下图

X-S的值是从window._webmsxyw(c,i)函数中获取到的

3.2:hook定位

观察x-s加密字段值的结构,前4位‘XYW_’值不变,对base64熟悉的朋友eyj并不陌生,ey - > base64解码 -> result = '{',对XYW_后面的整块值进行解码

解密发现其它字段均为明文,只有payload一处加密,定位到payload加密位置。Json对象转化为字符串必定会用到JSON.stringify()方法,对该方法进行hook

JSON.stringify_ = JSON.stringify;
// 重写JSON.stringify方法
JSON.stringify = function () {
    if (arguments[0] && arguments[0]['payload']) {
        // 设置断点
        debugger;
    }
    // 调用原始的JSON.stringify方法并返回其结果
    return JSON.stringify_.apply(this, arguments);
};

跟栈进入函数内部,发现是jsvmp

如何解决?

1.rpc调用

2.浏览器补环境

3.纯算还原算法

本次我们采用纯算法分析

4.纯算分析

对于小红书的纯算分析还原,可以看看志远大佬的视频,干货给的相当足。

4.1JSVMP是什么 

jsvmp(JavaScript Virtual Machine Protection)是一种前端代码虚拟化保护技术。它将JavaScript源代码首先编译为自定义的字节码,只有对应的解释器才能执行这种字节码。(图片来源老妖哥)


在JSVMP逆向分析中,寄存器,循环是重要的特征,还有有一个特性,加密结果是一个一个字符生成的,基本由一个循环就是for循环或者while循环以及switch case控制。这一点至关重要,算法的分析还原就依赖这个特性。

JSVMP,一般在代码中会有一个超长字符串(指令),然后会把这个字符串decode成一个大数组,不断循环从数组中取指令,分配函数执行运算操作,运算过程会在一个数组或者对象中不断放进或取出生成的值,最后生成目标结果,这个过程会有+,/,%,*操作,会有个apply操作,这些都是插桩的关键位置。

4.2代码简单分析

代码复制vscode,折叠

查看指令集大数组_ace_aec23,数组里面大部分函数都调用_ace_1ae3,而_ace_1ae3函数内部调用_ace_b81ca函数,所以_ace_b81ca是个插桩的日志点

插桩分析

4.3第一个插桩日志点

回到payload加密生成的位置,追溯堆栈,根据日志点对apply函数进行插桩。

本次的log日志点可以看一个大致的流程,如果有方法(split、trim等方法)对字符串操作,可以打印出来,加密结果也是字符串形式,所以本日志点可能打印出解密结果值。

//对应apply 函数 ,this , 参数
'11-111'.split("-") // 方法:split  , this:11-111 , 参数:-

// 为false断点不生效,但前面的js代码仍然运行
console.log(_ace_8712,_ace_25a6._ace_936,_ace_bdcc);false;  

日志打印:

div检测

检测dom、vm环境

window._webmsxyw(c,i),c的值/api/sns/web/v1/homefeed,参数传入应该会用到,搜索c的值,定位到最后一个

滑倒底部,1732584193, -271733879, -1732584194, 271733878,md5的初始化魔数

猜测对传入的参数进行md5加密:md5(url=/api/sns/web/v1/homefeed{"cursor_score":"","num":27,"refresh_type":1,"note_index":27,"unread_begin_note_id":"","unread_end_note_id":"","unread_note_count":0,"category":"homefeed_recommend","search_key":"","need_num":12,"image_formats":["jpg","webp","avif"],"need_filter_image":false})

result:755c054d97e5450acda5f156156232c2

继续向下查看日志:猜想正确,是对请求url进行md5加密

第一次插桩位置来看,没有看出太多的信息,主要是对环境的校验,以及对请求参数做md5加密

4.4第二个插桩日志点

把文件中指令集展开来看,定位到加法指令集,有字符拼接的过程,然后进行插桩(本地js文件替换目标js文件

日志15w多行,

encrypt_sign(c, i) ,参数c的值 /api/redcaptcha/v2/getconfig

日志中定位到最后一次出现该参数的位置

由第一个插桩日志分析可知,对入参数做了md5

md5(url=/api/redcaptcha/v2/getconfig{}) ,result = 6667296f17398985a2a087300d1474e4

既然做了md5,后续肯定有调用的地方,我们直接定位到最后一次调用md5加密值的位置

x1=6667296f17398985a2a087300d1474e4;x2=0|0|0|1|0|0|1|0|0|0|1|0|0|0|0;x3=18f7634e135lgkcv8aeo3eaixuf91jo1lopan6w4a30000208736;x4=1715678349667; (x1234)

该字符串由:

x1 = 6667296f17398985a2a087300d1474e4

x2 =0|0|0|1|0|0|1|0|0|0|1|0|0|0|0

x3 = 18f7634e135lgkcv8aeo3eaixuf91jo1lopan6w4a30000208736

x4 = 1715678349667

这4部分组成

x1 : md5(请求参数{})

x2:检测浏览器环境信息(不变),从两次插桩可以看出有大量的环境检测信息

x3:cookie中的a1 值

x4:当前时间的毫秒时间戳

继续查看日志,发现有个字符串一直逐字符增加

定位到最后

eDE9NjY2NzI5NmYxNzM5ODk4NWEyYTA4NzMwMGQxNDc0ZTQ7eDI9MHwwfDB8MXwwfDB8MXwwfDB8MHwxfDB8MHwwfDA7eDM9MThmNzYzNGUxMzVsZ2tjdjhhZW8zZWFpeHVmOTFqbzFsb3BhbjZ3NGEzMDAwMDIwODczNjt4ND0xNzE1Njc4MzQ5NjY3Ow==

看字符串格式应该是base64编码:

原来是对x1234进行了base64编码,但是这仍然不是我们目标payload的值,猜测可能是对base64(x1234)进行了某种加密运算

4.5第三个插桩日志点

上面分析_ace_b81ca是个插桩的日志点,现在对该函数进行插桩

该函数第一个参数在第二个插桩日志点已经分析过

从第二个参数_ace_7e97a开始分析

分析日志点,第二部插桩可知,对x1234做一个base64编码,直接搜索ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

继续向下分析,发现很多数字数组,遇到这种数组需要留意,向着常见的加密算法初始化魔数联想,方便快速识别出加密算法

520,134349312是des常用的标识数,找一份js 的des源码进行对比验证

16进制->10进制

0x208 - > 520

0x8020200 -> 134349312

现在确定是des算法,需要找key,key一般在加密的时候传入,直接定位到加密算法的头部。

在分析日志的时候发现'encrypt'相关的字眼,搜素发现第一次出现'encrypt'下方有一个数组,疑似key

des源码实现,git找一份源码实现,加解密正确


var encodeHex = (s) => {
  let r = '';
  const hexes = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
  for (let i = 0; i < s.length; i++) {r += hexes [s.charCodeAt(i) >> 4] + hexes [s.charCodeAt(i) & 0xf];}
  return r;
}

var decodeHex = function (h) {
  let r = '';
  for (let i = (h.substring(0, 2) === '0x') ? 2 : 0; i < h.length; i += 2) {
    r += String.fromCharCode(parseInt(h.substring(i, i + 2), 16));
  }
  return r;
}

//加密
param1 = "x1=a6bcbb01f6f503ed31a72e5699f50058;x2=1|0|0|1|0|0|1|0|0|0|1|0|0|0|0;x3=18e7f1486c6kbmd6ngao21fez0b9o9xw2pep1912330000407442;x4=1713171492576;"
result = encodeHex(des("", btoa(param1), 1, 0, undefined, 0))
console.log(result) //b0b6165929b8dfb112304496eb5ae3979e0cd4a7b8cc5483dc760b9dc8bb62bf2853bc3c9adade8de749dc8064bff3bd277705ea9f4abd360d74aa31b54c72cd0d74aa31b54c72cdac489b9da8ce5e48f4afb9acfc3ea26fe0b266a6b4cc3cb55feb2433893ad2194003d4f0991acda0cf6ab2786d98b16e03535f6b11656835f6b1d67df72fe1bb1132db9ac45bda86e0c6c2c1ddc6d73e45fa8a11b55a7c95af4d4230e9c63f5afc0b4ded490db4e36e5949374a6b095328cdc7a2bb270cf1


//解密
encrypt_param = "b0b6165929b8dfb112304496eb5ae3979e0cd4a7b8cc5483dc760b9dc8bb62bf2853bc3c9adade8de749dc8064bff3bd277705ea9f4abd360d74aa31b54c72cd0d74aa31b54c72cdac489b9da8ce5e48f4afb9acfc3ea26fe0b266a6b4cc3cb55feb2433893ad2194003d4f0991acda0cf6ab2786d98b16e03535f6b11656835f6b1d67df72fe1bb1132db9ac45bda86e0c6c2c1ddc6d73e45fa8a11b55a7c95af4d4230e9c63f5afc0b4ded490db4e36e5949374a6b095328cdc7a2bb270cf1"
res = atob(des("", decodeHex(encrypt_param), 0, 0, undefined, 0))
console.log(res)  //x1=a6bcbb01f6f503ed31a72e5699f50058;x2=1|0|0|1|0|0|1|0|0|0|1|0|0|0|0;x3=18e7f1486c6kbmd6ngao21fez0b9o9xw2pep1912330000407442;x4=1713171492576;

5.总结

分析推到过程大部分靠着经验而言,需要对常见的加密算法有所了解

  1. 分析x1是md5加密,md5初始化魔数要熟悉,在算法还原时,可以根据特征识别判断出MD5加密,从而能够节约大量的时间。

    A:0x67452301 (1732584193)

    B:0xefcdab89 (-271733879)

    C:0x98badcfe (-1732584194)

    D:0x10325476 (271733878)

  2. base64编码编号特征比较明显,字符串的尾部带有==号,或者代码中带着 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

  3. 分析Des。不知道秘钥和IV没关系。尝试插桩自吐出iv或者key的值也能完成加密。

      0x208 - > 520

      0x8020200 -> 134349312

  4. 插桩位置比较关键

        4.1 apply函数,涉及对字符串的操作

        4.2 加法指令集,涉及字符串的拼接

        4.3 通用函数,指令集都调用这个函数,可以抛出更多日志信息

        4.4 插桩根据日志分析,可以加一些过滤条件,减少无用日志输出。

还原jsvmp-某乎_x-zes-96参数算法,首先需要了解该算法的具体逻辑和实现方式。接下来是一份手把手教学,帮助你进行还原。 1. 阅读文档:首先,找到jsvmp-某乎_x-zes-96参数算法的相关文档或说明,并仔细阅读。理解算法的目的、输入、输出和具体实现细节。 2. 分析算法:根据文档中的描述,仔细分析算法的各个步骤和计算逻辑。了解算法使用的数据结构、数学模型和函数等。 3. 实践案例:找到使用该算法的实践案例,或者自己创建一个简单的案例。通过这个案例,可以更好地理解算法的工作方式和参数调整的影响。 4. 调试工具:使用调试工具对代码进行逐行调试。在关键节点上加入断点,观察变量和数据的变化过程,以及函数的执行顺序。通过这种方式,深入了解算法的执行过程。 5. 修改参数:通过调试分析,找到算法中的参数和默认设置。尝试更改这些参数的数值,观察算法的输出结果的变化。通过不断修改参数和分析结果,逐渐掌握算法的运行规律。 6. 反向工程:通过对算法代码的逆向分析,尝试还原参数的计算过程。对研究的代码进行逆向工程,分析其中的数学运算和逻辑判断。通过逆向工程,可以更好地理解参数的计算方式。 7. 文档总结:将还原过程中的关键步骤和分析结果总结起来,形成详细的文档。这份文档可以帮助其他人了解算法还原过程,同时也对自己的学习过程进行总结和回顾。 以上是一个基本的手把手教学,希望能够帮助你还原jsvmp-某乎_x-zes-96参数算法。请注意,由于算法的具体实现和难度因人而异,实际操作过程可能比上述步骤更加复杂和耗时,需要耐心和技术能力的支持。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CgfFan

感谢看官老爷赏的咖啡钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值