获取Powershell命令行参数

这个是偶然发现的,通过测试可以在r0中拿到在powershell输入的命令行参数。

原理是hook NtAlpcSendWaitReceivePort函数,通过解析该函数的第三个参数发现类型为0x01d8时候在偏移0xd0的位置就是powershell参数的位置

下面是代码

#include <Ntifs.h>
#include <ntimage.h>
#include <ntstrsafe.h>
typedef struct _LDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID      DllBase;
	PVOID      EntryPoint;
	ULONG32    SizeOfImage;
	UINT8      Unknow0[0x4];
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _SYSTEM_SERVICE_TABLE {
	PVOID       ServiceTableBase;
	PVOID       ServiceCounterTableBase;
	ULONGLONG   NumberOfServices;
	PVOID       ParamTableBase;
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;

PSYSTEM_SERVICE_TABLE KeServiceDescriptorTable;
ULONGLONG g_orgfunc = NULL;

//关闭写保护
KIRQL WPOFFx64() {
	KIRQL irql = KeRaiseIrqlToDpcLevel();
	UINT64 cr0 = __readcr0();
	cr0 &= 0xfffffffffffeffff;
	__writecr0(cr0);
	_disable();
	return irql;
}
//开启写保护
void WPONx64(KIRQL irql) {
	UINT64 cr0 = __readcr0();
	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);
	KeLowerIrql(irql);

}


//得到ntos的基地址
ULONGLONG GetOsBaseAddress(PDRIVER_OBJECT pDriverObject) {

	UNICODE_STRING osName = { 0 };
	WCHAR wzData[0x100] = L"ntoskrnl.exe";

	RtlInitUnicodeString(&osName, wzData);

	LDR_DATA_TABLE_ENTRY *pDataTableEntry, *pTempDataTableEntry;
	//双循环链表定义
	PLIST_ENTRY	pList;
	//指向驱动对象的DriverSection
	pDataTableEntry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection;
	//判断是否为空
	if (!pDataTableEntry)
		return;

	/*
	开始遍历驱动对象链表
	*/
	//得到链表地址
	pList = pDataTableEntry->InLoadOrderLinks.Flink;

	//判断是否等于头部
	while (pList != &pDataTableEntry->InLoadOrderLinks) {
		pTempDataTableEntry = (LDR_DATA_TABLE_ENTRY *)pList;
		if (RtlEqualUnicodeString(&pTempDataTableEntry->BaseDllName, &osName, TRUE))
			return (ULONGLONG)pTempDataTableEntry->DllBase;
		pList = pList->Flink;
	}
	return 0;
}
ULONG GetSSDTRVA(UCHAR *funcname) {

	NTSTATUS Status;
	HANDLE FileHandle;
	IO_STATUS_BLOCK ioStatus;
	FILE_STANDARD_INFORMATION FileInformation;
	//设置NTDLL路径
	UNICODE_STRING uniFileName;
	RtlInitUnicodeString(&uniFileName, L"\\SystemRoot\\system32\\ntoskrnl.exe");

	//初始化打开文件的属性
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes, &uniFileName,
		OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
	创建文件

	Status = IoCreateFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &objectAttributes,
		&ioStatus, 0, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT,
		NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING);
	if (!NT_SUCCESS(Status))
		return 0;
	//获取文件信息

	Status = ZwQueryInformationFile(FileHandle, &ioStatus, &FileInformation,
		sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
	if (!NT_SUCCESS(Status)) {
		ZwClose(FileHandle);
		return 0;
	}
	//判断文件大小是否过大
	if (FileInformation.EndOfFile.HighPart != 0) {
		ZwClose(FileHandle);
		return 0;
	}
	//取文件大小
	ULONG uFileSize = FileInformation.EndOfFile.LowPart;


	//分配内存
	PVOID pBuffer = ExAllocatePoolWithTag(PagedPool, uFileSize + 0x100, (ULONG)"PGu");
	if (pBuffer == NULL) {
		ZwClose(FileHandle);
		return 0;
	}

	//从头开始读取文件
	LARGE_INTEGER byteOffset;
	byteOffset.LowPart = 0;
	byteOffset.HighPart = 0;
	Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &ioStatus, pBuffer, uFileSize, &byteOffset, NULL);
	if (!NT_SUCCESS(Status)) {
		ZwClose(FileHandle);
		return 0;
	}
	//取出导出表
	PIMAGE_DOS_HEADER  pDosHeader;
	PIMAGE_NT_HEADERS  pNtHeaders;
	PIMAGE_SECTION_HEADER pSectionHeader;
	ULONGLONG     FileOffset;//这里是64位数的,所以这里不是32个字节
	PIMAGE_EXPORT_DIRECTORY pExportDirectory;
	//DLL内存数据转成DOS头结构
	pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
	//取出PE头结构
	pNtHeaders = (PIMAGE_NT_HEADERS)((ULONGLONG)pBuffer + pDosHeader->e_lfanew);
	//判断PE头导出表表是否为空


	if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
		return 0;

	//取出导出表偏移
	FileOffset = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

	//取出节头结构
	pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONGLONG)pNtHeaders + sizeof(IMAGE_NT_HEADERS));
	PIMAGE_SECTION_HEADER pOldSectionHeader = pSectionHeader;
	//遍历节结构进行地址运算
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}

	//导出表地址
	pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONGLONG)pBuffer + FileOffset);
	//取出导出表函数地址
	PLONG AddressOfFunctions;
	FileOffset = pExportDirectory->AddressOfFunctions;
	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfFunctions = (PULONG)((ULONGLONG)pBuffer + FileOffset);//这里注意一下foa和rva

	//取出导出表函数名字
	PUSHORT AddressOfNameOrdinals;
	FileOffset = pExportDirectory->AddressOfNameOrdinals;

	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfNameOrdinals = (PUSHORT)((ULONGLONG)pBuffer + FileOffset);//注意一下foa和rva

	//取出导出表函数序号
	PULONG AddressOfNames;
	FileOffset = pExportDirectory->AddressOfNames;

	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfNames = (PULONG)((ULONGLONG)pBuffer + FileOffset);//注意一下foa和rva
	//分析导出表
	ULONG uNameOffset;
	ULONG uOffset;
	LPSTR FunName;
	ULONG uAddressOfNames;
	ULONG TargetOff = 0;
	for (ULONG uIndex = 0; uIndex < pExportDirectory->NumberOfNames; uIndex++, AddressOfNames++, AddressOfNameOrdinals++) {
		uAddressOfNames = *AddressOfNames;
		pSectionHeader = pOldSectionHeader;
		for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
			if (pSectionHeader->VirtualAddress <= uAddressOfNames && uAddressOfNames <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
				uOffset = uAddressOfNames - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
		}
		FunName = (LPSTR)((ULONGLONG)pBuffer + uOffset);
		if (!_stricmp(funcname, FunName)) {
			TargetOff = (ULONG)AddressOfFunctions[*AddressOfNameOrdinals];
		}

	}

	ExFreePoolWithTag(pBuffer, (ULONG)"PGu");
	ZwClose(FileHandle);
	return TargetOff;
}

