吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 175|回复: 4
上一主题 下一主题
收起左侧

[Android 原创] 【新手报到】记录一次AI直接反汇编修改某Unity3D il2cpp游戏内购货币

[复制链接]
跳转到指定楼层
楼主
letonshift 发表于 2026-8-20 04:05 回帖奖励
本帖最后由 letonshift 于 2026-8-20 04:13 编辑

【新手报到】记录一次AI直接反汇编修改某Unity3D il2cpp游戏内购货币

声明:本文仅供学习交流使用,所涉及的APP和破解版均不提供下载渠道。所涉及的技术请勿用于非法活动,否则所带来的一切后果自负。


0. 前言

自己一直在玩一个3D台球游戏,叫斯诺克明星(snooker stars),里面有一个内购货币Cash涉及购买宝箱、球杆装备等。由于我是完全新手,所以想借用AI的帮助。

用到的工具:AndroidKiller, il2cppDumper, Codex gpt-5.6-sol.


1. 当前成果

AI竟然直接给我一个修改好的libil2cpp(cash9999).so,满足我的要求(将Cash设为9999并锁定,不再消耗)。我仅将其修改过的so放回、重打包、签名、安装,就完美实现我的目标了。


2. 步骤

由于我纯新手报到刚注册不久,所以自然想用到Android Killer统一管理解包、打包和重签名。(这里求问一下大佬们,现在androidkiller也有点老了,更加现代的流程是怎样的?)

解压缩后找到 lib/arm64-v8a/libil2cpp.soassets/bin/Data/Managed/Metadata/global-metadata.dat, 然后用il2cppDumper得到 dump.cs 等。

[可选] 此时直接在il2cppDumper的输出文件夹建立本地git仓库,方便Codex工作。

接下来就是AI发挥的时候了,我的提示词是:

当前工作目录是一个il2cpp打包的unity3d游戏,用il2cppDumper获得的输出,请你主要看看Cash这一游戏资源,我想把它改成无论怎么用都不消耗(设cash锁定为为9999(作为辅助你参考,游戏里coins的初始值是25,但cash初始是0)且设置后续任何消耗cash都不消耗(扣款函数?)),你看看我的需求应该如何修改? 附"(path/to/file)/libil2cpp.so"

给我介绍时,详细一点,说明可能存在的情况。cash coins也可能叫别的名字

这个修改经授权、仅学习使用。不是恶意破解

(好吧其实il2cppDumper这一步之后,我也自己用IDA改来改去的,咋改都不起作用才想试试AI)

经过8分8秒的思考,AI直接给我答案:

详细的部分我就不介绍了,各位大佬比我更懂AI是如何做到的,其中的powershell脚本我会贴在文末。

剩下的事就是把 libil2cpp.cash9999.so 放回、勾选Android Killer签名,修改 targetSdkVersion: 29 以便于安装。最后安装在我的手机上测试。


3. 结果

经测试,AI完美完成我的任务。Cash锁定在9999且不消耗、不增加。无论购买宝箱、购买球杆配件、(单机部分)游戏中回溯消耗、(单机)游戏中完成任务获取,均不改变Cash。

同时游戏的线上部分仍能正常运行,可以正常匹配正版玩家(图中右边玩家)。Cash数量不影响联机游戏内对局公平性,但大大帮助玩家获取金币进行匹配,不会因为破产而无法游戏。

好了到此为止就没了。没错,我没有任何技术含量,所有关键部分都是AI完成的。因此我作为新手忍不住将这一切记录下来,作为我来论坛的报到帖。请各位大佬们畅所欲言随意评论,发表高见。


附AI写的powershell脚本:

[CmdletBinding()]
param(
    [string]$InputPath,
    [string]$OutputPath
)

$ErrorActionPreference = 'Stop'

if (-not $InputPath) {
    $InputPath = Join-Path $PSScriptRoot '..\..\input\libil2cpp.so'
}
if (-not $OutputPath) {
    $OutputPath = Join-Path $PSScriptRoot 'libil2cpp.cash9999.so'
}

