2017-09-08 109 views
0

這裏是我的功能:NtQuerySystemInformation返回24(ERROR_BAD_LENGTH)

PVOID QuerySystemInformation(SYSTEMINFOCLASS SystemEnum) { 
     DWORD MemorySize = NULL; 
     NTSTATUS Status = NtQuerySystemInformation(SystemEnum, NULL, 0, &MemorySize); 
     if (NT_SUCCESS(Status)) { 
      PVOID Memory = PVOID(Allocate(MemorySize)); 
      if (Memory != ERROR) { 
       Status = NtQuerySystemInformation(SystemEnum, Memory, MemorySize, &MemorySize); 
       if (NT_SUCCESS(Status)) { 
        return Memory; 
       } 
       Free(Memory); 
      } 
     } 
     return ERROR; 
    } 

我通過SystemBasicInformation的功能。在第一次撥打NtQuerySystemInformation後,我收到一個錯誤消息。 RtlNtStatusToDosError(Status)的結果是24 (ERROR_BAD_LENGTH)。哪裏有問題?

+1

請不要破壞你自己的帖子。 – EJoshuaS

+0

更糟糕的是,你似乎得到了多個有用的答案。 – EJoshuaS

回答

0

NtQuerySystemInformation if SystemInformationLength對於保持信息返回錯誤STATUS_INFO_LENGTH_MISMATCH太小。 (RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH)==ERROR_BAD_LENGTH

需要明白,有些SystemInformationClass返回衆所周知固定大小的數據。爲例SystemBasicInformation

,所以你需要做的下一本固定大小的信息類別:

SYSTEM_BASIC_INFORMATION sbi; 
NTSTATUS status = ZwQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), 0); 
if (0 <= status) 
{ 
    // do something 
} 

但有些信息類返回可變長度的數據。所需的長度在開始時是未知的,在這裏是STATUS_INFO_LENGTH_MISMATCH絕對正常的錯誤(不是致命的)。可變長度信息類,你需要總是在循環查詢和檢查返回的狀態爲STATUS_INFO_LENGTH_MISMATCH有條件繼續循環:

do 
{ 
    ... 
    status = ZwQuerySystemInformation(...); 
    ... 
} while (status == STATUS_INFO_LENGTH_MISMATCH); 

爲什麼循環?因爲在系統返回您所需的緩衝區大小以接收所請求的信息之前以及在您以此緩衝區大小再次調用ZwQuerySystemInformation之前,所需長度可能會發生變化。

這個SystemProcessInformation的明亮示例,它獲得了有關當前在系統中運行的所有進程和線程的信息。在系統返回給你需要的緩衝區大小 - 新線程或進程可以在系統中啓動 - 因爲結果可能需要更大的緩衝區。

我們可以查詢在明年方式這個信息:

NTSTATUS QueryProcessInformation() 
{ 
    NTSTATUS status; 

    ULONG cb = 0x10000; 

    do 
    { 
     status = STATUS_INSUFFICIENT_RESOURCES; 

     if (void* buf = new BYTE[cb]) 
     { 
      if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &cb))) 
      { 
       union { 
        PVOID pv; 
        PBYTE pb; 
        PSYSTEM_PROCESS_INFORMATION pspi; 
       }; 

       pv = buf; 

       ULONG NextEntryOffset = 0; 

       do 
       { 
        pb += NextEntryOffset; 

        DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName); 

       } while (NextEntryOffset = pspi->NextEntryOffset); 
      } 

      delete [] buf; 
     } 

    } while (status == STATUS_INFO_LENGTH_MISMATCH); 

    return status; 
} 

或者我們也可以在堆棧使用累計分配(這只是針對用戶模式,在那裏我們有巨大的堆棧大小)

NTSTATUS QueryProcessInformation2() 
{ 
    NTSTATUS status; 

    union { 
     PVOID buf; 
     PBYTE pb; 
     PSYSTEM_PROCESS_INFORMATION pspi; 
    }; 

    ULONG cb = 0, rcb = 0x10000; 

    volatile UCHAR guz; 

    PVOID stack = alloca(guz); 

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

     if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb))) 
     { 
      ULONG NextEntryOffset = 0; 

      do 
      { 
       pb += NextEntryOffset; 

       DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName); 

      } while (NextEntryOffset = pspi->NextEntryOffset); 
     } 

    } while (status == STATUS_INFO_LENGTH_MISMATCH); 

    return status; 
} 
0

只是刪除

if (NT_SUCCESS(Status)) { 

,取而代之的是:

if(MemorySize){ 
+0

這是錯誤。所有有條件的'if'必須僅基於返回狀態 – RbMm

1

似乎是沒有問題的 - 錯誤是可以預期以零SystemInformationLength參數調用。

MSDN說,大約NtQuerySystemInformation

ReturnLength [出,可選] - 第四個參數

一個可選的指針,它指向函數寫請求的信息的實際大小的位置。如果該大小小於或等於SystemInformationLength參數,則該函數將信息複製到SystemInformation緩衝區; 否則,它將返回一個NTSTATUS錯誤代碼,並在ReturnLength中返回接收請求信息所需的緩衝區大小。

因此檢查DWORD MemorySize確實包含非零大小。

+0

Oooh。好,非常感謝你!對於不注意文檔,我太傻了! – johnsonlee

+0

現在在同一個函數中,我得到'0xC0000005:訪問衝突讀取位置0x4865764A'在對Allocate()的調用之後,有什麼明顯的陳述這個背後的推理? – johnsonlee

+0

我只能猜測,因爲我不知道你正在使用什麼分配器以及錯誤發生在哪裏。你不能使用調試器嗎? – zx485

相關問題