内核拦截DLL

1
2
3
4
5
6
7
8
9
FAST_MUTEX __AntiLoadDllLock;
PANTI_LOAD_DLL __AntiLoadDll = NULL;
VOID
InitializeAntiLoadDll(
)
{
ExInitializeFastMutex(&__AntiLoadDllLock);
BootReadFile();
}

处理文件信息

首先获取当前工作目录,然后将其与文件名 XXXX.ini 拼接起来,得到文件的路径。接着,使用 Windows API 函数 ZwCreateFile 打开文件,使用 ZwQueryInformationFile 获取文件长度,使用 ExAllocatePool 分配内存缓冲区,再使用 ZwReadFile 读取文件内容。最后,它调用 ParseAntiLoadFile 解析文件内容

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
BOOLEAN
BootReadFile(
)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
UNICODE_STRING v1 = { 0 };
HANDLE FileHandle = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK IoStatusBlock = { 0 };
FILE_STANDARD_INFORMATION FileStandardInfo = { 0 };
LARGE_INTEGER FileLength = { 0 };
LARGE_INTEGER ByteOffset = { 0 };
PVOID VirtualAddress = NULL;
WCHAR* v5 = NULL;
BOOLEAN IsOk = FALSE;

if (!__WorkPath.Length)
{
// 驱动路径
return FALSE;
}

v5 = (PWCHAR)AllocateBuffer(MAX_BYTE);
if (v5 == NULL)
{
return FALSE;
}
// 拼接出ini路径
Status = AppendWorkPath(
v5,
MAX_PATH,
FILE_NAME,
WCHAR_COUNT_BY_ARRAY(FILE_NAME)
);
if (Status != STATUS_SUCCESS)
{
goto Exit;
}
// 最终v5形如"\??\C:\911kisknl64\XXXX.ini"
//双字转换为Unicode
RtlInitUnicodeString(
&v1,
v5);
// 初始化OA
InitializeObjectAttributes(
&ObjectAttributes,
&v1,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);

//打开文件
Status = ZwCreateFile(
&FileHandle,
GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_RANDOM_ACCESS | FILE_COMPLETE_IF_OPLOCKED | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(Status))
{
goto Exit;
}

//计算文件长度
Status = ZwQueryInformationFile(
FileHandle,
&IoStatusBlock,
&FileStandardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
if (!NT_SUCCESS(Status))
{
goto Exit;
}

FileLength = FileStandardInfo.EndOfFile;

if (FileLength.QuadPart > 50 * 1024)
{
goto Exit;
}

// 申请一个非分页内存
VirtualAddress = ExAllocatePool(
NonPagedPool,
(ULONG)FileLength.LowPart + 1);
if (NULL == VirtualAddress)
{
goto Exit;
}

RtlZeroMemory(VirtualAddress, (ULONG)FileLength.LowPart + 1);
Status = ZwReadFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
VirtualAddress,
(ULONG)FileLength.LowPart,
&ByteOffset, //真正读取了多少
NULL
);
if (!NT_SUCCESS(Status))
{
goto Exit;
}
// 读出文件内容,转交ParseAntiLoadFile函数处理
IsOk = ParseAntiLoadFile((LPSTR)VirtualAddress);

Exit:

FreeBuffer(v5);
v5 = NULL;

if (VirtualAddress != NULL)
{
ExFreePool(VirtualAddress);
VirtualAddress = NULL;
}

if (NULL != FileHandle)
{
ZwClose(FileHandle);
FileHandle = NULL;
}

return IsOk;
}

拼接文件路径

将GLOBAL_LINK、__WorkPath.Buffer和Name三者拼接成一个完整的路径,存储在Path变量中,并返回操作的执行状态

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
NTSTATUS AppendWorkPath(
WCHAR* Path,
ULONG PathLength,
WCHAR* Name,
ULONG NameLength)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;

ExAcquireFastMutex(&__WorkPathLock);
if (__WorkPath.Buffer == NULL)
{
ExReleaseFastMutex(&__WorkPathLock);
return Status;
}

do
{
// 将GLOBAL_LINK复制到Path中
Status = RtlStringCchCopyW(Path, PathLength, GLOBAL_LINK);
Path += WCHAR_COUNT_BY_ARRAY(GLOBAL_LINK);
if (!NT_SUCCESS(Status))
break;
// 限制大小 将__WorkPath.Buffer拷贝到Path中
Status = RtlStringCchCopyNW(Path, PathLength, __WorkPath.Buffer, __WorkPath.Length / sizeof(WCHAR));
// 更新path指针位置
Path += __WorkPath.Length / sizeof(WCHAR);
if (!NT_SUCCESS(Status))
break;

// 检查__WorkPath.Buffer末尾是否是'\\'
if (__WorkPath.Buffer[__WorkPath.Length / sizeof(WCHAR) - 1] != L'\\')
{
// 没有,加上
Status = RtlStringCchCopyNW(Path, PathLength, L"\\", 1);
Path++;
if (!NT_SUCCESS(Status))
break;
}
// 将name变量内容也拷贝到Path中
Status = RtlStringCchCopyNW(Path, PathLength, Name, NameLength);
if (!NT_SUCCESS(Status))
break;

Status = STATUS_SUCCESS;
} while (FALSE);

ExReleaseFastMutex(&__WorkPathLock);

return Status;
}

xxxx.ini

1
2
[AntiLoadDll]
Count=2;1=1111;2=2222;

