tj_xxtea加解密算法求助

感谢大佬,圆了童年的梦,

文件名都是杂乱的,先弄个皮卡丘,其他有空慢慢整理
皮卡丘.zip (466.4 KB)

感谢 cyb464b6
这里包内文件名经过混淆可使用这个脚本还原

import json
import os
import shutil
from pathlib import Path

def restore_files_from_mapping(json_path, search_dir, output_dir):
    # 读取JSON文件
    with open(json_path, 'r', encoding='utf-8') as f:
        mapping_data = json.load(f)
    
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 统计处理结果
    total_files = len(mapping_data)
    success_count = 0
    failed_count = 0
    failed_files = []
    
    # 遍历JSON中的每一项
    for original_path, info in mapping_data.items():
        mapping_path = info.get('mapping')
        if not mapping_path:
            print(f"警告: {original_path} 没有mapping信息,跳过")
            failed_count += 1
            failed_files.append(original_path)
            continue
        
        # 构建完整的源文件路径和目标文件路径
        source_file = os.path.join(search_dir, mapping_path)
        dest_file = os.path.join(output_dir, original_path)
        
        try:
            # 确保目标目录存在
            os.makedirs(os.path.dirname(dest_file), exist_ok=True)
            
            # 复制文件
            shutil.copy2(source_file, dest_file)
            print(f"成功: {mapping_path} -> {original_path}")
            success_count += 1
        except FileNotFoundError:
            print(f"错误: 找不到文件 {mapping_path}")
            failed_count += 1
            failed_files.append(original_path)
        except Exception as e:
            print(f"错误: 处理 {original_path} 时发生异常 - {str(e)}")
            failed_count += 1
            failed_files.append(original_path)
    
    # 输出统计信息
    print("\n处理完成:")
    print(f"总文件数: {total_files}")
    print(f"成功: {success_count}")
    print(f"失败: {failed_count}")
    
    if failed_files:
        print("\n失败的文件列表:")
        for file in failed_files:
            print(file)

if __name__ == "__main__":
    # 配置路径
    json_file_path = input("请输入repo.mapping文件路径: ").strip()
    search_directory = r"C:\Users\youname\Desktop\apkunpack\MyLuaGame_9.8415\assets"
    output_directory = r"C:\Users\youname\Desktop\resout"
    
    # 执行恢复操作
    restore_files_from_mapping(json_file_path, search_directory, output_directory)
    
    # 等待用户按Enter退出
    input("\n按Enter键退出...")

repo.mapping文件可在解包后\assets\repository下找到

1 个赞

感谢大佬的恢复文件名方法
D9D1931275627F8CB397A57D53273F8C

他的视频下载下来还还需要解密不过审计了他的代码你只需要将这几个文件替换即可无视好感度解锁所有内容
repository.zip (7.2 KB)
下载下来后替换安装包内的文件如果是iOS就去https://www.csyproject.site/channel/FX01/mhbkm_9.7280403.ipa
下载ipa包然后使用Sideloadly签名安装注意勾选
image
之后使用爱思助手替换他文档路径下的文件即可

2 个赞

https://game-pc.cqzxdasha.com/details?gameId=18
Google的时候发现了还有一个版本这个版本的密钥有大佬能破解吗

这个网站还有色漫对决和幻想三国志都是这种加密,不知道该怎么写hook脚本,我太菜了 :sob:

hook在一个月前现学现用了一次忘了。。。
这是当时使用的脚本(应该。。。修改了一下函数还没试这个版本的宝可梦)

var so_name = "libcocos2dlua.so";
var fun_name = "_ZN8CCCrypto12decryptXXTEAEPhiS0_iPi";
function do_hook() {  
  var addr = Module.findExportByName(so_name, fun_name);
  console.log(addr); 
  Interceptor.attach(addr, {
      onEnter: function (args) {
                console.log('key: ' + Memory.readCString (args[2]));
      },
      onLeave: function (retval) {
      }
  })
}
function load_so_and_hook() {
  var dlopen = Module.findExportByName(null, "dlopen");
  var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
  Interceptor.attach(dlopen, {
      onEnter: function (args) {
          var path_ptr = args[0];
          var path = ptr(path_ptr).readCString();
          console.log("[dlopen:]", path);
          this.path = path;
      }, onLeave: function (retval) {
          if (this.path.indexOf(so_name) !== -1) { // 如果包含我想要的so文件
              console.log("[dlopen:]", this.path);
              do_hook();
          }
      }
  });
  Interceptor.attach(android_dlopen_ext, {
      onEnter: function (args) {
          var path_ptr = args[0];
          var path = ptr(path_ptr).readCString();
          this.path = path;
      }, onLeave: function (retval) {
          if (this.path.indexOf(so_name) !== -1) {
              console.log("\nandroid_dlopen_ext加载:", this.path);
              do_hook();
          }
      }
  });
}
load_so_and_hook();

