首页
社区
课程
招聘
[原创]一次svc简单绕过
发表于: 2024-2-26 10:44 3825

[原创]一次svc简单绕过

2024-2-26 10:44
3825

遇到一个unity的单机游戏,这个游戏是别人改过的,想对比和原版有什么区别,使用frida去dump内存中的so,无奈frida直接被退出,但是游戏还是正常进入的,如下图:

而原版是没有验证的,
Hook pthread_create看下发现是在一个叫libmod.so之后闪退的

解压apk看下,lib\arm64-v8a\目录下并没有libmod.so

那大概率可能是从assets目录下解压自己的资源,再加载自己的so,但是我们并不需要直接去找哪个so有没有在assets目录下,因为上面hook pthread_create打印堆栈已经有给我们地址了,直接去那个目录找就行了,但其实有原包的情况下,直接对比两个apk也能看出多出了什么文件,把多出的那几个文件找出来,并用010打开就能知道是什么文件了,用010打开是为了看文件格式,有些文件为了隐藏,去掉了后缀名,有些是改了后缀名,但其实这些都没用,用010打开都能看出文件是什么格式的文件,除非有些是加密过的。
ida打开libmod.so,查看init_array段

妥妥的ollvm的特征。
随便进入一个函数,如下图,

根本没法看,我们也不准备看这些乱七八糟的代码。
其实直接硬改后面两个线程启动的地方就能绕过验证。也就是在两个线程启动的地方直接nop

但这里还有一种方法绕过验证
frida spawn启动后,frida被退出,然后游戏还能正常进入,而且mod功能也是正常的,看最后一次线程被启动的地方,进入0x1971e4函数,在分析这个函数之前,我们先理解一个正常开发的逻辑,正常一个检测或一个功能,通常都是封装成一个函数,方便查看,而且便于之后维护,基于这点,我们直接在函数中找call,也就是sub_xxxx开头的
进入0x1971e4看下,

没几个sub_xxxx,经过查看,函数内有很多处都有调用sub_188374 ,进入看下,是个syscall


好家伙,难怪hook各种系统函数都无效,而且入参是56,对应信号就是openat ,循环读取了什么文件,hook sub_19F974函数,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
var soName = "libmod.so"
 
function myfun()
{
    var moduleBaseAddress = Module.getBaseAddress(soName);
    console.log(soName + "_address:", moduleBaseAddress);
    var nativePointer = moduleBaseAddress.add(0x19F974);
    Interceptor.attach(nativePointer,
    {
        onEnter: function (args)
        {
             
            this.v1051= this.context.x0
            var str3 = this.context.x3.readUtf8String();
            console.log("str3:" + str3);
 
        },
        onLeave: function (retval)
        {
            console.log("this.v1051:",this.v1051.readUtf8String());
 
        }
    }
    );
}
 
 
function hook_dlopen()
{
    var is_can_hook = false;
    Interceptor.attach(Module.findExportByName(null, "dlopen"),
    {
        onEnter: function (args)
        {
            var pathptr = args[0];
            if (pathptr !== undefined && pathptr != null)
            {
                var path = ptr(pathptr).readCString();
                if (path.indexOf(soName) >= 0)
                {
                    this.is_can_hook = true;
                }
            }
        },
        onLeave: function (retval)
        {
            if (this.is_can_hook)
            {
                myfun()
            }
        }
    }
    );
 
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
    {
        onEnter: function (args)
        {
            var pathptr = args[0];
            if (pathptr !== undefined && pathptr != null)
            {
                var path = ptr(pathptr).readCString();
                if (path.indexOf(soName) >= 0)
                {
                    this.is_can_hook = true;
                }
            }
        },
        onLeave: function (retval)
        {
            if (this.is_can_hook)
            {
                myfun()
            }
        }
    }
    );
}
 
setImmediate(hook_dlopen);


读取了各种文件,它的最后一个参数也是先经过init_array中的函数先解密

对于openat 的描述是:函数执行成功返回文件描述符,失败返回-1.
那我们就直接在sub_188374函数中直接返回1吧,结果是可以,并正常运行,
其实直接对syscall直接返回1是不严谨的,因为有些情况下这样操作会导致别的问题出现,只是这游戏刚好这么操作没有出现别的问题。
frida也能正常附加并dump

之后就可以愉快的使用dump的so和原版的so进行比较

总结:
文章写的很乱,没什么技术含量,有些防护做了一些花里胡哨的操作,有时候也不用硬杠,但前提是知道hook哪些关键函数,知道一些函数的作用

欢迎加入QQ群:812701781,542863693,欢迎分享一些骚操作(备注看的什么文章)

微信公众号:MoneyHoneyCome


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-2-26 10:47 被灯-等灯等灯~编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (3)
雪    币: 2328
活跃值: (10364)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

牢哥得给个样本学习啊

最后于 2024-2-27 10:02 被你瞒我瞒编辑 ,原因:
2024-2-27 10:02
0
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2024-2-27 10:47
1
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持一波
2024-2-27 21:39
0
游客
登录 | 注册 方可回帖
返回
//