首页
社区
课程
招聘
[原创]某韩国游戏驱动保护静态分析
2022-2-16 00:39 25254

[原创]某韩国游戏驱动保护静态分析

2022-2-16 00:39
25254

样本介绍:XIGNCODE3 是为大型多人线上游戏所发行的一款游戏反作弊软体,被用于如新枫之谷(南韩版)、战地之王等网路游戏中。XIGNCODE为wellbia所制作。

如果哪里写的不好欢迎大佬指正。

我大概分析了一下整个驱动的流程部分,下面会依次介绍这个驱动的分析过程和思路,在这个样本里不仅可以学习到很多内核编程的知识,也可以借鉴到一些设计模式上的东西。

那么我们直接开始分析,先从入口点开始。

1.驱动入口点

**在DriverMain中驱动主要做了几件事
①初始化系统版本偏移
②注册通信的分发函数
③设置了通讯函数
④注册通知和回调
⑤创建进程通知
图片描述

2.初始化系统版本偏移

主要是根据不同的系统版本号初始化一些全局变量,这里不做具体分析了。
图片描述

3.注册通信的分发函数

3.1 DisPatchCreate和DisPatchClose的分发

默认的分发函数,没什么好说的。
图片描述
图片描述

3.2 DispatchWrite函数的分发

3.2.1 通讯数据结构的部分分析

这里就比较关键了,可以注意到这里丢了两个通讯条件,一个是在通讯函数的头部存放了一个长度值,另一个是sysBuffer的值是一个固定值。
由此我们目前可以确定InputBuffer中的前8个字节0x345821AB00000270
前四个字节是长度,后四个字节是固定标识码,用于确认三环程序的身份。

 

图片描述

3.2.2 FuncCall分析

由于在上一小节中我们只知道了InputBuffer的前8个字节,我们直接看到我ida分析过后的代码,可以看到while中的条件判断是在判断FuncIndex,函数编号。
图片描述
我们双击FunCallArray进去看看里面是什么,可以看到是标准的8字节排列的对象,由此猜测这很可能是函数数组,那么我怎么确定这个事实,并且也确定FuncIndex就是函数索引的呢?我们继续看下一节“设置函数通讯你列表”
图片描述

4.设置通讯函数列表( SetKeyDisFuncArray的分析)

我们观察上面的截图,看到第一个140010F88(8字节)和140010F90(4字节)
再看看下方的截图,你发现了什么?
是吧?他就是一个8字节对齐的全局的结构体数组

1
2
3
4
5
struct _FunCallArray
{
  ULONG64 FuncAddr;
  ULONG FuncIndex;
};

由此我们可以知道3.2.2小节中FuncCall的命名由来,实际上他在根据索引确定函数的调用。

 

图片描述

 

接下来我挑几个我觉得比较有意思的函数发一下分析。

4.1 ReadProcessMemory

图片描述

4.2 DisObSetHandleAttribute

可以看到一个附加操作下面,又调用了一个函数,ok,继续跟进去,发现内部调用了“ObSetHandleAttributes”
图片描述
图片描述
如果你在逆向分析的时候不了解这种函数是做什么的,打开wrk搜索一下

1
2
3
4
5
6
7
NTKERNELAPI
NTSTATUS
ObSetHandleAttributes (
    __in HANDLE Handle,
    __in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,
    __in KPROCESSOR_MODE PreviousMode
    );

我们继续看一下HandleFlags的结构体类型

1
2
3
4
typedef struct _OBJECT_HANDLE_FLAG_INFORMATION {
    BOOLEAN Inherit;
    BOOLEAN ProtectFromClose;
} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;

基本可以确定这是一个用于关闭文件的函数。如果你不是十分肯定的话,再搜索引擎确认一下。

4.3 DispSetWin32kTable

