NtQueryInformationProcess一直都失败了

时间:2013-08-21 13:00:47

标签: c++ winapi

我尝试在Windows 7中获取另一个进程的命令行参数。我使用this article作为参考。

但是返回错误总是给我(NTSTATUS dwStatus)负数,如:

dwStatus = -1073741820

进程ID有效,apa = GetLastError();S_OK

这是我的代码:

头文件

class NtDll
{
...
typedef DWORD (WINAPI *PNtQueryInformationProcess)(HANDLE, DWORD, PVOID, DWORD, PVOID );
static PNtQueryInformationProcess NtQueryInformationProcess;
....
....
}

c ++文件

i do this to enable access :
//== only to have better chance to read processes =====
  if(!sm_EnableTokenPrivilege(SE_DEBUG_NAME))
  {
        return 0;
  }

// Attempt to access process

    BOOL  bReturnStatus                     = TRUE;
    DWORD dwSize                            = 0;
    DWORD dwSizeNeeded                      = 0;
    DWORD dwBytesRead                       = 0;
    DWORD dwBufferSize                      = 0;
    HANDLE hHeap                            = 0;
    WCHAR *pwszBuffer                       = NULL;

    smPROCESSINFO spi                       = {0};
    smPPROCESS_BASIC_INFORMATION pbi        = NULL;

    smPEB peb                               = {0};
    smPEB_LDR_DATA peb_ldr                  = {0};
    smRTL_USER_PROCESS_PARAMETERS peb_upp   = {0};

    ZeroMemory(&spi, sizeof(spi));
    ZeroMemory(&peb, sizeof(peb));
    ZeroMemory(&peb_ldr, sizeof(peb_ldr));
    ZeroMemory(&peb_upp, sizeof(peb_upp));



    // pSysProcess->dUniqueProcessId is the process number 

    HRESULT apa = 0;
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 
                                  PROCESS_VM_READ, FALSE,pSysProcess->dUniqueProcessId);
    if(hProcess == INVALID_HANDLE_VALUE) {
        return FALSE;
    }
    else if(hProcess == NULL)
    {
        apa = GetLastError();
    }
    // Try to allocate buffer 
    hHeap = GetProcessHeap();
    dwSize = sizeof(smPPROCESS_BASIC_INFORMATION);
    pbi = (smPPROCESS_BASIC_INFORMATION)HeapAlloc(hHeap,
                                                  HEAP_ZERO_MEMORY,
                                                  dwSize);
    // Did we successfully allocate memory
    if(!pbi) {
        CloseHandle(hProcess);
        return FALSE;
    }

    // Attempt to get basic info on process
    NTSTATUS dwStatus =  NtDll::NtQueryInformationProcess(hProcess,
                                                              ProcessBasicInformation,
                                                              pbi,
                                                              dwSize,
                                                              &dwSizeNeeded);

 HRESULT dwStatus_err = 0;
     dwStatus_err = GetLastError();  // This gives me always access denied

一切似乎都是正确的,但我仍然得到错误的结果,为什么会这样?

更新:

我添加了指示我做了sm_EnableTokenPrivilege 并且:

 dwStatus_err = GetLastError();  // This gives me always access denied

1 个答案:

答案 0 :(得分:3)

获取进程命令行参数的简单方法:

WMIC path win32_process get Caption,Processid,Commandline

通过代码的另一种方式(见article):