//得到ssdt表的基地址
ULONGLONG GetKeServiceDescriptorTable64(PDRIVER_OBJECT DriverObject) {
	/*
	KdDebuggerNotPresent,FFFFF80353C59B2B
	1: kd> u fffff803`539dcd07
		nt!KiSystemServiceStart+0x7:
		fffff803`539dcd07 8bf8            mov     edi,eax
		fffff803`539dcd09 c1ef07          shr     edi,7
		fffff803`539dcd0c 83e720          and     edi,20h
		fffff803`539dcd0f 25ff0f0000      and     eax,0FFFh
		nt!KiSystemServiceRepeat:
		fffff803`539dcd14 4c8d15659b3b00  lea     r10,[nt!KeServiceDescriptorTable (fffff803`53d96880)]
		fffff803`539dcd1b 4c8d1d5e1d3a00  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff803`53d7ea80)]
		fffff803`539dcd22 f7437880000000  test    dword ptr [rbx+78h],80h
		fffff803`539dcd29 7413            je      nt!KiSystemServiceRepeat+0x2a (fffff803`539dcd3e)
	*/
	char KiSystemServiceStart_pattern[13] = "\x8B\xF8\xC1\xEF\x07\x83\xE7\x20\x25\xFF\x0F\x00\x00";
	ULONGLONG CodeScanStart = GetSSDTRVA("_stricmp") + GetOsBaseAddress(DriverObject);//这样动态定位的就是真正函数的地址

	ULONGLONG i, tbl_address, b;
	for (i = 0; i < 0x50000; i++) {
		if (!memcmp((char*)(ULONGLONG)CodeScanStart + i,
			(char*)KiSystemServiceStart_pattern, 13)) {
			for (b = 0; b < 50; b++) {
				tbl_address = ((ULONGLONG)CodeScanStart + i + b);
				if (*(USHORT*)((ULONGLONG)tbl_address) == (USHORT)0x8d4c)
					return ((LONGLONG)tbl_address + 7) + *(LONG*)(tbl_address + 3);
			}
		}
	}
	return 0;
}
//通过名字得到当前函数的ssdt函数的id
ULONG GetIndexByName(UCHAR *sdName) {

	NTSTATUS Status;
	HANDLE FileHandle;
	IO_STATUS_BLOCK ioStatus;
	FILE_STANDARD_INFORMATION FileInformation;
	//设置NTDLL路径
	UNICODE_STRING uniFileName;
	RtlInitUnicodeString(&uniFileName, L"\\SystemRoot\\system32\\ntdll.dll");

	//初始化打开文件的属性
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes, &uniFileName,
		OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
	创建文件

	Status = IoCreateFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &objectAttributes,
		&ioStatus, 0, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT,
		NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING);
	if (!NT_SUCCESS(Status))
		return 0;
	//获取文件信息

	Status = ZwQueryInformationFile(FileHandle, &ioStatus, &FileInformation,
		sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
	if (!NT_SUCCESS(Status)) {
		ZwClose(FileHandle);
		return 0;
	}
	//判断文件大小是否过大
	if (FileInformation.EndOfFile.HighPart != 0) {
		ZwClose(FileHandle);
		return 0;
	}
	//取文件大小
	ULONG uFileSize = FileInformation.EndOfFile.LowPart;


	//分配内存
	PVOID pBuffer = ExAllocatePoolWithTag(PagedPool, uFileSize + 0x100, (ULONG)"Ntdl");
	if (pBuffer == NULL) {
		ZwClose(FileHandle);
		return 0;
	}

	//从头开始读取文件
	LARGE_INTEGER byteOffset;
	byteOffset.LowPart = 0;
	byteOffset.HighPart = 0;
	Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &ioStatus, pBuffer, uFileSize, &byteOffset, NULL);
	if (!NT_SUCCESS(Status)) {
		ZwClose(FileHandle);
		return 0;
	}
	//取出导出表
	PIMAGE_DOS_HEADER  pDosHeader;
	PIMAGE_NT_HEADERS  pNtHeaders;
	PIMAGE_SECTION_HEADER pSectionHeader;
	ULONGLONG     FileOffset;//这里是64位数的,所以这里不是32个字节
	PIMAGE_EXPORT_DIRECTORY pExportDirectory;
	//DLL内存数据转成DOS头结构
	pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
	//取出PE头结构
	pNtHeaders = (PIMAGE_NT_HEADERS)((ULONGLONG)pBuffer + pDosHeader->e_lfanew);
	//判断PE头导出表表是否为空


	if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
		return 0;

	//取出导出表偏移
	FileOffset = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

	//取出节头结构
	pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONGLONG)pNtHeaders + sizeof(IMAGE_NT_HEADERS));
	PIMAGE_SECTION_HEADER pOldSectionHeader = pSectionHeader;
	//遍历节结构进行地址运算
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}

	//导出表地址
	pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONGLONG)pBuffer + FileOffset);
	//取出导出表函数地址
	PLONG AddressOfFunctions;
	FileOffset = pExportDirectory->AddressOfFunctions;
	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfFunctions = (PULONG)((ULONGLONG)pBuffer + FileOffset);//这里注意一下foa和rva

	//取出导出表函数名字
	PUSHORT AddressOfNameOrdinals;
	FileOffset = pExportDirectory->AddressOfNameOrdinals;

	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfNameOrdinals = (PUSHORT)((ULONGLONG)pBuffer + FileOffset);//注意一下foa和rva

	//取出导出表函数序号
	PULONG AddressOfNames;
	FileOffset = pExportDirectory->AddressOfNames;

	//遍历节结构进行地址运算
	pSectionHeader = pOldSectionHeader;
	for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
		if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
			FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
	}
	AddressOfNames = (PULONG)((ULONGLONG)pBuffer + FileOffset);//注意一下foa和rva

	//分析导出表
	ULONG uNameOffset;
	ULONG uOffset;
	LPSTR FunName;
	PVOID pFuncAddr;
	ULONG uServerIndex;
	ULONG uAddressOfNames;
	for (ULONG uIndex = 0; uIndex < pExportDirectory->NumberOfNames; uIndex++, AddressOfNames++, AddressOfNameOrdinals++) {
		uAddressOfNames = *AddressOfNames;
		pSectionHeader = pOldSectionHeader;
		for (UINT32 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
			if (pSectionHeader->VirtualAddress <= uAddressOfNames && uAddressOfNames <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
				uOffset = uAddressOfNames - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
		}
		FunName = (LPSTR)((ULONGLONG)pBuffer + uOffset);
		if (FunName[0] == 'Z' && FunName[1] == 'w') {
			pSectionHeader = pOldSectionHeader;
			uOffset = (ULONG)AddressOfFunctions[*AddressOfNameOrdinals];
			for (UINT32 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++) {
				if (pSectionHeader->VirtualAddress <= uOffset && uOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
					uNameOffset = uOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
			}
			pFuncAddr = (PVOID)((ULONGLONG)pBuffer + uNameOffset);
			uServerIndex = *(PULONG)((ULONGLONG)pFuncAddr + 4);
			FunName[0] = 'N';
			FunName[1] = 't';
			if (!_stricmp(FunName, sdName)) {//获得指定的编号
				ExFreePoolWithTag(pBuffer, (ULONG)"Ntdl");
				ZwClose(FileHandle);
				return uServerIndex;
			}
			//DbgPrint("Name: %s index:%d\n ", FunName, uServerIndex);//index:%d\n, uServerIndex

		}
	}

	ExFreePoolWithTag(pBuffer, (ULONG)"Ntdl");
	ZwClose(FileHandle);
	return 0;
}
//通过id得到函数地址
ULONGLONG GetSSDTFuncAddrById(ULONG id) {
	/*
	mov rax, rcx ;rcx=Native API 的 index
	lea r10,[rdx] ;rdx=ssdt 基址
	mov edi,eax ;index
	shr edi,7
	and edi,20h
	mov r10, qword ptr [r10+rdi]//这里得到ServiceTableBase
	movsxd r11,dword ptr [r10+rax]//这里得到没有右移的假ssdt的地址
	mov rax,r11
	sar r11,4
	add r10,r11
	mov rax,r10
	ret
	*/
	LONG dwtmp = 0;
	PULONG ServiceTableBase = NULL;
	ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
	dwtmp = ServiceTableBase[id];
	dwtmp = dwtmp >> 4;
	return (LONGLONG)dwtmp + (ULONGLONG)ServiceTableBase;//需要先右移4位之后加上基地址,就可以得到ssdt的地址
}

//NtOpenProcess
typedef NTSTATUS(NTAPI *NTOPENPROCESS)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);
NTOPENPROCESS g_ntopenprocess = NULL;

