参考书籍《深入解析 Windows 操作系统》第六版,网上资料少且部分错误,另外很多内核书籍是以 WRK的LPC 原型来讲解,但 Vista 后LPC代码被移除,仅保留 LPC 的接 口,参考意义不大。
逆向ALPC通信原理仅作为我入职公司的压力测试,所以逆向时间有限,由于 ALPC 设计较复杂,目前仅以 ALPC 简单的通信为基础逆向得到下面的观点,如果有错误,那我也没有法子,哇哈哈。
Windows 需要一种机制来安全的在一个或多个进程之间传输数据,或者允许内核中的服务 和用户模式下的客户之间传输数据,从而实现了一种称为高级本地过程调用( advanced local procedure call ) ALPC 的内部 IPC 机制,这是一种高速的、可伸缩的、安全的消息传递 设施,可用于传递任意大小的消息。
ALPC 是一种内部机制,所以第三方开发人员无法使用,但应用于 windows 的各个部分,例 如本地模式 RPC 和内核模式 RPC 都是调用的 ALPC 。
ALPC_PORT 端口可以代表四种意思( 索引有相应的意义 ):
端口主要分两类:连接端口和通信端口。
0 。未连接通信端口:这是一个未命名的端口,自己和自己通信。
1 。服务器连接端口:这是一个命名的端口,也是服务器的连接请求点。客户通过此端口连 接到服务器。
2 。客户端通信端口:这是一个未命名的端口,客户线程利用这个端口与一个特定的服务器 进行通信。
3 。服务器通信端口:这是一个未命名的端口,服务器利用此端口与一个特定的客户进行通 信,针对每个活动的客户,服务器都有一个这样的端口。
初始化 PortObject 时 AlpcpInitializePort(PortObject, Type, 0) 这里进行了设置,里面这里的 INDEX 会是对应的 TYPE, 内部会根据这个进行大量的判断
数据传输内部实现:
1.0~512 字节以内:直接放入 Port_Message 结构体的末尾。
2.512 字节 ~64K 以内: 512 字节以内,直接放在 Port_Message 结构体的末尾, 512 字节 ~64K 字节,申请一块 Datalen-0x200 的空间放入 Message->ExtensionBuffer 里。
3.64K 以上:返回 Port_Message->Reserve 。【未触发,暂未逆】
消息队列: ( 红色部分是根据自己逆向推测 )
MainQueue: 主队列,消息已经被发送,客户正在出来该消息。
PendingQueue: 待处理消息,消息已经被发送,调用者正在等待应答,但是应答尚未被发 出, 会从 WaitQueue 里的线程池里选择一条线程来执行。
LargeMessageQueue: 大消息队列,消息已经被发送,但是调用者的缓冲区太小因而不能接 受该消息。调用者获得另一次机会来申请一个更大的缓冲区,并再次请求该消息的负荷数 据。
CanceledQueue: 已取消的队列,原本发送给该端口对象的消息,但是此后已被取消。
WaitQueue: 等待队列,它并没有把消息链接起来,相反,它把所有正在等待某个消息的线 程链接起来。
DirectQueue :直接队列。 由某个具体工作线程的处理的。
目前 ALPC 所使用的 BLOB 类型 + 资源类型 :
连接 BLOB : AlpcConnectionType _ALPC_COMMUNICATION_INFO
区域 BLOB : AlpcRegionType _KALPC_REGION
视图 BLOB : AlpcViewType _KALPC_VIEW
安全 BLOB : AlpcSecurityType _KALPC_SECURITY_DATA
内存 BLOB : AlpcSectionType _KALPC_SECTION 消息
BLOB : AlpcMessageType _KALPC_MESSAGE
保留 BLOB : AlpcReserveType _KALPC_RESERVE
句柄 BLOB : AlpcHandleDataType _KALPC_HANDLE_DATA
通过全局变量 AlpcpRegisteredTypes ,可以知道总共注册了多少个 ALPC 类型
AlpcConnectionType 这些属于 BLOB_TYPE 类型:
例如:
CommResources=AlpcpAllocateBlob(&AlpcConnectionType, 0x48, 1)
根据 BlobType 用不同的方 法创建 BLOB , 0x48 就是 _ALPC_COMMUNICATION_INFO 的长度。
最后形成的结构体类似 句柄 + 资源 :
t ypedef struct _COMMBLOB
{
_BLOB blob; _
ALPC_COMMUNICATION_INFO alpcCommInfo;
}COMMBLOB,*PCOMMBLOB
BLOB 结构体 :
ResourceId =BLOB_ID
--------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------
例如:这里是创建了连接
BLOB NewAlpcCommunicationInfo=AlpcpAllocateBlob(&AlpcConnectionType, 0x48, 1)
AlpcConnectionType=BLOB_TYPE NewAlpcCommunicationInfo=_ALPC_COMMUNICATION_INFO
windows 在启动阶段调用 LpcInitSystem() 来初始化 ALPC 里面主要实现三个功能:
1 。 windows 在 vista 后移除了所有的 LPC ,但为了兼容性的问题, LPC 包装了 ALPC 的调 用。
2. 通过 AlpcpInitSystem ,创建 _ALPC_PORT 的对象类型并加入到 ObTypeIndexTable 表中。
3. 通过 AlpcpInitSystem ,创建 Alpc 全局消息句柄表。 Windows 会根据消息数量动态的创建 AlpcpSecondaryMessageTables 数组,数组里面都是 HANDLE_TABLE
【在插入消息时,句柄 ID>=0x4000000 时就会进入 AlpcpSecondaryMessageTables 数组 Windows 句柄表是三层结构: 512*512*256=0x4000000 ,这就是由来。
而私有句柄表和全局句柄表是 OBJECT+ 权限,所以是 512*512*256, 而消息句柄表没有权 限,但也沿用了前者的模式】
原型:
NTSYSCALLAPI NTSTATUS NTAPI NtAlpcCreatePort(
_Out_ PHANDLE PortHandle,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes
);
NtAlpcCreatePort-->AlpcpCreateConnectionPort
1.AlpcpCreateConnectionPort->AlpcpCreatePort 来创建一个命名的服务端连接端口,让客户 端可以通过这个连接。
AlpcpCreatePort(ObjectAttributes, PreviousMode, &ServerConnectObject)
2.AlpcpCreateConnectionPort->AlpcpInitializePort 来初始化 Object 结构体。
AlpcpInitializePort(pServerConnectObject, 2, SynchronizationType)
初始化各个链表:
MainQueue: 主队列,消息已经被发送,客户正在处理该消息。
PendingQueue: 待处理消息,消息已经被发送,调用者正在等待应答,但是应答尚未被发 出。
LargeMessageQueue: 大消息队列,消息已经被发送,但是调用者的缓冲区太小因而不能接 受该消息。调用者获得另一次机会来申请一个更大的缓冲区,并再次请求该消息的负荷数 据。
CanceledQueue: 已取消的队列,原本发送给该端口对象的消息,但是此后已被取消。
WaitQueue: 等待队列,它并没有把消息链接起来,相反,它把所有正在等待某个消息的线 程链接起来。
DirectQueue :直接队列。
初始化事件或者信号量:
将当前的 ALPC_PORT 加入全局的 AlpcpPortList 链表
3. 创建连接 BLOB 和连接消息
ServerAlpcConnectCommInfo = AlpcpAllocateBlob(&AlpcConnectionType, 0x48, 1) 注 意 : ConnectionType 内部是调用 ExallocatePoolWithTag 来申请内存
pServerConnectObject->CommunicationInfo = ServerAlpcConnectCommInfo
pServerConnectObject->CommunicationInfo->ConnectionPort = pServerConnectObject;
pServerConnectObject->CommunicationInfo->ServerCommunicationPort = 0;
pServerConnectObject->CommunicationInfo->CloseMessage = 0;
ServerAlpcConnectCommInfo->ClientCommunicationPort = 0;
InitializeListHead(&ServerAlpcCommInfo->CommunicationList)
AlpcInitializeHandleTable(&ServerAlpcConnectCommInfo->HandleTable); // 初始化句柄表
ObInsertObjectEx(pServerConnectObject, 0, 0x1F0001u, 0, 0, 0, &Handle); // 将当前 object 对象 插入到 Server 端的私有句柄表里。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)