发表于 2022-2-16 15:32

申请会员ID:Capricornus


1、申请ID:Capricornus
2、个人邮箱:374954038@qq.com
3、原创软件:某韩国游戏驱动保护静态分析

样本介绍:XIGNCODE3 是为大型多人线上游戏所发行的一款游戏反作弊软体,被用于如新枫之谷(南韩版)、战地之王等网路游戏中。XIGNCODE为wellbia所制作。如果哪里写的不好欢迎大佬指正。我大概分析了一下整个驱动的流程部分,下面会依次介绍这个驱动的分析过程和思路,在这个样本里不仅可以学习到很多内核编程的知识,也可以借鉴到一些设计模式上的东西。那么我们直接开始分析,先从入口点开始。1.驱动入口点**在DriverMain中驱动主要做了几件事
①初始化系统版本偏移
②注册通信的分发函数
③设置了通讯函数
④注册通知和回调
⑤创建进程通知https://bbs.pediy.com/upload/attach/202202/924337_SBQCRU3QKQSTXK2.png2.初始化系统版本偏移主要是根据不同的系统版本号初始化一些全局变量,这里不做具体分析了。https://bbs.pediy.com/upload/tmp/924337_YXCAHJWP3AFG9KM.png3.注册通信的分发函数3.1 DisPatchCreate和DisPatchClose的分发默认的分发函数,没什么好说的。https://bbs.pediy.com/upload/attach/202202/924337_FAUHS3YQH23XCHW.png3.2 DispatchWrite函数的分发3.2.1 通讯数据结构的部分分析这里就比较关键了,可以注意到这里丢了两个通讯条件,一个是在通讯函数的头部存放了一个长度值,另一个是sysBuffer的值是一个固定值。
由此我们目前可以确定InputBuffer中的前8个字节0x345821AB00000270
前四个字节是长度,后四个字节是固定标识码,用于确认三环程序的身份。https://bbs.pediy.com/upload/attach/202202/924337_VZT493MVATXBAB2.png3.2.2 FuncCall分析由于在上一小节中我们只知道了InputBuffer的前8个字节,我们直接看到我ida分析过后的代码,可以看到while中的条件判断是在判断FuncIndex,函数编号。https://bbs.pediy.com/upload/attach/202202/924337_QSC28DMSGFMDJ7U.png我们双击FunCallArray进去看看里面是什么,可以看到是标准的8字节排列的对象,由此猜测这很可能是函数数组,那么我怎么确定这个事实,并且也确定FuncIndex就是函数索引的呢?我们继续看下一节“设置函数通讯你列表”https://bbs.pediy.com/upload/attach/202202/924337_SF9QYS6ENV7PE9M.png4.设置通讯函数列表( SetKeyDisFuncArray的分析)我们观察上面的截图,看到第一个140010F88(8字节)和140010F90(4字节)
再看看下方的截图,你发现了什么?
是吧?他就是一个8字节对齐的全局的结构体数组 由此我们可以知道3.2.2小节中FuncCall的命名由来,实际上他在根据索引确定函数的调用。https://bbs.pediy.com/upload/attach/202202/924337_X4K6KFZW3WMEM2N.png接下来我挑几个我觉得比较有意思的函数发一下分析。4.1 ReadProcessMemory
https://bbs.pediy.com/upload/attach/202202/924337_TM2Z2MPSD4CN8QD.png
4.2 DisObSetHandleAttribute可以看到一个附加操作下面,又调用了一个函数,ok,继续跟进去,发现内部调用了“ObSetHandleAttributes”https://bbs.pediy.com/upload/attach/202202/924337_38NCAJPS4BMF4C4.png如果你在逆向分析的时候不了解这种函数是做什么的,打开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一直跟进可以发现是在做一些函数全局变量的初始化。https://bbs.pediy.com/upload/attach/202202/924337_J57R374ZYBG4Z33.png

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; // BYREF
__int64 v26; // BYREF
const void *v27; // BYREF
__int64 v28; // BYREF
__int64 (__fastcall *v29)(_QWORD, _QWORD); // BYREF
__int64 W32pServiceTable2; // BYREF
UNICODE_STRING DestinationString; // BYREF
const void *win32kMemoryModule; // BYREF
__int64 v33; // BYREF
__int64 NtUserGetWindowDisplayAffinity; // BYREF
__int64 NtUserSetWindowDisplayAffinity; // 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 >= 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,
                        (__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,
                        (__int64)win32kMemoryModule,
                        (__int64)W32pServiceTable1,
                        (__int64)win32kModule);
                if ( v23 < 0
                  || (j_DbgPrint_61("resolve NtUserSetWindowDisplayAffinity\n"), v4 >= 0)
                  && (_mm_lfence(),
                      v23 = sub_1400070A4(
                              &v27,
                              v4,
                              (__int64)win32kMemoryModule,
                              (__int64)W32pServiceTable1,
                              (__int64)win32kModule),
                      v23 < 0)
                  || v4 >= 0
                  && (_mm_lfence(),
                      v23 = sub_1400070A4(
                              &v26,
                              v4,
                              (__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”https://bbs.pediy.com/upload/attach/202202/924337_SCJHMBS4T6VS5BD.png
我们继续跟进https://bbs.pediy.com/upload/attach/202202/924337_BH3HTB9XZHBEMVK.png可以发现里面申请了内存,然后把字符串拷贝进去,显然这是在创建需要检测的dll数据。ok,那我们知道了,这个驱动会在“dwmcore.dll”、“ gdi32.dll”、“ user32.dll” 上做一些监控。4.5 DispSetWindowDisplayAffinity
https://bbs.pediy.com/upload/attach/202202/924337_8DU89FRAVC7WHNS.png
继续跟进
https://bbs.pediy.com/upload/attach/202202/924337_V8NPN35GBWCHG45.png
进入“CreateKernelAndUserDetectThread”,参考图中注释可以看到这个函数在做什么。
https://bbs.pediy.com/upload/attach/202202/924337_NMD6VC65TTN4WE8.png
5.注册通知和回调里面干了两件事,红框圈出来的部分https://bbs.pediy.com/upload/attach/202202/924337_GKMMDRB6UKWYMVY.png我们深入进去看下RegisterCallBackhttps://bbs.pediy.com/upload/attach/202202/924337_84JU8AU96RTECKC.png6.创建进程通知
https://bbs.pediy.com/upload/attach/202202/924337_JCU25RPRQQJYDZV.png
我们深入进去看一下
https://bbs.pediy.com/upload/attach/202202/924337_SB3ZCVMFNKKDUAY.png
继续跟进CheckInformationProcess
看到两个关键点,ZwQueryInformationProcess, 查询号为27:ProcessImageFileName,然后也出现了ZwClose,兄弟们懂了吧,如果你有在这款驱动加载的情况下打开某些调试器的经验,那么大概就是这个函数搞的鬼。
https://bbs.pediy.com/upload/attach/202202/924337_2Q3ZGHDBG5N4XWP.png
7.完结。希望自己在学习分析时候遇到的一些经验和思路能够帮助吧友。

Hmily 发表于 2022-2-16 18:11

这复制的乱七八糟啊,你是原作者吗?
页: [1]
查看完整版本: 申请会员ID:Capricornus