大佬有无密钥获取方法可分享一下


image


找上来密钥可能在cocos2d::LuaStack结构里偏移是+40LL应该把给大佬一点参考…

从某个奇妙的地方扒了一段代码似乎是密钥生成逻辑

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import struct
import binascii

import md5
import lz4 # pip install lz4==0.8.2
# import zstd # 1.4.3.2
import subprocess

import tjutil

kCompanyName = "TianJi Information Technology Inc."
kCompanyShortName = "TianJi"


#####################################
# static char _toConfuse(char ch)
# {
# 	if (ch >= 'a' && ch <= 'z') return ch - 'a' + 'A';
# 	else if (ch == '_') return '+';
# 	else if (ch == '.' || ch == '6') return ';';
# 	return ch;
# }

# static std::string _toLuaPwd(std::string version)
# {
# 	// for code confusion
# 	// 1. a = _toConfuse("hello"+kCompanyShortName+",world"+kCompanyName)
# 	// 2. b = MD5(a) + string("20140516"+version+kCompanyShortName)
# 	// 3. c = _toConfuse(b)
# 	// 4. d = reverse(c)
# 	// 5. e = MD5(d)
# 	int pos = version.find_last_of('.'); //把最后一位舍掉了
# 	std::string confusion = "hello" + std::string(kCompanyShortName) + ",world" + kCompanyName;
# 	std::transform(confusion.begin(), confusion.end(), confusion.begin(), _toConfuse);
# 	std::string updatePass = ymextra::CCCrypto::MD5String((void*)confusion.c_str(), confusion.length());
# 	updatePass += "20140516" + version.substr(0, pos) + kCompanyShortName;
# 	std::transform(updatePass.begin(), updatePass.end(), updatePass.begin(), _toConfuse);
# 	std::reverse(updatePass.begin(), updatePass.end());
# 	return ymextra::CCCrypto::MD5String((void*)updatePass.c_str(), updatePass.length());
# }

def reverse(str):
	return str[::-1]
def toConfuse(str):
	ret = str.upper()
	ret = ret.replace('_','+')
	ret = ret.replace('.',';')
	ret = ret.replace('6',';')
	#return reverse(ret)
	return ret
def getMd5(str) :
	hash = md5.new()
	hash.update(str)
	return hash.hexdigest()
def toLuaPwd(version):
	pos = version[::-1].find('.')+1
	a = toConfuse("hello"+kCompanyShortName+",world"+kCompanyName)
	b = getMd5(a) + str("20140516"+version[:-pos]+kCompanyShortName)
	c = toConfuse(b)
	d = reverse(c)
	e = getMd5(d)
	return e

kAppVersion = str(os.environ.get('kAppVersion', '2.1.0.0'))
XXTEA_SIGN = kCompanyShortName
XXTEA_KEY = toLuaPwd(kAppVersion)

print 'tjz.kAppVersion', kAppVersion
print 'tjz.XXTEA_SIGN', XXTEA_SIGN
print 'tjz.XXTEA_KEY', XXTEA_KEY
print 'lz4.VERSION', lz4.VERSION

lz4compress = None
lz4uncompress = None
if lz4.VERSION == '0.8.2':
	# def compress(s):
	# 	lenpack = struct.pack('>L', len(s))[:4]
	# 	return lenpack + lz4.compress(s)
	lz4compress = lz4.compress
	lz4uncompress = lz4.uncompress

else:
	import lz4.block # pip install lz4==1.1.0
	lz4compress = lz4.block.compress
	lz4uncompress = lz4.block.decompress


def dataCompress(data, mode='lz4'):
	if mode == 'lz4':
		return lz4compress(data)
	# elif mode == 'zstd':
		# return zstd.compress(data)
	raise Exception('no such compress mode')

def isCompressed(data):
	# tj! = tjz + tje, use lz4
	# 整包少10+MB,暂时不替换,仍然用lz4
	# tj# = tjs + tje, use zstd
	return data[:3] in ('tjz', 'tje', 'tj!', 'tjs', 'tj#')

# tjz[4 bytes size][lz4 data...]
def compress(data, useLZ4=True):
	lenpack = struct.pack('<L', len(data))[:4]
	if useLZ4:
		return 'tjz' + lenpack + dataCompress(data, 'lz4')
	# else:
		# return 'tjs' + lenpack + dataCompress(data, 'zstd')

def compressToFile(data, path, useLZ4=True):
	with open(path, 'wb') as fp:
		fp.write(compress(data, useLZ4=useLZ4))

