进程间通信之alpc

参考:

1,Offensive Windows IPC Internals 3: ALPC · csandker.io

2,GitHub - csandker/InterProcessCommunication-Samples: Some Code Samples for Windows based Inter-Process-Communication (IPC)

***

下面出现的代码都来自参考链接中,非本人编写

***

常见的进程间通信有管道,共享内存等。下面代码演示一种交少见的机制,alpc (advanced local procedure call) 。

文件ALPC.h

#pragma once

#include <Windows.h>
#include <winternl.h>


//
// CONSTANTS
//


// PORT ATTRIBUTE FLAGS
#define ALPC_PORTFLG_NONE 0x0
#define ALPC_PORTFLG_LPCPORT 0x1000 // Only usable in kernel
#define ALPC_PORTFLG_ALLOWIMPERSONATION 0x10000 // Can be set by client to allow server to impersonation this client
#define ALPC_PORTFLG_ALLOW_LPC_REQUESTS 0x20000
#define ALPC_PORTFLG_WAITABLE_PORT 0x40000	// Allow port to be used with synchronization mechanisms like Semaphores
#define ALPC_PORTFLG_SYSTEM_PROCESS 0x100000 // Only usable in kernel
#define ALPC_PORTFLG_ALLOW_DUP_OBJECT 0x80000
#define ALPC_PORTFLG_LRPC_WAKE_POLICY1 0x200000
#define ALPC_PORTFLG_LRPC_WAKE_POLICY2 0x400000
#define ALPC_PORTFLG_LRPC_WAKE_POLICY3 0x800000
#define ALPC_PORTFLG_DIRECT_MESSAGE 0x1000000	// There are 5 queues, Main queue, Direct message queue, Large message queue, Pending queue, Canceled queue... guess this attribute specifies to use the direct message queue instead of main queue

// Uncertain
//#define ALPC_PORTFLG_ACCEPT_INDIRECT_HANDLES (from https://github.com/microsoft/terminal/blob/059f2031583fd22fb7b5f498e4a30196cf3150d4/src/interactivity/onecore/ConIoSrvComm.cpp)
//#define ALPC_PORTFLG_ALLOW_MULTI_HANDLE_ATTRIBUTE 0x2000000


// ERROS
/// just the ones i need to integrate into my code flow
const NTSTATUS STATUS_BUFFER_TOO_SMALL = 0xC0000023;
const NTSTATUS STATUS_PORT_CONNECTION_REFUSED = 0xC0000041;
const NTSTATUS STATUS_ACCESS_DENIED = 0xC0000022;
const NTSTATUS STATUS_SERVER_SID_MISMATCH = 0xC00002A0;

// ALPC Message Attributes
#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000
#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000
#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000
#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000
#define ALPC_MESSAGE_TOKEN_ATTRIBUTE 0x8000000
#define ALPC_MESSAGE_DIRECT_ATTRIBUTE 0x4000000
#define ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE 0x2000000
#define ALPC_MESSAGE_ATTRIBUTE_ALL ALPC_MESSAGE_SECURITY_ATTRIBUTE | ALPC_MESSAGE_VIEW_ATTRIBUTE | ALPC_MESSAGE_CONTEXT_ATTRIBUTE | ALPC_MESSAGE_HANDLE_ATTRIBUTE | ALPC_MESSAGE_TOKEN_ATTRIBUTE | ALPC_MESSAGE_DIRECT_ATTRIBUTE | ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE

// ALPC Message Flags
#define ALPC_MSGFLG_NONE 0x0
#define ALPC_MSGFLG_REPLY_MESSAGE 0x1
#define ALPC_MSGFLG_LPC_MODE 0x2
#define ALPC_MSGFLG_RELEASE_MESSAGE 0x10000
#define ALPC_MSGFLG_SYNC_REQUEST 0x20000		// synchronous message, needs a receive buffer or else error 0xC0000705 is returned
#define ALPC_MSGFLG_WAIT_USER_MODE 0x100000
#define ALPC_MSGFLG_WAIT_ALERTABLE 0x200000
#define ALPC_MSGFLG_WOW64_CALL 0x80000000

// ALPC Connection FLAGS
/// From: https://recon.cx/2008/a/thomas_garnier/LPC-ALPC-paper.pdf
#define ALPC_SYNC_CONNECTION 0x20000 // Synchronous connection request
#define ALPC_USER_WAIT_MODE 0x100000 // Wait in user mode
#define ALPC_WAIT_IS_ALERTABLE 0x200000 // Wait in alertable mode

// 0xc0020000 connection flag causing SF flag to be "1" in nt!AlpcpExposeViewAttribute and therefore calling nt!AlpcpExposeViewAttribute


//
// STRUCTS
//


// Based on https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/blob/main/NtApiDotNet/NtAlpcNative.cs#L82-L97
enum ALPC_MESSAGE_TYPE
{
	None = 0,
	Request = 1,
	Reply = 2,
	Datagram = 3,
	LostReply = 4,
	PortClosed = 5,
	ClientDied = 6,
	Exception = 7,
	DebugEvent = 8,
	ErrorEvent = 9,
	ConnectionRequest = 10,
	ConnectionReply = 11,
	UNKNOWN12 = 12,	// Seems to be something like an empty reply, PID and TID pointing to own thread
	PortDisconnected = 13 // Used by the kernel when disconnecting an exception port.
};
// End Based  ON

typedef struct _ALPC_PORT_ATTRIBUTES
{
    unsigned long Flags;
    SECURITY_QUALITY_OF_SERVICE SecurityQos;
    unsigned __int64 MaxMessageLength;
    unsigned __int64 MemoryBandwidth;
    unsigned __int64 MaxPoolUsage;
    unsigned __int64 MaxSectionSize;
    unsigned __int64 MaxViewSize;
    unsigned __int64 MaxTotalSectionSize;
	ULONG DupObjectTypes;
#ifdef _WIN64
	ULONG Reserved;
#endif
} ALPC_PORT_ATTRIBUTES, * PALPC_PORT_ATTRIBUTES;

typedef struct _ALPC_MESSAGE_ATTRIBUTES
{
	ULONG AllocatedAttributes;
	ULONG ValidAttributes;
} ALPC_MESSAGE_ATTRIBUTES, * PALPC_MESSAGE_ATTRIBUTES;

typedef struct _PORT_MESSAGE
{
	union
	{
		struct
		{
			USHORT DataLength;
			USHORT TotalLength;
		} s1;
		ULONG Length;
	} u1;
	union
	{
		struct
		{
			USHORT Type;
			USHORT DataInfoOffset;
		} s2;
		ULONG ZeroInit;
	} u2;
	union
	{
		CLIENT_ID ClientId;
		double DoNotUseThisField;
	};
	ULONG MessageId;
	union
	{
		SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages
		ULONG CallbackId; // only valid for LPC_REQUEST messages
	};
} PORT_MESSAGE, * PPORT_MESSAGE;


// FROM https://docs.rs/ntapi/0.3.6/ntapi/ntlpcapi/struct.ALPC_HANDLE_ATTR.html
typedef struct _ALPC_DATA_VIEW_ATTR {
	ULONG Flags;
	HANDLE SectionHandle;
	PVOID ViewBase;
	SIZE_T ViewSize;
} ALPC_DATA_VIEW_ATTR, * PALPC_DATA_VIEW_ATTR;

typedef struct _ALPC_TOKEN_ATTR
{
	ULONGLONG TokenId;
	ULONGLONG AuthenticationId;
	ULONGLONG ModifiedId;
} ALPC_TOKEN_ATTR, * PALPC_TOKEN_ATTR;

typedef struct _AlpcPortContext {
	HANDLE Handle;
} AlpcPortContext, * PAlpcPortContext;

typedef struct _ALPC_CONTEXT_ATTR {
	PVOID PortContext;
	PVOID MessageContext;
	ULONG Sequence;
	ULONG MessageId;
	ULONG CallbackId;
} ALPC_CONTEXT_ATTR, * PALPC_CONTEXT_ATTR;

typedef struct _ALPC_SECURITY_ATTR {
	ULONG Flags;
	PSECURITY_QUALITY_OF_SERVICE pQOS;
	HANDLE ContextHandle;
} ALPC_SECURITY_ATTR, * PALPC_SECURITY_ATTR;


typedef struct _SECURITY_CLIENT_CONTEXT
{
	SECURITY_QUALITY_OF_SERVICE SecurityQos;	//_KALPC_SECURITY_DATA
	LPVOID ClientToken;
	UCHAR DirectlyAccessClientToken;
	UCHAR DirectAccessEffectiveOnly;
	UCHAR ServerIsRemote;
	_TOKEN_CONTROL ClientTokenControl;
} SECURITY_CLIENT_CONTEXT, * PSECURITY_CLIENT_CONTEXT;

// From https://github.com/hakril/PythonForWindows/blob/3149961634cda0029a288e6ffa7779e4492adb13/ctypes_generation/definitions/structures/alpc.txt
typedef struct _ALPC_DIRECT_ATTR
{
	HANDLE Event;
} ALPC_DIRECT_ATTR, * PALPC_DIRECT_ATTR;