extern NTSTATUS NTAPI FakeOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);
/*
nt!NtOpenProcess:
fffff800`5d8235c0 4883ec38        sub     rsp,38h
fffff800`5d8235c4 65488b042588010000 mov   rax,qword ptr gs:[188h]
fffff800`5d8235cd 448a9032020000  mov     r10b,byte ptr [rax+232h]
fffff800`5d8235d4 4488542428      mov     byte ptr [rsp+28h],r10b
fffff800`5d8235d9 4488542420      mov     byte ptr [rsp+20h],r10b
fffff800`5d8235de e80d030000      call    nt!PsOpenProcess (fffff800`5d8238f0)
fffff800`5d8235e3 4883c438        add     rsp,38h
fffff800`5d8235e7 c3              ret
*/

NTSTATUS NTAPI Hook_pfnNtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId) {
	//DbgBreakPoint();
	return FakeOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}


typedef struct _PORT_MESSAGE{
	ULONG u1;
	ULONG u2;
	union{
		CLIENT_ID ClientId;
		float DoNotUseThisField;
	};
	ULONG MessageId;
	union{
		ULONG ClientViewSize;
		ULONG CallbackId;
	};
} PORT_MESSAGE, *PPORT_MESSAGE;
typedef struct _ALPC_MESSAGE_ATTRIBUTES{
	ULONG AllocatedAttributes;
	ULONG ValidAttributes;
} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;
#define MAX_PATH 0x00000104


