本笔记仅供学习交流使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,请各位自觉遵守相关法律法规。
小节目标:
- 了解 对称加密算法种类
- 熟悉 加密算法工作模式
- 掌握 加密算法的实现方式
对称加密(加密解密密钥相同):DES、3DES、AES、RC4
简介
对称式加密就是加密和解密使用同一个密钥。信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。对称加密算法用来对敏感数据等信息进行加密。
一. 常见算法归纳
**DES:**56位密钥,由于密钥太短,被逐渐被弃用。
**AES:**有128位、192位、256位密钥,现在比较流行。密钥长、可以增加破解的难度和成本。
1. 工作模式归纳
1. ECB模式
-
全称Electronic Codebook模式,译为电子密码本模式,每个数据块独立进行加/解密
-
ECB是最简单的工作模式,原理就是将明文分组,对每一组分别单独加密,加密后的每组密文之间没有联系,在将每一组加密的结果进行拼接
-
解密流程如下
2. CBC模式
-
全称Cipher Block Chaining模式,译为密文分组链接模式
-
这种模式的核心思想是每一个明文分组在被加密之前要与前一个的密文分组进行异或运算,即每一组的加密结果会参与下一个分组的加密,因此第一个分组加密需要有一个初始化向量(IV)参与。
-
最后将每个密文分组按顺序合并起来就得到加密结果
-
CBC模式是分组加密中使用最多的模式。
- 解密方式
3. CFB模式
- 全称Cipher FeedBack模式,译为密文反馈模式
- 这种工作模式吸收了流加密(流加密可以逐个加密数据,因此适用于流式数据,无需等待整个块加密完成)的特点,可以理解成实现了流加密的CBC 模式
- 加密时,首先对初始化向量(IV)加密,用加密的结果与第一个明文分组异或,得到第一个密文分组
- 然后将此密文分组进行加密(加密前要进行移位处理),将加密结果与第二个明文分组异或
- 解密过程与加密过程相似,仍然是将前一密文分组加密**(注意,这里仍然是加密,不是解密)**,用加密结果与当前密文分组异或,得到明文
4. OFB模式
-
全称Output Feedback模式,译为输出反馈模式。
-
OFB模式与CFB模式类似,区别在于使用上一个分组的密码序列加密生成当前分组的密码序列
-
解密过程
5. CTR模式
- 全称Counter模式,译为计数器模式。
- CTR模式与CFB、OFB模式为同一类。但它是通过将逐次累加的计数器进行加密来生成密码序列
- 也就是说,每一个的密文分组是通过将计数器加密得到的密码序列与明文分组进行异或而得到的
- 解密过程
6. 总结
- ECB模式和CBC是最常见的加密模式
二. DES算法
实例地址:https://bqcm0.cavip1.com/
简介:DES是一种分组加密算法,他以64
位为分组对数据加密。64
位一组的明文从算法的一端 输入,64
位的密文从另一端输出。DES是一个对称算法:加密和解密用的是同一个算法(除 密钥编排不同以外)。
密钥的长度为56
位(密钥通常表示为64
位的数,但每个第8位都用作奇偶检验,可以忽 略)。密钥可以是任意的56
位数,且可以在任意的时候改变。
DES算法的入口参数有3个:Key,Data,Mode
。其中Key
为8个字节共64位,是DES算法 的工作密钥;Data
也为8个字节64位,是要被加密或解密的数据:Mode为DES的工作方式,有 两种:加密或解密。
DES算法的工作过程:若Mode为加密,则用Key对数据Data进行加密,生成Data的密码 形式(64位)作为DES的输出结果;若Mode为解密,则用Key对密码形式的数据Data解密,还 原为Data的明码形式(64位)作为DES的输出结果。
简单地说,算法只不过是加密的一种基本技术,DES基本组建分组是这些技术的一种组合 ,他基于密钥作用于明文,这是众所周知的轮(round)。DES有16轮,这意味着要在明文分 组上16次实施相同的组合技术。
- mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。
- padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
参考资料:
- RFC 4772:https://datatracker.ietf.org/doc/rfc4772/
- DES 维基百科:https://en.wikipedia.org/wiki/Data_Encryption_Standard
1. JavaScript 实现
DES
算法的入口参数有3个
key、DATA、Mode、padding
key
为7个字节
共56位,是DES算法的工作密钥Data
为8个字节
64位,是要被加密或被解密的数据Mode
为DES
的工作方式padding
为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节,16个字节),填充
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')
function desEncrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = CryptoJS.enc.Utf8.parse(text),
// CBC 加密模式,Pkcs7 填充方式
encrypted = CryptoJS.DES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
function desDecrypt() {
var key = CryptoJS.enc.Utf8.parse(desKey),
iv = CryptoJS.enc.Utf8.parse(desIv),
srcs = encryptedData,
// CBC 加密模式,Pkcs7 填充方式
decrypted = CryptoJS.DES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
var text = "I love Python!" // 待加密对象
var desKey = "6f726c64f2c2057" // 密钥
var desIv = "0123456789ABCDEF" // 初始向量
var encryptedData = desEncrypt()
var decryptedData = desDecrypt()
console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)
// 加密字符串: +ndbEkWNw2QAfIYQtwC14w==
// 解密字符串: I love Python!
2. Python 实现
pip install pyDes
import binascii
# 加密模式 CBC,填充方式 PAD_PKCS5
from pyDes import des, CBC, PAD_PKCS5
def des_encrypt(key, text, iv):
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
en = k.encrypt(text, padmode=PAD_PKCS5)
return binascii.b2a_hex(en)
def des_decrypt(key, text, iv):
k = des(key, CBC, iv, pad=None, padmode=PAD_PKCS5)
de = k.decrypt(binascii.a2b_hex(text), padmode=PAD_PKCS5)
return de
if __name__ == '__main__':
secret_key = '12345678' # 密钥
text = 'hello world' # 加密对象
iv = secret_key # 偏移量
secret_str = des_encrypt(secret_key, text, iv)
print('加密字符串:', secret_str)
clear_str = des_decrypt(secret_key, secret_str, iv)
print('解密字符串:', clear_str)
# 加密字符串:b'302d3abf2421169239f829b38a9545f1'
# 解密字符串:b'I love Python!'
- 由于库和版本的不同,同样的加密算法在不一样的语言里结果可能不一致,做逆向时最好是选用node来加密网站数据,不使用python来进行加密
3. 实操练习1
1. 逆向目标
首页:https://www.endata.com.cn/BoxOffice/BO/Month/oneMonth.html
数据:https://www.endata.com.cn/API/GetData.ashx
逆向:加密数据
2. 逆向分析
1. 加密数据定位
- xhr断点数据地址
- 当前获取的数据是加密的信息,那么在发送ajax的时候一定会在处理响应数据的时候对加密数据进行处理,我们可以直接定位到发送ajax请求的位置,看处理数据的函数
-
关键字定位
- 获取的是加密的数据信息,在js是一定要进行解密的处理我们可以直接搜索关键字
decrypt
(关键字搜索的范围比较广,可以多打断点,在重新触发任务看是否能断在)
- 获取的是加密的数据信息,在js是一定要进行解密的处理我们可以直接搜索关键字
-
网址定位
- 根据部分网址有时也能定位成功
2. 加密代码分析
- 根据我们xhr的分析可以定位到他是对数据用
webInstace.shell
进行了解密,我们可以直接跟进函数,看函数做了什么事情
- 补js代码(缺什么补什么,要是像这种就是一个单独一个文件的可以全扣)
3.逆向结果
-
JavaScript代码
-
python代码
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import requests
import execjs
headers = {
"Accept": "text/plain, */*; q=0.01",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://www.endata.com.cn",
"Pragma": "no-cache",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
"sec-ch-ua": "^\\^Chromium^^;v=^\\^118^^, ^\\^Google",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "^\\^Windows^^"
}
url = "https://www.endata.com.cn/API/GetData.ashx"
data = {
"sdate1": "2023-10-13",
"edate1": "2023-10-15",
"sdate2": "2023-10-06",
"edate2": "2023-10-08",
"MethodName": "BoxOffice_GetWeekendInfoData"
}
response = requests.post(url, headers=headers, data=data)
with open('1111.js', 'r')as f:
js_code = f.read()
js = execjs.compile(js_code)
result = js.call('webInstace.shell', response.text)
print(result)
三. AES算法
环境安装
pip install pycryptodome -i pip源
1. 算法简介
简介:全称高级加密标准(英文名称:Advanced Encryption Standard),在密码学中又称 Rijndael 加密法,由美国国家标准与技术研究院 (NIST)于 2001 年发布,并在 2002 年成为有效的标准,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的 DES,已经被多方分析且广为全世界所使用,它本身只有一个密钥,即用来实现加密,也用于解密。
- mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。
- padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等。
参考资料:
- RFC 3268:https://datatracker.ietf.org/doc/rfc3268/
- AES 维基百科:https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
参数定义:
- key length(密钥位数,密码长度)
AES128,AES192,AES256(128 位、192 位或 256 位)
- key (密钥,密码)key指的就是密码了,
AES128
就是128位
的,如果位数不够,某些库可能会自动填充到128
。 - IV (向量)IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV。
- mode (加密模式)AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显。
- padding (填充方式)对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为
PKCS5, PKCS7, NOPADDING
。
加密原理:
AES加密算法采用分组密码体制,每个分组数据的长度为128位16个字节
,密钥长度可以是128位16个字节
、192位或256位
,一共有四种加密模式,我们通常采用需要初始向量IV的CBC模式,初始向量的长度也是128位16个字节
。
2. JavaScript 实现
类似网站:https://www.dns.com/login.html
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js')
function tripleAesEncrypt() {
var key = CryptoJS.enc.Utf8.parse(aesKey),
iv = CryptoJS.enc.Utf8.parse(aesIv),
srcs = CryptoJS.enc.Utf8.parse(text),
// CBC 加密方式,Pkcs7 填充方式
encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
function tripleAesDecrypt() {
var key = CryptoJS.enc.Utf8.parse(aesKey),
iv = CryptoJS.enc.Utf8.parse(aesIv),
srcs = encryptedData,
// CBC 加密方式,Pkcs7 填充方式
decrypted = CryptoJS.AES.decrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
var text = "I love Python!" // 待加密对象
var aesKey = "6f726c64f2c2057c" // 密钥,16 倍数
var aesIv = "0123456789ABCDEF" // 偏移量,16 倍数
var encryptedData = tripleAesEncrypt()
var decryptedData = tripleAesDecrypt()
console.log("加密字符串: ", encryptedData)
console.log("解密字符串: ", decryptedData)
// 加密字符串: dZL7TLJR786VGvuUvqYGoQ==
// 解密字符串: I love Python!
3. 实际案例1
1. 逆向目标
-
目标:建筑市场数据采集
-
主页:https://jzsc.mohurd.gov.cn/data/company
-
接口:https://jzsc.mohurd.gov.cn/api/webApi/dataservice/query/comp/list
-
逆向参数:
data加密
2. 逆向分析
1.加密数据定位
-
关键字
decrpyt
定位
-
xhr断点(同样的可以找到发送ajax的回调位置,不好找的话可以直接在执行一下步,因为他一定会进入到回调的位置进行解密)
2. 加密代码分析
-
通过m函数进行解密操作
-
解密方法为AES
3. 逆向结果
- JavaScript代码
var cryptojs = require('crypto-js')
function m(t) {
f = cryptojs.enc.Utf8.parse("jo8j9wGw%6HbxfFn");
h = cryptojs.enc.Utf8.parse("0123456789ABCDEF");
var e = cryptojs.enc.Hex.parse(t)
, n = cryptojs.enc.Base64.stringify(e)
, a = cryptojs.AES.decrypt(n, f, {
iv: h,
mode: cryptojs.mode.CBC,
padding: cryptojs.pad.Pkcs7
})
, r = a.toString(cryptojs.enc.Utf8);
return r.toString()
}
- python代码
import requests
import execjs
headers = {
"Referer": "https://jzsc.mohurd.gov.cn/data/company",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"timeout": "30000"
}
url = "https://jzsc.mohurd.gov.cn/APi/webApi/dataservice/query/comp/list"
params = {
"pg": "1",
"pgsz": "15",
"total": "450"
}
response = requests.get(url, headers=headers, params=params)
with open('建筑市场.js', 'r', encoding='utf-8')as f:
js_code = f.read()
js = execjs.compile(js_code)
result = js.call('m', response.text)
print(result)
4.实际案例2
1. 逆向目标
地址:https://www.kanzhun.com/
需求:表单 + 数据结果
2. 表单逆向分析
1.加密数据定位
- 关键字定位
encrypt
(搜索比较多需要多下断点)
- xhr断点定位(通过xhr断点离的位置可能比较远,我们需要跟栈分析)
2.加密代码分析
- b和kiv的值都是一样的 b是t赋值 kiv是a赋值
- t = (0,M.mA)(n, {iv: a}).replace(///g, “_”).replace(/+/g, “-”).replace(/=/g, “~”))); 调用的M.mA函数
- a = (0,M._A)() 调用的M._A函数
3.逆向结果
- JavaScript代码
var cryptojs = require('crypto-js')
function u() {
var e, t, n, r, i = null;
t = new RegExp("\\u200c", "g"),
n = new RegExp("\\u200d", "g"),
r = new RegExp(".{8}", "g"),
e = "".replace(r, (function (e) {
return String.fromCharCode(parseInt(e.replace(t, 1).replace(n, 0), 2))
}
)),
i = {
key: cryptojs.enc.Utf8.parse(e),
mode: cryptojs.mode.CBC,
pad: cryptojs.pad.Pkcs7
};
return i
}
p = function (e) {
void 0 === e && (e = 16);
for (var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""), n = "", r = 0; r < e; r++) {
n += t[Math.ceil(61 * Math.random())]
}
return n
}
l = function (e) {
t = p();
var n = u()
, r = cryptojs.AES.encrypt(e.toString(), n.key, {
iv: cryptojs.enc.Utf8.parse(t),
mode: n.mode,
padding: n.pad
});
return {
b: r.toString(),
kiv: t
}
}
res = l('{"query":"python","cityCode":101020100,"industryCodes":"","pageNum":1,"limit":15}')
console.log(res)
- python代码
import requests
import execjs
with open('demo.js', 'r', encoding='utf-8')as f:
js_code = f.read()
data = '{"query":"爬虫","cityCode":101010100,"industryCodes":"","pageNum":1,"limit":15}'
js = execjs.compile(js_code)
par = js.call('l', data)
print(par)
headers = {
"href": "https://www.kanzhun.com/search?cityCode=101010100&industryCodes=&pageNum=1&query=python&type=1",
"referer": "https://www.kanzhun.com/search?cityCode=101010100&industryCodes=&pageNum=1&query=python&type=1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
}
url = "https://www.kanzhun.com/api_to/search/company_v2.json"
params = {
"b": par['b'],
"kiv": par['kiv']
}
response = requests.get(url, headers=headers, params=params)
print(response.text)
print(response)
3.响应解密分析
1.解密代码定位
-
关键字
decrypt
定位 -
可以下Hook断点调试(通过hook定位响应解密位置的时候需要往上找,因为只有解密之后变成json数据了,才能进行JSON.parse转换成数组数据)
var my_parse = JSON.parse;
JSON.parse = function (params) {
//这里可以添加其他逻辑比如
debugger
console.log("json_parse params:",params);
return my_parse(params);
};
2.解密代码分析
-
可以看出数据是在(0,M.gy)(e.data, {iv: “string” == typeof n ? JSON.parse(n).kiv : n.kiv })进行解密的
-
跟进函数看解密的方法,可以明显看出来是AES的解密
-
解密的key就是用的请求参数加密时候的key
-
标准的算法我们没有必要去扣直接用标准库就行
3.逆向结果
- JavaScript代码
c = function (e, t) {
var n = u()
, r = cryptojs.AES.decrypt(e.toString(), n.key, {
iv: cryptojs.enc.Utf8.parse(t),
mode: n.mode,
padding: n.pad
});
return r = r.toString(cryptojs.enc.Utf8)
};
- python代码
import requests
import execjs
with open('demo.js', 'r', encoding='utf-8')as f:
js_code = f.read()
data = '{"query":"爬虫","cityCode":101010100,"industryCodes":"","pageNum":1,"limit":15}'
js = execjs.compile(js_code)
par = js.call('l', data)
print(par)
headers = {
"href": "https://www.kanzhun.com/search?cityCode=101010100&industryCodes=&pageNum=1&query=python&type=1",
"referer": "https://www.kanzhun.com/search?cityCode=101010100&industryCodes=&pageNum=1&query=python&type=1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
}
url = "https://www.kanzhun.com/api_to/search/company_v2.json"
params = {
"b": par['b'],
"kiv": par['kiv']
}
response = requests.get(url, headers=headers, params=params)
res = js.call('c', response.text, par['kiv'])
print(res)
四.魔改算法
魔改算法
通常指的是对现有算法进行修改或改进,以满足特定需求、优化性能或解决特定问题的过程
1. 逆向目标
地址:https://www.aigei.com/sound/class/role?page=7#resContainer
接口:https://www.aigei.com/gei-common/jsonComp/f/awd/log.json?t=5657288%2C30409027%2C29958178%2C5633685%2C5657573%2C5635533%2C30392468%2C5657696%2C5656237%2C5656067%2C30377190%2C5634248%2C41239479%2C2286941%2C29951406%2C69050439%2C5636242%2C2286905%2C5632707%2C68820738&w=rowPc&f=false
需求:解密数据(不做数据要求只需解密)
2. 逆向分析
1.加密数据定位
- xhr断点定位(需要对响应数据解密,找到ajax的回调方法)
- 关键字
decrypt(
定位(需要碰运气的成分)
2.加密代码分析
-
跟ajax断点定位到匿名函数
-
分析函数可以得出先将响应的b数据进行分割,这个判断条件是没有成立的可以不用管,直接扣for循环的代码
-
循环中c的赋值对我们用处也不大,我们可以不用扣下来
-
主要代码就是u = (new llii1i1iill).ilil111lii(u) 这个方法会将我们分割之后的数据在进行转换
-
u = ili11liii(u, “il1looOo”)会将转换之后的密文进行解密 这两个方法都是要扣的
-
ili11liii方法里可以看到是网站自己封装的一个魔改算法,所以我们需要把GeiJS算法给扣下来,这样的算法最好是我们可以拷贝他整个代码进行格式化,会更加方便些
3.逆向结果
-
JavaScript代码
-
python代码
import requests
import execjs
headers = {
"referer": "https://www.aigei.com/sound/class/role?page=11",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
}
url = "https://www.aigei.com/gei-common/jsonComp/f/awd/log.json"
params = {
"t": '5757651,5634335,5739749,5634319,31854576,5657618,5655610,5658078,5635730,5636124,5634306,30392499,5635683,30392510,5636099,30392498,31854584,5635575,5634806,5636275',
"w": "rowPc",
"f": "false"
}
response = requests.get(url, headers=headers, params=params)
with open('demo.js', 'r', encoding='utf-8')as f:
js_code = f.read()
js = execjs.compile(js_code)
res = js.call('aa', response.json())
print(res)
结语
以上就是关于js逆向技术中的消息摘要算法全部内容了,欢迎同学们在评论区讨论交流,有任何js逆向、数据采集相关需求也可以后台与我联系哟~
标签:逆向,加密,https,解密,js,key,CryptoJS From: https://blog.csdn.net/Zeno_wrj/article/details/141825566