一直跟进可以发现是在做一些函数全局变量的初始化。
图片描述

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
__int64 sub_1400075D4()
{
  unsigned int v0; // ebx
  __int64 (__fastcall *v1)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD); // r15
  __int64 (__fastcall *RtlCreateUserThreadFunc)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD); // r13
  __int64 result; // rax
  int *v4; // rdi
  const void *win32kModule; // r14
  __int64 win32kfullModule; // rax
  __int64 v7; // r8
  __int64 v8; // r9
  __int64 win32kfullModule1; // rsi
  __int64 v10; // r8
  __int64 v11; // r9
  __int64 v12; // r8
  __int64 v13; // r9
  __int64 v14; // r8
  __int64 v15; // r9
  __int64 v16; // r8
  __int64 v17; // r9
  __int64 v18; // r8
  __int64 v19; // r9
  PIMAGE_NT_HEADERS winkNts; // rax
  PIMAGE_NT_HEADERS winkNts1; // rsi
  __int64 win32SizeOfImage; // r12
  int v23; // eax
  const void *v24; // rbx
  const void *W32pServiceTable1; // [rsp+30h] [rbp-48h] BYREF
  __int64 v26; // [rsp+38h] [rbp-40h] BYREF
  const void *v27; // [rsp+40h] [rbp-38h] BYREF
  __int64 v28; // [rsp+48h] [rbp-30h] BYREF
  __int64 (__fastcall *v29)(_QWORD, _QWORD); // [rsp+50h] [rbp-28h] BYREF
  __int64 W32pServiceTable2; // [rsp+58h] [rbp-20h] BYREF
  UNICODE_STRING DestinationString; // [rsp+60h] [rbp-18h] BYREF
  const void *win32kMemoryModule; // [rsp+C0h] [rbp+48h] BYREF
  __int64 v33; // [rsp+C8h] [rbp+50h] BYREF
  __int64 NtUserGetWindowDisplayAffinity; // [rsp+D0h] [rbp+58h] BYREF
  __int64 NtUserSetWindowDisplayAffinity; // [rsp+D8h] [rbp+60h] BYREF
 
  v0 = 0;
  v1 = 0i64;
  v26 = 0i64;
  v27 = 0i64;
  v29 = 0i64;
  v28 = 0i64;
  if ( qword_140011700 )
    return 0i64;
  RtlInitUnicodeString_0(&DestinationString, L"RtlCreateUserThread");
  RtlCreateUserThreadFunc = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD))sub_140014948();
  if ( !RtlCreateUserThreadFunc )
  {
    v1 = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD))GetNtCreateThreadEx();
    if ( !v1 )
      return 0xE01AF211i64;
  }
  if ( version1 != 1 && version1 != 2 && version1 != 3 )
  {
    if ( version1 != 4 )
    {
      switch ( version1 )
      {
        case 6:
          v4 = (int *)&unk_140010480;
          break;
        case 7:
          v4 = (int *)&unk_1400104D0;
          break;
        case 8:
          v4 = (int *)&unk_140010520;
          break;
        default:
          result = sub_140006D7C();
          if ( (int)result < 0 )
          {
            _mm_lfence();
            return result;
          }
          v4 = (int *)&unk_140010570;
LABEL_20:
          j_DbgPrint_54("check ntusercalloneparam\n");
          if ( v4[9] >= 0 )
          {
            j_DbgPrint_55("load win32k image\n");
            if ( (int)readSysFileToMemory((__int64)&win32kMemoryModule, L"\\systemroot\\system32\\win32k.sys") >= 0 )
            {
              j_DbgPrint_56("get real win32k address\n");
              win32kModule = (const void *)QueryModules("win32k.sys");
              if ( !win32kModule )
                goto LABEL_23;
              j_DbgPrint_57("fetch win32k service table\n");
              win32kfullModule = QueryModules("win32kfull.sys");
              NtUserGetWindowDisplayAffinity = 0i64;
              win32kfullModule1 = win32kfullModule;
              NtUserSetWindowDisplayAffinity = 0i64;
              if ( win32kfullModule )
              {
                writeFileLog("win32kfull => %p\n", win32kfullModule, v7, v8);
                if ( (int)readSysFileToMemory((__int64)&v33, L"\\systemroot\\system32\\win32kfull.sys") < 0 )
                {
                  GetExportTableFunc(
                    &NtUserGetWindowDisplayAffinity,
                    win32kfullModule1,
                    (__int64)"NtUserGetWindowDisplayAffinity");
                  GetExportTableFunc(
                    &NtUserSetWindowDisplayAffinity,
                    win32kfullModule1,
                    (__int64)"NtUserSetWindowDisplayAffinity");
                  writeFileLog("getdisp %p", NtUserGetWindowDisplayAffinity, v16, v17);
                  writeFileLog("setdisp %p", NtUserSetWindowDisplayAffinity, v18, v19);
                }
                else
                {
                  writeFileLog("win32kfull safe => %p\n", v33, v10, v11);
                  if ( (int)GetExportTableFunc(
                              &NtUserGetWindowDisplayAffinity,
                              v33,
                              (__int64)"NtUserGetWindowDisplayAffinity") >= 0 )
                  {
                    writeFileLog(
                      "getdisp %p %08x => %p %p\n",
                      NtUserGetWindowDisplayAffinity,
                      NtUserGetWindowDisplayAffinity - v33,
                      win32kfullModule1);
                    NtUserGetWindowDisplayAffinity += win32kfullModule1 - v33;
                    writeFileLog("getdisp %p", NtUserGetWindowDisplayAffinity, v12, v13);
                  }
                  if ( (int)GetExportTableFunc(
                              &NtUserSetWindowDisplayAffinity,
                              v33,
                              (__int64)"NtUserSetWindowDisplayAffinity") >= 0 )
                  {
                    writeFileLog(
                      "setdisp %p %08x => %p %p\n",
                      NtUserSetWindowDisplayAffinity,
                      NtUserSetWindowDisplayAffinity - v33,
                      win32kfullModule1);
                    NtUserSetWindowDisplayAffinity += win32kfullModule1 - v33;
                    writeFileLog("setdisp %p", NtUserSetWindowDisplayAffinity, v14, v15);
                  }
                  tryPrint(v33);
                }
              }
              W32pServiceTable1 = 0i64;
              if ( (int)GetExportTableFunc(&W32pServiceTable1, (__int64)win32kMemoryModule, (__int64)"W32pServiceTable") >= 0
                && (W32pServiceTable2 = 0i64,
                    (int)GetExportTableFunc(&W32pServiceTable2, (__int64)win32kModule, (__int64)"W32pServiceTable") >= 0) )
              {
                _mm_lfence();
                j_DbgPrint_58("get real win32k nt header\n");
                winkNts = GetImageNts((__int64)win32kModule);
                winkNts1 = winkNts;
                if ( !winkNts )
                {
LABEL_44:
                  tryPrint((__int64)win32kMemoryModule);
                  return v0;
                }
                _mm_lfence();
                win32SizeOfImage = (__int64)win32kModule + winkNts->OptionalHeader.SizeOfImage;
                j_DbgPrint_59("resolve pNtUserGetForegroundWindow\n");
                v23 = sub_1400070A4(
                        &v28,
                        v4[4],
                        (__int64)win32kMemoryModule,
                        (__int64)W32pServiceTable1,
                        (__int64)win32kModule);
                _mm_lfence();
                if ( v23 < 0 )
                {
LABEL_43:
                  v0 = v23;
                  goto LABEL_44;
                }
                j_DbgPrint_60("resolve pNtUserQueryWindow\n");
                v23 = sub_1400070A4(
                        &v29,
                        v4[6],
                        (__int64)win32kMemoryModule,
                        (__int64)W32pServiceTable1,
                        (__int64)win32kModule);
                if ( v23 < 0
                  || (j_DbgPrint_61("resolve NtUserSetWindowDisplayAffinity\n"), v4[15] >= 0)
                  && (_mm_lfence(),
                      v23 = sub_1400070A4(
                              &v27,
                              v4[15],
                              (__int64)win32kMemoryModule,
                              (__int64)W32pServiceTable1,
                              (__int64)win32kModule),
                      v23 < 0)
                  || v4[16] >= 0
                  && (_mm_lfence(),
                      v23 = sub_1400070A4(
                              &v26,
                              v4[16],
                              (__int64)win32kMemoryModule,
                              (__int64)W32pServiceTable1,
                              (__int64)win32kModule),
                      v23 < 0) )
                {
                  _mm_lfence();
                  goto LABEL_43;
                }
                _mm_lfence();
                v24 = v27;
                W32pServiceTable11 = (__int64)W32pServiceTable1;
                qword_1400117C8 = v26;
                qword_140011850 = v28;
                qword_140011858 = v29;
                NtUserGetWindowDisplayAffinity1 = NtUserGetWindowDisplayAffinity;
                NtUserSetWindowDisplayAffinity2 = NtUserSetWindowDisplayAffinity;
                win32kMemoryModule1 = (__int64)win32kMemoryModule;
                win32kModule2 = (__int64)win32kModule;
                win32SizeOfImage1 = win32SizeOfImage;
                NtCreateThreadEx = v1;
                ::RtlCreateUserThreadFunc = RtlCreateUserThreadFunc;
                qword_1400117C0 = (__int64)v27;
                qword_140011708 = (__int64)win32kModule;
                qword_140011700 = (__int64)v4;
                j_DbgPrint_62("z s_safe_win32k == >  %p\n", win32kMemoryModule);
                j_DbgPrint_63("z w32_table == >  %p\n", W32pServiceTable1);
                j_DbgPrint_64("z win32k == >  %p\n", win32kModule);
                j_DbgPrint_65("z nt == >  %p\n", winkNts1);
                j_DbgPrint_66("z s_win32k_begin == >  %p\n", (const void *)win32kModule2);
                j_DbgPrint_67("z s_win32k_end == >  %p\n", (const void *)win32SizeOfImage1);
                j_DbgPrint_68("z s_win32k_table == >  %p\n", (const void *)W32pServiceTable11);
                j_DbgPrint_69("z pNtUserSetWindowDisplayAffinity == >  %p\n", v24);
              }
              else
              {
LABEL_23:
                tryPrint((__int64)win32kMemoryModule);
              }
            }
            return 0i64;
          }
          return 0xC0000001i64;
      }
      sub_140006AC8();
      goto LABEL_20;
    }
    v4 = (int *)&unk_140010430;
    goto LABEL_20;
  }
  return 0xC0000001i64;

