0

免责声明:

问题和以下代码存在的唯一原因是我的应用程序中使用的外部组件,至少在不久的将来无法替换。该组件的逻辑拦截来自应用程序的 WinAPI 调用,并根据这些调用执行各种任务。

组件所做的其中一件事是,它为应用程序内初始化的每个线程创建互斥锁。但是,它不会关闭互斥锁,这会导致句柄泄漏。

因此,为了防止泄漏并且因为我无法访问组件的源代码,我必须发明丑陋的变通方法并使用深奥的 API。

免责声明结束

我正在尝试检查我的应用程序中互斥锁的状态。为了做到这一点而不改变我检查的每个对象的状态,我必须使用NtQueryMutant来自ntdll.dll的方法。

基于此处此处的示例,我编写了以下代码来实现此目的:

enum MUTANT_INFORMATION_CLASS
{
    MutantBasicInformation
};

struct MUTANT_BASIC_INFORMATION {
    LONG CurrentCount;
    BOOLEAN OwnedByCaller;
    BOOLEAN AbandonedState;
};

typedef NTSTATUS(WINAPI*QueryMutexHandler)(HANDLE, MUTANT_INFORMATION_CLASS, PVOID, ULONG, PULONG);

//somewhere in the code:
QueryMutexHandler queryMutex = reinterpret_cast<QueryMutexHandler>(GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryMutant"));
MUTANT_BASIC_INFORMATION mutantInfo;
NTSTATUS status = queryMutex(objectHandleCopy, MutantBasicInformation, &mutantInfo, sizeof(MUTANT_BASIC_INFORMATION), nullptr);
if (NT_SUCCESS(status))
{
     //never arriving here
}

我在这里收到的status始终是-1073741790 (0xFFFF FFFF C000 0022),除了负数之外,它看起来与STATUS_ACCESS_DENIED完全相同。

这很奇怪,因为之前在代码中我同时使用了这两种方法NtQuerySystemInformation并且NtQueryObject没有任何问题。

其他详细信息:我的操作系统是 Windows 7 SP1,我尝试查询的互斥锁属于我正在执行查询的进程。

4

1 回答 1

2

为了有效地测试 Mutant,您需要它处理并访问掩码。你可以从SYSTEM_HANDLE_INFORMATION_EX结构中得到它。如果我们已经有MUTANT_QUERY_STATE- 可以直接查询,如果没有 - 需要重新打开句柄MUTANT_QUERY_STATE

NTSTATUS QueryMutant(HANDLE hMutant, ULONG GrantedAccess, MUTANT_BASIC_INFORMATION* pmbi)
{
    if (GrantedAccess & MUTANT_QUERY_STATE)
    {
        return ZwQueryMutant(hMutant, MutantBasicInformation, pmbi, sizeof(MUTANT_BASIC_INFORMATION), 0);
    }

    NTSTATUS status = ZwDuplicateObject(NtCurrentProcess(), hMutant, NtCurrentProcess(),&hMutant, 
        MUTANT_QUERY_STATE, 0, 0);

    if (0 <= status)
    {
        status = ZwQueryMutant(hMutant, MutantBasicInformation, pmbi, sizeof(MUTANT_BASIC_INFORMATION), 0);
        ZwClose(hMutant);
    }

    return status;
}

而且您不需要一直使用 NtQueryObject 来确定句柄类型。你可以使用SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ObjectTypeIndex. 通过此索引获取OBJECT_TYPE_INFORMATION 。为此,您只需要ZwQueryObject(0, ObjectAllTypeInformation, )在开始时调用一次,但存在如何转换SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ObjectTypeIndex为数组索引(零基)的问题。从 win8.1 开始 'OBJECT_TYPE_INFORMATION.TypeIndex' 有效并匹配到SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ObjectTypeIndex,但对于早期版本 - 您需要一次获取SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX.ObjectTypeIndex某些已知对象类型和计算增量

static volatile UCHAR guz;

NTSTATUS getProcessIndex(USHORT& ObjectTypeIndex)
{
    HANDLE hProcess;
    NTSTATUS status = ZwDuplicateObject(NtCurrentProcess(), NtCurrentProcess(), NtCurrentProcess(), &hProcess, 0, 0, DUPLICATE_SAME_ACCESS);

    if (0 <= status)
    {
        PVOID stack = alloca(guz);
        DWORD cb = 0, rcb = 0x10000;

        union {
            PVOID buf;
            PSYSTEM_HANDLE_INFORMATION_EX pshti;
        };

        do 
        {
            if (cb < rcb) cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);

            if (0 <= (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, buf, cb, &rcb)))
            {
                if (ULONG NumberOfHandles = (ULONG)pshti->NumberOfHandles)
                {
                    PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles = pshti->Handles;

                    ULONG_PTR UniqueProcessId = GetCurrentProcessId();
                    do 
                    {
                        if (Handles->UniqueProcessId == UniqueProcessId && (HANDLE)Handles->HandleValue == hProcess)
                        {
                            ObjectTypeIndex = Handles->ObjectTypeIndex;
                            goto __break;
                        }

                    } while (Handles++, --NumberOfHandles);
                }
            }

        } while (STATUS_INFO_LENGTH_MISMATCH == status);

__break:
        ZwClose(hProcess);
    }

    return status;
}

class ZOBJECT_ALL_TYPES_INFORMATION
{
    OBJECT_TYPE_INFORMATION* _TypeInformation;
    DWORD _NumberOfTypes, _TypeIndexDelta;

public:

    operator DWORD()
    {
        return _NumberOfTypes;
    }

    operator OBJECT_TYPE_INFORMATION*()
    {
        return _TypeInformation;
    }