typedef struct _ALPC_WORK_ON_BEHALF_ATTR
{
	ULONGLONG Ticket;
} ALPC_WORK_ON_BEHALF_ATTR, * PALPC_WORK_ON_BEHALF_ATTR;

typedef struct _ALPC_HANDLE_ATTR
{
	ULONG Flags;
	HANDLE Handle;
	ULONG ObjectType;
	ACCESS_MASK DesiredAccess;
} ALPC_HANDLE_ATTR, * PALPC_HANDLE_ATTR;

typedef struct _ALPC_HANDLE_ENTRY {
	LPVOID Object;
};

typedef struct _PORT_VIEW
{
	ULONG Length;
	HANDLE SectionHandle;
	ULONG SectionOffset;
	SIZE_T ViewSize;
	PVOID ViewBase;
	PVOID ViewRemoteBase;
} PORT_VIEW, * PPORT_VIEW;

typedef enum _ALPC_PORT_INFORMATION_CLASS
{
	AlpcBasicInformation, // q: out ALPC_BASIC_INFORMATION
	AlpcPortInformation, // s: in ALPC_PORT_ATTRIBUTES
	AlpcAssociateCompletionPortInformation, // s: in ALPC_PORT_ASSOCIATE_COMPLETION_PORT
	AlpcConnectedSIDInformation, // q: in SID
	AlpcServerInformation, // q: inout ALPC_SERVER_INFORMATION
	AlpcMessageZoneInformation, // s: in ALPC_PORT_MESSAGE_ZONE_INFORMATION
	AlpcRegisterCompletionListInformation, // s: in ALPC_PORT_COMPLETION_LIST_INFORMATION
	AlpcUnregisterCompletionListInformation, // s: VOID
	AlpcAdjustCompletionListConcurrencyCountInformation, // s: in ULONG
	AlpcRegisterCallbackInformation, // kernel-mode only
	AlpcCompletionListRundownInformation, // s: VOID
	AlpcWaitForPortReferences
} ALPC_PORT_INFORMATION_CLASS;

typedef struct _ALPC_SERVER_INFORMATION
{
	union
	{
		struct
		{
			HANDLE ThreadHandle;
		} In;
		struct
		{
			BOOLEAN ThreadBlocked;
			HANDLE ConnectedProcessId;
			UNICODE_STRING ConnectionPortName;
		} Out;
	};
} ALPC_SERVER_INFORMATION, * PALPC_SERVER_INFORMATION;

typedef struct _ALPC_BASIC_INFORMATION
{
	ULONG Flags;
	ULONG SequenceNo;
	PVOID PortContext;
} ALPC_BASIC_INFORMATION, * PALPC_BASIC_INFORMATION;

typedef enum _ALPC_MESSAGE_INFORMATION_CLASS {
	AlpcMessageSidInformation, // out PSID
	AlpcMessageTokenModifiedIdInformation,  // q: out LUID
	AlpcMessageDirectStatusInformation,
	AlpcMessageHandleInformation, // ALPC_MESSAGE_HANDLE_INFORMATION
	MaxAlpcMessageInfoClass
} ALPC_MESSAGE_INFORMATION_CLASS, * PALPC_MESSAGE_INFORMATION_CLASS;

typedef struct _ALPC_MESSAGE_HANDLE_INFORMATION {
	ULONG Index;
	ULONG Flags;
	ULONG Handle;
	ULONG ObjectType;
	ACCESS_MASK GrantedAccess;
} ALPC_MESSAGE_HANDLE_INFORMATION, * PALPC_MESSAGE_HANDLE_INFORMATION;


//
// FUNCTIONS
//


EXTERN_C
LPVOID NTAPI AlpcGetMessageAttribute(
	_In_ PALPC_MESSAGE_ATTRIBUTES Buffer,
	_In_ ULONG AttributeFlag
);

EXTERN_C
NTSTATUS NTAPI AlpcInitializeMessageAttribute(
	_In_ ULONG AttributeFlags,
	_Out_opt_ PALPC_MESSAGE_ATTRIBUTES Buffer,
	_In_ SIZE_T BufferSize,
	_Out_ PSIZE_T RequiredBufferSize
);

EXTERN_C
NTSTATUS NTAPI NtAlpcCreatePort(
	_Out_ PHANDLE PortHandle,
	_In_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes
);

EXTERN_C
NTSTATUS NTAPI NtAlpcConnectPort(
	_Out_ PHANDLE PortHandle,
	_In_ PUNICODE_STRING PortName,
	_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,
	_In_ DWORD ConnectionFlags,
	_In_opt_ PSID RequiredServerSid,
	_In_opt_ PPORT_MESSAGE ConnectionMessage,
	_Inout_opt_ PSIZE_T ConnectMessageSize,
	_In_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,
	_In_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,
	_In_opt_ PLARGE_INTEGER Timeout
);

EXTERN_C
NTSTATUS NTAPI NtAlpcSendWaitReceivePort(
    _In_ HANDLE PortHandle,
    _In_ DWORD Flags,
    _In_opt_ PPORT_MESSAGE SendMessage_,
    _In_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
    _Inout_opt_ PPORT_MESSAGE ReceiveMessage,
    _Inout_opt_ PSIZE_T BufferLength,
    _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
    _In_opt_ PLARGE_INTEGER Timeout
);

EXTERN_C
NTSTATUS NTAPI NtAlpcAcceptConnectPort(
	_Out_ PHANDLE PortHandle,
	_In_ HANDLE ConnectionPortHandle,
	_In_ DWORD Flags,
	_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes,
	_In_opt_ PVOID PortContext,
	_In_ PPORT_MESSAGE ConnectionRequest,
	_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,
	_In_ BOOLEAN AcceptConnection
);

EXTERN_C
SIZE_T NTAPI AlpcGetHeaderSize(
	ULONG TypeFlag
);

EXTERN_C
NTSTATUS NTAPI NtAlpcImpersonateClientOfPort(
	_In_ HANDLE         PortHandle,
	_In_ PPORT_MESSAGE  PortMessage,
	_Reserved_ PVOID    Reserved
);

EXTERN_C
NTSTATUS NTAPI NtAlpcImpersonateClientContainerOfPort(
	_In_ HANDLE PortHandle,
	_In_ PPORT_MESSAGE Message,
	_In_ ULONG Flags
);

EXTERN_C
NTSTATUS NTAPI NtAlpcDisconnectPort(
	_In_ HANDLE PortHandle,
	_In_ ULONG Flags
);

EXTERN_C
NTSTATUS NTAPI NtAlpcCreatePortSection(
	_In_ HANDLE PortHandle,
	_In_ ULONG Flags,
	_In_opt_ HANDLE SectionHandle,
	_In_ SIZE_T SectionSize,
	_Out_ PHANDLE AlpcSectionHandle,
	_Out_ PSIZE_T ActualSectionSize
);
EXTERN_C
NTSTATUS NTAPI NtAlpcCreateSectionView(
	_In_ HANDLE PortHandle,
	_Reserved_ ULONG Flags,
	_Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes
);
EXTERN_C
ULONG NTAPI AlpcMaxAllowedMessageLength();

EXTERN_C
NTSTATUS NTAPI NtAlpcQueryInformationMessage(
	_In_ HANDLE PortHandle,
	_In_ PPORT_MESSAGE PortMessage,
	_In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass,
	__out_bcount(Length) PVOID MessageInformation,
	_In_ SIZE_T Length,
	_Out_opt_ PSIZE_T ReturnLength
);

// From https://processhacker.sourceforge.io/doc/ntlpcapi_8h.html#a1c4ea76677db393f9bb13baabdcb242a
EXTERN_C
NTSTATUS NTAPI NtAlpcCreateSecurityContext(
	_In_ HANDLE  	PortHandle,
	_Reserved_ ULONG  	Flags,
	_Inout_ PALPC_SECURITY_ATTR  	SecurityAttribute
);

//EXTERN_C
//NTSTATUS NTAPI NtAlpcOpenSenderThread(
//	_Out_ PHANDLE ThreadHandle,
//	_In_ HANDLE PortHandle,
//	_In_ PPORT_MESSAGE PortMessage,
//	_In_ ULONG Flags,
//	_In_ ACCESS_MASK DesiredAccess,
//	_In_ POBJECT_ATTRIBUTES ObjectAttributes
//);


//
// CUSTOM Additions for my specific ALPC serer
//


typedef struct _CS_PORT_CONTEXT {
	ULONG PID;
	ULONG TID;
	ULONG ID;
} CS_PORT_CONTEXT, * PCS_PORT_CONTEXT;


typedef struct _ALPC_MESSAGE {
	PORT_MESSAGE PortHeader;
	BYTE PortMessage[1000]; // Hard limit for this is 65488. An Error is thrown if AlpcMaxAllowedMessageLength() is exceeded
} ALPC_MESSAGE, * PALPC_MESSAGE;


//
// OTHER Stuff
//


//typedef struct _PH_TOKEN_ATTRIBUTES
//{
//	HANDLE TokenHandle;
//	struct
//	{
//		ULONG Elevated : 1;
//		ULONG ElevationType : 2;
//		ULONG ReservedBits : 29;
//	};
//	ULONG Reserved;
//	PSID TokenSid;
//} PH_TOKEN_ATTRIBUTES, * PPH_TOKEN_ATTRIBUTES;