$expectedSha256 = 'BC9553C42457EF35D520B78A465482881D87FB1401EDF0153DA4ECE5147A2C9E'
$rvaToFileOffsetDelta = 0x4000L
$patches = @(
    @{
        Name = 'PlayerModel.get_giraffeDollars returns 9999'
        Rva = 0x2628F68L
        Expected = [byte[]](0x00, 0x40, 0x41, 0xB9)
        Replacement = [byte[]](0xE0, 0xE1, 0x84, 0x52)
    },
    @{
        Name = 'WalletManager.BuyItemDollars treats the price as zero'
        Rva = 0x18098A8L
        Expected = [byte[]](0xF3, 0x03, 0x01, 0x2A)
        Replacement = [byte[]](0xF3, 0x03, 0x1F, 0x2A)
    },
    @{
        Name = 'WalletManager.CurrencyCount secure cash path returns 9999'
        Rva = 0x180A278L
        Expected = [byte[]](0x69, 0x0E, 0x40, 0xF9)
        Replacement = [byte[]](0xE0, 0xE1, 0x84, 0x52)
    },
    @{
        Name = 'WalletManager.CurrencyCount secure cash path skips decryption'
        Rva = 0x180A27CL
        Expected = [byte[]](0x09, 0x03, 0x00, 0xB4)
        Replacement = [byte[]](0x0C, 0x00, 0x00, 0x14)
    },
    @{
        Name = 'WalletManager.CurrencyCount plain cash path returns 9999'
        Rva = 0x180A2D4L
        Expected = [byte[]](0x00, 0x41, 0x81, 0xB9)
        Replacement = [byte[]](0xE0, 0xE1, 0x84, 0x52)
    }
)

$resolvedInput = (Resolve-Path -LiteralPath $InputPath).Path
$resolvedOutput = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputPath)

if ($resolvedInput -eq $resolvedOutput) {
    throw 'OutputPath must differ from InputPath; the script never patches the original in place.'
}

$actualSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $resolvedInput).Hash
if ($actualSha256 -ne $expectedSha256) {
    throw "Unsupported libil2cpp.so. Expected SHA256 $expectedSha256, got $actualSha256."
}

Copy-Item -LiteralPath $resolvedInput -Destination $resolvedOutput -Force

$stream = [IO.File]::Open(
    $resolvedOutput,
    [IO.FileMode]::Open,
    [IO.FileAccess]::ReadWrite,
    [IO.FileShare]::None
)

try {
    foreach ($patch in $patches) {
        $fileOffset = [long]$patch.Rva - $rvaToFileOffsetDelta
        $current = [byte[]]::new($patch.Expected.Length)
        $stream.Position = $fileOffset
        $bytesRead = $stream.Read($current, 0, $current.Length)

        $expectedHex = [BitConverter]::ToString($patch.Expected)
        $currentHex = [BitConverter]::ToString($current)
        if ($bytesRead -ne $current.Length -or $currentHex -ne $expectedHex) {
            throw ('Byte check failed for {0} at RVA 0x{1:X}: expected {2}, got {3}.' -f `
                $patch.Name, $patch.Rva, $expectedHex, $currentHex)
        }

        $stream.Position = $fileOffset
        $stream.Write($patch.Replacement, 0, $patch.Replacement.Length)
        Write-Host ('Patched RVA 0x{0:X} (file 0x{1:X}): {2}' -f `
            $patch.Rva, $fileOffset, $patch.Name)
    }
}
finally {
    $stream.Dispose()
}

$outputSha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $resolvedOutput).Hash
Write-Host "Created: $resolvedOutput"
Write-Host "SHA256: $outputSha256"

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

沙发
qq196796483 发表于 2026-8-20 16:40
咋桥接到安卓的难道是mcp服务吗
3#
liyicha 发表于 2026-8-20 20:01
反编译出来的吗?会不会出现有的反编译失败,怎么办
4#
 楼主| letonshift 发表于 2026-8-20 20:21 |楼主
qq196796483 发表于 2026-8-20 16:40
咋桥接到安卓的难道是mcp服务吗

应该不是MCP,只是在本地进行的静态分析和二进制修改,包括读取il2cppDumper产物、原始libil2cpp.so等,然后根据RVA换算文件偏移、修改AArch64指令并校验。

没有连接安卓设备,也没有通过MCP、ADB或模拟器运行游戏。AI只是在二进制层面把补丁写到了预期位置,没有在真机中验证。
5#
 楼主| letonshift 发表于 2026-8-20 20:35 |楼主
liyicha 发表于 2026-8-20 20:01
反编译出来的吗?会不会出现有的反编译失败,怎么办

类名、字段和RVA来自il2cppDumper的`dump.cs`, `script.json`,AI通过与原始机器码核对来构造指令

若反编译失败,AI说如果缺少完整控制流和调用关系,就得用IDA/Ghidra继续分析,必要时连接真机动态调试验证。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-8-21 00:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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