# tje[16 bytes pass][4 bytes size][data...]
def encodeToFile(data, pwd, path, pwdIsHex=True):
	rnd = os.urandom(16)
	# rnd = '\0' * 16
	if pwdIsHex:
		pwd = binascii.unhexlify(pwd)
	bb = [ord(x) for x in pwd]
	aa = [ord(x) for x in rnd]
	cc = [0] * 16
	for i in xrange(max(len(aa), len(bb))):
		cc[i%16] = cc[i%16] ^ aa[i%len(aa)] ^ bb[i%len(bb)]
	newpwd = ''.join([chr(c) for c in cc])
	lenpack = struct.pack('<L', len(data))[:4]
	# print len(newpwd), repr(newpwd)

	with open(path, 'wb') as fp:
		fp.write(data)

	# xxtea
	XXTEA_SIGN = 'tje' + rnd + lenpack
	cmd = [tjutil.xxtea_exe, '-eh', binascii.hexlify(newpwd), '-sh', binascii.hexlify(XXTEA_SIGN), path, path]
	cmd = ' '.join(cmd)
	ret = subprocess.call(cmd, shell=True)

	if ret != 0:
		raise Exception('xxtea error')


# tj![16 bytes pass][4 bytes size][lz4 data...]
def encodeAndCompressToFile(data, pwd, path, pwdIsHex=True, useLZ4=True):
	rnd = os.urandom(16)
	# rnd = '\0' * 16
	if pwdIsHex:
		pwd = binascii.unhexlify(pwd)
	bb = [ord(x) for x in pwd]
	aa = [ord(x) for x in rnd]
	cc = [0] * 16
	for i in xrange(max(len(aa), len(bb))):
		cc[i%16] = cc[i%16] ^ aa[i%len(aa)] ^ bb[i%len(bb)]
	newpwd = ''.join([chr(c) for c in cc])

	# compress
	lenpack = struct.pack('<L', len(data))[:4]
	zdata = dataCompress(data, 'lz4' if useLZ4 else 'zstd')
	with open(path, 'wb') as fp:
		fp.write(zdata)

	# xxtea
	flag = 'tj!' if useLZ4 else 'tj#'
	XXTEA_SIGN = flag + rnd + lenpack
	cmd = [tjutil.xxtea_exe, '-eh', binascii.hexlify(newpwd), '-sh', binascii.hexlify(XXTEA_SIGN), path, path]
	cmd = ' '.join(cmd)
	ret = subprocess.call(cmd, shell=True)

	if ret != 0:
		raise Exception('xxtea error')


def decode(data, pwd, pwdIsHex=True):
	if not isCompressed(data):
		return data
	rawdata = data
	isLZ4 = data[2] == '!' or data[2] == 'z'
	isXXTEA = data[2] == '!' or data[2] == 'e'
	if pwdIsHex:
		pwd = binascii.unhexlify(pwd)

	sign = data[:3]
	data = data[3:] # flag
	if isXXTEA:
		rnd = data[:16] # rnd
		sign += rnd
		data = data[16:]
		bb = [ord(x) for x in pwd]
		aa = [ord(x) for x in rnd]
		cc = [0] * 16
		for i in xrange(max(len(aa), len(bb))):
			cc[i%16] = cc[i%16] ^ aa[i%len(aa)] ^ bb[i%len(bb)]
		pwd = ''.join([chr(c) for c in cc])

	length = struct.unpack('<L', data[:4]) # lenpack
	sign += data[:4]
	data = data[4:]
	# print '!!!sign', repr(sign)
	# print '!!!rnd', repr(rnd), len(rnd)
	# print '!!!length', length
	# print '!!!data', len(data)

	if isXXTEA:
		path = 'decode.tmp'
		with open(path, 'wb') as fp:
			fp.write(rawdata)

		cmd = [tjutil.xxtea_exe, '-dh', binascii.hexlify(pwd), '-sh', binascii.hexlify(sign), path, path]
		cmd = ' '.join(cmd)
		ret = subprocess.call(cmd, shell=True)
		if ret != 0:
			raise Exception('xxtea error')

		with open(path, 'rb') as fp:
			data = fp.read()

	if isLZ4:
		data = lz4uncompress(data)

	return data

在AppDelegate::AppDelegate发现了类似代码

这个版本的解密成功了参考密钥生成脚本

import hashlib

# 逆向出的查表数据
byte_D375B6 = [
    0x3F, 0x3C, 0x05, 0x23, 0x3C, 0x04, 0x6B, 0x61, 0x3D, 0x55,
    0x35, 0x24, 0x18, 0x6D, 0x10, 0x6B, 0x3F, 0x35, 0x63, 0x57,
    0x68, 0x18, 0x6E, 0x18, 0x1A, 0x6D, 0x6B, 0x05, 0x68, 0x63,
    0x5F
]