//0x4 bytes (sizeof)
struct _EX_PUSH_LOCK
{
	union
	{
		struct
		{
			ULONG Locked : 1;                                                 //0x0
			ULONG Waiting : 1;                                                //0x0
			ULONG Waking : 1;                                                 //0x0
			ULONG MultipleShared : 1;                                         //0x0
			ULONG Shared : 28;                                                //0x0
		};
		ULONG Value;                                                        //0x0
		PVOID Ptr;                                                          //0x0
	};
};

typedef struct _ALPC_HANDLE_TABLE{
	_ALPC_HANDLE_ENTRY Handles;
	UINT TotalHandles;
	UINT Flags;
	_EX_PUSH_LOCK Lock;
} ALPC_HANDLE_TABLE, * PALPC_HANDLE_TABLE;


//typedef struct _EPROCESS* PEPROCESS;
typedef struct _KALPC_SECURITY_DATA
{
	PALPC_HANDLE_TABLE HandleTable;	//_KALPC_SECURITY_DATA
	LPVOID ContextHandle;
	LPVOID OwningProcess;
	LPVOID OwnerPort;
	_SECURITY_CLIENT_CONTEXT DynamicSecurity;
} KALPC_SECURITY_DATA, * PKALPC_SECURITY_DATA;

文件CommandALPC.cpp

//#include<iostream>
#include<stdio.h>
#include<windows.h>
#include <sddl.h>

#include <AclAPI.h>

#include"ALPC.h"

// This could also be defined in the project properties, but i wanted to ensure everyone spots that you need to link against those libs
#pragma comment( lib, "ntdll" )
#pragma comment( lib, "User32" )

typedef struct _csTOKEN {
	LPWSTR pwsUSERSID;
	TOKEN_TYPE TokenType;
	LPWSTR pwsTokenType;
	LPWSTR pwsTokenImpersonationLevel;
} CSTOKEN, * PCSTOKEN;

BOOL EnablePriv(HANDLE hToken, LPCTSTR priv)
{
	TOKEN_PRIVILEGES tp;
	LUID luid;

	if (!LookupPrivilegeValue(NULL, priv, &luid))
	{
		printf("Priv Lookup FALSE\n");
		return FALSE;
	}

	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if (!AdjustTokenPrivileges(
		hToken,
		FALSE,
		&tp,
		sizeof(TOKEN_PRIVILEGES),
		(PTOKEN_PRIVILEGES)NULL,
		(PDWORD)NULL))
	{
		printf("Priv Adjust FALSE\n");
		return FALSE;
	}

	return TRUE;
}

BOOL printTokenType(HANDLE hToken, PCSTOKEN pCSToken) {
	PTOKEN_TYPE ptt = NULL;
	DWORD dwSize = 0;
	pCSToken->pwsTokenType = (LPWSTR)L"";
	if (!GetTokenInformation(hToken, TokenType, NULL, 0, &dwSize)
		&& ERROR_INSUFFICIENT_BUFFER != GetLastError())
	{
		return FALSE;
	}
	if (NULL != (ptt = (PTOKEN_TYPE)LocalAlloc(LPTR, dwSize)))
	{
		if (!GetTokenInformation(hToken, TokenType, ptt, dwSize, &dwSize))
		{
			LocalFree((HLOCAL)ptt);
			return FALSE;
		}
		pCSToken->TokenType = (TOKEN_TYPE)*ptt;
		switch (pCSToken->TokenType)
		{
		case TokenImpersonation:
			pCSToken->pwsTokenType = (LPWSTR)L"ImpersonationToken";
			return TRUE;
		case TokenPrimary:
			pCSToken->pwsTokenType = (LPWSTR)L"PrimaryToken";
			return TRUE;
		default:
			wprintf(L"[-] Undefined Token Type. \n");
			return FALSE;
		}

		LocalFree((HLOCAL)ptt);
	}
	return FALSE;
}

BOOL printTokenImpersonationLeven(HANDLE hToken, PCSTOKEN pCSToken) {
	PSECURITY_IMPERSONATION_LEVEL psil = NULL;
	DWORD dwSize = 0;
	pCSToken->pwsTokenImpersonationLevel = (LPWSTR)L"";
	if (!GetTokenInformation(hToken, TokenImpersonationLevel, NULL, 0, &dwSize)
		&& ERROR_INSUFFICIENT_BUFFER != GetLastError())
	{
		return FALSE;
	}
	if (NULL != (psil = (PSECURITY_IMPERSONATION_LEVEL)LocalAlloc(LPTR, dwSize)))
	{
		if (!GetTokenInformation(hToken, TokenImpersonationLevel, psil, dwSize, &dwSize))
		{
			LocalFree((HLOCAL)psil);
			return FALSE;
		}
		switch (*psil)
		{
		case SecurityAnonymous:
			pCSToken->pwsTokenImpersonationLevel = (LPWSTR)L"SecurityAnonymous";
			return TRUE;
		case SecurityIdentification:
			pCSToken->pwsTokenImpersonationLevel = (LPWSTR)L"SecurityIdentification";
			return TRUE;
		case SecurityImpersonation:
			pCSToken->pwsTokenImpersonationLevel = (LPWSTR)L"SecurityImpersonation";
			return TRUE;
		case SecurityDelegation:
			pCSToken->pwsTokenImpersonationLevel = (LPWSTR)L"SecurityDelegation";
			return TRUE;
		default:
			wprintf(L"[-] Undefined Impersonation Level. \n");
			return FALSE;
		}
		LocalFree((HLOCAL)psil);
	}
	return FALSE;
}

BOOL printTokenUserSid(HANDLE hToken, PCSTOKEN pCSToken)
{
	PTOKEN_USER ptu = NULL;
	DWORD dwSize = 0;
	pCSToken->pwsUSERSID = (LPWSTR)L"";
	if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize)
		&& ERROR_INSUFFICIENT_BUFFER != GetLastError())
	{
		return FALSE;
	}
	if (NULL != (ptu = (PTOKEN_USER)LocalAlloc(LPTR, dwSize)))
	{
		LPWSTR StringSid = NULL;
		if (!GetTokenInformation(hToken, TokenUser, ptu, dwSize, &dwSize))
		{
			LocalFree((HLOCAL)ptu);
			return FALSE;
		}
		if (ConvertSidToStringSidW(ptu->User.Sid, &StringSid))
		{
			pCSToken->pwsUSERSID = StringSid;

			//LocalFree((HLOCAL)StringSid);
			LocalFree((HLOCAL)ptu);
			return TRUE;
		}
		else {
			wprintf(L"[-] Failed to resolve SID to string.\n");
			return FALSE;
		}
		LocalFree((HLOCAL)ptu);
	}
	return FALSE;
}


void ExtractTokenInformation(HANDLE hToken) {
	BOOL result;
	PCSTOKEN pCSToken = new CSTOKEN;
	// Get UserSID
	result = printTokenUserSid(hToken, pCSToken);
	if (!result) wprintf(L" [-]... failed to get Token SID\n");
	else wprintf(L" [+] UserSID: %s\n", pCSToken->pwsUSERSID);
	// GET TokenType
	result = printTokenType(hToken, pCSToken);
	if (!result) wprintf(L" [-]... failed to get Token Type\n");
	else wprintf(L" [+] TokenType: %s\n", pCSToken->pwsTokenType);
	if (pCSToken->TokenType == TokenImpersonation) {
		// GET TokenImpersonationLevel
		result = printTokenImpersonationLeven(hToken, pCSToken);
		if (!result) wprintf(L" [-]... failed to get Token Type\n");
		else wprintf(L" [+] ImpersonationLevel: %s\n", pCSToken->pwsTokenImpersonationLevel);
	}

	if (pCSToken->pwsUSERSID)
	{
		LocalFree((HLOCAL)pCSToken->pwsUSERSID);
	}
}

void setWindowAccess() {
	DWORD error;
	wprintf(L"[*] Gettinng current process Window...");
	HWINSTA hWinSta = GetProcessWindowStation();
	if (hWinSta) {
		wprintf(L"Success.\n");
		wprintf(L"[*] Setting Security of current Proccess Window...");
		error = SetSecurityInfo(hWinSta,
			SE_WINDOW_OBJECT,
			DACL_SECURITY_INFORMATION,
			NULL,	// don't set the ownerSID
			NULL,	// don't set the primary GROUP
			NULL,	// DACL pointer, NULL=> full access to everyone
			NULL	// no setting SACL
		);
		if (error == ERROR_SUCCESS) wprintf(L"Success.\n");
		else wprintf(L"Error: %d.\n", error);
	}
	else wprintf(L"Error: %d.\n", GetLastError());
}

void setDesktopAccess() {
	DWORD error;
	wprintf(L"[*] Getting current Desktop..");
	HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
	if (hDesk) {
		wprintf(L"Success\n");
		wprintf(L"[*] Setting Security of current Desktop...");
		error = SetSecurityInfo(
			hDesk,
			SE_WINDOW_OBJECT,
			DACL_SECURITY_INFORMATION,
			NULL,	// don't set the ownerSID
			NULL,	// don't set the primary GROUP
			NULL,	// DACL pointer, NULL=> full access to everyone
			NULL	// no setting SACL
		);
		if (error == ERROR_SUCCESS) wprintf(L"Success\n");
		else wprintf(L"Error: %d\n", error);
	}
	else wprintf(L"Error: %d\n", GetLastError());
}

