首页
社区
课程
招聘
[原创]如何修改unity HybridCLR 热更dll
2022-12-22 14:27 29356

[原创]如何修改unity HybridCLR 热更dll

2022-12-22 14:27
29356

背景

由于很多原因比如修bug、减小包体积、迅速更新,游戏需要使用到热更。

目前比较热门的热更方法,一种是使用lua,比如xlua、tolua之类的,还有一种是使用热更框架,比如HybridCLR、ILRuntime。

如何修改lua,已经有很多文章了,证明了使用lua被篡改是很简单的一件事。那么,热更框架就安全了吗?

HybridCLR dump and  modify

项目地址:https://github.com/focus-creative-games/hybridclr

不得不说,通过阅读文档,这个框架是修改了il2cpp来实现的原生级热更,真的是很厉害。

原生的unity il2cpp是将游戏所有代码编译到libil2cpp.so,不会生成Assembly-CSharp.dll。

首先在github上拉取测试demo,并打包成apk,运行起来截图:

image-20221214142723805

我们可以看到游戏加载了热更的Assembly-CSharp.dll,并且输出hello,HybridCLR。

可以通过查找字符串“image can't be init again”来获取加载函数,找到这个函数并hook,就能将热更的dll dump下来,修改内容后并重新加载进去。

通过查找发现目标函数的偏移为0x66bbd0,获取到的dll内容为:

修改dll中的相关内容:

重新加载dll,逻辑就已被修改了:

附上frida js

//唯一需要修改的信息为InterpreterImage::load的偏移
let so = Process.findModuleByName("libil2cpp.so")
while (so == null)
    so = Process.findModuleByName("libil2cpp.so")

let i = 1;
Interceptor.attach(so.base.add(0x66BBD0),{
    onEnter:function (args) {
        let filePath = "/data/data/com.Dev.HybridCLRTrial/dump_"+i+".dll"
        if(access(filePath) == 0 ){
            var data = read(filePath);
            args[1] = data.data;
            args[2] = new NativePointer(ptr(data.size));
            console.log("load "+filePath)
        }else {
            const dumpfile = new File(filePath, "wb");
            let size = args[2]
            dumpfile.write( args[1].readByteArray(size.toInt32()))
            console.log("dump "+filePath)
        }


        i++
    }
})


function access(filePath){
    var ptr_access = Module.findExportByName("libc.so","access");
    var func_access = new NativeFunction(ptr_access,'int',['pointer','int']);
    var ptr_filepath = Memory.allocUtf8String(filePath);
    var ret = func_access(ptr_filepath,0);
    return ret;
}

function mkdir(Path){
    var ptr_mkdir = Module.findExportByName("libc.so","mkdir");
    var func_mkdir = new NativeFunction(ptr_mkdir,'int',['pointer','int']);
    var ptr_filepath = Memory.allocUtf8String(Path);
    var ret = func_mkdir(ptr_filepath,777);
    return ret;
}

function folder_mkdirs(p){
    var p_list = p.split("/");
    var pp = "/sdcard/fridadump/lua";
    for(var i = 0;i< p_list.length  ;i++){
        pp = pp + "/" + p_list[i];
        if(access(pp) != 0){
            var x = mkdir(pp)
            send("mkdir :"+pp+"ret :" +x);
        }
    }

}
// frida file 对象没有read
function read(filePath){
    var ptr_open = Module.findExportByName("libc.so","open");
    const open = new NativeFunction(ptr_open,'int',['pointer','int']);

    var ptr_read = Module.findExportByName("libc.so","read");
    const read = new NativeFunction(ptr_read,'int',['int','pointer','int']);

    var ptr_close = Module.findExportByName("libc.so","close");
    const close = new NativeFunction(ptr_close,'int',['int']);

    var fd = open(Memory.allocUtf8String(filePath),0);
    var size = get_file_size(fd);
    if(size >0){
        var data = Memory.alloc(size + 5);
        if( read(fd,data,size) <0){
            console.log('[+] Unable to read DLL [!]');
            close(fd);
            return 0;
        }
        close(fd);
        return {data:data,size:size};
    }

}

function get_file_size(fd){
    var statBuff = Memory.alloc(500);
    var fstatSymbol = Module.findExportByName('libc.so', 'fstat');
    var fstat = new NativeFunction(fstatSymbol, 'int', ['int', 'pointer']);
    if(fd > 0) {
        var ret = fstat(fd, statBuff);
        if(ret < 0) { console.log('[+] fstat --> failed [!]');
        }
    }
    var size = Memory.readS32(statBuff.add(0x30));
    if(size > 0) {
        return size;
    } else {
        return 0;
    }
}

如此就完成了关于使用HybridCLR 游戏的热更dll修改。其他逻辑信息就通过常规的分析il2cpp取获取。






[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2022-12-22 14:30 被八重嘤编辑 ,原因:
收藏
点赞8
打赏
分享
最新回复 (6)
雪    币: 6055
活跃值: (1271)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
财神爷999 2022-12-23 17:15
2
0
很好,试了下这个脚本,可以
雪    币: 3579
活跃值: (658)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
梨树生果 2023-12-15 11:38
3
0
试了一下,脚本运行后游戏卡死,修改后就好了,谢谢分享。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
逮虾户 2023-12-17 19:54
4
0
梨树生果 试了一下,脚本运行后游戏卡死,修改后就好了,谢谢分享。
老哥你修改的哪里啊?我也是卡死
雪    币: 3579
活跃值: (658)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
梨树生果 2023-12-28 18:42
5
0
逮虾户 老哥你修改的哪里啊?我也是卡死
找libil2cpp.so模块基地址那里有问题,卡死在循环了,换种方式找就OK了
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
逮虾户 2024-3-13 21:03
6
0
梨树生果 找libil2cpp.so模块基地址那里有问题,卡死在循环了,换种方式找就OK了
老哥求一份脚本,xx
雪    币: 602
活跃值: (2014)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
wuaiwu 3 2024-3-18 20:05
7
0
dnspy简单修改个字符串或者返回值还行。改逻辑就不行了。 替换dll这个思路我验证过ilruntime,也是热更新。只能玩玩demo。 不过,还是感谢分享。
游客
登录 | 注册 方可回帖
返回