爬虫逆向实战(二十四)--某鸟记录中心

news2025/3/17 18:40:15

一、数据接口分析

主页地址:某鸟记录中心

1、抓包

通过抓包可以发现数据接口是front/record/search/page
在这里插入图片描述

2、判断是否有加密参数

  1. 请求参数是否加密?
    通过查看“载荷”模块可以发现,请求参数是加密的
    在这里插入图片描述
  2. 请求头是否加密?
    通过查看“请求标头”可以发现RequestidSign是加密参数,并且有一个Timestamp时间戳
    在这里插入图片描述
  3. 响应是否加密?
    通过查看“响应”模块可以发现,响应中的数据是加密数据
    在这里插入图片描述
  4. cookie是否加密?

二、加密位置定位

1、加密参数以及请求头加密

(1)看启动器

查看启动器发现里面有一个pullData的调用堆栈,点进去查看
在这里插入图片描述
点进去后,可以看出,此处是发送ajax请求的位置,在此处下断点,再次翻页获取数据,发现可以断住,但是此处是明文数据,所以加密位置不在这里。
在这里插入图片描述

(2)搜索关键字

因为“载荷”是一整个密文,没有关键字,所以无法搜索

(3)hook

因为“载荷”是一整个密文,所以网站大概率会使用JSON.stringify将数据转换为json字符串再进行加密,所以我们可以hookJSON.stringify,hook代码:

var my_stringify = JSON.stringify;
JSON.stringify = function (params) {
    debugger
    console.log("json_stringify params:",params);
    return my_stringify(params);
};

运行hook代码,再次获取数据,发现可以断住
在这里插入图片描述
继续调试执行,可以发现,网站是使用ajaxSetup设置了ajax请求的全局配置,请求头和加密参数都是在此处进行赋值的。
在这里插入图片描述

2、响应数据

(1)hook

因为响应加密数据一般都是json数据加密,所以解密后会使用JSON.parse进行解密,所以我们可以对JSON.parse进行hook
hook代码段:

var my_parse = JSON.parse;
JSON.parse = function (params) {
    debugger
    console.log("json_parse params:",params);
    return my_parse(params);
};

运行hook代码,再次获取数据,发现可以断住明文
在这里插入图片描述
接着调试执行,就可以找到解密位置
在这里插入图片描述

三、扣js代码

1、加密参数及请求头

将定位到的加密位置的代码扣出,可以发现网站的数据加密是使用的JSEncrypt模块进行的RAS加密,所以我们可以直接使用标准模块进行加密,但是网站使用的encrypt.encryptUnicodeLong方法,node.js中是没有的,所以我们还需要将这个方法扣出来。下方请求头加密使用的md5,我们同样可以使用标准模块进行加密。
在这里插入图片描述

2、响应数据

将定位到的解密位置的代码扣出,进入到网站的解密方法BIRDREPORT_APIJS.decode中,可以发现,网站是使用的AES解密的,所以我们可以使用标准的AES模块进行解密。
在这里插入图片描述
JavaScript源码:

const JSEncrypt = require('jsencrypt');

var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var b64pad = "=";

function hex2b64(h) {
    var i;
    var c;
    var ret = "";
    for (i = 0; i + 3 <= h.length; i += 3) {
        c = parseInt(h.substring(i, i + 3), 16);
        ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
    }
    if (i + 1 == h.length) {
        c = parseInt(h.substring(i, i + 1), 16);
        ret += b64map.charAt(c << 2);
    } else if (i + 2 == h.length) {
        c = parseInt(h.substring(i, i + 2), 16);
        ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
    }
    while ((ret.length & 3) > 0) {
        ret += b64pad;
    }
    return ret;
}

JSEncrypt.prototype.encryptUnicodeLong = function (string) {
    var k = this.getKey();
    //根据key所能编码的最大长度来定分段长度。key size - 11:11字节随机padding使每次加密结果都不同。
    var maxLength = ((k.n.bitLength() + 7) >> 3) - 11;
        var subStr = "", encryptedString = "";
        var subStart = 0, subEnd = 0;
        var bitLen = 0, tmpPoint = 0;
        for (var i = 0, len = string.length; i < len; i++) {
            //js 是使用 Unicode 编码的,每个字符所占用的字节数不同
            var charCode = string.charCodeAt(i);
            if (charCode <= 0x007f) {
                bitLen += 1;
            } else if (charCode <= 0x07ff) {
                bitLen += 2;
            } else if (charCode <= 0xffff) {
                bitLen += 3;
            } else {
                bitLen += 4;
            }
            //字节数到达上限,获取子字符串加密并追加到总字符串后。更新下一个字符串起始位置及字节计算。
            if (bitLen > maxLength) {
                subStr = string.substring(subStart, subEnd)
                encryptedString += k.encrypt(subStr);
                subStart = subEnd;
                bitLen = bitLen - tmpPoint;
            } else {
                subEnd = i;
                tmpPoint = bitLen;
            }
        }
        subStr = string.substring(subStart, len)
        encryptedString += k.encrypt(subStr);
        return hex2b64(encryptedString);
};