VOID GetCommandLines()
{
    HRESULT hr = 0;
    IWbemLocator         *WbemLocator  = NULL;
    IWbemServices        *WbemServices = NULL;
    IEnumWbemClassObject *EnumWbem  = NULL;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------
    hr = CoInitializeEx(0, COINIT_MULTITHREADED);

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------
    // Note: If you are using Windows 2000, you need to specify -
    // the default authentication credentials for a user by using
    // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
    // parameter of CoInitializeSecurity ------------------------
    hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------
    hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &WbemLocator);

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method
    hr = WbemLocator->ConnectServer(L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &WbemServices);   

    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------
    hr = CoSetProxyBlanket(WbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----
    hr = WbemServices->ExecQuery(L"WQL", L"SELECT ProcessId,CommandLine FROM Win32_Process", WBEM_FLAG_FORWARD_ONLY, NULL, &EnumWbem);

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------
    if (EnumWbem != NULL) {
        IWbemClassObject *result = NULL;
        ULONG returnedCount = 0;

        while((hr = EnumWbem->Next(WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
            VARIANT ProcessId;
            VARIANT CommandLine;

            // access the properties
            hr = result->Get(L"ProcessId", 0, &ProcessId, 0, 0);
            hr = result->Get(L"CommandLine", 0, &CommandLine, 0, 0);            
            if (!(CommandLine.vt==VT_NULL))
            wprintf(L"%u  %s \r\n", ProcessId.uintVal, CommandLine.bstrVal);

            result->Release();
        }
    }

    // Cleanup
    // ========
    EnumWbem->Release();
    WbemServices->Release();
    WbemLocator->Release();

    CoUninitialize();    
    getchar();
}

如果您真的想让NtQueryInformationProcess正常工作,请参阅此blog entry或此file

DWORD GetRemoteCommandLineW(HANDLE hProcess, LPWSTR pszBuffer, UINT bufferLength)
{
  struct RTL_USER_PROCESS_PARAMETERS_I
  {
    BYTE Reserved1[16];
    PVOID Reserved2[10];
    UNICODE_STRING ImagePathName;
    UNICODE_STRING CommandLine;
  };

  struct PEB_INTERNAL
  {
    BYTE Reserved1[2];
    BYTE BeingDebugged;
    BYTE Reserved2[1];
    PVOID Reserved3[2];
    struct PEB_LDR_DATA* Ldr;
    RTL_USER_PROCESS_PARAMETERS_I* ProcessParameters;
    BYTE Reserved4[104];
    PVOID Reserved5[52];
    struct PS_POST_PROCESS_INIT_ROUTINE* PostProcessInitRoutine;
    BYTE Reserved6[128];
    PVOID Reserved7[1];
    ULONG SessionId;
  };

  typedef NTSTATUS (NTAPI* NtQueryInformationProcessPtr)(
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL);

  typedef ULONG (NTAPI* RtlNtStatusToDosErrorPtr)(NTSTATUS Status);

  // Locating functions
  HINSTANCE hNtDll = GetModuleHandleW(L"ntdll.dll");
  NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");
  RtlNtStatusToDosErrorPtr RtlNtStatusToDosError = (RtlNtStatusToDosErrorPtr)GetProcAddress(hNtDll, "RtlNtStatusToDosError");

  if(!NtQueryInformationProcess || !RtlNtStatusToDosError)
  {
    printf("Functions cannot be located.\n");
    return 0;
  }

  // Get PROCESS_BASIC_INFORMATION
  PROCESS_BASIC_INFORMATION pbi;
  ULONG len;
  NTSTATUS status = NtQueryInformationProcess(
    hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
  SetLastError(RtlNtStatusToDosError(status));
  if(NT_ERROR(status) || !pbi.PebBaseAddress)
  {
    printf("NtQueryInformationProcess(ProcessBasicInformation) failed.\n");
    return 0;
  }

  // Read PEB memory block
  SIZE_T bytesRead = 0;
  PEB_INTERNAL peb;
  if(!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), &bytesRead))
  {
    printf("Reading PEB failed.\n");
    return 0;
  }

  // Obtain size of commandline string
  RTL_USER_PROCESS_PARAMETERS_I upp;
  if(!ReadProcessMemory(hProcess, peb.ProcessParameters, &upp, sizeof(upp), &bytesRead))
  {
    printf("Reading USER_PROCESS_PARAMETERS failed.\n");
    return 0;
  }

  if(!upp.CommandLine.Length)
  {
    printf("Command line length is 0.\n");
    return 0;
  }

  // Check the buffer size
  DWORD dwNeedLength = (upp.CommandLine.Length+1) / sizeof(wchar_t) +1;
  if(bufferLength < dwNeedLength)
  {
    printf("Not enough buffer.\n");
    return dwNeedLength;
  }

  // Get the actual command line
  pszBuffer[dwNeedLength - 1] = L'\0';
  if(!ReadProcessMemory(hProcess, upp.CommandLine.Buffer, pszBuffer, upp.CommandLine.Length, &bytesRead))
  {
    printf("Reading command line failed.\n");
    return 0;
  }

  return bytesRead / sizeof(wchar_t);
}