从雀魂表情到 XOR

无意义的水文,主要记录极客思想,与日记不同的生活方式记录

blob 与定位

进入游戏,从寮舍查看人物档案的时候可以看到表情资源是通过 blob 加载的
majsoul-1
看 url 格式,大概是使用了类似于 base64toblob 之类的库,所以没法获取到真实地址,但是观察访问记录可以看到其实获取过原文件
majsoul-2
但是没法按照 png 的格式解析,我们下载下来也没法识别成任何文件形式,也不符合 gzip 压缩。

XOR

把 blob 获取到的图片和我们通过直链得到的图片进行对比,发现没有任何一对字节相同,猜测可能经过了异或处理,把两个文件进行异或之后,证明猜测正确

猜测与遍历

通过研究链接格式,我们猜测出其他人物的 id 和对应表情的编号,遍历下载并进行解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import subprocess, os

def dexor(filename): # 图片伪加密
b = bytearray(open(filename, 'rb').read())
for i in range(len(b)):
b[i] ^= 0x49
open(filename, 'wb').write(b)

def execute(filename, url): # 下载并解密
do = subprocess.Popen('wget -O img/' + filename + ' ' + url, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = do.communicate()
print("Dexoring " + filename)
dexor('img/'+filename)

FNULL = open(os.devnull, 'w')
version = ['v0.4.1.w', 'v0.4.232.w', 'v0.4.237.w', 'v0.5.34.w', 'v0.5.90.w']
url = "https://majsoul.union-game.com/0/%s/extendRes/emo/e2000%02d/%d.png"
role_name = ['yiji', 'erjietang', 'jianai', 'qianzhi', 'wunv', 'fuzi', 'bamuwei', 'jiutiao', 'zeniya', 'kawei']

for role in range(1,9): # 八个角色
for img_id in range(9): # 初始九张表情
execute(role_name[role-1] + '-' + str(img_id) + '.png', url % (version[3], role, img_id))
for img_id in range(10, 14): # 三张契约表情 + 春节限定
execute(role_name[role-1] + '-' + str(img_id) + '.png', url % (version[3], role, img_id))
for role in range(9,11): # 新增两个角色
for img_id in range(9):
execute(role_name[role-1] + '-' + str(img_id) + '.png', url % (version[4], role, img_id))
if role == 9:
for img_id in range(10, 13): # 三张契约表情
execute(role_name[role-1] + '-' + str(img_id) + '.png', url % (version[4], role, img_id))

整理后的表情包

后记

留坑,鸽了很久,感想有点忘记了

Buy me a coffee, encourage me keep writing.