爬虫逆向实战(36)-某建设监管平台(RSA,魔改)
一、数据接口分析
主页地址:某建设监管平台
1、抓包
通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口,用于获取滑块验证码的图片
滑块验证之后,请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这个接口,来获取数据
2、判断是否有加密参数
- 请求参数是否加密?
通过查看“载荷”模块可以发现,这两个接口都是只有一个params
的加密参数
- 请求头是否加密?
无 - 响应是否加密?
无 - cookie是否加密?
无
二、加密位置定位
1、看启动器
查看启动器发现里面包含异步,所以无法正确找到加密位置
2、搜索关键字
通过搜索关键字,发现可以搜出来很多位置,无法准确定位到加密位置
3、Hook
因为请求参数中只有一个params
参数,所以网站大概率会使用JSON.stringify
方法将明文数据转json之后再加密。
通过hook,我们可以找到加密位置
同时,可以发现params是进行了双重加密,首先使用W_e().encrypt
进行了一次加密(此处有点类似于AES或DES加密,但是通过测试,发现加密结果不一致,所以可能是魔改加密算法),然后将加密结果再使用X_e
进行二次加密(此处是标准RSA加密)。
三、扣js代码
将W_e().encrypt
方法扣出,缺啥补啥即可,X_e
方法可以扣网站代码,也可以直接使用标准模块。
注:
此网站的滑块验证码,仅需将缺口距离在第二次数据接口请求时带上即可
源代码:
const JSEncrypt = require('jsencrypt');
const G_e = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC29miF1Wp9XlhCECo+FYpCHad1ipEMgXf4IdgYjMIQwczzo9GXdcZ4eeV+9lkh6+aTqzzU843rdkMt0vrSnujU+GOuDPLfa5LZ6SfanAoysi6xxTX02Xizb3k+Z1USIzm9QAwE+SR1AQ78rGTRFHWFu7OGPkVNeF+vrX3inQTiawIDAQAB";function Jbe(e) {var t = n7(e), n = t[0], o = t[1];return (n + o) * 3 / 4 - o
}function exe(e) {var t, n = n7(e), o = n[0], r = n[1], s = new Xbe(Qbe(e, o, r)), a = 0, l = r > 0 ? o - 4 : o, i;for (i = 0; i < l; i += 4)t = oo[e.charCodeAt(i)] << 18 | oo[e.charCodeAt(i + 1)] << 12 | oo[e.charCodeAt(i + 2)] << 6 | oo[e.charCodeAt(i + 3)],s[a++] = t >> 16 & 255,s[a++] = t >> 8 & 255,s[a++] = t & 255;return r === 2 && (t = oo[e.charCodeAt(i)] << 2 | oo[e.charCodeAt(i + 1)] >> 4,s[a++] = t & 255),r === 1 && (t = oo[e.charCodeAt(i)] << 10 | oo[e.charCodeAt(i + 1)] << 4 | oo[e.charCodeAt(i + 2)] >> 2,s[a++] = t >> 8 & 255,s[a++] = t & 255),s
}
function txe(e) {return Vo[e >> 18 & 63] + Vo[e >> 12 & 63] + Vo[e >> 6 & 63] + Vo[e & 63]
}
function nxe(e, t, n) {for (var o, r = [], s = t; s < n; s += 3)o = (e[s] << 16 & 16711680) + (e[s + 1] << 8 & 65280) + (e[s + 2] & 255),r.push(txe(o));return r.join("")
}
function oxe(e) {for (var t, n = e.length, o = n % 3, r = [], s = 16383, a = 0, l = n - o; a < l; a += s)r.push(nxe(e, a, a + s > l ? l : a + s));return o === 1 ? (t = e[n - 1],r.push(Vo[t >> 2] + Vo[t << 4 & 63] + "==")) : o === 2 && (t = (e[n - 2] << 8) + e[n - 1],r.push(Vo[t >> 10] + Vo[t >> 4 & 63] + Vo[t << 2 & 63] + "=")),r.join("")
}var jc = {};
jc.byteLength = Jbe;
jc.toByteArray = exe;
jc.fromByteArray = oxe;
const O6 = jc;
var Vo = [], oo = [], Xbe = typeof Uint8Array != "undefined" ? Uint8Array : Array, Lu = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var js = 0, Zbe = Lu.length; js < Zbe; ++js)Vo[js] = Lu[js],oo[Lu.charCodeAt(js)] = js;
class V_e {static stringToArrayBufferInUtf8(t) {const n = typeof window == "undefined" ? yd.TextEncoder : window.TextEncoder;return new n().encode(t)}static utf8ArrayBufferToString(t) {const n = typeof window == "undefined" ? yd.TextDecoder : window.TextDecoder;return new n("utf-8").decode(t)}static arrayBufferToBase64(t) {return O6.fromByteArray(t)}static base64ToArrayBuffer(t) {return O6.toByteArray(t)}
}const Sr = V_e, to = 16, Di = Uint8Array.from([214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72]), L_e = Uint32Array.from([462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257]), Oi = Uint32Array.from([2746333894, 1453994832, 1736282519, 2993693404]);class R_e {constructor(t) {let n = Sr.stringToArrayBufferInUtf8(t.key);if (n.length !== 16)throw new Error("key should be a 16 bytes string");this.key = n;let o = new Uint8Array(0);if (t.iv !== void 0 && t.iv !== null && (o = Sr.stringToArrayBufferInUtf8(t.iv),o.length !== 16))throw new Error("iv should be a 16 bytes string");this.iv = o,this.mode = "cbc",["cbc", "ecb"].indexOf(t.mode) >= 0 && (this.mode = t.mode),this.cipherType = "base64",["base64", "text"].indexOf(t.outType) >= 0 && (this.cipherType = t.outType),this.encryptRoundKeys = new Uint32Array(32),this.spawnEncryptRoundKeys(),this.decryptRoundKeys = Uint32Array.from(this.encryptRoundKeys),this.decryptRoundKeys.reverse()}doBlockCrypt(t, n) {let o = new Uint32Array(36);o.set(t, 0);for (let s = 0; s < 32; s++)o[s + 4] = o[s] ^ this.tTransform1(o[s + 1] ^ o[s + 2] ^ o[s + 3] ^ n[s]);let r = new Uint32Array(4);return r[0] = o[35],r[1] = o[34],r[2] = o[33],r[3] = o[32],r}spawnEncryptRoundKeys() {let t = new Uint32Array(4);t[0] = this.key[0] << 24 | this.key[1] << 16 | this.key[2] << 8 | this.key[3],t[1] = this.key[4] << 24 | this.key[5] << 16 | this.key[6] << 8 | this.key[7],t[2] = this.key[8] << 24 | this.key[9] << 16 | this.key[10] << 8 | this.key[11],t[3] = this.key[12] << 24 | this.key[13] << 16 | this.key[14] << 8 | this.key[15];let n = new Uint32Array(36);n[0] = t[0] ^ Oi[0],n[1] = t[1] ^ Oi[1],n[2] = t[2] ^ Oi[2],n[3] = t[3] ^ Oi[3];for (let o = 0; o < 32; o++)n[o + 4] = n[o] ^ this.tTransform2(n[o + 1] ^ n[o + 2] ^ n[o + 3] ^ L_e[o]),this.encryptRoundKeys[o] = n[o + 4]}rotateLeft(t, n) {return t << n | t >>> 32 - n}linearTransform1(t) {return t ^ this.rotateLeft(t, 2) ^ this.rotateLeft(t, 10) ^ this.rotateLeft(t, 18) ^ this.rotateLeft(t, 24)}linearTransform2(t) {return t ^ this.rotateLeft(t, 13) ^ this.rotateLeft(t, 23)}tauTransform(t) {return Di[t >>> 24 & 255] << 24 | Di[t >>> 16 & 255] << 16 | Di[t >>> 8 & 255] << 8 | Di[t & 255]}tTransform1(t) {let n = this.tauTransform(t);return this.linearTransform1(n)}tTransform2(t) {let n = this.tauTransform(t);return this.linearTransform2(n)}padding(t) {if (t === null)return null;let n = to - t.length % to, o = new Uint8Array(t.length + n);return o.set(t, 0),o.fill(n, t.length),o}dePadding(t) {if (t === null)return null;let n = t[t.length - 1];return t.slice(0, t.length - n)}uint8ToUint32Block(t, n=0) {let o = new Uint32Array(4);return o[0] = t[n] << 24 | t[n + 1] << 16 | t[n + 2] << 8 | t[n + 3],o[1] = t[n + 4] << 24 | t[n + 5] << 16 | t[n + 6] << 8 | t[n + 7],o[2] = t[n + 8] << 24 | t[n + 9] << 16 | t[n + 10] << 8 | t[n + 11],o[3] = t[n + 12] << 24 | t[n + 13] << 16 | t[n + 14] << 8 | t[n + 15],o}encrypt(t) {let n = Sr.stringToArrayBufferInUtf8(t), o = this.padding(n), r = o.length / to, s = new Uint8Array(o.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < r; l++) {let i = l * to, c = this.uint8ToUint32Block(o, i);a[0] = a[0] ^ c[0],a[1] = a[1] ^ c[1],a[2] = a[2] ^ c[2],a[3] = a[3] ^ c[3];let u = this.doBlockCrypt(a, this.encryptRoundKeys);a = u;for (let f = 0; f < to; f++)s[i + f] = u[parseInt(f / 4)] >> (3 - f) % 4 * 8 & 255}} elsefor (let a = 0; a < r; a++) {let l = a * to, i = this.uint8ToUint32Block(o, l), c = this.doBlockCrypt(i, this.encryptRoundKeys);for (let u = 0; u < to; u++)s[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}return this.cipherType === "base64" ? Sr.arrayBufferToBase64(s) : Sr.utf8ArrayBufferToString(s)}decrypt(t) {let n = new Uint8Array;this.cipherType === "base64" ? n = Sr.base64ToArrayBuffer(t) : n = Sr.stringToArrayBufferInUtf8(t);let o = n.length / to, r = new Uint8Array(n.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < o; l++) {let i = l * to, c = this.uint8ToUint32Block(n, i), u = this.doBlockCrypt(c, this.decryptRoundKeys), f = new Uint32Array(4);f[0] = a[0] ^ u[0],f[1] = a[1] ^ u[1],f[2] = a[2] ^ u[2],f[3] = a[3] ^ u[3],a = c;for (let d = 0; d < to; d++)r[i + d] = f[parseInt(d / 4)] >> (3 - d) % 4 * 8 & 255}} elsefor (let a = 0; a < o; a++) {let l = a * to, i = this.uint8ToUint32Block(n, l), c = this.doBlockCrypt(i, this.decryptRoundKeys);for (let u = 0; u < to; u++)r[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}let s = this.dePadding(r);return Sr.utf8ArrayBufferToString(s)}
}
var j_e = {sm4: R_e
}
function W_e() {const t = {};t.key = "B6*40.2_C9#e4$E3",t['mode'] = 'ecb',t.cipherType = "base64";const n = t, o = j_e['sm4'];return new o(n)
}function get_params(data) {e = W_e().encrypt(JSON.stringify(data))var encrypt = new JSEncrypt();encrypt.setPublicKey(G_e);const o = 117, r = Math['ceil'](e['length'] / o);let s = [];for (let a = 0; a < r; a++) {const l = e.slice(a * o, (a + 1) * o), i = encrypt.encrypt(l);s.push(i)}return s
}
相关文章:

