隐蔽通讯常见种类介绍

5次阅读
没有评论

正常通信流程:

R3-> 符号链接 -> 设备对象 -> 驱动对象 -> 驱动功能

驱动通信实质上是设备通信

设备是挂在驱动上的 DeviceObject 上面的

正常 IO 通信

R0:

// 创建设备名称
UNICODE_STRING Devicename;
RtlInitUnicodeString(&Devicename,L"\\Device\\MyDevice");

// 创建设备
IoCreateDevice(
    pDriver,    // 当前设备所属的驱动对象
    0,
    &Devicename,    // 设备对象的名称
    FILE_DEVICE_UNKNOWN,
    FILE_DEVICE_SECURE_OPEN,
    FALSE,
    &pDeviceObj    // 设备对象指针
);

R3:

CreateFileW(SYMBOL_LINK_NAME,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
DeviceIoControl(g_Device,KillAPP,&pEprocess,sizeof(DWORD),&outBuffer,sizeof(DWORD),NULL,NULL))

 

 

隐蔽通讯常见种类介绍

隐蔽通信原理与常见种类

正常的设备通信会被各种 ark 或其他工具遍历到

winobj:https://learn.microsoft.com/zh-cn/sysinternals/downloads/winobj

隐蔽通讯常见种类介绍

devicetree.exe

隐蔽通讯常见种类介绍

其次通过无模块加载技术加载的驱动没有驱动对象,也无法创建正常的 io 通信。所以我们另寻通信方式。

任何能从 3 环主动发起 0 环能接收到的 API 或方法都能作为通信方法,如果对通信的实时性没要求也可去掉“主动”一词

常见隐蔽通信方式

1. 劫持 io 通信

故名意思,去劫持系统白名单驱动的通信。

在导入表有查看是否有建立 IO 通信的函数

隐蔽通讯常见种类介绍

隐蔽通讯常见种类介绍

发现没有 IRP_MJ_DEVICE_CONTROL 我们可以给他增加一个来作为我们的通信

2.minifilter 端口

FltCreateCommunicationPort
FltCloseCommunicationPort
通过回调函数的 InputBuffer 接受用户态的消息并通过 OutputBuffer 回复
用户态通过 FilterConnectCommunicationPort 和 FilterSendMessage 通信

3. 共享内存

3 环申请一块内存,0 环使用 mdl 映射

3. 注册表

3 环和内核都有可以读写注册表的函数,故而可以作为通信

 if (!WriteRegistryDword(HKEY_LOCAL_MACHINE, L"", L"oPid", GetCurrentProcessId())) {return false;}
    if (!WriteRegistryQword(HKEY_LOCAL_MACHINE, L"", L"oAddr", reinterpret_cast<DWORD_PTR>(req))) {
InitializeObjectAttributes(&ObjectAttributes, &RegPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

	Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
	if (!NT_SUCCESS(Status)) {return Status;}

	KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
	Status = ZwQueryValueKey(KeyHandle, &AddrValueName, KeyValuePartialInformation, &KeyValueInfo, sizeof(KeyValueInfo) + sizeof(DWORD), &ResultLength);

	if (NT_SUCCESS(Status)) {if (KeyValueInfo.Type == REG_QWORD && KeyValueInfo.DataLength == sizeof(uintptr_t)) {RtlCopyMemory(&Buffer, KeyValueInfo.Data, sizeof(uintptr_t));
			oAddr = Buffer;
		}
		else {Status = STATUS_INVALID_PARAMETER;}
	}

	ZwClose(KeyHandle);

4. 文件

同上 3 和 0 都有操作文件的函数

5. 套接字

使用 socket 进行通信

6.data ptr

.data 是目前恶意程序最主流的通信方式,因为太多了,很难全部监控,如果找到的.data 足够隐蔽,那么很难短时间内检测到。

有很多内核函数中是函数指针的调用方式,而这些函数指针存在.data 区,或者.rdata 区,我们通过交互指针的方法,让函数执行到我们模块的函数中。

_guard_dispatch_icall_fptr是 Windows 系统中与控制流防护 (CFG) 相关的关键函数指针,主要用于验证间接函数调用的合法性, 我们可以搜索“_guard_dispatch_icall_fptr”来枚举可利用的指针。

ntoskrnl.exe 被 PG 和各大安全软件监控较为严重,我们可以去其他模块中寻找 data ptr(写个脚本让 ida 去跑)

File->Script file…

隐蔽通讯常见种类介绍

隐蔽通讯常见种类介绍

隐蔽通讯常见种类介绍

像这种 NtUser 开头的函数一般都可从 3 环调用到,并且可以发现具有可利用指针

利用 InterlockedExchangePointer 函数交换指针

 const  PVOID win32k = system::get_kernel_modulebase(("win32k.sys"), &nSize);
		 if (win32k) {nt_qword = system::search_kernel((uintptr_t)win32k, NT_QWORD_SIG, NT_QWORD_MASK);

			 const uintptr_t nt_qword_deref = (uintptr_t)nt_qword + 7 + *(int*)((unsigned char*)nt_qword + 3);
			 *(void**)&oNtOldFun = InterlockedExchangePointer((void**)nt_qword_deref, (void*)NtFun);

	
		 }

我们只需要把一个参数当作结构体指针使用,并约定通信码,3 环调用 API 填入指定参数即可完成通信,其他应用不知晓通信码,即可正确调用原 API。

(LoadLibraryA)(("user32.dll"));
		(LoadLibraryA)(("win32u.dll"));

		const HMODULE win32u = (GetModuleHandleA)(("win32u.dll"));
		if (!win32u)
		{return 0;}


		*(void**)&NtUserFun= GetProcAddress(win32u, ("函数名"));

隐蔽通讯常见种类介绍

检测方法

内存与文件做对比,检测指针有效性,栈回溯地址是否在合法模块等等

python 脚本

1765376842-find_data_ptr

正文完
 0
评论(没有评论)