typedef NTSTATUS(*PNTALPCSENDWAITRECEIVEPORT)(_In_ HANDLE PortHandle,_In_ ULONG 	Flags,_In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE 	SendMessage,_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES 	SendMessageAttributes,_Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage,_Inout_opt_ PSIZE_T 	BufferLength,_Inout_opt_ PALPC_MESSAGE_ATTRIBUTES 	ReceiveMessageAttributes,_In_opt_ PLARGE_INTEGER 	Timeout);
PNTALPCSENDWAITRECEIVEPORT g_OldNtAlpcSendWaitReceivePort = NULL;
extern NTSTATUS NTAPI FakeNtAlpcSendWaitReceivePort(_In_ HANDLE PortHandle, _In_ ULONG 	Flags, _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE 	SendMessage, _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES 	SendMessageAttributes, _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage, _Inout_opt_ PSIZE_T 	BufferLength, _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES 	ReceiveMessageAttributes, _In_opt_ PLARGE_INTEGER 	Timeout);
typedef NTSTATUS(*PfnZwQueryInformationProcess) (__in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __out_bcount(ProcessInformationLength) PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength);
PfnZwQueryInformationProcess ZwQueryInformationProcess;

//正则匹配
BOOLEAN IsPatternMatch(PUNICODE_STRING Expression, PUNICODE_STRING Name, BOOLEAN IgnoreCase){
	return FsRtlIsNameInExpression(Expression,Name,IgnoreCase,/*如果这里设置为TRUE,那么Expression必须是大写的*/NULL);
}
NTSTATUS  GetProcessFullNameByPid(HANDLE nPid, PUNICODE_STRING  FullPath){
	HANDLE               hFile = NULL;
	ULONG                nNeedSize = 0;
	NTSTATUS             nStatus = STATUS_SUCCESS;
	NTSTATUS             nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
	PEPROCESS            Process = NULL;
	KAPC_STATE           ApcState = { 0 };
	PVOID                lpBuffer = NULL;
	OBJECT_ATTRIBUTES    ObjectAttributes = { 0 };
	IO_STATUS_BLOCK      IoStatus = { 0 };
	PFILE_OBJECT         FileObject = NULL;
	PFILE_NAME_INFORMATION FileName = NULL;
	WCHAR                FileBuffer[MAX_PATH] = { 0 };
	DECLARE_UNICODE_STRING_SIZE(ProcessPath, MAX_PATH);
	DECLARE_UNICODE_STRING_SIZE(DosDeviceName, MAX_PATH);

	PAGED_CODE();

	nStatus = PsLookupProcessByProcessId(nPid, &Process);
	if (NT_ERROR(nStatus)){
		DbgPrint("%s error PsLookupProcessByProcessId.\n", __FUNCTION__);
		return nStatus;
	}

	__try{

		KeStackAttachProcess(Process, &ApcState);

		nStatus = ZwQueryInformationProcess(
			NtCurrentProcess(),
			ProcessImageFileName,
			NULL,
			NULL,
			&nNeedSize
		);

		if (STATUS_INFO_LENGTH_MISMATCH != nStatus){
			DbgPrint("%s NtQueryInformationProcess error.\n", __FUNCTION__);
			nStatus = STATUS_MEMORY_NOT_ALLOCATED;
			__leave;

		}

		lpBuffer = ExAllocatePoolWithTag(NonPagedPool, nNeedSize, 'GetP');
		if (lpBuffer == NULL){
			DbgPrint("%s ExAllocatePoolWithTag error.\n", __FUNCTION__);
			nStatus = STATUS_MEMORY_NOT_ALLOCATED;
			__leave;
		}

		nStatus = ZwQueryInformationProcess(
			NtCurrentProcess(),
			ProcessImageFileName,
			lpBuffer,
			nNeedSize,
			&nNeedSize
		);

		if (NT_ERROR(nStatus)){
			DbgPrint("%s NtQueryInformationProcess error2.\n", __FUNCTION__);
			__leave;
		}

		RtlCopyUnicodeString(&ProcessPath, (PUNICODE_STRING)lpBuffer);
		InitializeObjectAttributes(
			&ObjectAttributes,
			&ProcessPath,
			OBJ_CASE_INSENSITIVE,
			NULL,
			NULL
		);

		nStatus = ZwCreateFile(
			&hFile,
			FILE_READ_ATTRIBUTES,
			&ObjectAttributes,
			&IoStatus,
			NULL,
			FILE_ATTRIBUTE_NORMAL,
			0,
			FILE_OPEN,
			FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
			NULL,
			0
		);

		if (NT_ERROR(nStatus)){
			hFile = NULL;
			__leave;
		}

		nStatus = ObReferenceObjectByHandle(
			hFile,
			NULL,
			*IoFileObjectType,
			KernelMode,
			(PVOID*)&FileObject,
			NULL
		);

		if (NT_ERROR(nStatus)){
			FileObject = NULL;
			__leave;
		}

		FileName = (PFILE_NAME_INFORMATION)FileBuffer;

		nStatus = ZwQueryInformationFile(
			hFile,
			&IoStatus,
			FileName,
			sizeof(WCHAR)*MAX_PATH,
			FileNameInformation
		);

		if (NT_ERROR(nStatus)){
			__leave;
		}

		if (FileObject->DeviceObject == NULL){
			nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
			__leave;
		}

		nDeviceStatus = RtlVolumeDeviceToDosName(FileObject->DeviceObject, &DosDeviceName);

	}__finally{
		if (NULL != FileObject){
			ObDereferenceObject(FileObject);
		}

		if (NULL != hFile){
			ZwClose(hFile);
		}

		if (NULL != lpBuffer){
			ExFreePool(lpBuffer);
		}

		KeUnstackDetachProcess(&ApcState);

	}

	if (NT_SUCCESS(nStatus)){
		RtlInitUnicodeString(&ProcessPath, FileName->FileName);

		if (NT_SUCCESS(nDeviceStatus)){
			RtlCopyUnicodeString(FullPath, &DosDeviceName);
			RtlUnicodeStringCat(FullPath, &ProcessPath);
		}else{
			RtlCopyUnicodeString(FullPath, &ProcessPath);
		}
	}


	return nStatus;
}

