STATUS_ACCESS_DENIED при вызове NtQueryMutant

Отказ от ответственности:

Единственная причина существования вопроса и приведенного ниже кода — это внешний компонент, используемый в моем приложении, который не может быть заменен, по крайней мере, в ближайшем будущем. Логика этого компонента перехватывает вызовы 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, мьютексы, к которым я пытаюсь обратиться, относятся к процессу, с которого я выполняю запрос.

-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);
}
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]