    DWORD operator[](OBJECT_TYPE_INFORMATION* TypeInformation)
    {
        return (DWORD)(TypeInformation - _TypeInformation) + _TypeIndexDelta;
    }

    OBJECT_TYPE_INFORMATION* operator[](DWORD Index)
    {
        return Index < _NumberOfTypes ? _TypeInformation + Index : 0;
    }

    ULONG TypeIndexToIndex(DWORD ObjectTypeIndex)
    {
        return ObjectTypeIndex -= _TypeIndexDelta;
    }

    OBJECT_TYPE_INFORMATION* operator[](PCUNICODE_STRING TypeName);

    ZOBJECT_ALL_TYPES_INFORMATION();

    ~ZOBJECT_ALL_TYPES_INFORMATION();
};

ZOBJECT_ALL_TYPES_INFORMATION g_AOTI;

OBJECT_TYPE_INFORMATION* ZOBJECT_ALL_TYPES_INFORMATION::operator[](PCUNICODE_STRING TypeName)
{
    if (DWORD NumberOfTypes = _NumberOfTypes)
    {
        OBJECT_TYPE_INFORMATION* TypeInformation = _TypeInformation;

        do 
        {
            if (RtlEqualUnicodeString(TypeName, &TypeInformation->TypeName, TRUE))
            {
                return TypeInformation;
            }
        } while (TypeInformation++, -- NumberOfTypes);
    }

    return 0;
}

ZOBJECT_ALL_TYPES_INFORMATION::ZOBJECT_ALL_TYPES_INFORMATION()
{
    _TypeInformation = 0, _NumberOfTypes = 0;

    USHORT ProcessTypeIndex;
    if (0 > getProcessIndex(ProcessTypeIndex))
    {
        return ;
    }

    NTSTATUS status;
    PVOID stack = alloca(guz);

    union {
        PVOID pv;
        OBJECT_TYPES_INFORMATION* poati;
    };

    DWORD cb = 0, rcb = 0x2000;
    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
        }

        if (0 <= (status = ZwQueryObject(0, ObjectAllTypeInformation, poati, cb, &rcb)))
        {
            if (DWORD NumberOfTypes = poati->NumberOfTypes)
            {
                if (OBJECT_TYPE_INFORMATION* TypeInformation = (OBJECT_TYPE_INFORMATION*)LocalAlloc(0, rcb))
                {
                    _NumberOfTypes = NumberOfTypes;
                    _TypeInformation = TypeInformation;

                    ULONG Index = 0;

                    union {
                        ULONG_PTR uptr;
                        OBJECT_TYPE_INFORMATION* pti;
                    };

                    union {
                        PWSTR buf;
                        PBYTE pb;
                        PVOID pv;
                    };

                    pti = poati->TypeInformation;
                    pv = TypeInformation + NumberOfTypes;

                    do 
                    {
                        STATIC_UNICODE_STRING_(Process);

                        if (RtlEqualUnicodeString(&Process, &pti->TypeName, TRUE))
                        {
                            _TypeIndexDelta = ProcessTypeIndex - Index;
                        }

                        ULONG Length = pti->TypeName.Length, MaximumLength = pti->TypeName.MaximumLength;
                        memcpy(buf, pti->TypeName.Buffer, Length);

                        *TypeInformation = *pti;
                        TypeInformation++->TypeName.Buffer = buf;
                        pb += Length;
                        uptr += (sizeof(OBJECT_TYPE_INFORMATION) + MaximumLength + sizeof(PVOID)-1) & ~ (sizeof(PVOID)-1);
                    } while (Index++, --NumberOfTypes);
                }
            }
        } 
    } while (status == STATUS_INFO_LENGTH_MISMATCH);
}

ZOBJECT_ALL_TYPES_INFORMATION::~ZOBJECT_ALL_TYPES_INFORMATION()
{
    if (_TypeInformation)
    {
        LocalFree(_TypeInformation);
    }
}

最后使用下一个代码,没有 NtQueryObject:

void TestMutant()
{
    NTSTATUS status;
    PVOID stack = alloca(guz);
    DWORD cb = 0, rcb = 0x10000;

    union {
        PVOID buf;
        PSYSTEM_HANDLE_INFORMATION_EX pshti;
    };

    do 
    {
        if (cb < rcb) cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);

        if (0 <= (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, buf, cb, &rcb)))
        {
            if (ULONG NumberOfHandles = (ULONG)pshti->NumberOfHandles)
            {
                PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles = pshti->Handles;

                ULONG_PTR UniqueProcessId = GetCurrentProcessId();
                do 
                {
                    if (Handles->UniqueProcessId == UniqueProcessId)
                    {
                        if (OBJECT_TYPE_INFORMATION* poti = g_AOTI[g_AOTI.TypeIndexToIndex(Handles->ObjectTypeIndex)])
                        {
                            STATIC_UNICODE_STRING_(Mutant);

                            if (RtlEqualUnicodeString(&Mutant, &poti->TypeName, TRUE))
                            {
                                MUTANT_BASIC_INFORMATION mbi;
                                QueryMutant((HANDLE)Handles->HandleValue, Handles->GrantedAccess, &mbi);
                            }
                        }
                    }

                } while (Handles++, --NumberOfHandles);
            }
        }

    } while (STATUS_INFO_LENGTH_MISMATCH == status);
}

可以测试

    void Az()
{
    HANDLE hMutant;
    if (0 <= ZwCreateMutant(&hMutant, SYNCHRONIZE, 0, TRUE))
    {
        TestMutant();
        ZwClose(hMutant);
    }
}
于 2016-08-14T16:15:04.153 回答