byte_D375D5 = [
    0x45, 0x77, 0x53, 0x09, 0x4E, 0x49, 0x30, 0x16, 0x7C, 0x1B,
    0x59, 0x3E, 0x3A, 0x1F, 0x17, 0x0B, 0x73, 0x43, 0x7A, 0x1A,
    0x48, 0x78, 0x36, 0x00, 0x6F, 0x1E, 0x67, 0x12, 0x72, 0x29,
    0x7D, 0x70, 0x32, 0x40, 0x3B, 0x57, 0x62, 0x4F, 0x3F, 0x60,
    0x31, 0x2C, 0x56, 0x2B, 0x04, 0x4D, 0x27, 0x25, 0x76, 0x4C,
    0x37, 0x34, 0x26, 0x65, 0x7B, 0x2A, 0x75, 0x39, 0x11, 0x66,
    0x41, 0x61, 0x50, 0x54, 0x5B, 0x6A, 0x23, 0x0E, 0x21, 0x13,
    0x42, 0x35, 0x1C, 0x5E, 0x03, 0x46, 0x0A, 0x6B, 0x06, 0x64,
    0x07, 0x0D, 0x5A, 0x4B, 0x58, 0x6D, 0x02, 0x68, 0x5D, 0x7E,
    0x3C, 0x5F, 0x71, 0x44, 0x69, 0x2E, 0x2F, 0x47, 0x01, 0x63,
    0x33, 0x18, 0x5C, 0x1D, 0x6E, 0x08, 0x14, 0x20, 0x51, 0x79,
    0x6C, 0x19, 0x22, 0x52, 0x7F, 0x05, 0x15, 0x38, 0x74, 0x55,
    0x4A, 0x28, 0x24, 0x3D, 0x2D, 0x0F, 0x10, 0x0C, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]


def decode_company_name():
    """通过查表解码隐藏的公司全名"""
    decoded_bytes = [byte_D375D5[b] for b in byte_D375B6]
    return bytes(decoded_bytes).decode('latin1')


def to_confuse(s):
    """字符替换规则"""
    s = s.upper()
    return s.replace('_', '+').replace('.', ';').replace('6', ';')


def generate_key(version="2.1.0.0"):
    # 常量定义
    COMPANY_SHORT = "Gameboys"  # 伪代码中硬编码的短名称
    DATE_STRING = "2o20o516"  # 伪代码中插入的日期

    # 1. 解码公司全名
    company_full = decode_company_name()  # 结果为"TianJi Information Technology Inc."

    # 2. 处理版本号(去掉最后的小版本)
    version_main = version[:version.rfind('.')] if '.' in version else version

    # 3. 构建第一阶段字符串
    phase1_str = f"hell0{COMPANY_SHORT},w0rld{company_full}"

    # 4. 字符混淆处理
    processed_phase1 = to_confuse(phase1_str)

    # 5. 第一次MD5
    md5_phase1 = hashlib.md5(processed_phase1.encode('utf-8')).hexdigest()

    # 6. 构建第二阶段字符串
    phase2_str = f"{md5_phase1}{DATE_STRING}{version_main}{COMPANY_SHORT}"

    # 7. 二次混淆处理
    processed_phase2 = to_confuse(phase2_str)

    # 8. 反转字符串
    reversed_str = processed_phase2[::-1]

    # 9. 最终MD5生成密钥
    final_key = hashlib.md5(reversed_str.encode('utf-8')).hexdigest()

    return final_key


if __name__ == "__main__":
    # 测试输出
    test_version = "2.1.0.0"
    print(f"Version: {test_version}")
    print(f"Generated Key: {generate_key(test_version)}")

    # 验证解码结果
    print(f"\nDecoded Company Name: {decode_company_name()}")

AppDelegate函数伪代码

