2016-08-11 75 views
-2

免責聲明:STATUS_ACCESS_DENIED在通話過程中NtQueryMutant

的問題,下面的代碼中存在的唯一原因是在我的應用程序使用的外部元件,這是不能被取代,至少在不久的將來。該組件的邏輯截獲來自應用程序的WinAPI調用,並根據這些調用執行各種任務。

組件所做的一件事是,它爲在應用程序內初始化的每個線程創建互斥鎖。但是,它不關閉互斥鎖,這會導致句柄泄漏。

因此,爲了防止泄漏,並且因爲我無法訪問組件的源代碼,我不得不製造醜陋的變通方法並使用深奧的API。

免責聲明

末我想查一下我的應用程序互斥的狀態。爲了做到這一點而不改變我檢查的每個對象的狀態,我必須使用ntdll.dll中的NtQueryMutant方法。

,基於實施例和herehere我寫下面的代碼來實現這一點:

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

這很奇怪,因爲之前在代碼中我使用NtQuerySystemInformationNtQueryObject都沒有任何問題。

附加信息:我的操作系統是Windows 7 SP1,我嘗試查詢的互斥量屬於我正在執行查詢的過程。

+1

測試爲什麼你需要檢查互斥鎖的狀態?使用前檢查是介紹非常常見的競爭條件錯誤的好方法。 – andlabs

+0

@andlabs這是一個骯髒的解決方法 - 防止應用程序使用的外部組件中的句柄泄漏。 – galenus

+1

你不顯示你如何打開突變體。對於查詢,您需要在句柄中具有MUTANT_QUERY_STATE訪問權限。更快的你沒有這個訪問。和NtQueryObject在這裏無關,因爲它不需要任何處理權限。 NtQuerySystemInformation - 在所有不相關 – RbMm

回答

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該指數。爲此,您只需在開始時調用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); 
    } 
} 
+0

我收到一個** 0x1F0001 **爲GrantedAccess字段,但仍然,'NtQueryMutant'失敗,具有相同的狀態代碼。 – galenus

+0

@galenus - 這很奇怪,因爲#define MUTANT_QUERY_STATE 0x0001就夠了。我自己測試,並尋找例如https://github.com/mic101/windows/blob/master/WRK-v1.2/base/ntos/ex/mutant.c – RbMm

+0

@galenus需要更多的看現場系統爲什麼這發生。只基於你的信息難說 – RbMm

相關問題