4.4 DetectUserDrawDllHook

可以看到这个函数里的关键部分“CraeteDrawDLLDetectMemory”
图片描述

 

我们继续跟进
图片描述
可以发现里面申请了内存,然后把字符串拷贝进去,显然这是在创建需要检测的dll数据。ok,那我们知道了,这个驱动会在“dwmcore.dll”、“ gdi32.dll”、“ user32.dll” 上做一些监控。

4.5 DispSetWindowDisplayAffinity

图片描述
继续跟进
图片描述
进入“CreateKernelAndUserDetectThread”,参考图中注释可以看到这个函数在做什么。
图片描述

5.注册通知和回调

里面干了两件事,红框圈出来的部分
图片描述
我们深入进去看下RegisterCallBack
图片描述

6.创建进程通知

图片描述
我们深入进去看一下
图片描述
继续跟进CheckInformationProcess
看到两个关键点,ZwQueryInformationProcess, 查询号为27:ProcessImageFileName,然后也出现了ZwClose,兄弟们懂了吧,如果你有在这款驱动加载的情况下打开某些调试器的经验,那么大概就是这个函数搞的鬼。
图片描述

7.完结。

希望自己在学习分析时候遇到的一些经验和思路能够帮助吧友。


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2022-2-16 10:44 被铜锣湾扛把子编辑 ,原因: 上传缺失图片
收藏
点赞10
打赏
分享
最新回复 (12)
雪    币: 1085
活跃值: (250)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bxb 2022-2-16 15:56
2
0
能分享一下分析文件吗
雪    币: 1556
活跃值: (2087)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
killleer 2022-2-19 23:34
3
0