void __fastcall AppDelegate::AppDelegate(AppDelegate *this)
{
  __int64 v2; // x8
  int v3; // w10
  signed __int64 v4; // x21
  _BYTE *v5; // x9
  char *v6; // x9
  bool v7; // zf
  char *v8; // x8
  char *v9; // x8
  char *v10; // x8
  char *v11; // x8
  char *v12; // x8
  char *v13; // x8
  __int64 v14; // x0
  __int64 v15; // x0
  __int64 i; // x9
  char *v17; // x13
  char *v18; // x1
  size_t v19; // x2
  __int64 v20; // x0
  int v21; // w2
  unsigned __int64 v22; // x11
  CCCrypto *v23; // x12
  unsigned int v24; // w13
  unsigned __int64 v25; // x9
  CCCrypto *v26; // x10
  int v27; // w11
  CCCrypto *v28; // x0
  unsigned __int64 v29; // x1
  size_t v30; // x8
  unsigned __int64 v31; // x9
  _BYTE *v32; // x21
  size_t v33; // x20
  char *v34; // x22
  __int64 v35; // x0
  _BYTE *v36; // x8
  unsigned __int64 v37; // x8
  char *v38; // x9
  bool v39; // zf
  char *v40; // x9
  size_t v41; // x8
  char *v42; // x9
  char *v43; // x9
  char *v44; // x9
  char *v45; // x9
  char *v46; // x9
  char *v47; // x1
  size_t v48; // x2
  __int64 v49; // x0
  char *v50; // x1
  size_t v51; // x2
  int v52; // w2
  unsigned __int64 v53; // x9
  char *v54; // x10
  size_t v55; // x12
  unsigned __int64 v56; // x11
  _BYTE *v57; // x13
  int v58; // w9
  size_t v59; // x13
  char *v60; // x11
  char *v61; // x13
  unsigned __int64 v62; // x9
  char v63; // w12
  bool v64; // cc
  bool v65; // zf
  unsigned __int64 v66; // x9
  CCCrypto *v67; // x0
  unsigned __int64 v68; // x1
  int v69; // w2
  cocos2d::FileUtils *v70; // x0
  unsigned __int64 v71; // x1
  unsigned __int8 v72; // [xsp+8h] [xbp-128h]
  _BYTE v73[15]; // [xsp+9h] [xbp-127h] BYREF
  void *v74; // [xsp+18h] [xbp-118h]
  __int64 v75; // [xsp+20h] [xbp-110h] BYREF
  unsigned int v76; // [xsp+28h] [xbp-108h]
  void *v77; // [xsp+30h] [xbp-100h]
  __int64 v78; // [xsp+38h] [xbp-F8h] BYREF
  size_t v79; // [xsp+40h] [xbp-F0h]
  void *v80; // [xsp+48h] [xbp-E8h]
  __int64 v81; // [xsp+50h] [xbp-E0h] BYREF
  size_t v82; // [xsp+58h] [xbp-D8h]
  void *v83; // [xsp+60h] [xbp-D0h]
  unsigned __int64 v84; // [xsp+68h] [xbp-C8h] BYREF
  size_t v85; // [xsp+70h] [xbp-C0h]
  void *v86; // [xsp+78h] [xbp-B8h]
  __int128 v87; // [xsp+80h] [xbp-B0h] BYREF
  void *v88; // [xsp+90h] [xbp-A0h]
  __int128 v89; // [xsp+A0h] [xbp-90h] BYREF
  char *v90; // [xsp+B0h] [xbp-80h]
  __int128 v91; // [xsp+C0h] [xbp-70h] BYREF
  CCCrypto *v92; // [xsp+D0h] [xbp-60h]

  _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
  cocos2d::Application::Application(this);
  v2 = 0LL;
  *(_QWORD *)this = off_1025FF0;
  *((_QWORD *)this + 1) = 0LL;
  *((_QWORD *)this + 2) = 0LL;
  *((_QWORD *)this + 3) = 0LL;
  v72 = 14;
  v74 = 0LL;
  strcpy(v73, "2.1.0.0");
  v73[8] = 0;
  *(_WORD *)&v73[9] = 0;
  *(_DWORD *)&v73[11] = 0;
  while ( v2 != -7 )
  {
    v3 = (unsigned __int8)v73[v2-- + 6];
    if ( v3 == 46 )
    {
      v4 = &v73[v2 + 7] - v73;
      goto LABEL_6;
    }
  }
  LODWORD(v4) = -1;
LABEL_6:
  v85 = 0LL;
  v86 = 0LL;
  v84 = 0LL;
  std::string::append((int)&v84, 8uLL, 0);
  v5 = v86;
  if ( (v84 & 1) == 0 )
    v5 = (char *)&v84 + 1;
  *v5 = 71;
  v6 = (char *)v86;
  v7 = (v84 & 1) == 0;
  if ( (v84 & 1) == 0 )
    v6 = (char *)&v84 + 1;
  v6[1] = 97;
  v8 = (char *)v86;
  if ( v7 )
    v8 = (char *)&v84 + 1;
  v8[2] = 109;
  v9 = (char *)v86;
  if ( v7 )
    v9 = (char *)&v84 + 1;
  v9[3] = 101;
  v10 = (char *)v86;
  if ( v7 )
    v10 = (char *)&v84 + 1;
  v10[4] = 98;
  v11 = (char *)v86;
  if ( v7 )
    v11 = (char *)&v84 + 1;
  v11[5] = 111;
  v12 = (char *)v86;
  if ( v7 )
    v12 = (char *)&v84 + 1;
  v12[6] = 121;
  v13 = (char *)v86;
  if ( v7 )
    v13 = (char *)&v84 + 1;
  v13[7] = 115;
  v14 = std::string::insert((int)&v84, 0, "hell0", 5uLL);
  v88 = *(void **)(v14 + 16);
  v87 = *(_OWORD *)v14;
  *(_QWORD *)(v14 + 8) = 0LL;
  *(_QWORD *)(v14 + 16) = 0LL;
  *(_QWORD *)v14 = 0LL;
  v15 = std::string::append((int)&v87, ",w0rld", 6uLL);
  v90 = *(char **)(v15 + 16);
  v89 = *(_OWORD *)v15;
  *(_QWORD *)(v15 + 8) = 0LL;
  *(_QWORD *)(v15 + 16) = 0LL;
  *(_QWORD *)v15 = 0LL;
  v82 = 0LL;
  v83 = 0LL;
  v81 = 0LL;
  std::string::append((int)&v81, 0x1FuLL, 0);
  for ( i = 0LL; i != 31; ++i )
  {
    if ( (v81 & 1) != 0 )
      v17 = (char *)v83;
    else
      v17 = (char *)&v81 + 1;
    v17[i] = byte_D375D5[byte_D375B6[i]];
  }
  if ( (v81 & 1) != 0 )
    v18 = (char *)v83;
  else
    v18 = (char *)&v81 + 1;
  if ( (v81 & 1) != 0 )
    v19 = v82;
  else
    v19 = (unsigned __int64)(unsigned __int8)v81 >> 1;
  v20 = std::string::append((int)&v89, v18, v19);
  v92 = *(CCCrypto **)(v20 + 16);
  v91 = *(_OWORD *)v20;
  *(_QWORD *)(v20 + 8) = 0LL;
  *(_QWORD *)(v20 + 16) = 0LL;
  *(_QWORD *)v20 = 0LL;
  if ( (v81 & 1) != 0 )
  {
    operator delete(v83);
    if ( (v89 & 1) == 0 )
    {
LABEL_35:
      if ( (v87 & 1) == 0 )
        goto LABEL_36;
      goto LABEL_72;
    }
  }
  else if ( (v89 & 1) == 0 )
  {
    goto LABEL_35;
  }
  operator delete(v90);
  if ( (v87 & 1) == 0 )
  {
LABEL_36:
    if ( (v84 & 1) == 0 )
      goto LABEL_38;
    goto LABEL_37;
  }
LABEL_72:
  operator delete(v88);
  if ( (v84 & 1) != 0 )
LABEL_37:
    operator delete(v86);
LABEL_38:
  v22 = (unsigned __int8)v91;
  v24 = DWORD2(v91);
  v23 = v92;
  v25 = (unsigned __int64)(unsigned __int8)v91 >> 1;
  if ( (v91 & 1) != 0 )
  {
    v25 = *((_QWORD *)&v91 + 1);
    v26 = v92;
  }
  else
  {
    v26 = (CCCrypto *)((char *)&v91 + 1);
  }
  if ( v25 )
  {
    while ( 1 )
    {
      v27 = *(unsigned __int8 *)v26;
      if ( (unsigned int)(v27 - 97) > 0x19 )
      {
        switch ( v27 )
        {
          case '.':
            goto LABEL_47;
          case '_':
            LOBYTE(v27) = 43;
            break;
          case '6':
LABEL_47:
            LOBYTE(v27) = 59;
            break;
        }
      }
      else
      {
        LOBYTE(v27) = v27 - 32;
      }
      --v25;
      *(_BYTE *)v26 = v27;
      v26 = (CCCrypto *)((char *)v26 + 1);
      if ( !v25 )
      {
        v22 = (unsigned __int8)v91;
        v24 = DWORD2(v91);
        v23 = v92;
        break;
      }
    }
  }
  if ( (v22 & 1) != 0 )
    v28 = v23;
  else
    v28 = (CCCrypto *)((char *)&v91 + 1);
  if ( (v22 & 1) != 0 )
    v29 = v24;
  else
    v29 = (unsigned int)(v22 >> 1);
  CCCrypto::MD5String(&v81, v28, (void *)v29, v21);
  v30 = (int)v4;
  v85 = 0LL;
  v86 = 0LL;
  if ( (v72 & 1) != 0 )
    v31 = *(_QWORD *)&v73[7];
  else
    v31 = (unsigned __int64)v72 >> 1;
  if ( (v72 & 1) != 0 )
    v32 = v74;
  else
    v32 = v73;
  if ( v31 >= v30 )
    v33 = v30;
  else
    v33 = v31;
  v84 = 0LL;
  if ( v33 >= 0xFFFFFFFFFFFFFFF0LL )
    std::__basic_string_common<true>::__throw_length_error(&v84);
  if ( v33 >= 0x17 )
  {
    v34 = (char *)operator new((v33 + 16) & 0xFFFFFFFFFFFFFFF0LL);
    v85 = v33;
    v86 = v34;
    v84 = (v33 + 16) & 0xFFFFFFFFFFFFFFF0LL | 1;
    goto LABEL_75;
  }
  v34 = (char *)&v84 + 1;
  LOBYTE(v84) = 2 * v33;
  if ( v33 )
LABEL_75:
    memcpy(v34, v32, v33);
  v34[v33] = 0;
  v35 = std::string::insert((int)&v84, 0, "2o20o516", 8uLL);
  v88 = *(void **)(v35 + 16);
  v87 = *(_OWORD *)v35;
  *(_QWORD *)(v35 + 8) = 0LL;
  *(_QWORD *)(v35 + 16) = 0LL;
  *(_QWORD *)v35 = 0LL;
  v79 = 0LL;
  v80 = 0LL;
  v78 = 0LL;
  std::string::append((int)&v78, 8uLL, 0);
  if ( (v78 & 1) != 0 )
    v36 = v80;
  else
    v36 = (char *)&v78 + 1;
  *v36 = 71;
  v37 = (unsigned __int8)v78;
  v38 = (char *)v80;
  v39 = (v78 & 1) == 0;
  if ( (v78 & 1) == 0 )
    v38 = (char *)&v78 + 1;
  v38[1] = 97;
  v40 = (char *)v80;
  v41 = v37 >> 1;
  if ( v39 )
    v40 = (char *)&v78 + 1;
  v40[2] = 109;
  v42 = (char *)v80;
  if ( v39 )
    v42 = (char *)&v78 + 1;
  v42[3] = 101;
  v43 = (char *)v80;
  if ( v39 )
    v43 = (char *)&v78 + 1;
  v43[4] = 98;
  v44 = (char *)v80;
  if ( v39 )
    v44 = (char *)&v78 + 1;
  v44[5] = 111;
  v45 = (char *)v80;
  if ( v39 )
    v45 = (char *)&v78 + 1;
  v45[6] = 121;
  v46 = (char *)v80;
  if ( v39 )
    v46 = (char *)&v78 + 1;
  v46[7] = 115;
  if ( v39 )
    v47 = (char *)&v78 + 1;
  else
    v47 = (char *)v80;
  if ( v39 )
    v48 = v41;
  else
    v48 = v79;
  v49 = std::string::append((int)&v87, v47, v48);
  v90 = *(char **)(v49 + 16);
  v89 = *(_OWORD *)v49;
  *(_QWORD *)(v49 + 8) = 0LL;
  *(_QWORD *)(v49 + 16) = 0LL;
  *(_QWORD *)v49 = 0LL;
  if ( (v89 & 1) != 0 )
    v50 = v90;
  else
    v50 = (char *)&v89 + 1;
  if ( (v89 & 1) != 0 )
    v51 = *((_QWORD *)&v89 + 1);
  else
    v51 = (unsigned __int64)(unsigned __int8)v89 >> 1;
  std::string::append((int)&v81, v50, v51);
  if ( (v89 & 1) != 0 )
  {
    operator delete(v90);
    if ( (v78 & 1) == 0 )
    {
LABEL_107:
      if ( (v87 & 1) == 0 )
        goto LABEL_108;
      goto LABEL_155;
    }
  }
  else if ( (v78 & 1) == 0 )
  {
    goto LABEL_107;
  }
  operator delete(v80);
  if ( (v87 & 1) == 0 )
  {
LABEL_108:
    if ( (v84 & 1) == 0 )
      goto LABEL_110;
    goto LABEL_109;
  }
LABEL_155:
  operator delete(v88);
  if ( (v84 & 1) != 0 )
LABEL_109:
    operator delete(v86);
LABEL_110:
  v53 = (unsigned __int8)v81;
  v55 = v82;
  v54 = (char *)v83;
  v56 = (unsigned __int64)(unsigned __int8)v81 >> 1;
  if ( (v81 & 1) != 0 )
  {
    v56 = v82;
    v57 = v83;
  }
  else
  {
    v57 = (char *)&v81 + 1;
  }
  if ( v56 )
  {
    while ( 1 )
    {
      v58 = (unsigned __int8)*v57;
      if ( (unsigned int)(v58 - 97) > 0x19 )
      {
        switch ( v58 )
        {
          case '.':
            goto LABEL_119;
          case '_':
            LOBYTE(v58) = 43;
            break;
          case '6':
LABEL_119:
            LOBYTE(v58) = 59;
            break;
        }
      }
      else
      {
        LOBYTE(v58) = v58 - 32;
      }
      --v56;
      *v57++ = v58;
      if ( !v56 )
      {
        v53 = (unsigned __int8)v81;
        v55 = v82;
        v54 = (char *)v83;
        break;
      }
    }
  }
  if ( (v53 & 1) != 0 )
    v59 = v55;
  else
    v59 = v53 >> 1;
  if ( (v53 & 1) != 0 )
    v60 = v54;
  else
    v60 = (char *)&v81 + 1;
  if ( v59 )
  {
    v61 = &v60[v59];
    if ( v61 - 1 > v60 )
    {
      v62 = (unsigned __int64)(v61 - 2);
      do
      {
        v63 = *v60;
        *v60++ = *(_BYTE *)(v62 + 1);
        v64 = v62 > (unsigned __int64)v60;
        *(_BYTE *)(v62-- + 1) = v63;
      }
      while ( v64 );
      v53 = (unsigned __int8)v81;
      LODWORD(v55) = v82;
      v54 = (char *)v83;
    }
  }
  v65 = (v53 & 1) == 0;
  v66 = v53 >> 1;
  if ( v65 )
    v67 = (CCCrypto *)((char *)&v81 + 1);
  else
    v67 = (CCCrypto *)v54;
  if ( v65 )
    v68 = (unsigned int)v66;
  else
    v68 = (unsigned int)v55;
  CCCrypto::MD5String(&v75, v67, (void *)v68, v52);
  if ( (v81 & 1) != 0 )
  {
    operator delete(v83);
    if ( (v91 & 1) == 0 )
    {
LABEL_142:
      if ( (v72 & 1) == 0 )
        goto LABEL_144;
      goto LABEL_143;
    }
  }
  else if ( (v91 & 1) == 0 )
  {
    goto LABEL_142;
  }
  operator delete(v92);
  if ( (v72 & 1) != 0 )
LABEL_143:
    operator delete(v74);
LABEL_144:
  if ( (v75 & 1) != 0 )
    v70 = (cocos2d::FileUtils *)v77;
  else
    v70 = (cocos2d::FileUtils *)((char *)&v75 + 1);
  if ( (v75 & 1) != 0 )
    v71 = v76;
  else
    v71 = (unsigned __int64)(unsigned __int8)v75 >> 1;
  cocos2d::FileUtils::lua_cocos2dx_ui_RichElement_equalType__Terminology(v70, (const char *)v71, v69);
  if ( (v75 & 1) != 0 )
    operator delete(v77);
}

