• 记一次简单的js逆向分析


    背景

            朋友让帮忙爬一点数据,用作数据分析来用,网址如下:

            aHR0cHM6Ly93d3cub2tsaW5rLmNvbS96aC1jbi9idGMvdHgtbGlzdD9saW1pdD0yMCZwYWdlTnVtPTE=

    分析该网站

    1. 抓包

            该接口下请求头中的 `x-apiKey` 参数,就是我们需要破解的参数。看起来像是base64加密,废话不多说,去 在线加密解密 中测试一下,结果如下:

    ​        确实是一个base64加密,是由两个参数通过 `|` 连接起来的,接下来就是分析,这两个参数的生成逻辑了。

    2. 定位js代码

            然后,重新刷新网页,发现断点生效,并定位到关键代码

    ​3. 解密参数生成逻辑

    3.1 通过单步调试js代码,发现如下代码

    3.2 分析js代码

            3.2.1 getApiKey函数

                    变量t是获取当前时间,变量e是调用encryptApiKey函数实现的;

                    返回值t是把变量t作为参数传递给encryptTime函数得到的值t1;

                    最后把t1和e作为参数,传递给comb函数,获得最终的x-apiKey。

            3.2.2 encryptTime函数

                    t为传进来的时间戳,经过 `(1 * t + 1111111111111).toString().split("")` 处理后得到e;

                    r, n, o 为[0-10]的随机整数,经过 `e.concat([r, n, o]).join("")` 处理生成新的值。

            3.3.3 encryptApiKey函数

                    this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab",为固定值;

                    该函数在API_KEY的基础上进行基础的字符串操作,得到新的值。

            3.3.4 comb函数

                    对参数t和e通过 `|` 合并起来,并进行btoa操作。

    4. 复写js代码

    1. global.Buffer = global.Buffer || require('buffer').Buffer;
    2. if (typeof btoa === 'undefined') {
    3. global.btoa = function (str) {
    4. return new Buffer.from(str).toString('base64');
    5. };
    6. }
    7. if (typeof atob === 'undefined') {
    8. global.atob = function (b64Encoded) {
    9. return new Buffer.from(b64Encoded, 'base64').toString();
    10. };
    11. }
    12. var self = global
    13. window = {}
    14. function encryptTime(t){
    15. var e = (1 * t + 1111111111111).toString().split(""),
    16. r = parseInt(10 * Math.random(), 10),
    17. n = parseInt(10 * Math.random(), 10),
    18. o = parseInt(10 * Math.random(), 10);
    19. return e.concat([r, n, o]).join("")
    20. }
    21. function encryptApiKey(){
    22. //this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
    23. var t = "a2c903cc-b31e-4547-9299-b6d07b7631ab",
    24. e = t.split(""),
    25. r = e.splice(0, 8);
    26. console.log(e.concat(r).join(""))
    27. return e.concat(r).join("")
    28. }
    29. function comb(e, t){
    30. /*
    31. * var r = "".concat(t, "|").concat(e) 时
    32. * 得到的结果为:Mjc2ODExNzExOTg2MTg4OXwtYjMxZS00NTQ3LTkyOTktYjZkMDdiNzYzMWFiYTJjOTAzY2M=
    33. * 经过base64解密后的结果为:2768117119861889|-b31e-4547-9299-b6d07b7631aba2c903cc
    34. *
    35. * 而浏览器最终生成的x-apiKey的值为:LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3NjgxMTM1Nzc3MzE4ODk=
    36. * 经过解密后的值为:-b31e-4547-9299-b6d07b7631aba2c903cc|2768113577731889
    37. *
    38. * 两次解密的结果不一样,区别就是 `|` 前后的顺序不一致
    39. *
    40. * 所以,把t和e的位置颠倒一下即可
    41. * 即:当 r = "".concat(e, "|").concat(t) 时,能得到正确的x-apiKey
    42. */
    43. var r = "".concat(e, "|").concat(t);
    44. return self.btoa(r)
    45. }
    46. function getApiKey(){
    47. var t = (new Date).getTime(),
    48. e = encryptApiKey();
    49. return t = encryptTime(t), comb(e, t)
    50. }
    51. res = getApiKey()
    52. console.log(res)

    5. python代码实现

    1. # _*_ coding: utf-8 _*_
    2. # @Time: 6:29 下午
    3. # @File: demo.py
    4. # @Author: liyf
    5. import requests
    6. import execjs
    7. def get_apikey():
    8. with open('demo.js', 'r') as f:
    9. js_str = f.readlines()
    10. ctx = execjs.compile(''.join(js_str))
    11. return ctx.call('getApiKey')
    12. def get_json_data():
    13. url = 'aHR0cHM6Ly93d3cub2tsaW5rLmNvbS96aC1jbi9idGMvdHgtbGlzdD9saW1pdD0yMCZwYWdlTnVtPTE='
    14. headers = {
    15. 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
    16. 'x-apiKey': get_apikey()
    17. }
    18. response = requests.get(url, headers=headers)
    19. return response.json()
    20. def parse():
    21. result = get_json_data()
    22. data_list = result['data']['hits']
    23. for data in data_list:
    24. print(f'交易哈希: {data["hash"]}\n所在区块: {data["blockHeight"]}\n输入: {data["inputsCount"]}\n输出: {data["outputsCount"]}\n数量(BTC): {data["realTransferValue"]}')
    25. print('***'*30)
    26. if __name__ == '__main__':
    27. parse()

    6. 运行结果展示

  • 相关阅读:
    Java多并发(七)| Executor框架(四种线程池详解)
    POJ2676Sudoku题解
    每日一题:leetcode 2594 修车的最少时间
    聚观早报 | 问界新 M7 车型破单日大定纪录;iQOO 12影像大升级
    【二叉树】- 层序遍历( js 实现)
    回溯算法总结
    Nginx + RTMP + nginx-http-flv-module 环境搭建(CentOS 7)
    C和指针 第9章 字符串、字符和字节 9.14 编程练习
    web学生网页设计作业源码 HTML+CSS+JS 网上鲜花商城购物网站
    微信扫一扫抽奖活动怎么做
  • 原文地址:https://blog.csdn.net/qq_42598133/article/details/125619096