吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2416|回复: 23
收起左侧

[Android 原创] PC安卓模拟器跑只带arm64的so的apk实现修改

[复制链接]
cqy666 发表于 2026-8-13 21:10
本帖最后由 cqy666 于 2026-9-7 18:15 编辑

image.png
image.png image.png
image.png
image.png
image.png
image.png
image.png
f823b3e64e579b527cfc826d734822e6.png
image.png image.png image.png

x64雷神9安卓模拟器,ce看代码,frida直接patch arm64代码,雷神会实时转义arm64到x64代码,效果出来了。

手动清缓存后
地址确保不变情况下,
优化一键启动pwsh命令:
[Python] 纯文本查看 复制代码
$PKG = "com.FDGEntertainment.redball4.gp";adb shell am force-stop $PKG; adb shell monkey -p $PKG -c android.intent.category.LAUNCHER 1; & "F:\newfrida\.venv\Scripts\frida.exe" -UF $PKG -l "F:\core\frida\fridaroot\无限命x64.js"

原理:
  • T0 首次启动:CE获取 SO 内存基址,记录目标函数偏移
  • T1 Force Stop:清空应用缓存与旧映射
  • T2 二次启动:Linker 加载 ARM64 SO 到内存
  • T3 注入 Patch:在 Houdini 翻译前,通过 Frida/CE调试器写入补丁(⚡ 窗口期极短)
  • T4 Houdini 翻译:读取已 Patch 的 ARM64 指令
  • T5 执行生效:后续调用直接使用新 TB,补丁落地

  • 把 Houdini 想象成一个同声传译员,ARM64 代码是"外语演讲稿",x86 代码是"中文译文":
  • 先听一遍记地址:第一次启动 App,记下演讲稿放在桌上哪个位置
  • 擦掉旧译文:Force Stop,把翻译官脑子里的旧译文全部擦掉
  • 重新摆上演讲稿:第二次启动,演讲稿重新放到桌上
  • 抢在翻译前改稿子:趁翻译官还没开口,冲上去把稿子上的关键句子改掉
  • 翻译官读到改过的稿子:他照着修改后的内容翻译,中文译文自然就包含了你的改动
  • 听众听到新译文:App 执行的就是带补丁的新逻辑


无需借助CE,Frida完整实例(20260907):

