-
-
[原创]鸿蒙IPC通信漏洞挖掘方法论(1)
-
发表于: 3天前 226
-
首先需要选择一个SA,以DistributedBms为例:
在 Stub 侧找到 IPC 入口 OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)。它是 IPCObjectStub 的虚函数,由 IPC 框架在服务端线程收到跨进程请求时派发到具体实现。
任何通过samgr持有该 IRemoteObject 句柄的进程都能直接 SendRequest 并自行构造 data。

其中
GetDescriptor()
ReadInterfaceToken()
负责校验调用方的身份。
switch (code) {
case static_cast<uint32_t>(DistributedInterfaceCode::GET_REMOTE_ABILITY_INFO):
case static_cast<uint32_t>(DistributedInterfaceCode::GET_REMOTE_ABILITY_INFO_WITH_LOCALE):
return HandleGetRemoteAbilityInfo(data, reply);
...负责根据调用方的不同code把参数分发给不同的方法来具体执行业务逻辑,以HandleGetRemoteAbilityInfo为例:

其中ReadParcelable<ElementName>()函数负责将data反序列化成ElementName对象,具体调用链如下:
SA 进程 OnRemoteRequest
└─ HandleGetRemoteAbilityInfo(Parcel &data, Parcel &reply) <-- 这个函数里决定了怎么处理数据
└─ data.ReadParcelable<ElementName>()
└─ Parcel::ReadParcelable<ElementName>()
├─ int32_t size = ReadInt32(); if (size == 0) → nullptr
└─ ElementName::Unmarshalling(*this)
└─ new (std::nothrow) ElementName()
└─ ReadFromParcel(parcel)
├─ parcel.ReadString16() → bundleName_
├─ parcel.ReadString16() → abilityName_
└─ parcel.ReadString16() → deviceId_
int ret = GetRemoteAbilityInfo(*elementName, localeInfo, remoteAbilityInfo);
在GetRemoteAbilityInfo函数里外部输入真正被消费,用于实现业务逻辑。
在框架层面,可以作为攻击面的地方:
1.依照proxy 的 WriteXxx 序列,逐行对照 stub 的 ReadXxx来发现是否存在读写mismatch的地方。
2.ReadXXX例如ReadString16(),ReadInt32()是否有上限、长度的溢出回绕等。
3.Marshalling 的 WRITE_PARCEL_* 次数 与 ReadFromParcel 的 Read* 次数是否一致,不一致则后续字段全部串位。
4.栈上未初始化的变量,若其在被写进reply之前未被赋值,则可能回泄栈上地址。内核 binder 驱动在reply之前会一直阻塞,回写后按 pending transaction 投递,reply原路回到等待的客户端线程。(由于IDL生成的存在,这类问题大多已缓解)
在下一节,我们将探讨外部输入在业务函数中实际消费的地方,如GetDistributedBundleInfo函数,有哪些常见的攻击面。
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。