这个是偶然发现的,通过测试可以在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