[C#] 纯文本查看 复制代码
 
 public void RunBall()
    {
        const string ProcessName = "Red Ball 4";
        const string DeviceId = "emulator-5554";
        Session session = null;
        Script script = null;

        //pwsh手动
        //$PKG = "com.FDGEntertainment.redball4.gp";adb shell am force-stop $PKG;adb shell am start -a android.settings.APPLICATION_DETAILS_SETTINGS -d package:$PKG
        //清缓存
        string pkg = "com.FDGEntertainment.redball4.gp";

        var psi = new ProcessStartInfo("adb")
        {
            Arguments = $"shell \"am force-stop {pkg}; monkey -p {pkg} -c android.intent.category.LAUNCHER 1\"",
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true
        };

        using var process0 = Process.Start(psi);
        process0?.WaitForExit();

        string output = process0?.StandardOutput.ReadToEnd();
        try
        {
            // 1. 查找设备与进程
            var deviceManager = new DeviceManager();
            var device = deviceManager.EnumerateDevices()
                .FirstOrDefault(d => d.Id == DeviceId)
                ?? throw new InvalidOperationException($"未找到设备: {DeviceId}");

            var process = device.EnumerateProcesses()
                .FirstOrDefault(p => p.Name == ProcessName)
                ?? throw new InvalidOperationException($"未找到进程: {ProcessName}");

            Log($"[Frida] 已附加到 {process.Name} (PID={process.Pid})");
            session = device.Attach(process.Pid);

            // 2. JS脚本:监听C#发来的指令,执行后回传结果
            var js = @"
function getModuleBase(name) {
        // 1. 标准 API
        var mod = Process.findModuleByName(name);
        if (mod) return mod.base;

        // 2. /proc/self/maps: r-xp + offset=0 + 路径含name + 最低地址
        var base = null;
        try {
            File.readAllText(""/proc/self/maps"").split(""\n"").forEach(function (l) {
                if (l.indexOf(name) !== -1 && l.indexOf("" r-xp "") !== -1 && l.split(/\s+/)[2] === ""00000000"") {
                    var addr = ptr(""0x"" + l.trim().split(""-"")[0]);
                    if (!base || addr.compare(base) < 0) base = addr;
                }
            });
            if (base) return base;
        } catch (e) { }

        // 3. 内存扫描 ELF magic + 路径含name + 最低地址
        var res = [];
        Process.enumerateRanges('r--').forEach(function (r) {
            if (r.size < 4e6 || r.size > 1e8) return;
            try {
                if (r.base.readU32() !== 0x464C457F) return;
                if (r.file && r.file.path.indexOf(name.replace(/^lib|\.so$/g, """")) !== -1)
                    res.push(r.base);
            } catch (e) { }
        });
        res.sort(function (a, b) { return a.compare(b); });
        return res.length ? res[0] : null;
    }

recv('patch', function(msg) {
    try {
        var il2cpp = getModuleBase('libil2cpp.so');
        if (!il2cpp) { send({ type:'result', ok:false, error:'libil2cpp.so not found' }); return; }

        var target = il2cpp.add(msg.offset);
        console.log(' Target address: ' + target);

        Memory.protect(target, 8, 'rwx');
        target.writeU32(msg.opcode);        // MOV W0, #N
        target.add(4).writeU32(0xD65F03C0); // RET

        send({ type:'result', ok:true, address: target.toString() });
    } catch(e) {
        send({ type:'result', ok:false, error: e.message });
    }
});
";

            script = session.CreateScript(js);

            // 3. 用 TaskCompletionSource 将 Message 回调转为同步等待
            var tcs = new TaskCompletionSource<string>();

            script.Message += (s, msg) =>
            {
                Log($"[Frida] {msg.Message}");

                try
                {
                    var json = JObject.Parse(msg.Message);
                    if (json["type"]?.ToString() == "send")
                    {
                        var payload = json["payload"];
                        if (payload?["type"]?.ToString() == "result")
                            tcs.TrySetResult(payload.ToString());
                    }
                }
                catch { /* 非结构化消息忽略 */ }
            };

            script.Load();

            // 4. 发送指令(替代字符串拼接构建JS)
            var command = JsonConvert.SerializeObject(new
            {
                type = "patch",
                offset = 0x1138810,
                opcode = 0x52800060   // MOV W0, #3
            });
            script.Post(command);

            // 5. 同步等待结果(带超时保护)
            bool completed = tcs.Task.Wait(TimeSpan.FromSeconds(10));
            if (!completed)
                throw new TimeoutException("Frida 脚本响应超时");

            var result = JObject.Parse(tcs.Task.Result);
            if (result["ok"]?.Value<bool>() == true)
                Log($"[Frida] &#10003; 无限生命补丁已写入 @ {result["address"]}");
            else
                Log($"[Frida] &#10007; 补丁失败: {result["error"]}");
        }
        catch (Exception ex)
        {
            Log($"[Frida] 错误: {ex.Message}");
        }
        finally
        {
            script?.Unload();
            session?.Detach();
        }
    }

image.png

免费评分

参与人数 8吾爱币 +6 热心值 +7 收起 理由
Iamx688110 + 1 + 1 我很赞同!
maoliangs + 1 我很赞同!
MKStoler + 1 我很赞同!
jaffa + 1 谢谢@Thanks!
Relax7990 + 1 + 1 我很赞同!
toxic9n + 1 + 1 我很赞同!
czrbbxh + 1 + 1 我很赞同!
ChiZhu + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

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

laoser 发表于 2026-8-13 21:35
frida saggg
晓源 发表于 2026-8-13 21:54
4018290 发表于 2026-8-14 08:11
虽然看不懂,但是看起来很厉害的样子!是安卓模拟器的PC版吗?
xiulisan 发表于 2026-8-14 08:52
没看懂的路过
toufaluanle 发表于 2026-8-14 09:05
看不懂。。。
travishua 发表于 2026-8-14 09:41
谢谢分享啊
datangshizhewu 发表于 2026-8-14 10:49
回帖 收藏
RHank 发表于 2026-8-14 13:37
手机模拟PC吗?
toxic9n 发表于 2026-8-14 14:26
PC模拟手机吧 雷电模拟器
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-9-8 05:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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