BOOL execCommand(HANDLE hDuppedToken, LPCWSTR command) {
	// -- Execute Process
	BOOL bSuccess;
	PROCESS_INFORMATION pi;
	STARTUPINFOW si;
	//SECURITY_ATTRIBUTES sa;
	ZeroMemory(&si, sizeof(STARTUPINFO));
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
	//memset(&pi, 0x00, sizeof(PROCESS_INFORMATION));
	si.cb = sizeof(STARTUPINFO);
	wprintf(L"[*] Trying to launch '%s' with CreateProcessWithTokenW ... ", command);
	/*
	创建新进程及其主线程。 新进程在指定令牌的安全上下文中运行。 它可以选择性地加载指定用户的用户配置文件。

    调用 CreateProcessWithTokenW 的进程必须具有SE_IMPERSONATE_NAME特权。
	如果此函数失败并出现 ERROR_PRIVILEGE_NOT_HELD (1314) ,请改用 CreateProcessAsUser 或 CreateProcessWithLogonW 函数。
	通常,调用的进程CreateProcessAsUser 必须具有SE_INCREASE_QUOTA_NAME特权,并且如果令牌不可分配,
	则可能需要SE_ASSIGNPRIMARYTOKEN_NAME特权。 CreateProcessWithLogonW 不需要特殊权限,但必须允许指定的用户帐户以交互方式登录。 
	通常,最好使用 CreateProcessWithLogonW 创建具有备用凭据的进程。
	*/
	bSuccess = CreateProcessWithTokenW(
		hDuppedToken,
		0,
		command,
		NULL,
		CREATE_NEW_CONSOLE,
		NULL,
		NULL,
		&si,
		&pi
	);
	if (!bSuccess) {
		wprintf(L"failed (Error: %d).\n", GetLastError());
	}
	else wprintf(L"Success.\n");
	return bSuccess;
}

BOOL execImpersonatedWindowCommand(HANDLE hPort, ALPC_MESSAGE pmReceived, LPCWSTR command) {
	BOOL bSuccess;
	HANDLE hToken, hDuppedToken;
	//HANDLE hDuppedToken = INVALID_HANDLE_VALUE;

	wprintf(L"[*] Trying to impersonate client...");
	NTSTATUS lSuccess = NtAlpcImpersonateClientOfPort(
		hPort, // client connection port
		(PPORT_MESSAGE)&pmReceived,//&PortMessage,	// the port messages
		NULL			// reserved
	);
	if (NT_SUCCESS(lSuccess)) {
		wprintf(L"Success.\n");
		wprintf(L"[*] Trying to open Thread token...");
		bSuccess = OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken);
		if (bSuccess) {
			wprintf(L"Success.\n");
			ExtractTokenInformation(hToken);

			// Duplicate Token
			wprintf(L"[*] Trying to duplicate impersonated token...");
			bSuccess = DuplicateTokenEx(hToken,
				TOKEN_ALL_ACCESS,
				NULL,
				SecurityImpersonation,
				TokenPrimary,
				&hDuppedToken);
			if (bSuccess) wprintf(L"Success!\n");
			else wprintf(L"Error: %d.\n", GetLastError());
			ExtractTokenInformation(hDuppedToken);

			// -- Revert back to original thread identity 
			wprintf(L"Reverting back to self...");
			bSuccess = RevertToSelf();
			if (!bSuccess)
			{
				wprintf(L"Failed to revert back from RPC client impersonation to server identity. Error 0x%x.\n", GetLastError());
			}
			else printf("Success.\n");

			bSuccess = execCommand(hDuppedToken, command);
			// Close Handles
			CloseHandle(hToken);
			CloseHandle(hDuppedToken);
		}
		else {
			wprintf(L"Error: %d\n", GetLastError());
			bSuccess = false;
		}
	}
	else if (lSuccess == STATUS_ACCESS_DENIED) {
		wprintf(L"Access Denied! (Error: 0x%X) Maybe the ALPC_PORTFLG_AllowImpersonation was not set?\n", lSuccess);
		bSuccess = false;
	}
	else {
		wprintf(L"Error: 0x%X\n", lSuccess);
		bSuccess = false;
	}
	return bSuccess;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ALPC_MESSAGE_TYPE get_message_type(ULONG ulType) {
	ULONG ulConverted = ulType & 0xFF;
	return ALPC_MESSAGE_TYPE(ulConverted);
}

LPCWSTR message_type_to_sz(ULONG ulType) {
	ALPC_MESSAGE_TYPE mType = get_message_type(ulType);
	switch (mType)
	{
	case None:   return L"None";
	case Request:   return L"Request";
	case Reply: return L"Reply";
	case Datagram: return L"Datagram";
	case LostReply: return L"LostReply";
	case PortClosed: return L"PortClosed";
	case ClientDied: return L"ClientDied";
	case Exception: return L"Exception";
	case DebugEvent: return L"DebugEvent";
	case ErrorEvent: return L"ErrorEvent";
	case ConnectionRequest: return L"ConnectionRequest";
	case ConnectionReply: return L"ConnectionReply";
	case UNKNOWN12: return L"UNKNOWN12";
	case PortDisconnected: return L"PortDisconnected";
	default:      return L"Unknown";
	}
}

VOID print_port_message(ALPC_MESSAGE portMessage) {
	for (int i = 0; i <= portMessage.PortHeader.u1.s1.DataLength; i++) {
		BYTE* pbyReadPointer = (BYTE*)portMessage.PortMessage + i;
		BYTE byRead = *pbyReadPointer;
		printf("%c", byRead);
	}
	wprintf(L"\n");
}

VOID print_clientSID_from_alpc_message(HANDLE hConnectionPort, PPORT_MESSAGE pPortMessage) {
	NTSTATUS lSuccess;
	LPVOID pAlloced;
	SIZE_T ulRequiredSize;
	SIZE_T ulAllocedSize = 0x1c;
	// Allow memory for SID
	pAlloced = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulAllocedSize);

	lSuccess = NtAlpcQueryInformationMessage(
		hConnectionPort,
		pPortMessage,
		ALPC_MESSAGE_INFORMATION_CLASS::AlpcMessageSidInformation,
		pAlloced,
		ulAllocedSize,
		&ulRequiredSize
	);
	if (NT_SUCCESS(lSuccess)) {
		PSID pSID = (PSID)pAlloced;
		LPWSTR szSID;
		ConvertSidToStringSidW(
			pSID,
			&szSID
		);
		wprintf(L"%s\n", szSID);
	}
}

NTSTATUS impersonate_client(HANDLE hPort, ALPC_MESSAGE pmReceived) {
	BOOL bSuccess;

	// usually not needed for local impersonation
	/*setWindowAccess();
	setDesktopAccess();*/

	wchar_t command[] = L"C:\\Windows\\System32\\cmd.exe";
	bSuccess = execImpersonatedWindowCommand(hPort, pmReceived, command);
	return bSuccess;
}

VOID add_request_message(PALPC_MESSAGE pMessage, LPCSTR messageContent) {
	 Add a message
	//LPVOID lpPortMessage = &(pMessage.PortMessage);
	int lMsgLen = wcslen(messageContent);
	//char msg[100] = "Hello Client";
	//int lMsgLen = strlen(msg);

	//memmove(lpPortMessage, msg, lMsgLen);
	//pMessage.PortHeader.u1.s1.DataLength = lMsgLen;
	//pMessage.PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + lMsgLen;
	pMessage.PortHeader.u1.s1.TotalLength = sizeof(pMessage);


	LPVOID lpPortMessage = pMessage->PortMessage;
	//char msg[100] = "Hello Client";
	//int lMsgLen = strlen(msg);
	int lMsgLen = strlen(messageContent);
	memmove(lpPortMessage, messageContent, lMsgLen);
	pMessage->PortHeader.u1.s1.DataLength = lMsgLen;
	pMessage->PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + lMsgLen;
}

VOID print_received_alpc_message(ALPC_MESSAGE pmReceived, HANDLE hAlpcPort, BOOL printRequestingSID) {
	TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pmReceived.PortHeader.ClientId.UniqueProcess);

	//GetProcessImageFileName(hProcess, szProcessName, MAX_PATH);

	// PROCESS CONNECTION
	wprintf(L"[+] Received data!\n\tFom Process PID: %d (Thead TID: %d) [Process: %s]\n\tType: %s\n\tConnectionMessage Length: %d\n",
		pmReceived.PortHeader.ClientId.UniqueProcess,
		pmReceived.PortHeader.ClientId.UniqueThread,
		szProcessName,
		message_type_to_sz(pmReceived.PortHeader.u2.s2.Type),
		pmReceived.PortHeader.u1.s1.DataLength
	);
	if (pmReceived.PortHeader.u1.s1.DataLength > 0) {
		wprintf(L"\tConnecting Message: ");
		print_port_message(pmReceived);
	}
	else { wprintf(L"\n"); }
	if (printRequestingSID) {
		wprintf(L"\tClient SID: ");
		print_clientSID_from_alpc_message(hAlpcPort, (PPORT_MESSAGE)&pmReceived);
	}
}