ULONGLONG flag = 0;
extern void __fastcall lockenter(ULONGLONG *flag);
extern void __fastcall lockleave(ULONGLONG *flag);
/*
nt!NtAlpcSendWaitReceivePort:
fffff800`5d7daf00 488bc4          mov     rax,rsp
fffff800`5d7daf03 56              push    rsi
fffff800`5d7daf04 4881ecb0000000  sub     rsp,0B0h
fffff800`5d7daf0b 48895808        mov     qword ptr [rax+8],rbx
fffff800`5d7daf0f 0f57c0          xorps   xmm0,xmm0
fffff800`5d7daf12 48896810        mov     qword ptr [rax+10h],rbp
fffff800`5d7daf16 8bda            mov     ebx,edx
fffff800`5d7daf18 4c896020        mov     qword ptr [rax+20h],r12

*/
NTSTATUS Hook_NtAlpcSendWaitReceivePort(HANDLE PortHandle,ULONG Flags,PPORT_MESSAGE SendMessage,PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,PPORT_MESSAGE ReceiveMessage,PSIZE_T BufferLength,PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,PLARGE_INTEGER 	Timeout){
	NTSTATUS status = NULL;
	ULONG g_Pid = 0;
	UNICODE_STRING StrProcessName = { 0 };
	StrProcessName.MaximumLength = MAX_PATH * sizeof(WCHAR);
	StrProcessName.Length = 0;
	WCHAR tmp[MAX_PATH] = { 0 };
	StrProcessName.Buffer = tmp;
	UNICODE_STRING uExpression = { 0 };
	RtlInitUnicodeString(&uExpression, L"*POWERSHELL.EXE");

	if (SendMessage){
		g_Pid = PsGetCurrentProcessId();//这里是发送消息的一方
		GetProcessFullNameByPid((HANDLE)g_Pid, &StrProcessName);//这里是得到当前进程的名字
		if (IsPatternMatch(&uExpression, &StrProcessName, TRUE)){
			DbgBreakPoint();
			//DbgPrint("aaddress %llX   Parent:%wZ\n", *(ULONGLONG *)SendMessage, &StrProcessName);
		}
	}
	lockenter(&flag);
	status = FakeNtAlpcSendWaitReceivePort(PortHandle, Flags, SendMessage, SendMessageAttributes, ReceiveMessage, BufferLength, ReceiveMessageAttributes, Timeout);
	lockleave(&flag);
	return status;//这里应该会时延
}



