吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 208|回复: 5
上一主题 下一主题
收起左侧

[原创工具] vx小游戏,圈了个地 - 院长模拟器,获取无限金币

[复制链接]
跳转到指定楼层
楼主
wabc666 发表于 2026-9-19 23:59 回帖奖励
本帖最后由 wabc666 于 2026-9-20 00:01 编辑





[Python] 纯文本查看 复制代码
import ctypes
import ctypes.wintypes
import sys


import pymem
import base64
import json
import time
import urllib.parse
import urllib.request
import zlib
import random
from urllib.parse import parse_qs





##### #读取游戏登录参数 #####
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
user32 = ctypes.WinDLL("user32", use_last_error=True)

PROCESS_VM_READ = 0x0010
MEM_COMMIT = 0x1000
PAGE_NOACCESS = 0x01

class MEMORY_BASIC_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("BaseAddress", ctypes.c_void_p),
        ("AllocationBase", ctypes.c_void_p),
        ("AllocationProtect", ctypes.wintypes.DWORD),
        ("RegionSize", ctypes.c_size_t),
        ("State", ctypes.wintypes.DWORD),
        ("Protect", ctypes.wintypes.DWORD),
        ("Type", ctypes.wintypes.DWORD),
    ]

# 存储窗口信息
window_list = []
def enum_windows_callback(hwnd, lparam):
    title_buf = ctypes.create_unicode_buffer(256)
    user32.GetWindowTextW(hwnd, title_buf, 256)
    wnd_title = title_buf.value
    pid = ctypes.wintypes.DWORD()
    user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
    hwnd_val = int(ctypes.c_void_p(hwnd).value)
    window_list.append({"hwnd":hwnd_val, "title":wnd_title, "pid":pid.value})
    return True

def get_all_windows():
    global window_list
    window_list = []
    WND_ENUM = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p)
    user32.EnumWindows(WND_ENUM(enum_windows_callback), 0)
    return window_list

def search_memory(pid: int, target_bytes: bytes, offset_left=100, offset_right=100):
    h_process = kernel32.OpenProcess(PROCESS_VM_READ, False, pid)
    if not h_process:
        err = ctypes.get_last_error()
        print(f"OpenProcess失败 PID={pid}, error={err},跳过")
        return []

    mbi = MEMORY_BASIC_INFORMATION()
    address = 0
    found_results = []

    while True:
        ret = kernel32.VirtualQueryEx(h_process, ctypes.c_void_p(address), ctypes.byref(mbi), ctypes.sizeof(mbi))
        if ret == 0:
            break
        address = ctypes.cast(mbi.BaseAddress, ctypes.c_void_p).value + mbi.RegionSize

        if mbi.State != MEM_COMMIT or (mbi.Protect & PAGE_NOACCESS):
            continue

        buffer = ctypes.create_string_buffer(mbi.RegionSize)
        bytes_read = ctypes.c_size_t()
        success = kernel32.ReadProcessMemory(
            h_process, mbi.BaseAddress, buffer, mbi.RegionSize, ctypes.byref(bytes_read)
        )
        if not success or bytes_read.value == 0:
            continue

        data = buffer.raw[:bytes_read.value]
        pos = 0
        while True:
            idx = data.find(target_bytes, pos)
            if idx == -1:
                break
            absolute_addr = ctypes.cast(mbi.BaseAddress, ctypes.c_void_p).value + idx
            start = max(0, idx - offset_left)
            end = min(len(data), idx + len(target_bytes) + offset_right)
            context_data = data[start:end]
            found_results.append({
                "pid": pid,
                "absolute_address": hex(absolute_addr),
                "match_offset_in_region": idx,
                "context_raw": context_data
            })
            pos = idx + len(target_bytes)

    kernel32.CloseHandle(h_process)
    return found_results

def search_string_by_pymem(pid: int, target_bytes: bytes):
    pm = pymem.Pymem()
    pm.open_process_from_id(pid)
    result = pm.pattern_scan_all(target_bytes, return_multiple=True)
    print(f"✅找到 {len(result)} 个地址:")
    for addr in result:
        print(f"0x{addr:X}")
    return pm, result

def read_memory(pm, address, pre=100, post=100):
    start_addr = address - pre
    total_len = pre + post
    data = pm.read_bytes(start_addr, total_len)
    return data, pre

# ===================== 刷金币相关代码 =====================
API = "https://apps-gz-vpc2.uufuns.com/bslwxapi/api.php"

def yypack_encode(obj, level=6):
    data = json.dumps(obj, separators=(",", ":"), ensure_ascii=False).encode("utf-8") + b"\x00"
    co = zlib.compressobj(level, zlib.DEFLATED, -15)
    body = co.compress(data) + co.flush()
    raw = bytearray((5 + len(body)).to_bytes(4, "big") + bytes([2]) + body)
    if len(raw) >= 16:
        a = len(raw) % 10 + 1
        raw[5], raw[5 + a] = raw[5 + a], raw[5]
    return base64.b64encode(bytes(raw)).decode()