typedef enum _POOL_TYPE
{
	NonPagedPool,
	PagedPool,
	NonPagedPoolMustSucceed,
	DontUseThisType,
	NonPagedPoolCacheAligned,
	PagedPoolCacheAligned,
	NonPagedPoolCacheAlignedMustS
} POOL_TYPE, * PPOOL_TYPE;

typedef struct _OBJECT_TYPE_INFORMATION
{
	UNICODE_STRING Name;
	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 ValidAccess;
	BOOLEAN SecurityRequired;
	BOOLEAN MaintainHandleCount;
	USHORT MaintainTypeList;
	POOL_TYPE PoolType;
	ULONG PagedPoolUsage;
	ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_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;

VOID print_valid_message_attribues(PALPC_MESSAGE_ATTRIBUTES pMsgAttr, BOOL bIsServer = FALSE) {
	int iFoundFlags = 0;
	wprintf(L"[*] Valid Message Attributes:\n");
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_TOKEN_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_TOKEN_ATTRIBUTE\n");
		ALPC_TOKEN_ATTR tokenAttr = *(PALPC_TOKEN_ATTR)AlpcGetMessageAttribute(pMsgAttr, ALPC_MESSAGE_TOKEN_ATTRIBUTE);
		wprintf(L"\t  TokenId: %lu -- AuthenticationId: %lu -- ModifiedId: %lu \n", tokenAttr.TokenId, tokenAttr.AuthenticationId, tokenAttr.ModifiedId);
		iFoundFlags += ALPC_MESSAGE_TOKEN_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_SECURITY_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_SECURITY_ATTRIBUTE\n");
		ALPC_SECURITY_ATTR securitAttr = *(PALPC_SECURITY_ATTR)AlpcGetMessageAttribute(pMsgAttr, ALPC_MESSAGE_SECURITY_ATTRIBUTE);
		iFoundFlags += ALPC_MESSAGE_SECURITY_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_CONTEXT_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_CONTEXT_ATTRIBUTE\n");
		if(  bIsServer ){
			ALPC_CONTEXT_ATTR contextAttr = *(PALPC_CONTEXT_ATTR)AlpcGetMessageAttribute(pMsgAttr, ALPC_MESSAGE_CONTEXT_ATTRIBUTE);
			CS_PORT_CONTEXT csPortContext = *(PCS_PORT_CONTEXT)contextAttr.PortContext;
			wprintf(L"\t  Caller ID: %d\n", csPortContext.ID);
		}
		iFoundFlags += ALPC_MESSAGE_CONTEXT_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_VIEW_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_VIEW_ATTRIBUTE\n");
		ALPC_DATA_VIEW_ATTR viewAttr = *(PALPC_DATA_VIEW_ATTR)AlpcGetMessageAttribute(pMsgAttr, ALPC_MESSAGE_VIEW_ATTRIBUTE);
		wprintf(L"\t ViewSize: %d\n", viewAttr.ViewSize);
		iFoundFlags += ALPC_MESSAGE_VIEW_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_HANDLE_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_HANDLE_ATTRIBUTE\n");
		ALPC_HANDLE_ATTR handleAttr = *(PALPC_HANDLE_ATTR)AlpcGetMessageAttribute(pMsgAttr, ALPC_MESSAGE_HANDLE_ATTRIBUTE);
		// We could Query the object type like this, code snippet taken from: https://github.com/SinaKarvandi/Process-Magics/blob/master/EnumAllHandles/EnumAllHandles/EnumAllHandles.cpp
		//POBJECT_TYPE_INFORMATION OBJECT_TYPE;
		//ULONG GuessSize = 256;
		//ULONG ulRequiredSize;
		 Allocate Memory
		//OBJECT_TYPE = (POBJECT_TYPE_INFORMATION)VirtualAlloc(NULL, (SIZE_T)GuessSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
		//NTSTATUS lSuccess = NtQueryObject(handleAttr.Handle, ObjectTypeInformation, OBJECT_TYPE, GuessSize, &ulRequiredSize);
		// We could read the file like this
		//LPVOID lpAllocTest = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
		//BOOL success = ReadFile(handleAttr.Handle, lpAllocTest, 10, NULL, NULL);
		
		iFoundFlags += ALPC_MESSAGE_HANDLE_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_DIRECT_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_DIRECT_ATTRIBUTE\n");
		iFoundFlags += ALPC_MESSAGE_DIRECT_ATTRIBUTE;
	}
	if (pMsgAttr->ValidAttributes & ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE) {
		wprintf(L"\tALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE\n");
		iFoundFlags += ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE;
	}
	if (iFoundFlags != pMsgAttr->ValidAttributes) {
		wprintf(L"\t 0x%X Unkwon Message Attribute(s)\n", pMsgAttr->ValidAttributes - iFoundFlags);
	}
}

VOID print_port_flags(ULONG ulPortAttributeFlags) {
	int iFoundFlags = 0;
	wprintf(L"[*] Valid Message Attributes: ");
	if (ALPC_PORTFLG_LPCPORT & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_LPCPORT  | ");
		iFoundFlags += ALPC_PORTFLG_LPCPORT;
	}
	if (ALPC_PORTFLG_ALLOWIMPERSONATION & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_ALLOWIMPERSONATION | ");
		iFoundFlags += ALPC_PORTFLG_ALLOWIMPERSONATION;
	}
	if (ALPC_PORTFLG_ALLOW_LPC_REQUESTS & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_ALLOW_LPC_REQUESTS | ");
		iFoundFlags += ALPC_PORTFLG_ALLOW_LPC_REQUESTS;
	}
	if (ALPC_PORTFLG_WAITABLE_PORT & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_WAITABLE_PORT | ");
		iFoundFlags += ALPC_PORTFLG_WAITABLE_PORT;
	}
	if (ALPC_PORTFLG_SYSTEM_PROCESS & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_SYSTEM_PROCESS | ");
		iFoundFlags += ALPC_PORTFLG_SYSTEM_PROCESS;
	}
	if (ALPC_PORTFLG_ALLOW_DUP_OBJECT & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_ALLOW_DUP_OBJECT | ");
		iFoundFlags += ALPC_PORTFLG_ALLOW_DUP_OBJECT;
	}
	if (ALPC_PORTFLG_LRPC_WAKE_POLICY1 & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_LRPC_WAKE_POLICY1 | ");
		iFoundFlags += ALPC_PORTFLG_LRPC_WAKE_POLICY1;
	}
	if (ALPC_PORTFLG_LRPC_WAKE_POLICY2 & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_LRPC_WAKE_POLICY2 | ");
		iFoundFlags += ALPC_PORTFLG_LRPC_WAKE_POLICY2;
	}
	if (ALPC_PORTFLG_LRPC_WAKE_POLICY3 & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_LRPC_WAKE_POLICY3 | ");
		iFoundFlags += ALPC_PORTFLG_LRPC_WAKE_POLICY3;
	}
	if (ALPC_PORTFLG_DIRECT_MESSAGE & ulPortAttributeFlags) {
		wprintf(L"ALPC_PORTFLG_DIRECT_MESSAGE | ");
		iFoundFlags += ALPC_PORTFLG_DIRECT_MESSAGE;
	}
	
	if (iFoundFlags != ulPortAttributeFlags) {
		wprintf(L"\n[!]\t 0x%X unkwon Port Flag(s)\n", ulPortAttributeFlags - iFoundFlags);
	}
	else {
		wprintf(L"\n");
	}
}

BOOL accept_connection_request() {
	//
	// ACCEPT OR DENY DECISION
	//
	NTSTATUS lSuccess;
	BOOL bAutoAcceptConnection = TRUE;
	BOOL bAcceptConnection;

	if (!bAutoAcceptConnection) {
		wprintf(L"[.] Do you want to accept the connection? [Y]: ");
		WCHAR wcAcceptConnection[2];

		//std::wcin.getline(wcAcceptConnection, 2);

		if (wcscmp(wcAcceptConnection, L"Y") == 0 || wcscmp(wcAcceptConnection, L"y") == 0) {
			bAcceptConnection = TRUE;
		}
		else {
			bAcceptConnection = FALSE;
		};
	}
	else { bAcceptConnection = TRUE; }

	return bAcceptConnection;
}

PSECURITY_DESCRIPTOR create_sd_from_string(LPCWSTR szDACL) {
	PSECURITY_DESCRIPTOR pSD;
	ULONG ulSDSize = 0;
	BOOL success = ConvertStringSecurityDescriptorToSecurityDescriptorW(
		szDACL,
		SDDL_REVISION_1,
		&pSD,
		&ulSDSize
	);
	return pSD;
}