爬虫逆向实战(36)-某建设监管平台(RSA,魔改)
一、数据接口分析 主页地址:某建设监管平台 1、抓包 通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口,用于获取滑块验证码的图片 滑块验证之后,请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这…...

DeepLearning in Pytorch|共享单车预测NN详解(思路+代码剖析)
目录 概要 一、代码概览 二、详解 基本逻辑 1.数据准备 2.设计神经网络 初版 改进版 测试 总结 概要 原文链接:DeepLearning in Pytorch|我的第一个NN-共享单车预测 我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用…...

如何配置Apache的反向代理
目录 前言 一、反向代理的工作原理 二、Apache反向代理的配置 1. 安装Apache和相关模块 2. 配置反向代理规则 3. 重启Apache服务器 三、常见的使用案例 1. 负载均衡 2. 缓存 3. SSL加密 总结 前言 随着Web应用程序的不断发展和扩展,需要处理大量的请求和…...

Vue.js 应用实现监控可观测性最佳实践
前言 Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。 TinyPro 是一套使用 Vue …...

Rust 语言中符号 :: 的使用场景
在 Rust 语言中,:: 符号主要用于以下几个场合: 指定关联函数或关联类型: 关联函数(也称为静态方法)是与类型关联而非实例关联的函数。它们使用 :: 符号来调用。例如: let value String::from("Hello,…...

Java 获取笔记本WiFi网络基站信息的方法
在Android开发中,获取基站信息(如基站ID、运营商信息、信号强度等)通常涉及使用TelephonyManager类。请注意,由于隐私和安全的考虑,从Android 10(API级别29)开始,对访问此类信息的权…...

Python如何处理拥塞控制
拥塞控制是计算机网络中用于防止网络拥塞(即过多的数据导致网络性能下降)的一系列技术和算法。在Python中,处理拥塞控制通常不直接涉及到代码层面的实现,因为拥塞控制主要是在网络协议栈(如TCP/IP)和操作系…...

【ArcGIS】栅格数据进行标准化(归一化)处理
栅格数据进行标准化(归一化)处理 方法1:栅格计算器方法2:模糊分析参考 栅格数据进行标准化(归一化)处理 方法1:栅格计算器 栅格计算器(Raster Calculator) 计算完毕后,得到归一化…...

【CMake】顶层 CMakeList.txt 常用命令总结
文章目录 cmake_minimum_required简介使用案例普通设置执行构建的cmake版本低于<min> project简介使用案例普通设置 set简介使用案例普通设置 cmake_minimum_required 简介 功能:为项目设置cmake的最低要求版本常用程度:⭐⭐⭐⭐⭐命令格式 cma…...

mac启动elasticsearch
1.首先下载软件,然后双击解压,我用的是7.17.3的版本 2.然后执行如下命令 Last login: Thu Mar 14 23:14:44 on ttys001 diannao1xiejiandeMacBook-Air ~ % cd /Users/xiejian/local/software/elasticsearch/elasticsearch-7.17.3 diannao1xiejiandeMac…...

【FFmpeg】ffmpeg 命令行参数 ⑤ ( 使用 ffmpeg 命令提取 音视频 数据 | 保留封装格式 | 保留编码格式 | 重新编码 )
文章目录 一、使用 ffmpeg 命令提取 音视频 数据1、提取音频数据 - 保留封装格式2、提取视频数据 - 保留封装格式3、提取视频数据 - 保留编码格式4、提取视频数据 - 重新编码5、提取音频数据 - 保留编码格式6、提取音频数据 - 重新编码 一、使用 ffmpeg 命令提取 音视频 数据 1…...

JMeter 二次开发之环境准备
通过JMeter二次开发,可以充分发挥JMeter的潜力,定制化和扩展工具的能力以满足具体需求。无论是开发自定义插件、函数二次开发还是定制UI,深入学习和掌握JMeter的二次开发技术,将为接口功能测试/接口性能测试工作带来更多的便利和效…...

Laravel Class ‘Facade\Ignition\IgnitionServiceProvider‘ not found 解决
Laravel Class Facade\Ignition\IgnitionServiceProvider not found 问题解决 问题 在使用laravel 更新本地依赖环境时,出现报错,如下: 解决 这时候需要更新本地的composer,然后在更新本地依赖环境。 命令如下: co…...

DNS 技巧与窍门
简介 在本文中,您将学习三种可以使用 DNS 完成的技巧。如果您曾经进行过任何与 DNS 配置相关的工作,这些小技巧可能会帮助您更快地完成工作流程。您将学习一些在终端中使用的命令和处理 DNS 数据的方法,比如如何检查当前的域名服务器。完成后…...

第2章 信息技术基础
本章学习要点 全面了解医院信息系统建设所涉及的主要信息技术以及这些技术的应用情况。 计算机与网络、信息技术与信息系统、数字媒体与数据存储技术、条形码(二维码)、RFID技术、云计算、APP技术 1.XML 可扩展标记语言与Access,Oracle和SQL Server等数据库不同…...

uniapp 微信小程序和h5处理文件(pdf)下载+保存到本地+预览功能
uniapp实现微信小程序下载资源功能和h5有很大的不同,后台需返回blob文件流 1.微信小程序实现下载资源功能 步骤1:下载文件 uni.downloadFile({url:url,//调接口返回urlsuccess:(res)>{uni.hideLoading();if(res.statusCode200){var tempFilePath …...

Linux从0到1——Linux第一个小程序:进度条
Linux从0到1——Linux第一个小程序:进度条 1. 输出缓冲区2. 回车和换行的本质3. 实现进度条3.1 简单原理版本3.2 实际工程版本 1. 输出缓冲区 1. 小实验: 编写一个test.c文件,: #include <stdio.h> #include <unistd.h…...

软件工程师,是时候了解下Rust编程语言了
背景 2024年年初,美国政府发布了一份网络安全报告,呼吁软件开发人员停止使用容易出现内存安全漏洞的编程语言,比如:C和C,转而使用内存安全的编程语言。这份报告由美国网络空间总监办公室 (ONCD) 发布,旨在落…...

SSL---VPN
文章目录 目录 一.SSL-VPN概述 优点 二.SSL协议的工作原理 三.虚拟网关技术 用户认证方式 本地认证 服务器认证: 证书匿名认证 Web代理 Web-link和Web改写 端口转发 网络扩展(允许UDP协议) 总结 一.SSL-VPN概述 SLL VPN是一种基于HTTPS&am…...

Chrome 跨域问题CORS 分析
先叠个甲,有错误,望沟通指正! 文章目录 1.什么是跨域报错2.为什么postman可以,浏览器访问就不行?根本原因是什么?2.1浏览器是依据什么来报错跨域的? 3.常规解决方案的分析方案1.通过代理解决方案2.被请求的B域的服务端开启Access-Control-Allow-Origin返回头的支持方案3.通…...

GPU性能测试中的张量和矩阵运算
正文共:888 字 7 图,预估阅读时间:1 分钟 前面我们使用PyTorch将Tesla M4跑起来之后(成了!Tesla M4Windows 10AnacondaCUDA 11.8cuDNNPython 3.11),一直有个问题,那就是显存容量的问…...

Linux运维_Bash脚本_编译安装FreeRDP-3.3.0
Linux运维_Bash脚本_编译安装FreeRDP-3.3.0 Bash (Bourne Again Shell) 是一个解释器,负责处理 Unix 系统命令行上的命令。它是由 Brian Fox 编写的免费软件,并于 1989 年发布的免费软件,作为 Sh (Bourne Shell) 的替代品。 您可以在 Linux…...

CMake官方教程4--使用表达式生成器
1. 使用表达式生成器产生警告 CMakeList.txt cmake_minimum_required(VERSION 3.15)project(Tutorial VERSION 1.0)add_library(tutorial_compiler_flags INTERFACE) target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)set(gcc_like_cxx "$<COM…...

git for windows
记录,git svn混用,检出代码时出错及解决方案, 执行命令: git svn clone svn_project_url 报错: certificate problem.(R)eject,accept (t)emporarily or accept (p)ermanently 解决: 在弹框中 输入P …...

C++实验 面向对象编程
一、实验目的: 掌握类中静态成员的定义方法,初始化方法,使用方法; 掌握类的友元说明方法,理解友元的使用特点 二、实验内容: 1、编写程序,统计某旅馆住宿客人的总数,要求输入客人…...

VC++ 设置网卡接口MTU大小
在 Windows C/C 之中一共有三种方法可以设置网卡的MTU大小。 方法一: SetIpInterfaceEntry 法 static bool SetInterfaceMtu2(int interface_index, int mtu) noexcept{PIP_ADAPTER_ADDRESSES pAddresses NULL;ULONG ulBufLen 0;GetAdaptersAddresses(AF_UNSPEC…...

dpdk-19.11 对向量指令的使用情况分析
不同向量指令识别关键字 __m128i sse uint64x2_t neon __m256i avx2 __m512i avx512 vector altivec dpdk 向量收发包函数 支持 arm neno 向量收发包函数的 pmd 驱动 bnxt hns3 i40e ixgbe mlx5 virtio 支持 sse 向量收发包函数的 pmd 驱动 axgbe hinic fm10k bnxt i40e …...

使用CIP采集欧姆龙EtherNet/IP从入门到精通
本文将会从以下几个方面介绍 1.CIP是什么 2.EtherNet/IP通信是什么 3.CIP通信报文解析 4.使用CIP常用的方法和功能介绍(UCMM) 5.自己封装了一个类,只要知道标签名称,和数据类型即可读写数据 6.demo展示 1.CIP是什么 CIP通信…...

企业如何高效管理微信里的客户?
对于企业来说,懂得高效管理微信列表的客户是非常重要的一件事,只有把客户管理好了,才能更好地提高客户的满意度和忠诚度,我们的销售业务才能顺利进行。 那么,应该怎样管理才能算是高效管理呢?下面就给大家…...

怎么在windows系统上查看kylinos的md5、sha1、sha256值
背景 当前信创行业正如火如荼进行中,当下载kylinos镜像到windows系统下,如何核对镜像是否有损坏,确保文件不被篡改,需要使用工具计算md5、sha1、sha256、sha512值,并与出库邮件中的md5比对。 QuickHash GUI软件简介 QuickHash GUI是一款开源代码的哈希工具,注意哈希能够…...