如何验证 COM 接口





4.00/5 (7投票s)
解释如何验证 COM 接口和旧的 IsValidateInteface
引言
在 ole32.dll 中有一个 IsValidInterface
函数,但现在没有被使用。 一个函数的形状是活的,并且可能在内部使用。 在 Windows 中,许多程序员使用 IsBadReadPtr
来验证指针,这很有用。 就像这样,如果你用 COM 编程,就需要一个像 COM 版本的 IsBadReadPtr
这样的验证方法。 然而,MSDN 说“这个函数 (IsValidInterface
) 已经过时了。” 我真的很想使用这个函数,所以我尝试探索并提出这个问题,“真相是什么?”
IsValidInterface
IsValidInterface
在 ole32.dll 中声明。 因此,我们可以通过 GetProcAddress
API 获取地址。 然而,为什么 MSDN 说,“不要使用它!?” 为了回答这个问题,我反汇编了 IsValidInterface
函数并翻译了 C 代码。
BOOL IsValidInterface(LPVOID lpInterface)
{
if(lpInterface == NULL) {
return FALSE;
}
// Almost, Result of ValidateInPointers is TRUE. so following code may be not work.
if(ValidateInPointers( lpInterface ) == FALSE) {
return FALSE;
}
// some code.
// - but there is no control code. so all following code will
// return TRUE without exception.
return TRUE;
}
这段代码是 IsValidInterface
的 C 代码 (绝对不是完整代码)。 几乎,ValidateInPointers
函数返回 TRUE
。 ValidateInPointers
检查 PEB
元素并返回。 ValidateInPointers
检查的 PEB
元素几乎是 0
。 总之,这个 IsValidInterface
函数的主要代码是一个 NULL
检查,仅此而已。 分析之后,我对这个函数感到失望。 我不知道这个函数的旧代码,但现在它只是一个 NULL
检查器函数,这不是一个合适的验证方法。
欢迎来到 React OS 的代码
React OS 是一个类似于 Windows 的操作系统。 所以,它的几乎所有源代码都与 Windows 架构共享。 当我在编程方面遇到问题时,我会参考 React OS 的源代码,这有助于我认识和找出问题。 解决问题的最有效和正确的方法是分析 Real OS 及其代码。 在现实世界中,没有时间去做这件事。 React OS 具有以下代码
BOOL WINAPI IsValidInterface ( LPUNKNOWN punk )
{
return !(IsBadReadPtr(punk,4) ||
IsBadReadPtr(punk->lpVtbl,4) ||
IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
);
}
在这段代码中,通过 IsBadCodePtr
和 IsBadReadPtr
确认代码和接口,然后检查 COM 接口的基本点。 注意用 QueryInterface
进行 9 字节的检查。 IUnknown
接口的第一个函数是 QueryInterface
。 所以,来自 QueryInterface
的 9 个字节也属于同一个 COM 组件,并且必须存在。 即使没有真正的问题,这也是不好的编码风格。 检查 4 个字节比检查 9 个字节更好。 此外,与 ||
运算符一起运行操作是不好的。 这是因为它不清楚操作的顺序。 即使有 C 和 C++ 标准,这也不是好风格。
新的 IsValidInterface
现在,让我们创建一个新的 IsValidInterface
。
BOOL IsValidInterface ( LPUNKNOWN punk )
{
if(IsBadReadPtr(punk, 4)) {
return FALSE;
}
if(IsBadReadPtr(punk->lpVtbl, 4)) {
return FALSE;
}
if(IsBadReadPtr(punk->lpVtbl->QueryInterface, 3 * sizeof(LPVOID))) {
return FALSE;
}
if(IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)) {
return FALSE;
}
return TRUE;
}
这段代码是修复我们讨论的问题的结果。 我将 9 个字节更改为 4 个字节,并更改了代码顺序。
历史
2008-02-01:首次发布。
2008-02-11:IsValidInterface 函数更新 (IsBadReadPtr 的 Size 参数从 '4' 更改为 '3 * sizeof(LPVOID)')