def yypack_decode(b64):
    raw = bytearray(base64.b64decode(b64))
    if len(raw) < 6 or raw[4] != 2:
        raise ValueError("bad header %s" % bytes(raw[:8]).hex(" "))
    if len(raw) >= 16:
        a = len(raw) % 10 + 1
        raw[5], raw[5 + a] = raw[5 + a], raw[5]
    out = zlib.decompress(bytes(raw[5:]), -15)
    if out.endswith(b"\x00"):
        out = out[:-1]
    return json.loads(out.decode("utf-8"))

def send(sess, cmds, timeout=20):
    q = dict(sess)
    q["req"] = yypack_encode(cmds)
    data = urllib.parse.urlencode(q).encode()
    req = urllib.request.Request(API, data=data, headers={
        "Content-Type": "application/x-www-form-urlencoded",
        "User-Agent": "Opera/9.47.(Windows NT 6.0; ig-NG) Presto/2.9.183 Version/10.00",
    })
    txt = urllib.request.urlopen(req, timeout=timeout).read().decode("utf-8", "replace")
    outer = json.loads(txt)
    inner = outer.get("body")
    if isinstance(inner, str):
        try:
            inner = yypack_decode(inner)
        except Exception as e:
            inner = f"<decode fail: {e}>"
    return outer.get("ret"), inner

def snapshot(sess):
    try:
        _, inner = send(sess, [{"cmd": "userLogin"}])
        b = inner[0].get("body") or {}
        return {k: b.get(k) for k in ("cash", "coins", "exp", "egy", "star", "vipscore", "lcoins")}
    except Exception as e:
        return {"__error__": str(e)}

GAME_DATA = {"step": 20, "lastRecoverStamp": 0, "cashAddTime": 0, "getRwTime": 0,
             "score": 0, "free_time": 0, "exp": 0,
             "last": {"allCellsLvInfo": [], "fillRate": 0, "score": 0, "currRwNum": 0}}

DEFAULT_LIMIT = 500

def coins(sess):
    return snapshot(sess).get("coins")

def _cmd(score):
    return {"cmd": "mini_game", "method": "mergeGameResult", "score": score,
            "exp": 0, "drop_prop": {}, "game_data": GAME_DATA}

def merge_once(sess, score):
    _, inner = send(sess, [_cmd(score)])
    i0 = inner[0] if isinstance(inner, list) and inner else {}
    body = i0.get("body")
    au = None
    if isinstance(body, dict):
        tg = body.get("the_good") or {}
        if isinstance(tg, dict):
            au = tg.get("add_uattr")
    return i0.get("ret"), au

def merge_batch(sess, score, n):
    _, inner = send(sess, [_cmd(score) for _ in range(n)])
    return inner if isinstance(inner, list) else []

def _coins_got(item):
    if not isinstance(item, dict) or item.get("ret") != 0:
        return 0
    body = item.get("body")
    if not isinstance(body, dict):
        return 0
    tg = body.get("the_good")
    if not isinstance(tg, dict):
        return 0
    au = tg.get("add_uattr")
    if not isinstance(au, dict):
        return 0
    return au.get("coins", 0) or 0

# 改动:增加 times 参数
def run_coin_task(session_params, TIMES):
    num = random.randint(500, 1000)
    SCORE = num
    DELAY = 0
    BATCH = 50
    LIMIT = 100
    I_UNDERSTAND_RISK = True

    MANUAL_SESSION = {
        "ver": "2.1",
        "svrid": "3",
    }
    MANUAL_SESSION = MANUAL_SESSION | session_params

    if TIMES > LIMIT and not I_UNDERSTAND_RISK:
        print(f"[x] 请求次数 {TIMES} 超过安全上限 {LIMIT}。请修改 I_UNDERSTAND_RISK=True")
        return

    sess = MANUAL_SESSION.copy()
    print(f" uid = {sess['uid']}")
    start_coins = coins(sess)
    print(f" 起始 coins = {start_coins}")

    ret, au = merge_once(sess, SCORE)
    probe_coins = coins(sess)
    if not au:
        print("[!] 探针未返回奖励 —— 通道可能失效,中止。")
        return
    per = (au or {}).get("coins", 0)

    remaining = TIMES - 1
    if remaining <= 0:
        print(f" 结束 coins = {coins(sess)}")
        return

    batch = max(1, BATCH)
    n_req = (remaining + batch - 1) // batch
    print(f"[2] 开始执行,总循环次数 {TIMES}")
    prev = probe_coins
    total = per
    ok = 0
    fail = 0
    reqs = 0
    done = 0
    t0 = time.time()
    while done < remaining:
        n = min(batch, remaining - done)
        results = merge_batch(sess, SCORE, n)
        reqs += 1
        for it in results:
            got = _coins_got(it)
            if got:
                total += got
                ok += 1
            else:
                fail += 1
        if len(results) < n:
            fail += (n - len(results))
        done += n
        if DELAY:
            time.sleep(DELAY)
        if reqs % 5 == 0 or done >= remaining:
            now = coins(sess)
            print(f"    已结算 {done}/{remaining} 请求={reqs} coins={now} (本段 {(now or 0)-(prev or 0)}) 成功={ok} 失败={fail}")
            prev = now
    cost = time.time() - t0
    end_coins = coins(sess)
    print(f" 结束 coins = {end_coins}")
    print(f" 实际净增 = {(end_coins or 0)-(start_coins or 0)}   理论累计 = {total}")
    print("[!] 任务执行完毕")