你们做个人吧。。。

雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_punpkihu 2022-5-12 19:25
4
0
666 大佬也有群吗 
雪    币: 12837
活跃值: (8998)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
hzqst 3 2022-5-12 19:51
5
0
killleer 你们做个人吧。。。
666666 XC3读写.dll准备就绪是吧
雪    币: 1556
活跃值: (2087)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
killleer 2022-5-12 21:59
6
0
hzqst 666666 XC3读写.dll准备就绪是吧

貌似出来N年了不当人了这是,当然第一个里面可能搞了个远控就是了

最后于 2022-5-12 22:01 被killleer编辑 ,原因:
雪    币: 1556
活跃值: (2087)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
killleer 2022-5-12 22:09
7
0
hzqst 666666 XC3读写.dll准备就绪是吧

还有这样的:

雪    币: 14
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovenikola 2022-5-17 02:23
8
0
XIGNCODE3的驱动不是VMP了吗?
雪    币: 234
活跃值: (1763)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
IKAIL 2022-11-9 03:41
9
0
大佬666
雪    币: 1657
活跃值: (4285)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Oxygen1a1 2022-11-9 08:27
10
0
插个眼
雪    币: 4427
活跃值: (3454)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
木志本柯 2023-3-7 16:39
11
0
代码就只有这么点吗  还是说其他的被加vm了?  没有什么干货的检测淫技
雪    币: 1792
活跃值: (5199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
PEDIY 2023-3-8 03:09
12
1

大陆人: 软件、程序、网络、鼠标

台湾人: 軟體、程式、網路、滑鼠

模仿台湾人的大陆人: 软体、网路

为何模仿?因为早期(十五~二十年前)台湾的计算机大牛多的很, 很多资料都是繁体或繁转简的台湾大牛写的资料. 大陆还比较落后(那时的优秀中文PC游戏, 甚至故意找都叫不出一款大陆的. 而台湾开发的作品比比皆是).所以很多大陆人模仿台湾人对上述术语的称呼, 显得学问更高深, 让外行人更看不懂(更有助于装). 但近十年大陆大牛和简体资料也越来越多, 就很少见继续模仿台湾人的大陆人了.

雪    币: 1792
活跃值: (5199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
PEDIY 2023-3-8 03:12
13
0

最后于 2023-3-8 03:12 被PEDIY编辑 ,原因:
游客
登录 | 注册 方可回帖
返回