65.9K
CodeProject 正在变化。 阅读更多。
Home

如何验证 COM 接口

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (7投票s)

2008年2月4日

CPOL

2分钟阅读

viewsIcon

41412

解释如何验证 COM 接口和旧的 IsValidateInteface

引言

ole32.dll 中有一个 IsValidInterface 函数,但现在没有被使用。 一个函数的形状是活的,并且可能在内部使用。 在 Windows 中,许多程序员使用 IsBadReadPtr 来验证指针,这很有用。 就像这样,如果你用 COM 编程,就需要一个像 COM 版本的 IsBadReadPtr 这样的验证方法。 然而,MSDN 说“这个函数 (IsValidInterface) 已经过时了。” 我真的很想使用这个函数,所以我尝试探索并提出这个问题,“真相是什么?”

IsValidInterface

IsValidInterfaceole32.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 函数返回 TRUEValidateInPointers 检查 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)
        );
}

在这段代码中,通过 IsBadCodePtrIsBadReadPtr 确认代码和接口,然后检查 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)')

© . All rights reserved.