算法暴露接口(xhs、dy、ks、wx、hnw)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

431 lines
12 KiB

import base64
import binascii
import ctypes
import gzip
import hashlib
import json
import time
from urllib.parse import quote, urlparse, parse_qs, quote_plus
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def encrypt_aes_cbc(plaintext):
key = "z7Jut6Ywr2Pe5Nhx".encode("utf-8")
iv = "0807060504030201".encode("utf-8")
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(bytes.fromhex(plaintext), AES.block_size))
return base64.b64encode(ciphertext).decode()
def decrypt_aes_128_cbc(ciphertext):
"""
"""
key = "z7Jut6Ywr2Pe5Nhx".encode("utf-8")
iv = "0807060504030201".encode("utf-8")
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(base64.b64decode(ciphertext))
strs = binascii.b2a_hex(plaintext).decode()
print(strs, len(strs))
return binascii.b2a_hex(unpad(plaintext, AES.block_size))
def md5_(bytearray):
md5 = hashlib.md5()
md5.update(bytearray)
result = md5.hexdigest()
# print(result)
return result
def hex_2_str(v: int):
v = v & 0xffffffff # 将结果转换为32位有符号整数
return str(hex(v))[2:]
def get_md5Array(hex_md5):
md5_list = [hex_md5[i: i + 8] for i in range(0, len(hex_md5), 8)]
for j in range(len(md5_list)):
m = [md5_list[j][i: i + 2] for i in range(0, len(md5_list[j]), 2)]
md5_list[j] = "".join(m[::-1])
# print(md5_list)
md5_int_list = []
for q in md5_list:
decimal_num = int(q, 16)
# decimal_num = is_overflow(decimal_num)
md5_int_list.append(decimal_num)
# print(md5_int_list)
return md5_int_list
def hex_reserve(i):
st1 = hex_2_str(i)
st1 = '0' * (8 - len(st1)) + st1 if len(st1) < 8 else st1
return "".join([st1[i: i + 2] for i in range(0, len(st1), 2)][::-1])
def logical_left_shift(n, bits):
# 有符号左移
return ctypes.c_int(n << bits).value
def logical_right_shift(n, bits):
# 无符号右移
return (n % 0x100000000) >> bits
def python_2_js(value, size):
# python转为和js一样 ^
return (value ^ size) % (2**32)
def iu(jo):
jp = []
for jq in range(0, len(jo), 2):
jr = jo[jq:jq + 2]
js = int(jr, 16)
jp.append(js)
# print(jp)
return jp
def ix(jo):
if jo is None:
jo = []
jp = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]
result = "".join([jp[jo_item >> 4 & 15] + jp[15 & jo_item] for jo_item in jo])
return result
def is_(jo):
jp = quote(jo)
# print(jp)
jq = []
jr = 0
while jr < len(jp):
js = jp[jr]
if "%" == js:
jt = jp[jr + 1] + jp[jr + 2]
ju = int(jt, 16)
jq.append(ju)
jr += 2
else:
jq.append(ord(js[0]))
jr += 1
# print(len(jq), jq)
return jq
def _iD(jo):
raw_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
new_table = 'ZmserbBoHQtNP+wOcza/LpngG8yJq42KWYj0DSfdikx3VT16IlUAFM97hECvuRX5='
dictionary_decode = str.maketrans(new_table, raw_table) # 创建字符映射关系 用于base64decode
dictionary_encode = dict(zip(dictionary_decode.values(), dictionary_decode.keys())) # 创建一个与上面反向的映射关系用于base64encode
result_b64 = base64.b64encode(bytearray(jo)).decode()
new_result_b64 = result_b64.translate(dictionary_encode)
# print(new_result_b64)
return new_result_b64
def get_k2(jo, jp):
"""
iO(jo, jp)
jo: url相关的数组
jp: 时间戳
"""
m = len(jo) % 4
jj = jp ^ len(jo)
ju = 1540483477 # 固定
# 每四个为一组
for i in range(0, len(jo) - m, 4):
tmp1 = (jo[i] & 255) | logical_left_shift((jo[i + 1] & 255), 8)
tmp2 = logical_left_shift((jo[i + 2] & 255), 16)
tmp3 = tmp1 | tmp2
tmp4 = tmp3 | logical_left_shift(jo[i + 3] & 255, 24)
tmp5 = (tmp4 & 65535) * ju
tmp6 = logical_left_shift((((logical_right_shift(tmp4, 16)) * ju) & 65535), 16)
tmp7 = tmp5 + tmp6
tmp8 = python_2_js(tmp7, logical_right_shift(tmp7, 24))
tmp9 = (tmp8 & 65535) * ju
tmp10 = logical_left_shift((((logical_right_shift(tmp8, 16)) * ju) & 65535), 16)
tmp11 = tmp9 + tmp10
tmp12 = (jj & 65535) * ju
tmp13 = logical_left_shift((((logical_right_shift(jj, 16)) * ju) & 65535), 16)
tmp14 = tmp12 + tmp13
jj = python_2_js(tmp11, tmp14)
i = i + 4
if m == 3:
jj = python_2_js(jj , logical_left_shift(255 & jo[i + 2], 16))
jj = python_2_js(jj , logical_left_shift(255 & jo[i + 1], 8))
jj = python_2_js(jj, (255 & jo[i]))
jj = (65535 & jj) * ju + logical_left_shift(logical_right_shift(jj, 16) * ju & 65535, 16)
elif m == 2:
jj = python_2_js(jj , logical_left_shift(255 & jo[i + 1], 8))
jj = python_2_js(jj, (255 & jo[i]))
jj = (65535 & jj) * ju + logical_left_shift(logical_right_shift(jj, 16) * ju & 65535, 16)
elif m == 1:
jj = python_2_js(jj, (255 & jo[i]))
jj = (65535 & jj) * ju + logical_left_shift(logical_right_shift(jj, 16) * ju & 65535, 16)
tmp0 = python_2_js(jj, logical_right_shift(jj, 13))
tmp1 = (tmp0 & 65535) * ju
tmp2 = logical_left_shift((logical_right_shift(tmp0, 16) * ju) & 65535, 16)
tmp3 = tmp1 + tmp2
tmp4 = logical_right_shift(python_2_js(tmp3, logical_right_shift(tmp3, 15)), 0)
res = ctypes.c_int(tmp4 ^ ju).value
# print(res)
return res
def iy(jo, jq):
jr = 0
js = 0
jt = []
ju = len(jq)
# print(f"{jq} 长度为 {ju}")
for jv in range(ju):
jr = (jr + 1) % 256
js = (js + jo[jr]) % 256
jp = jo[jr]
jo[jr] = jo[js]
jo[js] = jp
jt.append(ord(jq[jv]) ^ jo[(jo[jr] + jo[js]) % 256])
return jt
def get_k1(jZ, jp):
array1 = [i for i in range(256)]
array2 = jZ
jr = 0
for i in range(256):
jt = i % 256
n = i % 16
js = array1[jt]
jr = (jr + js + array2[n] + 31) % 256
array1[jt] = array1[jr]
array1[jr] = js
# print(f"ararry1 => {array1}")
jt_ = iy(array1, jp)
# print(f"_arrary1 => {array1}")
jZ.extend(jt_)
# print(f" jZ => {len(jZ)} => {jZ}")
k1 = _iD(jZ) # a5
return k1
def get_kh(jS, kb, kf, x0=4):
m = [0] * 2
m[0] = jS << x0
m[1] = jS << (32 - x0)
m[0] = m[0] | m[1]
kg = m[0]
kf[0] = kf[0] ^ kg
kf[1] = kf[1] ^ kb
kf[2] = kf[2] ^ kb ^ kg
kf[3] = kf[3] ^ kf[0]
kh_list = []
for i in kf:
kh_list.append(hex_reserve(i))
kh = "".join(kh_list)
return kh
def iv(jo):
jp = []
jp.append((jo >> 24) & 255)
jp.append((jo >> 16) & 255)
jp.append((jo >> 8) & 255)
jp.append(jo & 255)
return jp
def bc(p):
t = 256
f = [None] * t
while t:
c = 8
t -= 1
a = t
while c:
if a & 1:
a = python_2_js(logical_right_shift(a, 1), 3988292384)
else:
a = logical_right_shift(a, 1)
c -= 1
f[t] = logical_right_shift(a, 0)
c = 0
t = -1
while c < len(p):
t = f[python_2_js(255 & t, p[c])] ^ logical_right_shift(t, 8)
c += 1
return python_2_js(t, 306674911) - 2 ** 32
def get_a6(a6):
"""
直接读取a6
并修改a6的部分内容
:return:
"""
env = from_a6(a6[4:])
A = gzip.compress(env.encode("utf-8"), compresslevel=1)
C = encrypt_aes_cbc(A.hex())
C = "w1.3" + C
return C
def get_JP(url):
"""
处理url
"""
parse_result = urlparse(url)
path = parse_result.path
param_dict = parse_qs(parse_result.query)
param_list = list(param_dict.keys())
param_list.sort() # 排序从小到大
params = "&".join([f'{i}={quote_plus(param_dict[i][0])}' for i in param_list])
target_ = f"GET {path} {params}"
JP = is_(target_)
return JP
def get_a5(i, y, qa):
"""
a5 生成
"""
d = i & 4294967295
p = iv(d)
g = []
g.extend(is_(y))
g.extend(p)
v = md5_(bytearray(g))
m = iu(v[:15])
f = 0 # env 环境值
m[7] = 255 & (f ^ bc(p))
m.extend(p)
l = iv(4294967295 & bc(m))
m.extend(l)
a5 = get_k1(m, qa)
return a5
def get_main(i, a6, a3, a7, url, jq):
# i = 1723618362188 # 时间戳 TODO:需要二次处理
o = i & 4294967295
a5 = get_a5(i, a6, jq)
tmp = is_(a6)
l = iv(o)
tmp.extend(l)
g = bytearray(tmp)
v = md5_(g)
w = get_JP(url)
S = get_k2(w, i)
C = iv(S)
A = get_k2(bytearray(is_(a5)), i)
I = iv(A)
c = [S, A, S ^ o, S ^ A ^ o]
O = iu("".join([hex_reserve(i) for i in c]))
tmp = []
tmp.extend(C)
tmp.extend(I)
tmp.extend(O)
D = ix(tmp) # a4
d = logical_right_shift(A, 0)
T = f"1.2{i}{a3}{D}{d}{v}{a7}"
tmp = md5_(bytearray(is_(T)))
j = get_md5Array(tmp)
d1 = get_kh(o, d, j, x0=3) # 到这一步就是 小程序的 d1
mtgsig = {
"a1": "1.2",
"a2": i, # 时间戳 估计有校验
"a3": a3, # 服务器下发
"a4": D, # 计算
"a5": a5, # 计算 暂时不清楚入参
"a6": a6, # 计算环境 需要确定环境信息
"a7": a7, # wxcode 固定
"x0": 3, # 固定
"d1": d1 # 计算 比h5少一步
}
return mtgsig
def from_a6(a6):
"""
根据版本迭代 a6
:param a6:
:return:
"""
decode_res = decrypt_aes_128_cbc(a6)
plain_text = gzip.decompress(bytes.fromhex(decode_res.decode()))
p = json.loads(plain_text.decode())
p[-3] = int(time.time()) # 修改时间戳
p[-4][-6] = "3.9.12" # 修改版本
p[-4][-9] = "3.6.3" # 修改另外一个版本 **目前没有看到其他的需要修改的地方
res = json.dumps(p, ensure_ascii=False, separators=(',', ':'))
return res
def mtgsig_run(url, b8, a3, a6):
"""
mtgsig 对外调用接口
:param url: 需要加密的链接
:param b8: 累加
:param a3: a3服务器下发 暂时写死
:param a6: 目标设备环境
:return:
"""
a6 = get_a6(a6)
a7 = "wx734c1ad7b3562129"
# m = 1723688535465
i = int(time.time() * 1000)
# diff = i - m
# i = i - diff # 处理时间 这块暂时先写死
_jq = {"b7": int(time.time()) - 200,
"b1": {"miniProgram": {"appId": "wx734c1ad7b3562129", "envVersion": "release", "version": "9.37.232"}},
"b6": "", "b8": b8, "b2": "pages/poi/poi"}
jq = json.dumps(_jq, separators=(',', ':'))
mtgsig = json.dumps(get_main(i, a6, a3, a7, url, jq), ensure_ascii=False, separators=(',', ':'))
return mtgsig
if __name__ == '__main__':
url = "https://mapi.dianping.com/mapi/wechat/weshop.bin?yodaReady=wx&csecappid=wx734c1ad7b3562129&csecplatform=3&csecversionname=9.64.0&csecversion=1.4.0&optimus_uuid=18b229261a3c8-c53ac1e606702-0-0-18b229261a3c8&optimus_platform=13&optimus_partner=203&optimus_risk_level=71&optimus_code=10&redirect_from=pages%252Fdetail%252Fdetail&shopUuid=k9Kcg8I6w4GBcuGF&shopType=10&shopStyle=bigpic&online=1&shopuuid=k9Kcg8I6w4GBcuGF&pageName=shop&lat=40.055335628194634&lng=116.35128357647478&mtsiReferrer=pages%252Fdetail%252Fdetail%253Fredirect_from%253Dpages%25252Fdetail%25252Fdetail%2526shopUuid%253Dk9Kcg8I6w4GBcuGF%2526shopType%253D10%2526shopStyle%253Dbigpic%2526online%253D1%2526shopuuid%253Dk9Kcg8I6w4GBcuGF%2526shopId%253Dk9Kcg8I6w4GBcuGF%2526pageName%253Dshop&cookieid=-4TzrChF1yPgyQBn5D7NrKC2_vuFu9oL8DiAq28T-Kk&device_system=MAC&wxmp_version=9.64.0"
# print(mtgsig_run(url))
a6 = "w1.3grvNcRFZkE6QoEQ31ALPuc415J6/VKamSdeIXCVWX/DGsGA+taQlBpn7QF0z/ffrSmLkkQW0dqtDnWECJyGr9iFEhTKHYlyKRbYWwffNlvlDZ9tmFet/PyCSfKJw7xVZe8/4QYaAcbk1eJ7tWMUQllVcQDKlxku5Smml4r566JVAOGi48LCGAHxImhjIuI2KomDqOtCQb7Ii2cbGd2Y7vmWjypGGJbTtrztH/1weiEULAxadX72+RdjpXDa8UMgGbVmEUu5LLIwoyNEi6leK6f/QvV9/EvVfb5vtKyL5IAQND5B9g5qndP4GOuTftOM2ylQKb4rguR4TEQsR3uyruBJusZlID67k1d8jPCM+ol2mbFJP88EfBwnrQ+BSDWfVQjjfIj2mWpEnI+oA72gkPxuHteESJaXzZz94udFusf1tUtdf0q15QiQPSBX7JjK2P/lLHMfe+867ZiGMyoivxisrw1d9bbal27BjMTm32IrAN+ywQFoP9bHXNThdxmai"
print(get_a6(a6))
print(from_a6(a6[4:]))