• 获取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
  • 相关阅读:
    rgba()和opacity的比较(转)
    CSS定位以及z-index属性(层叠性)的详解(转)
    hadoop 集群HA高可用搭建以及问题解决方案
    服务容错模式
    分布式系统基础总结
    当Kubernets遇上阿里云 -之七层负载均衡(一).
    HAProxy负载均衡原理及企业级实例部署haproxy集群
    基于Docker Compose构建的MySQL MHA集群
    使用 Mesos 管理虚拟机
    VMware VSAN 入门与配置(一)
  • 原文地址:https://www.cnblogs.com/csnd/p/16675602.html
Copyright © 2020-2023  润新知