login_params_cache = None

def get_login_params():
    global login_params_cache
    print("===== 开始枚举窗口,寻找【圈了个地】 =====")
    windows = get_all_windows()
    target_pid = None
    for w in windows:
        print(f"HWND:{hex(w['hwnd'])} PID:{w['pid']} Title:{w['title']}")
        if "圈了个地" in w["title"]:
            target_pid = w["pid"]
    if target_pid is None:
        print("&#10060;没有找到标题包含【圈了个地】的窗口,请先打开游戏")
        return
    print(f"&#9989;找到【圈了个地】窗口,PID = {target_pid}")
    TARGET_PID = target_pid
    target = b"gd_session"
    try:
        pm, addr_list = search_string_by_pymem(TARGET_PID, target)
    except Exception as e:
        print(f"&#10060;打开进程失败:{e},请以管理员运行程序")
        return
    login_params_cache = None
    for addr in addr_list:
        print(f"\n===== 读取地址 0x{addr:X},前后各100字节 =====")
        data, offset = read_memory(pm, addr, pre=100, post=100)
        try:
            text = data.decode('utf-8', errors='replace')
            params = parse_qs(text)
            login_params_cache = {
                "openid": params["openid"][0],
                "uid": params["uid"][0],
                "gd_session": params["gd_session"][0],
                "openkey": params["openkey"][0]
            }
            print(f"&#9989;成功读取登录参数:{login_params_cache}")
            break
        except Exception as e:
            print(f"解码失败:{e}")
            continue
    pm.close_process()
    if login_params_cache is None:
        print("&#10060;未能从内存解析出登录参数")
    else:
        print("&#9989;登录参数获取完成,可以执行刷金币!")

if __name__ == "__main__":
    while True:
        print("\n===== 主菜单 =====")
        print("1. 获取游戏登录参数")
        print("2. 执行刷金币任务(加1万)")
        print("3. 执行刷金币任务(加10万)")
        print("4. 执行刷金币任务(加100万)")
        print("0. 退出程序")
        choice = input("请输入选项:").strip()
        if choice == "1":
            get_login_params()
        elif choice == "2":
            if login_params_cache is None:
                print("&#9888;&#65039;请先执行【1 获取游戏登录参数】!")
            else:
                print("========== 开始执行刷金币任务 ==========")
                try:
                    run_coin_task(login_params_cache, TIMES=1000)
                except Exception as e:
                    print(f"任务异常:{e}")
        elif choice == "3":
            if login_params_cache is None:
                print("&#9888;&#65039;请先执行【1 获取游戏登录参数】!")
            else:
                print("========== 开始执行刷金币任务 ==========")
                try:
                    run_coin_task(login_params_cache, TIMES=10000)
                except Exception as e:
                    print(f"任务异常:{e}")
        elif choice == "4":
            if login_params_cache is None:
                print("&#9888;&#65039;请先执行【1 获取游戏登录参数】!")
            else:
                print("========== 开始执行刷金币任务 ==========")
                try:
                    run_coin_task(login_params_cache, TIMES=100000)
                except Exception as e:
                    print(f"任务异常:{e}")
        elif choice == "0":
            print("程序退出")
            break
        else:
            print("输入无效,请重新选择")

image.png (437.8 KB, 下载次数: 0)

image.png

免费评分

参与人数 1吾爱币 +1 收起 理由
aigc + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 5#
 楼主| wabc666 发表于 2026-9-20 01:39 |楼主
泡泡汽水 发表于 2026-9-20 00:34
&#9989;找到【圈了个地】窗口,PID = 17788
&#9989;找到 3 个地址:
0x701C05CBDC59

读内存是为了获取这个游戏账号关联的参数,但是window不同版本可能兼容性有问题,可以自己抓包提取一下,或者内存搜索一下拿出来贴进代码也能运行

login_params_cache = {
                "openid": params["openid"][0],
                "uid": params["uid"][0],
                "gd_session": params["gd_session"][0],
                "openkey": params["openkey"][0]
            }
沙发
qiyx 发表于 2026-9-20 00:04
3#
泡泡汽水 发表于 2026-9-20 00:34
&#9989;找到【圈了个地】窗口,PID = 17788
&#9989;找到 3 个地址:
0x701C05CBDC59
0x701C05CBDC89
0x701C05CD3D39

===== 读取地址 0x701C05CBDC59,前后各100字节 =====
解码失败:'openid'

===== 读取地址 0x701C05CBDC89,前后各100字节 =====
解码失败:'openid'

===== 读取地址 0x701C05CD3D39,前后各100字节 =====
解码失败:'openid'
&#10060;未能从内存解析出登录参数
4#
Turbo86 发表于 2026-9-20 00:46
有空玩玩
6#
AE86zdm 发表于 2026-9-20 04:55
还可以,下来玩玩
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-20 05:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表