PALPC_MESSAGE_ATTRIBUTES alloc_message_attribute(ULONG ulAttributeFlags) {
	NTSTATUS lSuccess;
	PALPC_MESSAGE_ATTRIBUTES pAttributeBuffer;
	LPVOID lpBuffer;
	SIZE_T lpReqBufSize;
	SIZE_T ulAllocBufSize;

	ulAllocBufSize = AlpcGetHeaderSize(ulAttributeFlags); // this calculates: sizeof(ALPC_MESSAGE_ATTRIBUTES) + size of attribute structures
	lpBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulAllocBufSize);
	if (GetLastError() != 0) {
		wprintf(L"[-] Failed to allocate memory for ALPC Message attributes.\n");
		return NULL;
	}
	pAttributeBuffer = (PALPC_MESSAGE_ATTRIBUTES)lpBuffer;
	//wprintf(L"[*] Initializing ReceiveMessage Attributes (0x%X)...", ulAttributeFlags);
	lSuccess = AlpcInitializeMessageAttribute(
		ulAttributeFlags,	// attributes
		pAttributeBuffer,	// pointer to attributes structure
		ulAllocBufSize,	// buffer size
		&lpReqBufSize
	);
	if (!NT_SUCCESS(lSuccess)) {
		//wprintf(L"Error: 0x%X\n", lSuccess);
		//pAttributeBuffer->ValidAttributes = ulAttributeFlags;
		return NULL;
	}
	else {
		//wprintf(L"Success.\n");
		return pAttributeBuffer;
	}
}

PALPC_MESSAGE_ATTRIBUTES setup_sample_message_attributes(HANDLE hAlpcPort, HANDLE hSection, ULONG ulMessageAttributes) {
	NTSTATUS lSuccess;
	INT iNextMsgAttrBufferOffset;
	SIZE_T ulReqBufSize;
	SIZE_T ulMessageAttributeBufSize = AlpcGetHeaderSize(ulMessageAttributes);
	LPVOID lpAllocTest = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulMessageAttributeBufSize); // NOTE: This buffer is never freed... for this sample i just don't care for this
	PALPC_MESSAGE_ATTRIBUTES pMsgAttrSend = (PALPC_MESSAGE_ATTRIBUTES)lpAllocTest;

	lSuccess = AlpcInitializeMessageAttribute(
		ulMessageAttributes,			// the MessageAttribute 
		pMsgAttrSend,				// pointer to allocated buffer that is used to holf attributes structures
		ulMessageAttributeBufSize,	// buffer that has been allocated
		&ulReqBufSize				// the size that would be needed (in case of the buffer allocated was too small)
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error calling AlpcInitializeMessageAttribute: 0x%X\n", lSuccess);
	}
	iNextMsgAttrBufferOffset = 8; // 4 bytes allocated attributes + 4 bytes valid attributes
	
	if (ulMessageAttributes & ALPC_MESSAGE_SECURITY_ATTRIBUTE) {
		// ALPC_MESSAGE_SECURITY_ATTRIBUTE
		SECURITY_QUALITY_OF_SERVICE SecurityQos;
		ALPC_SECURITY_ATTR securityAttr;
		RtlZeroMemory(&securityAttr, sizeof(securityAttr));
		SecurityQos.ImpersonationLevel = SecurityImpersonation; // SecurityIdentification;
		SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
		SecurityQos.EffectiveOnly = 0;
		SecurityQos.Length = sizeof(SecurityQos);
		securityAttr.pQOS = &SecurityQos;
		securityAttr.Flags = 0; // 0x10000;
		lSuccess = NtAlpcCreateSecurityContext(hAlpcPort, 0, &securityAttr);
		if (!NT_SUCCESS(lSuccess)) {
			wprintf(L"[-] Error creating security context: 0x%X\n", lSuccess);
		}
		else {
			memmove((PBYTE)pMsgAttrSend + iNextMsgAttrBufferOffset, &securityAttr, sizeof(securityAttr));
			iNextMsgAttrBufferOffset += sizeof(securityAttr);
		}
		//RtlSecureZeroMemory(&securityAttr, sizeof(securityAttr));
		/*securityAttr.ContextHandle = &securityContext;
		securityAttr.Flags = 0;
		securityAttr.pQOS = &SecurityQos;*/
	}
	if (ulMessageAttributes & ALPC_MESSAGE_VIEW_ATTRIBUTE) {
		// ALPC_MESSAGE_VIEW_ATTRIBUTE
		ALPC_DATA_VIEW_ATTR viewAttr;
		viewAttr.Flags = 0;	//unknown
		viewAttr.SectionHandle = hSection;
		viewAttr.ViewBase = 0;
		viewAttr.ViewSize = 20*1024;//50;//sizeof(PORT_VIEW);
		lSuccess = NtAlpcCreateSectionView(
			hAlpcPort, //_In_ HANDLE PortHandle,
			0, // _Reserved_ ULONG Flags,
			&viewAttr //_Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes
		);
		if (!NT_SUCCESS(lSuccess)) {
			wprintf(L"[-] Error creating SectionView: 0x%X\n", lSuccess);
		}
		else {
			// Fill section with some sample junk
			RtlFillMemory(viewAttr.ViewBase, 0x41, 50);
			// place ALPC_MESSAGE_VIEW_ATTRIBUTE structure
			memmove((PBYTE)pMsgAttrSend + iNextMsgAttrBufferOffset, &viewAttr, sizeof(viewAttr));
		};
		iNextMsgAttrBufferOffset += sizeof(viewAttr);
	}
	
	if (ulMessageAttributes & ALPC_MESSAGE_HANDLE_ATTRIBUTE) {
		// ALPC_MESSAGE_HANDLE_ATTRIBUTE
		HANDLE hFile = CreateFileW(L"C:\\Users\\Public\\testfile.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		ALPC_HANDLE_ATTR handleAttr;
		handleAttr.Handle = hFile;
		handleAttr.ObjectType = 0;
		handleAttr.Flags = 0;
		handleAttr.DesiredAccess = GENERIC_READ;
		memmove((PBYTE)pMsgAttrSend + iNextMsgAttrBufferOffset, &handleAttr, sizeof(handleAttr));
		iNextMsgAttrBufferOffset += sizeof(handleAttr);
	}
	
	if (ulMessageAttributes & ALPC_MESSAGE_HANDLE_ATTRIBUTE) {
		// ALPC_MESSAGE_DIRECT_ATTRIBUTE
		/// not yet implemented
	}

	if (ulMessageAttributes & ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE) {
		//ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE
		/// not yet implemented
	}

	return pMsgAttrSend;
}

文件CPP-ALPC-Basic-Client.cpp

//#include <winnt.h>
//#include <sddl.h>

#include "..\ALPC-Utils\ALPC.h"
#include "..\ALPC-Utils\CommonALPC.cpp"

const long MAX_MESSAGE_SIZE = 0x100;