const CryptoJS = require('crypto-js')

function getUuid() {
    var s = [];
    var a = "0123456789abcdef";
    for (var i = 0; i < 32; i++) {
        s[i] = a.substr(Math.floor(Math.random() * 0x10), 1)
    }
    s[14] = "4";
    s[19] = a.substr((s[19] & 0x3) | 0x8, 1);
    s[8] = s[13] = s[18] = s[23];
    var b = s.join("");
    return b
}

function sort_ASCII(a) {
    var b = new Array();
    var c = 0;
    for (var i in a) {
        b[c] = i;
        c++
    }
    var d = b.sort();
    var e = {};
    for (var i in d) {
        e[d[i]] = a[d[i]]
    }
    return e
}

function url2json(a) {
    var b = /^[^\?]+\?([\w\W]+)$/
        , reg_para = /([^&=]+)=([\w\W]*?)(&|$|#)/g
        , arr_url = b.exec(a)
        , ret = {};
    if (arr_url && arr_url[1]) {
        var c = arr_url[1], result;
        while ((result = reg_para.exec(c)) != null) {
            ret[result[1]] = result[2]
        }
    }
    return ret
}

function dataTojson(a) {
    var b = [];
    var c = {};
    b = a.split('&');
    for (var i = 0; i < b.length; i++) {
        if (b[i].indexOf('=') != -1) {
            var d = b[i].split('=');
            if (d.length == 2) {
                c[d[0]] = d[1]
            } else {
                c[d[0]] = ""
            }
        } else {
            c[b[i]] = ''
        }
    }
    return c
}

const serialize = function (a) {
    var b = [];
    for (var p in a)
        if (a.hasOwnProperty(p) && a[p]) {
            b.push(encodeURIComponent(p) + '=' + encodeURIComponent(a[p]))
        }
    return b.join('&')
};
var paramPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvxXa98E1uWXnBzXkS2yHUfnBM6n3PCwLdfIox03T91joBvjtoDqiQ5x3tTOfpHs3LtiqMMEafls6b0YWtgB1dse1W5m+FpeusVkCOkQxB4SZDH6tuerIknnmB/Hsq5wgEkIvO5Pff9biig6AyoAkdWpSek/1/B7zYIepYY0lxKQIDAQAB";
var encrypt = new JSEncrypt();
encrypt.setPublicKey(paramPublicKey);


function get_params() {
    var b_data = 'page=1&limit=20&taxonid=&startTime=&endTime=&province=&city=&district=&pointname=%E6%B2%B3%E5%8D%97&username=&serial_id=&ctime=&taxonname=&state=&mode=0&outside_type=0'
    var c = Date.parse(new Date());
    var d = getUuid();
    var e = JSON.stringify(sort_ASCII(dataTojson(b_data || '{}')));
    b_data = encrypt.encryptUnicodeLong(e);
    var f = CryptoJS.MD5(e + d + c).toString();
    return [{
        timestamp: c.toString(),
        requestId: d.toString(),
        sign: f.toString()
    }, b_data]
}

var key = '3583ec0257e2f4c8195eec7410ff1619';
var iv = 'd93c0d5ec6352f20'
apijs_decode = function(a) {
        var b = CryptoJS.enc.Utf8.parse(key);
        var c = CryptoJS.enc.Utf8.parse(iv);
        var d = CryptoJS.AES.decrypt(a, b, {
            iv: c,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return d.toString(CryptoJS.enc.Utf8)
    }

function get_data(r_data) {
    var decode_str = apijs_decode(r_data);
    return JSON.parse(decode_str)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/942825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Python魔法大冒险》002 编程是什么?

魔法师:在这个充满魔法和奇迹的数字时代,你是否好奇过计算机是如何运作的?当你用手机玩游戏、在电脑上浏览网页、看动画电影,你是否想过这背后的秘密是什么?别担心,今天我们将揭开这神秘的面纱,一起来探索编程的神奇世界! 编程,简单地说,就是一种让计算机执行任务的…

Nginx详解 二:配置文件部分

文章目录 1. Nginx 配置文件1.1 主配置文件1.2 子配置文件1.3 全局配置1.3.1 修改启动的进程数1.3.2 cpu和work进程绑定&#xff08;nginx调优&#xff09;1.3.3 修改PID路径1.3.4 nginx进程的优先级&#xff08;work进程的优先级&#xff09;1.3.5 调试work进程打开的文件的个…

3D点云处理:基于2D边缘提取的方法提取3D点云边缘(占位待补充)

文章目录 0. 实现效果 微信&#xff1a;dhlddx B站演示视频 0. 实现效果

【程序猿书籍大放送:第二期】《强化学习:原理与Python实战》

&#x1f339;欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 爱书不爱输的程序猿&#xff1a;送书第二期 一、搞懂大模型的智能基因&#xff0c;RLHF系统设计关键问答1.RLHF是什么&#xff1f;2.RLHF适用于哪些任务&#xff1f;3…

Redis进阶 - Lua语法

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - Lua语法 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-lua-language.html 初识 Lua Lua 是一种轻量小巧的脚本语言&#xff0c;用标准的 C 语言编写并以源代码形式开放&#…

ClickHouse进阶(四):ClickHouse TTL

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_Apache Doris,大数据OLAP体系技术栈,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…

Elasticsearch:为什么从 Elasticsearch 7.0.0 及更高版本中删除了映射类型 type?

在 Elasticsearch 7.0.0 或更高版本中创建的索引不再接受 _default_ 映射。 在 6.x 中创建的索引将继续在 Elasticsearch 6.x 中像以前一样运行。 7.0 中的 API 中已弃用类型 type&#xff0c;并对索引创建、放置映射、获取映射、放置模板、获取模板和获取字段映射 API 进行了重…

战略文化派,战略形成是集体信念和愿景形成的过程

战略文化派&#xff1a;战略形成是集体信念和愿景形成的过程 趣讲大白话&#xff1a;在乎集体认同 【趣讲信息科技271期】 **************************** 关于企业文化的故事很多 比如&#xff1a;中国海尔砸冰箱后蜕变的文化 比如&#xff1a;日本的稻盛和夫倡导的东方利他文化…

Nacos安装

Windows安装 下载安装包 在Nacos的GitHub页面https://github.com/alibaba/nacos/releases&#xff0c;下载安装包 解压 将这个包解压到任意非中文目录下 目录说明&#xff1a; bin&#xff1a;启动脚本 conf&#xff1a;配置文件 配置 配置文件路径 默认端口为8848 启…

ResNet详解:网络结构解读与PyTorch实现教程

目录 一、深度残差网络&#xff08;Deep Residual Networks&#xff09;简介深度学习与网络深度的挑战残差学习的提出为什么ResNet有效&#xff1f; 二、深度学习与梯度消失问题梯度消失问题定义为什么会出现梯度消失&#xff1f;激活函数初始化方法网络深度 如何解决梯度消失问…

新KG视点 | Jeff Pan、陈矫彦等——大语言模型与知识图谱的机遇与挑战

OpenKG 大模型专辑 导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织…

HDU 1911 Showstopper 二分搜素

一、题目翻译 如果没有发现细微的形式&#xff0c;那么对大量数据集合进行数据挖掘是一件痛苦而又长时间的过程。 一家公司的某个软件成对的使用组件生成了大量的数据对象&#xff0c;因为是成对使用&#xff0c;所以每个数据对象出现的次数一定为偶数次&#xff0c;但是在多…

学生成绩管理系统【控制台+MySQL】(Java课设)

系统类型 控制台类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87738977 更多系统资源库地…

验收测试怎么做?需要怎么配合

验收测试的流程&#xff0c;是验证系统是否达到了用户需求规格说明书&#xff08;可能包括项目或产品验收准则&#xff09;中的要求&#xff0c;测试试图尽可能地发现软件中存留的缺陷&#xff0c;从而为软件进一步改善提供帮助&#xff0c;并保证系统或软件产品Z终被用户接受。…

如何用 QGIS 下载高清天地图影像机,同时解决下载质量差的问题!

使用 QGIS 我们可以获得下面这种图像,既有大范围,又有更高的细节(地图级别),基本上把整个苏州市中心城区的建筑物都囊括进去了。 还可以下载大范围、高清晰度的各种在线卫星底图服务的影像,比如大面积的哨兵2影像,但国外的服务器一般都很烂,不可能是电信、移动的问题,…

Python环境下载安装使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

03.OA项目之我的会议(查询会议排座送审)

目录 会议查询 会议排座 会议送审 思路&#xff1a; 关键性会议SQL的编写后台实现前台实现 会议查询 MeetingInfoDao.java // 通用的会议查询SQL语句&#xff0c;包含会议信息表数据&#xff0c;主持人姓名、审批人姓名、会议状态private String getSQL() {return "…

四、MySQL(表操作)如何添加字段?修改表?删除字段?修改表名?删除表?格式化某张表?

1、添加字段 &#xff08;1&#xff09;基础语法&#xff1a; alter table 表名 add 字段名 类型名(长度) [comment注释] [约束]; &#xff08;2&#xff09;示例&#xff1a;添加nickname这个字段 2、修改表 修改表中某个字段的【数据类型】/【数据类型&字段名】 &…

【视频录制】MAC下录频软件对比

目录 各软件对比 OBS FiImage Omi录频专家 好录 各软件对比 名称下载地址优点缺点OBSOpen Broadcaster Software | OBS 1. 免费使用 2. 视频高清 3. 可做直播 1. 没有暂停继续 2. 开启没有缓冲时间&#xff0c;需要手动剪辑片头片尾 3. 配置音频麻烦 4. 有时会CPU很高卡死…

图像扭曲之锯齿

源码&#xff1a; void wave_sawtooth(cv::Mat& src,cv::Mat& dst,double amplitude,double wavelength) {dst.create(src.rows, src.cols, CV_8UC3);dst.setTo(0);double xAmplitude amplitude;double yAmplitude amplitude;int xWavelength wavelength;int yWave…