VOID HookFunc(PVOID OrigAddress , PVOID TargetAddress) {
	KIRQL irql;
	ULONGLONG myfun;
	UCHAR jmp_code[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0\x00\x00";//mov rax xxx,jmp rax
	myfun = (ULONGLONG)TargetAddress;//替换成自己的函数地址
	RtlCopyMemory(jmp_code + 2, &myfun, 8);
	//debg();
	irql = WPOFFx64();
	RtlCopyMemory(OrigAddress, jmp_code, 12);
	WPONx64(irql);
	
}

VOID UnhookSSDT(PVOID org_address ,PUCHAR org_opcode,UINT32 size) {
	KIRQL irql;
	irql = WPOFFx64();
	RtlCopyMemory(org_address, org_opcode, size);
	WPONx64(irql);

}

#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
VOID MySleep(LONG msec){
	LARGE_INTEGER my_interval;
	my_interval.QuadPart = DELAY_ONE_MILLISECOND;
	my_interval.QuadPart *= msec;
	KeDelayExecutionThread(KernelMode, 0, &my_interval);
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject) {

	
	UCHAR fix_code[] = "\x48\x83\xec\x38\x65\x48\x8b\x04\x25\x88\x01\x00\x00\x44\x8a\x90\x32\x02\x00\x00";
	UnhookSSDT(g_ntopenprocess, fix_code,sizeof(fix_code)-1);//这里有一个\0


	UCHAR fix_lpc[] = "\x48\x8b\xc4\x56\x48\x81\xec\xb0\x00\x00\x00\x48\x89\x58\x08\x0f\x57\xc0";
	UnhookSSDT(g_OldNtAlpcSendWaitReceivePort, fix_lpc, sizeof(fix_lpc) - 1);//WMIHook.sys+0x2048
	//WMIHook.sys+0x1ae6

	//DbgBreakPoint();

	//这里做一个延时
	int i = 0;
	while (flag != 0) {
		DbgPrint("flag:   %d   \n", flag);
		MySleep(100);
	}
	
	
	DbgPrint("See You !\n");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath) {

	DriverObject->DriverUnload = DriverUnload;
	KeServiceDescriptorTable = GetKeServiceDescriptorTable64(DriverObject);

	UNICODE_STRING UtrZwQueryInformationProcessName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess");
	ZwQueryInformationProcess =(PfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&UtrZwQueryInformationProcessName);

	g_ntopenprocess =GetSSDTFuncAddrById(GetIndexByName("NtOpenProcess"));//这个是用来做测试的
	HookFunc(g_ntopenprocess, Hook_pfnNtOpenProcess);

	g_OldNtAlpcSendWaitReceivePort = GetSSDTFuncAddrById(GetIndexByName("NtAlpcSendWaitReceivePort"));
	HookFunc(g_OldNtAlpcSendWaitReceivePort, Hook_NtAlpcSendWaitReceivePort);



	return STATUS_SUCCESS;
}

没什么好说的就是需要对ALPC有一点了解,我也不是很清楚就不卖弄了,例子的地址我是链接

把asm文件也带上吧,最后说一下测试的操作系统是win10 1903的

.code


EXTERN g_ntopenprocess: qword
EXTERN g_OldNtAlpcSendWaitReceivePort: qword

FakeOpenProcess    proc

	sub     rsp,38h
	mov     rax,qword ptr gs:[188h]
	mov     r10b,byte ptr [rax+232h]
	
	;处理返回地址
	mov     rax,g_ntopenprocess
	add     rax,14h
	push    rax

	;mov     rax,qword ptr gs:[188h]
	;mov     r10b,byte ptr [rax+232h]

	ret

FakeOpenProcess    endp


FakeNtAlpcSendWaitReceivePort    proc
	

	mov     rax,rsp
	push    rsi
	sub     rsp,0B0h
	mov     qword ptr [rax+8],rbx

	push    rax
	push    rax

	mov     rax,g_OldNtAlpcSendWaitReceivePort
	add     rax,0fh

	mov     [rsp+8],rax
	pop     rax


	ret

FakeNtAlpcSendWaitReceivePort    endp


lockenter    proc
		mov rax,1
		lock add  [rcx],rax
		ret
	
lockenter    endp


lockleave    proc
	
		mov rax,1
		lock sub  [rcx],rax
		ret
	
lockleave    endp


end

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值