int main() {
	HANDLE hSrvCommPort;
	NTSTATUS lSuccess;
	CLIENT_ID clientID;
	ALPC_MESSAGE pmReceived;
	ALPC_MESSAGE pmSend;
	SIZE_T ulSendSize;
	SIZE_T ulReceivedSize;
	SECURITY_QUALITY_OF_SERVICE SecurityQos;
	ALPC_PORT_ATTRIBUTES PortAttributes;
	PALPC_MESSAGE_ATTRIBUTES pMsgAttrSend;
	PALPC_MESSAGE_ATTRIBUTES pMsgAttrReceived;
	ALPC_MESSAGE_ATTRIBUTES inMsgAttr;
	UNICODE_STRING usPortName;
	LPCWSTR pwsPortName = L"\\RPC Control\\CSALPCPort"; // the name of the ALPC port we're attempting to connect to 
	PSID pSID = NULL;
	BOOL bVerifyServerSID = FALSE;

	//
	// INITIALIZAITONS
	//
	DWORD dwPID = GetCurrentProcessId();
	DWORD dwTID = GetCurrentThreadId();
	clientID.UniqueProcess = &dwPID;
	clientID.UniqueThread = &dwTID;
	// Received Message attributes.. I'm fine with getting all of them
	pMsgAttrReceived = alloc_message_attribute(ALPC_MESSAGE_ATTRIBUTE_ALL);

	// QOS
	SecurityQos.ImpersonationLevel = SecurityImpersonation; // SecurityIdentification; // ;
	SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
	SecurityQos.EffectiveOnly = 0;
	SecurityQos.Length = sizeof(SecurityQos);
	// ALPC Port Attributs
	PortAttributes.Flags = ALPC_PORTFLG_ALLOW_DUP_OBJECT | ALPC_PORTFLG_ALLOWIMPERSONATION | ALPC_PORTFLG_LRPC_WAKE_POLICY1 | ALPC_PORTFLG_LRPC_WAKE_POLICY2 | ALPC_PORTFLG_LRPC_WAKE_POLICY3; // | ALPC_PORTFLG_DIRECT_MESSAGE;
	PortAttributes.MaxMessageLength = sizeof(ALPC_MESSAGE); // technically the hard limit for this is 65535, if no constrains you can use AlpcMaxAllowedMessageLength() to set this limit
	PortAttributes.MemoryBandwidth = 512;
	PortAttributes.MaxSectionSize = 0xffffffff; // 20000; 
	PortAttributes.MaxViewSize = 0xffffffff; // 20000; // sizeof(PORT_VIEW); 
	PortAttributes.MaxTotalSectionSize = 0xffffffff;// 20000;
	PortAttributes.DupObjectTypes = 0xffffffff;
	PortAttributes.MaxPoolUsage = 0xffffffff; // 0x4000;
	PortAttributes.SecurityQos = SecurityQos;

	wprintf(L"[*] Starting Client. PID: %d | TID: %d\n", dwPID, dwTID);

	RtlInitUnicodeString(&usPortName, pwsPortName);	// Initialize Unicode String
	//
	// CONNECT TO SERVER PORT
	//
	RtlSecureZeroMemory(&pmSend, sizeof(pmSend));
	add_request_message(&pmSend, "Hello Server");
	ulSendSize = sizeof(pmSend);
	// OPTIONALLY: Verify SID 
	if (bVerifyServerSID) {
		ConvertStringSidToSid(L"S-1-5-21-258271829-1673813934-3670761721-1000", &pSID);
	}
	wprintf(L"[*] Connecting to port '%s'...", pwsPortName);
	
	/*LARGE_INTEGER timeout;
	timeout.QuadPart = 10000000;*/
	lSuccess = NtAlpcConnectPort(
		&hSrvCommPort,				// REQUIRED: empty Communication port handle, fill be set by kernel
		&usPortName,				// REQUIRED: Server Connect port name to connect to
		NULL,						// OPTIONAL: Object Attributes, none in this case
		&PortAttributes,			// OPTIONAL: PortAtrributes, used to set various port connection attributes, most imporatnly port flags
		ALPC_SYNC_CONNECTION,		// OPTOONAL: Message Flags, no Flags
		pSID,						// OPTIONAL: Server SID
		(PPORT_MESSAGE)&pmSend,		// connection message
		&ulSendSize,				// connection message size
		NULL,//pMsgAttrSend,		// out messages attribtus
		pMsgAttrReceived,			// in message attributes
		0 //&timeout				// OPTIONAL: Timeout, none in this case
	);
	if (lSuccess == STATUS_PORT_CONNECTION_REFUSED) {
		wprintf(L"\n[*] The Server denied the connection request.\n");
		return 0;
	}
	else if (lSuccess == STATUS_SERVER_SID_MISMATCH) {
		wprintf(L"\n[*] The specified Server SID does not match with the Server. Connected to the wrong server?.\n");
		return 0;
	}
	else if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");
	print_received_alpc_message(pmSend, NULL, false);
	print_valid_message_attribues(pMsgAttrReceived);

	// Impersonation Attempt
	/*lSuccess = impersonate_client(hSrvCommPort, pmSend);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"[-] Failed to impersonate: 0x%X\n", lSuccess);
	};*/

	//
	// Send Message To Server
	//
	RtlSecureZeroMemory(&pmReceived, sizeof(pmReceived));
	RtlSecureZeroMemory(&pmSend, sizeof(pmSend));
	add_request_message(&pmSend, "Whatzzzzzuuuuuup");

	HANDLE hServerSection;
	SIZE_T nServerSectionSize;
	wprintf(L"[*] Creating Port Section...");
	lSuccess = NtAlpcCreatePortSection(
		hSrvCommPort,		// _In_ HANDLE PortHandle,
		0,					// _In_ flags	// 0x40000 found in rpcrt4.dll
		NULL,				// OPTIONAL SectionHandle,
		1024,				// SectionSize,
		&hServerSection,	// _Out_ HANDLE AlpcSectionHandle,
		&nServerSectionSize // _Out_ ActualSectionSize
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success, Section created. Size: %d\n", nServerSectionSize);
	pMsgAttrSend = setup_sample_message_attributes(hSrvCommPort, hServerSection, ALPC_MESSAGE_VIEW_ATTRIBUTE); //ALPC_MESSAGE_SECURITY_ATTRIBUTE

	wprintf(L"[*] [PID: %d; TID: %d] Sending Message (len: %d) to Port ....", GetCurrentProcessId(), GetCurrentThreadId(), pmSend.PortHeader.u1.s1.DataLength);
	pMsgAttrSend->ValidAttributes |= ALPC_MESSAGE_VIEW_ATTRIBUTE;  // Mark an attribute as valid
	lSuccess = NtAlpcSendWaitReceivePort(
		hSrvCommPort,				// our port handle
		ALPC_MSGFLG_SYNC_REQUEST,		// message Flags
		(PPORT_MESSAGE)&pmSend,		// sending message
		pMsgAttrSend,				// sending attributes
		(PPORT_MESSAGE)&pmReceived,		// receiving message
		&ulReceivedSize,						// receiving message length
		pMsgAttrReceived,			// receive message attributes
		0							// no timeout
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");
	print_received_alpc_message(pmReceived, NULL, false);
	print_valid_message_attribues(pMsgAttrReceived);
			
	//
	// CLOSING Port
	//
	wprintf(L"[*] Closing Port connection...");
	NtAlpcDisconnectPort(hSrvCommPort, 0);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");
	CloseHandle(hSrvCommPort);

	getchar();
	// Finish
	return 0;
}

 文件CPP-ALPC-Basic-Server.cpp

#include<stdio.h>

#include "..\ALPC-Utils\ALPC.h"
#include "..\ALPC-Utils\CommonALPC.cpp"

#pragma comment( lib, "ntdll" )
#pragma comment( lib, "User32" )

int main(){
	//
	// DEFINITIONS
	//
	NTSTATUS lSuccess;
	HANDLE hConnectionPort;
	HANDLE hCommunicationPort;
	UNICODE_STRING usAlpcPortName;
	OBJECT_ATTRIBUTES objAttributes;
	ALPC_PORT_ATTRIBUTES PortAttributes;
	SECURITY_QUALITY_OF_SERVICE SecurityQos;
	ALPC_MESSAGE pmReceived;
	ALPC_MESSAGE pmRequest;
	SIZE_T ulReceivedSize;
	PALPC_MESSAGE_ATTRIBUTES pMsgAttrSend;
	PALPC_MESSAGE_ATTRIBUTES pMsgAttrReceived;
	LPCWSTR pwsPortName = L"\\RPC Control\\CSALPCPort"; // the name of the ALPC port we're creating
	CS_PORT_CONTEXT portContext;
	UUID uuid;
	BOOL bAttemptImpersonation = TRUE;
	//
	// INITIALIZAITONS
	//
	DWORD dwPID = GetCurrentProcessId();
	DWORD dwTID = GetCurrentThreadId();
	// QOS
	//RtlZeroMemory(&SecurityQos, sizeof(SECURITY_QUALITY_OF_SERVICE));
	SecurityQos.ImpersonationLevel = SecurityIdentification; // SecurityImpersonation; // ; // ; // ;// ;
	SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
	SecurityQos.EffectiveOnly = 0;
	SecurityQos.Length = sizeof(SecurityQos);
	// ALPC Port Attributs
	PortAttributes.Flags = ALPC_PORTFLG_ALLOW_DUP_OBJECT | ALPC_PORTFLG_ALLOWIMPERSONATION | ALPC_PORTFLG_LRPC_WAKE_POLICY1 | ALPC_PORTFLG_LRPC_WAKE_POLICY2 | ALPC_PORTFLG_LRPC_WAKE_POLICY3; //0xb84a3f0;// ALPC_PORTFLG_ALLOW_DUP_OBJECT | ALPC_PORTFLG_AllowImpersonation | ALPC_PORTFLG_LRPC_WAKE_POLICY1 | ALPC_PORTFLG_LRPC_WAKE_POLICY2 | ALPC_PORTFLG_LRPC_WAKE_POLICY3; // ; //0x8080000;// ALPC_PORFLG_ALLOW_LPC_REQUESTS;// ALPC_PORFLG_ALLOW_LPC_REQUESTS;// | ALPC_PORFLG_SYSTEM_PROCESS;//0x010000 | 0x020000;	// Found '0x3080000' in rpcrt4.dll
	PortAttributes.MaxMessageLength = sizeof(ALPC_MESSAGE); // technically the hard limit for this is 65535, if no constrains you can use AlpcMaxAllowedMessageLength() to set this limit
	PortAttributes.MemoryBandwidth = 512;
	PortAttributes.MaxPoolUsage = 0xffffffff;
	PortAttributes.MaxSectionSize = 0xffffffff; // 20000;  
	PortAttributes.MaxViewSize = 0xffffffff; // 20000; // sizeof(PORT_VIEW); 
	PortAttributes.MaxTotalSectionSize = 0xffffffff; // 20000;
	PortAttributes.DupObjectTypes = 0xffffffff;
	RtlSecureZeroMemory(&SecurityQos, sizeof(SecurityQos));
	PortAttributes.SecurityQos = SecurityQos;
	// Security Descriptopr
	LPCWSTR szDACL = L"D:(A;OICI;GAGW;;;AU)";// Allow full control to authenticated users
	PSECURITY_DESCRIPTOR pSD = create_sd_from_string(szDACL);
	
	// Received Message attributes.. I'm fine with getting all of them
	pMsgAttrReceived = alloc_message_attribute(ALPC_MESSAGE_ATTRIBUTE_ALL);

	wprintf(L"[*] Starting Server. PID: %d | TID: %d\n", dwPID, dwTID);
	
	// 
	// CREATE PORT
	//
	RtlInitUnicodeString(&usAlpcPortName, pwsPortName);	// Initialize Unicode String
	InitializeObjectAttributes(						// set up OBJECT_ATTRIBUTES structure
		&objAttributes,		// the pointer to the OBJECT_ATTRIBUTES structure
		&usAlpcPortName,	// the name the object we want to obtain a handle for
		0,					// no flags, ref.: https://docs.microsoft.com/en-us/windows/win32/api/ntdef/nf-ntdef-initializeobjectattributes
		NULL,				// no root directry handle as our port name is a full qualified path
		NULL//pSD				// security descriptor
	);
	wprintf(L"[*] Creating ALPC Port '%s'...", pwsPortName);
	lSuccess = NtAlpcCreatePort(
		&hConnectionPort,			// the handle to our port name
		&objAttributes,		// the OBJECT_ATTRIBUTES structure we just initialized
		&PortAttributes //0 				// additional port attributes
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");
	print_port_flags(PortAttributes.Flags);

	//
	// Create Section - just to play around with sections, not necessarily needed
	//
	HANDLE hServerSection;
	SIZE_T nServerSectionSize;
	wprintf(L"[*] Creating Port Section...");
	lSuccess = NtAlpcCreatePortSection(
		hConnectionPort, //_In_ HANDLE PortHandle,
		0, //_In_ ULONG Flags,	// 0x40000 found in rpcrt4.dll
		NULL, //_In_opt_ HANDLE SectionHandle,
		1000, // _In_ SIZE_T SectionSize,
		&hServerSection, //_Out_ HANDLE AlpcSectionHandle,
		&nServerSectionSize //_Out_ PSIZE_T ActualSectionSize
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success, Section created. Size: %d\n", nServerSectionSize);
	
	//
	// Setup Message attributes
	//	--> We set these up once, and reuse the buffer while specifing different valid attributes for different messages
	//
	pMsgAttrSend = setup_sample_message_attributes(hConnectionPort, hServerSection, ALPC_MESSAGE_SECURITY_ATTRIBUTE | ALPC_MESSAGE_VIEW_ATTRIBUTE | ALPC_MESSAGE_HANDLE_ATTRIBUTE);
	
	//
	// WAIT FOR INITIAL CONNECTION
	//
	wprintf(L"[*] Wait for incoming connections...");
	RtlSecureZeroMemory(&pmReceived, sizeof(pmReceived));
	lSuccess = NtAlpcSendWaitReceivePort(
		hConnectionPort,
		ALPC_MSGFLG_NONE,			// no flags
		NULL,		// SendMessage_
		NULL,		// SendMessageAttributes
		(PPORT_MESSAGE)&pmReceived,	// ReceiveBuffer
		&ulReceivedSize,		// BufferLength
		pMsgAttrReceived,//&test,		// ReceiveMessageAttributes
		0				// no timeout
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X.\n", lSuccess);
		return 1;
	}
	else {
		wprintf(L"Success.\n");
	}
	print_received_alpc_message(pmReceived, NULL, false);
	print_valid_message_attribues(pMsgAttrReceived, TRUE);

	
	//
	// ACCEPT OR REJECT MESSAGE
	//
	BOOL bAcceptConnection = accept_connection_request();
	RtlSecureZeroMemory(&pmRequest, sizeof(pmRequest));
	pmRequest.PortHeader.MessageId = pmReceived.PortHeader.MessageId; // Set the messageID from the received client connection to send the message back to the same client
	
	// Create client context so I can identify the client in every call
	portContext.PID = (ULONG)pmReceived.PortHeader.ClientId.UniqueProcess;
	portContext.TID = (ULONG)pmReceived.PortHeader.ClientId.UniqueThread;
	portContext.ID = portContext.PID + portContext.TID; // not a good UUID for production purposes...just as an example, could be anything
	
	pMsgAttrSend->ValidAttributes |= ALPC_MESSAGE_SECURITY_ATTRIBUTE; // ALPC_MESSAGE_HANDLE_ATTRIBUTE; // Mark the an attribute as valid
	if (bAcceptConnection) { 
		wprintf(L"[*] Accepting Incoming Connection...");
		add_request_message(&pmRequest, "I'll accept your connection...");
	}
	else {
		wprintf(L"[*] Denying Incoming Connection...");
		add_request_message(&pmRequest, "Nope, you're not allowed to connect...");
	}
	lSuccess = NtAlpcAcceptConnectPort(
		&hCommunicationPort,		// Communication port handle
		hConnectionPort,			// Connection port handle
		ALPC_SYNC_CONNECTION,		// connection flags
		NULL,						// no object attributs
		&PortAttributes, //0,		// port attributes
		&portContext,				// port context
		(PPORT_MESSAGE)&pmRequest,	// connection request
		pMsgAttrSend,				// connection message attributes
		bAcceptConnection			// accepting the connection
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Done\n");

	//
	// WAIT FOR INCOMING DATA
	//
	RtlSecureZeroMemory(&pmReceived, sizeof(pmReceived));
	RtlSecureZeroMemory(&pmRequest, sizeof(pmRequest));
	wprintf(L"[*] Waiting for incoming data...");
	lSuccess = NtAlpcSendWaitReceivePort(
		hConnectionPort,					// we need to use the connection port
		ALPC_MSGFLG_LPC_MODE,				// message flags
		NULL,//(PPORT_MESSAGE)&pmRequest,	//Sending message
		NULL, //pMsgAttrSend,				// SendMessageAttributes
		(PPORT_MESSAGE)&pmReceived,			// ReceivingMessage
		&ulReceivedSize,					// Receive BufferLength
		pMsgAttrReceived,					// ReceiveMessageAttributes
		0									// no timeout
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"[-] Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");
	print_received_alpc_message(pmReceived, hConnectionPort, true);
	print_valid_message_attribues(pMsgAttrReceived, TRUE);

	//
	// ATTEMPT IMPERSONATION 
	//
	if (bAttemptImpersonation) {
		wprintf(L"[*] Trying to impersonate client...\n");
		lSuccess = impersonate_client(hCommunicationPort, pmReceived);
		if (!NT_SUCCESS(lSuccess)) {
			wprintf(L"[-] Error: 0x%X\n", lSuccess);
		}
		else wprintf(L"Done.\n");
	}

	//
	// REPLY TO client 
	//	-- note this could as well have been included in the previous NtAlpcSendWaitReceivePort call, this is just to show case that you could also do something with the message before responding
	//
	add_request_message(&pmRequest, "Data received!");
	pmRequest.PortHeader.MessageId = pmReceived.PortHeader.MessageId;
	pMsgAttrSend->ValidAttributes |= ALPC_MESSAGE_VIEW_ATTRIBUTE; // ALPC_MESSAGE_SECURITY_ATTRIBUTE; // Mark the an attribute as valid
	wprintf(L"[*] Sending data to port");
	lSuccess = NtAlpcSendWaitReceivePort(
		hConnectionPort,		// we need to use the connection port
		ALPC_MSGFLG_REPLY_MESSAGE,			// no flags
		(PPORT_MESSAGE)&pmRequest, //		// SendMessage_
		pMsgAttrSend,		// SendMessageAttributes
		NULL, //(PPORT_MESSAGE)&pmReceived,//ReceiveMessage,  // ReceiveBuffer
		NULL, //&pmReceivedSize,		// Receive BufferLength
		NULL, // pMsgAttrReceived,		// ReceiveMessageAttributes
		0		// no timeout
	);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"[-] Error: 0x%X\n", lSuccess);
		return 1;
	}
	else wprintf(L"Success.\n");

	// We could wait for new data, but this is just a PoC...
	//wprintf(L"Sleeping for 1 seconds..");
	//Sleep(1000);
	//while (TRUE) {

	//	wprintf(L"[*] Wait for incoming connections...");
	//	RtlSecureZeroMemory(&pmReceived, sizeof(pmReceived));
	//	lSuccess = NtAlpcSendWaitReceivePort(
	//		hConnectionPort,
	//		ALPC_MSGFLG_LPC_MODE,			// no flags
	//		NULL,		// SendMessage_
	//		NULL,		// SendMessageAttributes
	//		(PPORT_MESSAGE)&pmReceived,	// ReceiveBuffer
	//		&ulReceivedSize,		// BufferLength
	//		pMsgAttrReceived,//&test,		// ReceiveMessageAttributes
	//		0				// no timeout
	//	);
	//	if (!NT_SUCCESS(lSuccess)) {
	//		wprintf(L"Error: 0x%X.\n", lSuccess);
	//		return 1;
	//	}
	//	else {
	//		wprintf(L"Success.\n");
	//	}
	//	print_received_alpc_message(pmReceived, hConnectionPort, FALSE);
	//	print_valid_message_attribues(pMsgAttrReceived, TRUE);
	//}

	//
	// CLOSING Port
	//
	wprintf(L"[*] Closing Port connection...");
	NtAlpcDisconnectPort(hCommunicationPort, 0);
	NtAlpcDisconnectPort(hConnectionPort, 0);
	if (!NT_SUCCESS(lSuccess)) {
		wprintf(L"Error: 0x%X\n", lSuccess);
	}
	else wprintf(L"Success.\n");
	CloseHandle(hConnectionPort);
	CloseHandle(hCommunicationPort);

	getchar();

	// Finish
	return 0;
}

 

编译运行结果如下图:

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值