From 74de15666c689eb3687fbedffc0e67940ebc4b98 Mon Sep 17 00:00:00 2001 From: amos wong Date: Sat, 28 Feb 2026 23:50:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 38 ++++ .idea/.gitignore | 8 + .idea/misc.xml | 14 ++ pom.xml | 17 ++ script/qxzb/auto_login.py | 208 ++++++++++++++++++++ script/qxzb/exchange_item.py | 355 +++++++++++++++++++++++++++++++++++ script/qxzb/start_capture.sh | 81 ++++++++ script/qxzb/test_bypass.py | 187 ++++++++++++++++++ 8 files changed, 908 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 pom.xml create mode 100755 script/qxzb/auto_login.py create mode 100644 script/qxzb/exchange_item.py create mode 100755 script/qxzb/start_capture.sh create mode 100644 script/qxzb/test_bypass.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..32f8b4c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..9c954cc --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + pers.amos + game + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + \ No newline at end of file diff --git a/script/qxzb/auto_login.py b/script/qxzb/auto_login.py new file mode 100755 index 0000000..b07c177 --- /dev/null +++ b/script/qxzb/auto_login.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 +""" +Flash 游戏自动登录脚本 +""" + +import struct +import requests +import sys + +class AMF0: + """AMF0 协议编码器""" + + NUMBER = 0x00 + STRING = 0x02 + NULL = 0x05 + STRICT_ARRAY = 0x0A + + @staticmethod + def encode_number(num): + return struct.pack('!Bd', AMF0.NUMBER, float(num)) + + @staticmethod + def encode_string(s): + s_bytes = s.encode('utf-8') + return struct.pack('!BH', AMF0.STRING, len(s_bytes)) + s_bytes + + @staticmethod + def encode_null(): + return struct.pack('!B', AMF0.NULL) + + @staticmethod + def encode_strict_array(items): + data = struct.pack('!BI', AMF0.STRICT_ARRAY, len(items)) + for item in items: + if isinstance(item, (int, float)): + data += AMF0.encode_number(item) + elif isinstance(item, str): + data += AMF0.encode_string(item) + elif item is None: + data += AMF0.encode_null() + return data + + @staticmethod + def encode_amf_request(target_uri, response_uri, params): + data = b'' + data += struct.pack('!H', 0x0000) # AMF 版本 + data += struct.pack('!H', 0x0000) # Header count + data += struct.pack('!H', 0x0001) # Message count + + # Target URI + target_bytes = target_uri.encode('utf-8') + data += struct.pack('!H', len(target_bytes)) + target_bytes + + # Response URI + response_bytes = response_uri.encode('utf-8') + data += struct.pack('!H', len(response_bytes)) + response_bytes + + # Length + data += struct.pack('!I', 0xFFFFFFFF) + + # Body + data += AMF0.encode_strict_array(params) + + return data + + +def login(username, password): + """登录游戏""" + print("🎮 Flash 游戏自动登录") + print("="*60) + print(f"👤 用户名: {username}") + print(f"🔑 密码: {'*' * len(password)}") + print("="*60) + print() + + url = "http://47.121.191.22:8012/gateway" + + # 构造登录请求 + amf_data = AMF0.encode_amf_request( + target_uri="com.huzi.base.action.AccountAction.loginInner", + response_uri="/1", + params=[username, password] + ) + + headers = { + 'Host': '47.121.191.22:8012', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:102.0) Gecko/20100101 Firefox/102.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Origin': 'http://47.121.191.22:8012', + 'Connection': 'keep-alive', + 'Referer': 'http://47.121.191.22:8012/swf13/Load.swf', + 'Content-Type': 'application/x-amf', + 'Content-Length': str(len(amf_data)) + } + + print("🌐 正在连接服务器...") + print(f"📤 请求方法: AccountAction.loginInner") + print(f"📦 请求大小: {len(amf_data)} 字节") + print() + + try: + session = requests.Session() + response = session.post(url, data=amf_data, headers=headers, timeout=10) + + print(f"📥 响应状态: {response.status_code}") + print(f"📦 响应大小: {len(response.content)} 字节") + print() + + if response.status_code == 200: + # 提取 Cookie + cookie = None + if 'Set-Cookie' in response.headers: + set_cookie = response.headers['Set-Cookie'] + if 'JSESSIONID=' in set_cookie: + cookie = set_cookie.split(';')[0] + print(f"🔑 获取到 Cookie: {cookie}") + + # 解析响应 + data = response.content + + # 查找 result 字段 + result_pos = data.find(b'result') + if result_pos > 0 and data[result_pos + 6] == 0x00: + result_value = struct.unpack('!d', data[result_pos+7:result_pos+15])[0] + result = int(result_value) + + if result == 0: + print("✅ 登录成功!") + print() + + # 提取用户信息 + user_id_pos = data.find(b'userId') + if user_id_pos > 0 and data[user_id_pos + 6] == 0x00: + user_id = int(struct.unpack('!d', data[user_id_pos+7:user_id_pos+15])[0]) + print(f"👤 用户ID: {user_id}") + + point_pos = data.find(b'point') + if point_pos > 0 and data[point_pos + 5] == 0x00: + point = int(struct.unpack('!d', data[point_pos+6:point_pos+14])[0]) + print(f"💰 当前积分: {point}") + + print() + print("="*60) + + if cookie: + # 保存 Cookie 到文件 + cookie_file = "/Users/amos/Downloads/game/7q/latest_cookie.txt" + with open(cookie_file, 'w') as f: + f.write(cookie) + print(f"💾 Cookie 已保存到: {cookie_file}") + print() + print("💡 使用方法:") + print(f" python3 exchange_item.py \"{cookie}\" 9") + print("="*60) + + return cookie, session + + return None, session + else: + print(f"❌ 登录失败 (result={result})") + + # 查找错误消息 + msg_pos = data.find(b'msg') + if msg_pos > 0 and data[msg_pos + 3] == 0x02: + msg_len = struct.unpack('!H', data[msg_pos+4:msg_pos+6])[0] + if msg_len > 0: + msg = data[msg_pos+6:msg_pos+6+msg_len].decode('utf-8', errors='ignore') + print(f"💬 错误信息: {msg}") + + return None, None + + print("⚠️ 无法解析响应") + return None, None + else: + print(f"❌ 请求失败: HTTP {response.status_code}") + return None, None + + except Exception as e: + print(f"❌ 请求异常: {e}") + import traceback + traceback.print_exc() + return None, None + + +def main(): + if len(sys.argv) >= 3: + username = sys.argv[1] + password = sys.argv[2] + else: + # 默认账号(从抓包中获取) + username = "amos" + password = "xiaobiao." + print("⚠️ 使用默认账号") + print("💡 提示: 可以通过参数传入: python3 auto_login.py 用户名 密码") + print() + + cookie, session = login(username, password) + + if cookie: + sys.exit(0) + else: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/script/qxzb/exchange_item.py b/script/qxzb/exchange_item.py new file mode 100644 index 0000000..f52a7a2 --- /dev/null +++ b/script/qxzb/exchange_item.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +""" +Flash 游戏兑换脚本 +基于抓包分析:登录后需要先调用 getExchangeItemList,然后才能兑换 +""" + +import struct +import requests +import sys +import time + +# ==================== 配置 ==================== +USERNAME = "amos" +PASSWORD = "xiaobiao." +SERVER_URL = "http://47.121.191.22:8012/gateway" +COOKIE_FILE = "/Users/amos/Downloads/game/7q/latest_cookie.txt" +# ============================================== + +class AMF0: + """AMF0 协议编码器""" + + NUMBER = 0x00 + STRING = 0x02 + NULL = 0x05 + STRICT_ARRAY = 0x0A + + @staticmethod + def encode_amf_request(target_uri, response_uri, params): + """编码 AMF 请求""" + data = b'' + data += struct.pack('!H', 0x0000) # AMF 版本 + data += struct.pack('!H', 0x0000) # Header count + data += struct.pack('!H', 0x0001) # Message count + + # Target URI + target_bytes = target_uri.encode('utf-8') + data += struct.pack('!H', len(target_bytes)) + target_bytes + + # Response URI + response_bytes = response_uri.encode('utf-8') + data += struct.pack('!H', len(response_bytes)) + response_bytes + + # Length + data += struct.pack('!I', 0xFFFFFFFF) + + # Body - Strict array + data += struct.pack('!BI', AMF0.STRICT_ARRAY, len(params)) + for item in params: + if isinstance(item, (int, float)): + data += struct.pack('!Bd', AMF0.NUMBER, float(item)) + elif isinstance(item, str): + s_bytes = item.encode('utf-8') + data += struct.pack('!BH', AMF0.STRING, len(s_bytes)) + s_bytes + + return data + + +def login(session): + """登录获取 Cookie""" + print("🔐 正在登录...") + + amf_data = AMF0.encode_amf_request( + target_uri="com.huzi.base.action.AccountAction.loginInner", + response_uri="/1", + params=[USERNAME, PASSWORD] + ) + + headers = { + 'Host': '47.121.191.22:8012', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:102.0) Gecko/20100101 Firefox/102.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Origin': 'http://47.121.191.22:8012', + 'Connection': 'keep-alive', + 'Referer': 'http://47.121.191.22:8012/swf13/Load.swf', + 'Content-Type': 'application/x-amf' + } + + response = session.post(SERVER_URL, data=amf_data, headers=headers, timeout=10) + + if response.status_code == 200: + # 提取 Cookie + if 'Set-Cookie' in response.headers: + set_cookie = response.headers['Set-Cookie'] + if 'JSESSIONID=' in set_cookie: + jsessionid = set_cookie.split(';')[0] + print(f"✅ 登录成功: {jsessionid}") + return jsessionid + + print("❌ 登录失败") + return None + + +def init_exchange(session, cookie, item_id, request_id): + """初始化兑换(调用 getShowExchange)""" + print(f"📋 初始化物品 {item_id} 的兑换信息...") + + amf_data = AMF0.encode_amf_request( + target_uri="com.huzi.play.action.ExchangeAction.getShowExchange", + response_uri=f"/{request_id}", + params=[item_id] + ) + + headers = { + 'Host': '47.121.191.22:8012', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:102.0) Gecko/20100101 Firefox/102.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Cookie': cookie, + 'Origin': 'http://47.121.191.22:8012', + 'Connection': 'keep-alive', + 'Referer': 'http://47.121.191.22:8012/swf13/Load.swf', + 'Content-Type': 'application/x-amf' + } + + try: + response = session.post(SERVER_URL, data=amf_data, headers=headers, timeout=10) + if response.status_code == 200: + data = response.content + print(f"✅ 初始化成功 (响应大小: {len(data)} 字节)") + + # 打印响应内容用于分析 + print(f"🔍 响应内容 (十六进制前200字节):") + hex_data = data[:200].hex() + for i in range(0, len(hex_data), 64): + print(f" {hex_data[i:i+64]}") + + print(f"🔍 响应内容 (可读文本):") + try: + readable = data.decode('utf-8', errors='ignore') + lines = [line for line in readable.split('\n') if line.strip()] + for line in lines[:20]: # 只显示前20行 + print(f" {line}") + except: + pass + + return True + else: + print(f"❌ 初始化失败: HTTP {response.status_code}") + return False + except Exception as e: + print(f"❌ 初始化异常: {e}") + return False + + +def exchange_item(session, cookie, item_id, quantity, request_id): + """兑换物品""" + + amf_data = AMF0.encode_amf_request( + target_uri="com.huzi.play.action.ExchangeAction.exchangeItem", + response_uri=f"/{request_id}", + params=[item_id, quantity] + ) + + headers = { + 'Host': '47.121.191.22:8012', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:102.0) Gecko/20100101 Firefox/102.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Cookie': cookie, + 'Origin': 'http://47.121.191.22:8012', + 'Connection': 'keep-alive', + 'Referer': 'http://47.121.191.22:8012/swf13/Load.swf', + 'Content-Type': 'application/x-amf' + } + + print(f"\n 📤 请求: ExchangeAction.exchangeItem({item_id}, {quantity})") + print(f" 📍 Response URI: /{request_id}") + + try: + response = session.post(SERVER_URL, data=amf_data, headers=headers, timeout=10) + + print(f" 📥 响应状态: {response.status_code}") + + if response.status_code == 200: + data = response.content + print(f" 📦 响应大小: {len(data)} 字节") + + # 检查是否是错误响应 + if b'onStatus' in data: + print(f" ⚠️ 检测到 onStatus (错误响应)") + print(f" 🔧 完整响应 (十六进制):") + hex_data = data.hex() + for i in range(0, len(hex_data), 64): + print(f" {hex_data[i:i+64]}") + print(f" 🔧 完整响应 (ASCII):") + try: + readable = data.decode('utf-8', errors='ignore') + for line in readable.split('\n'): + if line.strip(): + print(f" {line}") + except: + pass + + if b'NullPointerException' in data: + print(f" ⚠️ NullPointerException - 需要先初始化") + return False, "服务器错误" + + # 查找 result 字段 + result_pos = data.find(b'result') + + if result_pos > 0: + value_pos = result_pos + 6 + + if value_pos < len(data): + value_type = data[value_pos] + + if value_type == 0x00: # Number + if value_pos + 9 <= len(data): + result_value = struct.unpack('!d', data[value_pos+1:value_pos+9])[0] + result = int(result_value) + print(f" 📊 result = {result}") + + if result == 0: + return True, "成功" + else: + # 查找 msg + msg = None + msg_pos = data.find(b'msg') + if msg_pos > 0: + msg_value_pos = msg_pos + 3 + if msg_value_pos < len(data): + msg_type = data[msg_value_pos] + if msg_type == 0x02: # String + try: + if msg_value_pos + 3 <= len(data): + msg_len = struct.unpack('!H', data[msg_value_pos+1:msg_value_pos+3])[0] + if msg_len > 0 and msg_value_pos + 3 + msg_len <= len(data): + msg = data[msg_value_pos+3:msg_value_pos+3+msg_len].decode('utf-8', errors='ignore') + print(f" 💬 msg = {msg}") + except: + pass + return False, msg if msg else f"失败(result={result})" + + return False, "无法解析响应" + else: + return False, f"HTTP {response.status_code}" + except Exception as e: + import traceback + traceback.print_exc() + return False, f"异常: {e}" + + +def read_cookie(): + """从文件读取 Cookie""" + try: + with open(COOKIE_FILE, 'r') as f: + cookie = f.read().strip() + if cookie: + return cookie + except FileNotFoundError: + print(f"⚠️ Cookie 文件不存在: {COOKIE_FILE}") + except Exception as e: + print(f"⚠️ 读取 Cookie 失败: {e}") + return None + + +def main(): + print("🎮 Flash 游戏兑换脚本") + print("="*60) + print(f"👤 账号: {USERNAME}") + + # 从文件读取 Cookie + cookie = read_cookie() + if not cookie: + print("❌ 无法读取 Cookie,请确保游戏已登录") + sys.exit(1) + + print(f"🔑 Cookie: {cookie}") + print("⚠️ 需要在游戏中保持登录状态") + + # 物品ID + if len(sys.argv) >= 2: + item_id = int(sys.argv[1]) + else: + item_id = 9 + print(f"\n⚠️ 使用默认物品 ID: {item_id}") + + # 兑换次数 + if len(sys.argv) >= 3: + total_count = int(sys.argv[2]) + else: + print("\n💡 请输入兑换次数") + while True: + try: + count_input = input("兑换次数 (默认1次): ").strip() + total_count = int(count_input) if count_input else 1 + if total_count > 0: + break + print("❌ 请输入大于0的数字") + except ValueError: + print("❌ 请输入有效的数字") + + print("\n" + "="*60) + print(f"🎁 物品ID: {item_id}") + print(f"🔢 兑换次数: {total_count}") + print("="*60) + + # 创建 Session + session = requests.Session() + + request_id = 2 + + # 初始化兑换(调用 getShowExchange,关键步骤!) + if not init_exchange(session, cookie, item_id, request_id): + print("\n❌ 初始化失败,无法继续") + sys.exit(1) + + request_id += 1 + + print("\n" + "="*60) + print("🚀 开始批量兑换") + print("="*60) + + success_count = 0 + fail_count = 0 + + for i in range(total_count): + print(f"\n[{i+1}/{total_count}] 兑换中...", end=" ") + + success, message = exchange_item(session, cookie, item_id, 1, request_id) + request_id += 1 + + if success: + success_count += 1 + print(f"✅ {message}") + else: + fail_count += 1 + print(f"❌ {message}") + + if fail_count >= 3: + print("\n⚠️ 连续失败3次") + choice = input("是否继续? (y/n): ").strip().lower() + if choice != 'y': + break + fail_count = 0 + + if i < total_count - 1: + time.sleep(0.5) + + print("\n" + "="*60) + print("📊 兑换统计") + print("="*60) + print(f"✅ 成功: {success_count} 次") + print(f"❌ 失败: {fail_count} 次") + if success_count + fail_count > 0: + print(f"📈 成功率: {success_count/(success_count+fail_count)*100:.1f}%") + print("="*60) + + +if __name__ == "__main__": + main() diff --git a/script/qxzb/start_capture.sh b/script/qxzb/start_capture.sh new file mode 100755 index 0000000..2cc7205 --- /dev/null +++ b/script/qxzb/start_capture.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Flash 游戏抓包脚本 +# 用于捕获游戏的 HTTP 请求并转换为可读文本 +# + +# 输出目录 +OUTPUT_DIR="/Users/amos/Downloads/game/7q" + +# 确保目录存在 +mkdir -p "${OUTPUT_DIR}" + +echo "🎮 Flash 游戏抓包工具" +echo "======================================" +echo "" +echo "📡 目标服务器: 47.121.191.22:8012" +echo "🔍 过滤条件: HTTP 请求" +echo "📁 输出目录: ${OUTPUT_DIR}" +echo "" +echo "⚠️ 按 Ctrl+C 停止录制" +echo "" +echo "======================================" +echo "" + +# 生成时间戳文件名 +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") +PCAP_FILE="${OUTPUT_DIR}/game_capture_${TIMESTAMP}.pcapng" +TEXT_FILE="${OUTPUT_DIR}/game_capture_${TIMESTAMP}.txt" +COOKIE_FILE="${OUTPUT_DIR}/latest_cookie.txt" + +echo "💾 二进制文件: ${PCAP_FILE}" +echo "📄 文本文件: ${TEXT_FILE}" +echo "" +echo "🚀 开始录制..." +echo "" + +# 直接录制并转换为文本(和你的命令一样) +sudo tshark -i any -f "host 47.121.191.22 and port 8012" -Y "http" -V | tee "${TEXT_FILE}" + +echo "" +echo "======================================" +echo "✅ 录制已停止" +echo "" + +# 同时保存一份到 pcapng(可选,用于后续分析) +echo "� 统计信息:" +echo " 文本文件大小: $(ls -lh ${TEXT_FILE} | awk '{print $5}')" +echo " HTTP 请求数量: $(grep -c "POST\|GET" ${TEXT_FILE})" +echo "" + +# 提取 Cookie +echo "🔑 提取 Cookie..." +COOKIE=$(grep -o "JSESSIONID=[A-Z0-9]*" "${TEXT_FILE}" | head -1) + +if [ -n "$COOKIE" ]; then + echo "✅ 找到 Cookie: ${COOKIE}" + echo "" + echo "💡 使用方法:" + echo " cd game" + echo " python3 exchange_item.py \"${COOKIE}\" 9" + echo "" + + # 保存 Cookie 到文件 + echo "${COOKIE}" > "${COOKIE_FILE}" + echo "💾 Cookie 已保存到: ${COOKIE_FILE}" +else + echo "⚠️ 未找到 Cookie,请确保在游戏中进行了操作" +fi + +echo "" +echo "📋 提取的 API 调用:" +grep "Target URI:" "${TEXT_FILE}" | sed 's/.*Target URI: / - /' | sort | uniq + +echo "" +echo "======================================" +echo "📁 生成的文件:" +echo " ${TEXT_FILE}" +echo " ${COOKIE_FILE}" +echo "" +echo "💡 提示: 文本文件可以直接发给 AI 分析" +echo "======================================" diff --git a/script/qxzb/test_bypass.py b/script/qxzb/test_bypass.py new file mode 100644 index 0000000..9ee60e7 --- /dev/null +++ b/script/qxzb/test_bypass.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +""" +测试绕过兑换条件的脚本 +警告:这些方法可能不起作用,仅用于学习研究 +""" + +import struct +import requests +import sys +import time + +SERVER_URL = "http://47.121.191.22:8012/gateway" +COOKIE_FILE = "/Users/amos/Downloads/game/7q/latest_cookie.txt" + +class AMF0: + """AMF0 协议编码器""" + + NUMBER = 0x00 + STRING = 0x02 + NULL = 0x05 + STRICT_ARRAY = 0x0A + + @staticmethod + def encode_amf_request(target_uri, response_uri, params): + """编码 AMF 请求""" + data = b'' + data += struct.pack('!H', 0x0000) + data += struct.pack('!H', 0x0000) + data += struct.pack('!H', 0x0001) + + target_bytes = target_uri.encode('utf-8') + data += struct.pack('!H', len(target_bytes)) + target_bytes + + response_bytes = response_uri.encode('utf-8') + data += struct.pack('!H', len(response_bytes)) + response_bytes + + data += struct.pack('!I', 0xFFFFFFFF) + + data += struct.pack('!BI', AMF0.STRICT_ARRAY, len(params)) + for item in params: + if isinstance(item, (int, float)): + data += struct.pack('!Bd', AMF0.NUMBER, float(item)) + elif isinstance(item, str): + s_bytes = item.encode('utf-8') + data += struct.pack('!BH', AMF0.STRING, len(s_bytes)) + s_bytes + + return data + + +def read_cookie(): + """从文件读取 Cookie""" + try: + with open(COOKIE_FILE, 'r') as f: + return f.read().strip() + except: + return None + + +def test_exchange(session, cookie, item_id, quantity, test_name): + """测试兑换""" + print(f"\n{'='*60}") + print(f"🧪 测试: {test_name}") + print(f"{'='*60}") + print(f"物品ID: {item_id}, 数量: {quantity}") + + amf_data = AMF0.encode_amf_request( + target_uri="com.huzi.play.action.ExchangeAction.exchangeItem", + response_uri="/1", + params=[item_id, quantity] + ) + + headers = { + 'Host': '47.121.191.22:8012', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:102.0) Gecko/20100101 Firefox/102.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Cookie': cookie, + 'Origin': 'http://47.121.191.22:8012', + 'Connection': 'keep-alive', + 'Referer': 'http://47.121.191.22:8012/swf13/Load.swf', + 'Content-Type': 'application/x-amf' + } + + try: + response = session.post(SERVER_URL, data=amf_data, headers=headers, timeout=10) + + if response.status_code == 200: + data = response.content + + # 查找 result + result_pos = data.find(b'result') + if result_pos > 0: + value_pos = result_pos + 6 + if value_pos < len(data) and data[value_pos] == 0x00: + if value_pos + 9 <= len(data): + result_value = struct.unpack('!d', data[value_pos+1:value_pos+9])[0] + result = int(result_value) + + # 查找 msg + msg = None + msg_pos = data.find(b'msg') + if msg_pos > 0: + msg_value_pos = msg_pos + 3 + if msg_value_pos < len(data) and data[msg_value_pos] == 0x02: + try: + msg_len = struct.unpack('!H', data[msg_value_pos+1:msg_value_pos+3])[0] + if msg_len > 0 and msg_value_pos + 3 + msg_len <= len(data): + msg = data[msg_value_pos+3:msg_value_pos+3+msg_len].decode('utf-8', errors='ignore') + except: + pass + + if result == 0: + print(f"✅ 成功!") + return True + else: + print(f"❌ 失败: result={result}, msg={msg}") + return False + + print(f"❌ 无法解析响应") + return False + else: + print(f"❌ HTTP {response.status_code}") + return False + except Exception as e: + print(f"❌ 异常: {e}") + return False + + +def main(): + print("🎮 Flash 游戏兑换绕过测试") + print("="*60) + print("⚠️ 警告:这些测试可能触发服务端安全机制") + print("="*60) + + cookie = read_cookie() + if not cookie: + print("❌ 无法读取 Cookie") + sys.exit(1) + + print(f"🔑 Cookie: {cookie}") + + session = requests.Session() + + item_id = int(sys.argv[1]) if len(sys.argv) > 1 else 9 + + # 测试1: 正常请求(基准) + test_exchange(session, cookie, item_id, 1, "正常请求 (数量=1)") + time.sleep(1) + + # 测试2: 零数量 + test_exchange(session, cookie, item_id, 0, "零数量 (数量=0)") + time.sleep(1) + + # 测试3: 负数数量(整数溢出) + test_exchange(session, cookie, item_id, -1, "负数数量 (数量=-1)") + time.sleep(1) + + # 测试4: 小数数量 + test_exchange(session, cookie, item_id, 0.1, "小数数量 (数量=0.1)") + time.sleep(1) + + # 测试5: 超大数量 + test_exchange(session, cookie, item_id, 999999, "超大数量 (数量=999999)") + time.sleep(1) + + # 测试6: 尝试其他物品ID + print(f"\n{'='*60}") + print("🔍 尝试其他物品ID") + print(f"{'='*60}") + + for test_id in range(1, 20): + if test_id == item_id: + continue + print(f"\n测试物品ID: {test_id}") + if test_exchange(session, cookie, test_id, 1, f"物品ID={test_id}"): + print(f"🎉 物品ID {test_id} 可以兑换!") + break + time.sleep(0.5) + + print(f"\n{'='*60}") + print("测试完成") + print(f"{'='*60}") + + +if __name__ == "__main__": + main()