做游戏网站要备案吗网站一直做竞价么
2026/4/4 4:18:33 网站建设 项目流程
做游戏网站要备案吗,网站一直做竞价么,东莞专业做网站公司,网站实名认证中心题目背景与初步分析1.1 题目描述本题是一道Mobile类别的CTF挑战题#xff0c;题目提供了一个文件#xff1a;__APP__.wxapkg。1.2 什么是wxapkg文件.wxapkg是微信小程序的打包文件格式。微信小程序是运行在微信客户端内的轻量级应用程序#xff0c;其代码包就以这种特殊格式…题目背景与初步分析1.1 题目描述本题是一道Mobile类别的CTF挑战题题目提供了一个文件__APP__.wxapkg。1.2 什么是wxapkg文件.wxapkg是微信小程序的打包文件格式。微信小程序是运行在微信客户端内的轻量级应用程序其代码包就以这种特殊格式分发。wxapkg文件的特点二进制格式无法直接用文本编辑器查看包含小程序的所有资源JavaScript代码、页面模板、样式表、配置文件等有特定的文件结构包含文件头、索引区和数据区1.3 解题思路解包wxapkg文件提取其中的代码分析JavaScript代码找到加密逻辑理解加密算法的工作原理编写解密脚本获取flag二、wxapkg文件格式详解2.1 文件结构分析一个标准的wxapkg文件由三部分组成┌─────────────────────────────────────┐│ 文件头部 (Header) │├─────────────────────────────────────┤│ - First Mark (1字节): 标识字节 ││ - Info1 (4字节): 信息段 ││ - Info2 (4字节): 信息段 ││ - Data Offset (4字节): 数据区偏移 ││ - Reserved (1字节): 保留字节 │├─────────────────────────────────────┤│ 索引区 (Index Section) │├─────────────────────────────────────┤│ - File Count (4字节): 文件数量 ││ - File List: 文件列表 ││ * Name Length (4字节) ││ * Name (变长): 文件名 ││ * Offset (4字节): 文件偏移 ││ * Size (4字节): 文件大小 │├─────────────────────────────────────┤│ 数据区 (Data Section) │├─────────────────────────────────────┤│ 各个文件的实际数据内容 │└─────────────────────────────────────┘关键技术点多字节整数使用大端序Big-Endian存储文件偏移量是从wxapkg文件开头计算的绝对位置文件名是UTF-8编码的字符串2.2 为什么需要解包wxapkg是二进制打包格式直接查看只能看到乱码。我们需要解析文件头获取文件列表信息根据偏移量和大小提取每个文件的数据还原成原始的目录结构三、实战解包wxapkg文件3.1 编写解包工具我们使用Python的struct模块来解析二进制数据#!/usr/bin/env python3import structimport osdef unpack_wxapkg(wxapkg_file, output_dir):解包微信小程序 wxapkg 文件with open(wxapkg_file, rb) as f:# 读取头部信息first_mark struct.unpack(B, f.read(1))[0]f.read(4) # 跳过Info1f.read(4) # 跳过Info2# 读取数据区偏移量 (大端序用I表示)data_section_offset struct.unpack(I, f.read(4))[0]f.read(1) # 跳过保留字节# 读取文件数量file_count struct.unpack(I, f.read(4))[0]# 读取文件列表file_list []for i in range(file_count):# 文件名长度name_len struct.unpack(I, f.read(4))[0]# 文件名 (UTF-8编码)name f.read(name_len).decode(utf-8)# 文件偏移和大小offset struct.unpack(I, f.read(4))[0]size struct.unpack(I, f.read(4))[0]file_list.append({name: name,offset: offset,size: size})# 创建输出目录if not os.path.exists(output_dir):os.makedirs(output_dir)# 解包每个文件for file_info in file_list:name file_info[name].lstrip(/)file_path os.path.join(output_dir, name)file_dir os.path.dirname(file_path)# 创建文件所在目录if file_dir and not os.path.exists(file_dir):os.makedirs(file_dir)# 读取并写入文件数据f.seek(file_info[offset])file_data f.read(file_info[size])with open(file_path, wb) as out_f:out_f.write(file_data)print(fExtracted: {file_info[name]})技术要点解释struct.unpack(B, data)解包1个无符号字节struct.unpack(I, data)解包4字节无符号整数大端序表示大端序I表示无符号整数unsigned intdecode(utf-8)将字节序列解码为UTF-8字符串3.2 执行解包运行解包脚本python3 unpacker.py输出结果Unpacking __APP__.wxapkg...First mark: 190Data section offset: 170832File count: 24File 1: /__debug__/__jscore-debug__.png, offset: 907, size: 178...File 11: /chunk_0.appservice.js, offset: 65008, size: 15834...Extracted: /chunk_0.appservice.js...Done!成功解包出24个文件其中最关键的是chunk_0.appservice.js。3.3 解包后的文件结构unpacked/├── __debug__/ # 调试文件├── app-config.json # 小程序配置├── app-service.js # 服务层主文件├── appservice.app.js # 应用逻辑├── chunk_0.appservice.js # ★ 关键包含页面逻辑├── chunk_1.appservice.js # 代码分块├── common.app.js # 公共代码├── pages/ # 页面目录│ ├── index/ # 首页│ │ ├── index.html│ │ └── index.wxss│ └── logs/ # 日志页│ ├── logs.html│ └── logs.wxss└── page-frame.html # 页面框架四、代码分析定位加密逻辑4.1 查看小程序配置首先查看app-config.json了解小程序结构{entryPagePath: pages/index/index.html,pages: [pages/index/index, pages/logs/logs],...}可以看到入口页面是pages/index/index这应该是我们的重点分析对象。4.2 分析关键文件打开chunk_0.appservice.js这个文件包含了index页面的逻辑代码。虽然代码经过了混淆但我们仍能识别出关键函数。在第2行找到了核心逻辑为便于阅读这里进行了格式化Page({data: {inputValue: ,animationData: {}},// 输入框变化处理onInputChange: function(a) {this.setData({inputValue: a.detail.value});},// ★ 关键加密函数enigmaticTransformation: function(a, t) {// a: 明文// t: 密钥// ... 加密逻辑 ...},// 自定义加密入口customEncrypt: function(a, t) {return this.enigmaticTransformation(a, t);},// ★ 验证逻辑onCheck: function() {var a this.data.inputValue;if ( ! a.trim()) {var t this.customEncrypt(a, newKey2025!);console.log(t);JSON.stringify(t) JSON.stringify([1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65])? wx.showToast({title: Right, icon: success, duration: 2e3}): wx.showToast({title: Wrong, icon: error, duration: 2e3});}}});关键发现密钥newKey2025!预期密文[1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65]加密函数enigmaticTransformation五、深入分析5.1 完整提取加密逻辑enigmaticTransformation: function(a, t) {// 步骤1: 将密钥转换为ASCII码数组i Array.from(t).map(function(a) {return a.charCodeAt(0);});s i.length;// 步骤2: 计算循环移位参数cc function(a) {for (var t 0, e 0; e a.length; e) {switch(e % 4) {case 0: t 1 * a[e]; break;case 1: t a[e] 0; break;case 2: t 0 | a[e]; break; // 按位或0case 3: t 0 ^ a[e]; break; // 按位异或0}}return t;}(i) % 8;// 步骤3: 逐字符加密r [];for (o 0; o a.length; o) {var u;// 3.1: 异或运算switch(o % 3) {case 0:u a.charCodeAt(o) ^ i[o % s];break;case 1:u i[o % s] ^ a.charCodeAt(o);break;case 2:e a.charCodeAt(o);n i[o % s];u e ^ n;break;}// 3.2: 循环左移var h;switch(c) {case 0: h u; break;case 1: h 255 (u 1 | u 7 1); break;case 2: h 255 (u 2 | u 6 3); break;case 3: h 255 (u 3 | u 5 7); break;case 4: h 255 (u 4 | u 4 15); break;case 5: h 255 (u 5 | u 3 31); break;case 6: h 255 (u 6 | u 2 63); break;case 7: h 255 (u 7 | u 1 127); break;default: h 255 (u c | u (8 - c)); break;}// 3.3: 添加到结果数组r.push(h);}return r;}5.2 算法流程图输入: 明文字符串, 密钥字符串↓步骤1: 密钥处理- 将密钥转为ASCII码数组- key newKey2025! → [110, 101, 119, 75, 101, 121, 50, 48, 50, 53, 33]↓步骤2: 计算移位参数- 对密钥数组各元素求和- sum 110101119751011215048505333 861- c 861 % 8 5↓步骤3: 逐字符加密对于每个明文字符:3.1 异或运算- plain_char ^ key[i % key_length] → u3.2 循环左移- rotate_left(u, c) → h3.3 添加到结果- result.append(h)↓输出: 密文字节数组5.3 关键技术点详解5.3.1 异或运算XOR基本性质A ^ B C 则 C ^ B A自反性A ^ 0 AA ^ A 0为什么用异或加密和解密使用相同的运算简单高效数学上具有对称性代码中的混淆虽然代码中有三种switch-case分支case 0: u a.charCodeAt(o) ^ i[o % s];case 1: u i[o % s] ^ a.charCodeAt(o);case 2: u (a.charCodeAt(o)) ^ (i[o % s]);但由于异或的交换律A ^ B B ^ A这三种方式结果完全相同这是一种代码混淆技巧目的是增加逆向分析的难度。5.3.2 循环左移Rotate Left什么是循环左移将一个字节的所有位向左移动n位左侧溢出的位移到右侧。原始: a b c d e f g h↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓左移3位: d e f g h a b c实现原理以左移5位为例本题中c5h 255 (u 5 | u 3 31)分解步骤假设 u 0b10110011 (179)步骤1: u 5 (左移5位)10110011 → 01100000 (96)(左侧5位溢出)步骤2: u 3 (右移3位8-53)10110011 → 00010110 (22)步骤3: (u 3) 31 (取低5位)00010110 00011111 00010110 (22)步骤4: 左移结果 | 右移结果01100000 | 00010110 01110110 (118)步骤5: 255 (确保在0-255范围)01110110 11111111 01110110 (118)结果: 10110011 循环左移5位 → 01110110图示说明原始字节: 1 0 1 1 0 0 1 1╰─────────╯╰──╯↓ ↓左移5位后: 0 1 1 0 0 0 0 0 (左移部分)↓右移3位后: 0 0 0 1 0 1 1 0 (溢出部分)↓ 按位或最终结果: 0 1 1 1 0 1 1 05.3.3 完整加密示例让我们完整演示flag第一个字符f的加密过程明文字符: f↓1. 获取ASCII码f → 102 → 0b011001102. 异或运算 (位置0使用key[0]n110)102 ^ 110 0b01100110 ^ 0b01101110 0b00001000 83. 循环左移5位u 8 0b00001000左移5位: 8 5 0b00000000 0右移3位: 8 3 0b00000001 1取低5位: 1 31 1按位或: 0 | 1 1h 14. 输出密文cipher[0] 1 ✓验证成功预期密文的第一个元素确实是1。六、逆向解密编写解密脚本6.1 解密思路加密过程是明文 → 异或 → 循环左移 → 密文解密过程是逆运算密文 → 循环右移 → 异或 → 明文关键认识循环左移的逆运算是循环右移异或的逆运算仍是异或因为 (A ^ B) ^ B A6.2 实现循环右移def rot_right(x, n):循环右移函数参数:x: 待移位的字节值n: 右移位数返回:循环右移n位后的结果x 0xFF # 确保在0-255范围内return ((x n) | (x (8 - n))) 0xFF原理说明循环右移 右移n位 | 左移(8-n)位例如右移5位:原始: a b c d e f g h↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓右移5位: 0 0 0 0 0 a b c (右侧5位溢出)左移3位: f g h 0 0 0 0 0 (将溢出位移回)↓ 按位或结果: f g h 0 0 a b c6.3 完整解密函数def decrypt(cipher, key):解密函数参数:cipher: 密文字节数组key: 密钥字符串返回:解密后的明文字符串# 步骤1: 密钥转ASCII码数组key_array [ord(c) for c in key]key_length len(key_array)# 步骤2: 计算移位参数 (与加密时相同)c sum(key_array) % 8# 步骤3: 逐字节解密plaintext []for position, cipher_byte in enumerate(cipher):cipher_byte 0xFF# 3a: 还原循环左移 → 执行循环右移after_rotate rot_right(cipher_byte, c)# 3b: 还原异或 (异或是自反运算)plain_code after_rotate ^ key_array[position % key_length]# 3c: 转换为字符plaintext.append(chr(plain_code))return .join(plaintext)6.4 执行解密# 从小程序代码中提取的数据cipher [1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65]key newKey2025!# 解密flag decrypt(cipher, key)print(fFlag: {flag})运行结果CTF题目: EZMiniAPP - 微信小程序逆向解密[输入] 密文数组:[1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65]长度: 25 字节[输入] 密钥:newKey2025!长度: 11 字符开始解密...[调试] 密钥ASCII码数组: [110, 101, 119, 75, 101, 121, 50, 48, 50, 53, 33][调试] 密钥数组和: 861[调试] 移位参数c: 5[调试] 位置0:密文字节: 1 (0b00000001)右移5位后: 8 (0b00001000)密钥字节: 110异或结果: 102 (ASCII: f)[调试] 位置1:密文字节: 33 (0b00100001)右移5位后: 9 (0b00001001)密钥字节: 101异或结果: 108 (ASCII: l)[调试] 位置2:密文字节: 194 (0b11000010)右移5位后: 22 (0b00010110)密钥字节: 119异或结果: 97 (ASCII: a)解密完成![结果] Flag: flag{JustEasyMiniProgram}6.5 验证解密正确性为了确保解密结果正确我们实现完整的加密函数将解密得到的flag重新加密def encrypt(plaintext, key):完整复现JavaScript的加密算法key_array [ord(c) for c in key]key_length len(key_array)c sum(key_array) % 8result []for position in range(len(plaintext)):# 异或plain_code ord(plaintext[position])u plain_code ^ key_array[position % key_length]# 循环左移if c 5:h 255 (u 5 | u 3 31)# ... 其他case ...result.append(h)return result# 验证encrypted encrypt(flag{JustEasyMiniProgram}, newKey2025!)original [1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65]if encrypted original:print(✓ 验证成功解密结果正确)运行结果加密验证 - 验证解密结果的正确性[输入] 明文: flag{JustEasyMiniProgram}[输入] 密钥: newKey2025![输出] 加密结果:[1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65][对比] 原始密文:[1, 33, 194, 133, 195, 102, 232, 104, 200, 14, 8, 163, 131, 71, 68, 97, 2, 76, 72, 171, 74, 106, 225, 1, 65]✓ 验证成功解密结果正确Flag: flag{JustEasyMiniProgram}完美验证通过证明我们的解密算法完全正确。七、知识点总结与技术深化7.1 二进制文件解析技术Python struct模块常用格式格式字符 C类型 Python类型 字节数B unsigned char integer 1H unsigned short integer 2I unsigned int integer 4Q unsigned long long integer 8字节序标识标识 字节序 说明 小端序 Little-Endian 大端序 Big-Endian 本机序 Native示例# 大端序读取4字节无符号整数offset struct.unpack(I, f.read(4))[0]# 小端序读取2字节无符号短整数value struct.unpack(H, f.read(2))[0]7.2 位运算详解7.2.1 异或运算XOR运算规则0 ^ 0 00 ^ 1 11 ^ 0 11 ^ 1 0重要性质交换律A ^ B B ^ A结合律(A ^ B) ^ C A ^ (B ^ C)自反性A ^ B ^ B A恒等律A ^ 0 A归零律A ^ A 0在加密中的应用# 加密cipher plaintext ^ key# 解密使用相同的keyplaintext cipher ^ key# 证明# plaintext ^ key ^ key plaintext7.2.2 移位运算左移x n # 左移n位右侧补05 2 # 0b00000101 → 0b00010100 (5 → 20)右移x n # 右移n位左侧补020 2 # 0b00010100 → 0b00000101 (20 → 5)循环移位的实现# 循环左移n位def rotate_left(x, n):return ((x n) | (x (8 - n))) 0xFF# 循环右移n位def rotate_right(x, n):return ((x n) | (x (8 - n))) 0xFF7.2.3 位掩码作用提取或保留特定的位x 0xFF # 保留低8位 (0-255)x 0x0F # 保留低4位 (0-15)x 0x01 # 保留最低位 (0或1)# 示例value 0b11010110low_4_bits value 0x0F # 0b00000110 67.3 代码混淆识别本题中使用的混淆技巧7.3.1 等价分支混淆switch(e % 4) {case 0: t 1 * a[e]; break; // 等价于 t a[e]case 1: t a[e] 0; break; // 等价于 t a[e]case 2: t 0 | a[e]; break; // 等价于 t a[e]case 3: t 0 ^ a[e]; break; // 等价于 t a[e]}所有分支实际效果相同7.3.2 冗余操作混淆switch(o % 3) {case 0: u a ^ b; break;case 1: u b ^ a; break; // 与case 0相同case 2: u a ^ b; break; // 与case 0相同}利用异或的交换律制造不同的假象。7.3.3 变量命名混淆使用无意义的单字母变量名a, t, e, n, r, i, s, c, o, u, h识别方法分析每个分支的实际计算结果简化位运算表达式找出运算的数学本质7.4 逆向分析方法论┌─────────────────┐│ 静态分析 │ 阅读代码理解逻辑├─────────────────┤│ 动态分析 │ 运行代码观察行为├─────────────────┤│ 数学分析 │ 找出运算的逆运算├─────────────────┤│ 验证测试 │ 确认解密正确性└─────────────────┘具体步骤识别加密算法类型对称/非对称、流密码/分组密码提取关键参数密钥、初始向量、轮数等理解运算流程每一步的数学含义推导逆运算找到每个步骤的逆操作实现解密编写代码实现逆运算验证结果重新加密检验八、完整解题流程回顾步骤总结第一步文件分析├─ 识别wxapkg格式└─ 了解文件结构第二步解包提取├─ 编写解包工具 (Python struct)├─ 解析文件头和索引└─ 提取所有文件第三步代码定位├─ 查看小程序配置├─ 找到入口页面└─ 定位加密函数第四步算法分析├─ 提取enigmaticTransformation函数├─ 理解加密流程│ ├─ 密钥处理│ ├─ 参数计算│ └─ 逐字符加密└─ 识别代码混淆第五步逆向解密├─ 推导逆运算│ ├─ 循环左移 → 循环右移│ └─ 异或 → 异或├─ 实现解密函数└─ 获取flag第六步验证结果├─ 实现加密函数├─ 重新加密flag└─ 对比原始密文九、扩展学习资源

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询