解析对抗DLL加载

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
#define FILE_NAME           L"XXXX.ini"
#define KEY_NAME "[AntiLoadDll]"
#define SUB_KEY_COUNT_NAME "Count="
#define SEPARATE_NAME ";"

typedef struct _ANTI_LOAD_DLL_ENTRY
{
ULONG PathHash;
}ANTI_LOAD_DLL_ENTRY, *PANTI_LOAD_DLL_ENTRY;

typedef struct _ANTI_LOAD_DLL_
{
int Count;
ANTI_LOAD_DLL_ENTRY Entry[1];
}ANTI_LOAD_DLL, * PANTI_LOAD_DLL;

BOOLEAN
ParseAntiLoadFile(
__in PSTR VirtualAddress
)
{
BOOLEAN IsOk = FALSE;
PSTR v1 = NULL;
PSTR v2 = NULL;
CHAR Key[32] = { 0 };
CHAR KeyValue[MAX_PATH] = { 0 };
INT Count = 0;
ULONG ViewSize = 0;
INT i = 0;
ULONG PathHash = 0; // 字符串的Hash值表达
ANSI_STRING v3;
UNICODE_STRING v4;
NTSTATUS Status = STATUS_UNSUCCESSFUL;

if (VirtualAddress == NULL)
{
return IsOk;
}
ExAcquireFastMutex(&__AntiLoadDllLock);
do
{
// 从VirtualAddress查找第一次出现KEY_NAME的位置,返回到v1
// 检查文件头
v1 = strstr(VirtualAddress, KEY_NAME);
if (v1 == NULL)
{
break;
}

// 找到文件开始位置
v1 = strstr(v1, SUB_KEY_COUNT_NAME);
if (v1 == NULL)
{
break;
}

// 移动指针到内容
v1 += strlen(SUB_KEY_COUNT_NAME);
if (v1 == NULL)
{
break;
}

// 指针v2指向第一个分号
v2 = strstr(v1, SEPARATE_NAME);
if (v2 == NULL)
{
break;
}

RtlZeroMemory(Key, sizeof(Key));
RtlZeroMemory(KeyValue, sizeof(KeyValue));
// 按照规则创建一个格式化的字符串 %d
Status = RtlStringCchPrintfA(
Key,
32,
"%d",
DLL_MAX_COUNT
);
if (!NT_SUCCESS(Status))
{
break;
}
//Count = 100,120
if ((v2 <= v1) ||
(v2 - v1 > (int)strlen(Key)))
{
// 指针位置不对
break;
}

// 将v1、v2之间的内容拷贝到KeyValue中,转换成UnicodeString
RtlCopyMemory(KeyValue, v1, v2 - v1);
RtlInitAnsiString(&v3, KeyValue);
Status = RtlAnsiStringToUnicodeString(
&v4,
&v3,
TRUE //动态申请内存
); //单字转换成双字
if (!NT_SUCCESS(Status))
{
break;
}
//转换成Int
Status = RtlUnicodeStringToInteger(
&v4,
0,
(PULONG)&Count
);
// Count中是dll的总数
RtlFreeUnicodeString(&v4);
if (!NT_SUCCESS(Status))
{
break;
}

if ((Count < 0) ||
(Count > DLL_MAX_COUNT))
{
break;
}
// 先释放之前的结构
if (__AntiLoadDll != NULL) //二维指针 [int]【】【】【】【】【】【】
{
FreeBuffer((PVOID)__AntiLoadDll);
__AntiLoadDll = NULL;
}

ViewSize = Count * sizeof(ANTI_LOAD_DLL_ENTRY) + sizeof(int);
__AntiLoadDll = (PANTI_LOAD_DLL)AllocateBuffer(ViewSize);
if (__AntiLoadDll == NULL)
{
break;
}
RtlZeroMemory(__AntiLoadDll, ViewSize);

__AntiLoadDll->Count = Count;
for (i = 0; i < Count; i++)
{
// 遍历所有数量
RtlZeroMemory(Key, sizeof(Key));
// key变为“i=”格式
Status = RtlStringCchPrintfA(
Key,
32,
"%d=",
i + 1
);

//Key[32] "1="
if (!NT_SUCCESS(Status))
{
break;
}
//Count=100, 1= 查找位置
v2 = strstr(v1, Key);
if (v2 == NULL)
{
break;
}
// 移动指针,查找分号位置
v1 = v2;
v2 = strstr(v1, SEPARATE_NAME);
if (v2 == NULL)
{
break;
}
// 移动指针过key
v1 += strlen(Key);
// 验证指针不超过;
if ((v2 <= v1) ||
(v2 - v1 >= DLL_HASH_COUNT))
{
break;
}
// 取出等号后的KeyValue
RtlZeroMemory(KeyValue, sizeof(KeyValue));
RtlCopyMemory(KeyValue, v1, v2 - v1);
RtlInitAnsiString(&v3, KeyValue);
Status = RtlAnsiStringToUnicodeString(
&v4,
&v3,
TRUE
);
if (!NT_SUCCESS(Status))
{
break;
}
// KeyValue即是文件hash,取到结构中
PathHash = 0;
Status = RtlUnicodeStringToInteger(
&v4,
0,
&PathHash
);
RtlFreeUnicodeString(&v4);
if (!NT_SUCCESS(Status) || (PathHash <= 0))
{
break;
}
__AntiLoadDll->Entry[i].PathHash = PathHash;
}

IsOk = TRUE;
} while (FALSE);

ExReleaseFastMutex(&__AntiLoadDllLock);

return IsOk;
}