其中两个数组数据

unsigned char byte_D375B6[] =
{
  0x3F, 0x3C, 0x05, 0x23, 0x3C, 0x04, 0x6B, 0x61, 0x3D, 0x55, 
  0x35, 0x24, 0x18, 0x6D, 0x10, 0x6B, 0x3F, 0x35, 0x63, 0x57, 
  0x68, 0x18, 0x6E, 0x18, 0x1A, 0x6D, 0x6B, 0x05, 0x68, 0x63, 
  0x5F
};

unsigned char byte_D375D5[] =
{
  0x45, 0x77, 0x53, 0x09, 0x4E, 0x49, 0x30, 0x16, 0x7C, 0x1B, 
  0x59, 0x3E, 0x3A, 0x1F, 0x17, 0x0B, 0x73, 0x43, 0x7A, 0x1A, 
  0x48, 0x78, 0x36, 0x00, 0x6F, 0x1E, 0x67, 0x12, 0x72, 0x29, 
  0x7D, 0x70, 0x32, 0x40, 0x3B, 0x57, 0x62, 0x4F, 0x3F, 0x60, 
  0x31, 0x2C, 0x56, 0x2B, 0x04, 0x4D, 0x27, 0x25, 0x76, 0x4C, 
  0x37, 0x34, 0x26, 0x65, 0x7B, 0x2A, 0x75, 0x39, 0x11, 0x66, 
  0x41, 0x61, 0x50, 0x54, 0x5B, 0x6A, 0x23, 0x0E, 0x21, 0x13, 
  0x42, 0x35, 0x1C, 0x5E, 0x03, 0x46, 0x0A, 0x6B, 0x06, 0x64, 
  0x07, 0x0D, 0x5A, 0x4B, 0x58, 0x6D, 0x02, 0x68, 0x5D, 0x7E, 
  0x3C, 0x5F, 0x71, 0x44, 0x69, 0x2E, 0x2F, 0x47, 0x01, 0x63, 
  0x33, 0x18, 0x5C, 0x1D, 0x6E, 0x08, 0x14, 0x20, 0x51, 0x79, 
  0x6C, 0x19, 0x22, 0x52, 0x7F, 0x05, 0x15, 0x38, 0x74, 0x55, 
  0x4A, 0x28, 0x24, 0x3D, 0x2D, 0x0F, 0x10, 0x0C, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

其他的游戏类似加密方式都可以参考这个方法

这里还有一个版本

我记得就俩版本我提供的这个脚本密钥的版本就是h365的那个版本应该,早期好感度道具是通用的后面为了骗米搞了vip还有不同角色使用的好感度道具

进游戏看像是一样的,但密钥不一样

87这个版本密钥是fee1cb9fce8a5d6cfa330efe666b0b8b

我知道,我看见你发的脚本了

大佬方便帮忙看看这个官方的口袋觉醒的加密吗 :tired_face:FilePizza • Your files, delivered.

佬,你发的这个游戏skel和atlas还有png名字好乱啊

佬,密钥脚本是生成87版的,有H365的密钥吗,365版动画文件多一些,跪求~duang~duang~duang…dddd…