0

免責事項:

質問と以下のコードが存在する唯一の理由は、私のアプリケーションで使用されている外部コンポーネントであり、少なくとも近い将来には置き換えることができません。このコンポーネントのロジックは、アプリケーションからの WinAPI 呼び出しをインターセプトし、これらの呼び出しに基づいてさまざまなタスクを実行します。

コンポーネントが行うことの 1 つは、アプリケーション内で初期化された各スレッドのミューテックスを作成することです。ただし、ミューテックスを閉じないため、ハンドル リークが発生します。

したがって、リークを防ぐために、またコンポーネントのソース コードにアクセスできないため、厄介な回避策を考案し、難解な API を使用する必要があります。

免責事項の終了

アプリケーションでミューテックスの状態を確認しようとしています。チェックする各オブジェクトの状態を変更せずにこれを行うには、ntdll.dllNtQueryMutantのメソッドを使用する必要があります。

ここここの例に基づいて、これを実現するために次のコードを書きました。

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問題なく両方を使用していたため、これは非常に奇妙です。

追加の詳細:私の OS は Windows 7 SP1 です。クエリを実行しようとしているミューテックスは、クエリを実行しているプロセスに属しています。

4

1 に答える 1

2

効果的なテストミュータントのためには、それを処理し、マスクにアクセスする必要があります。構造から取得できます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を取得します。このためには、開始時に1回呼び出すだけで済みますが、配列インデックス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 に答える