Question

My goal is to get the full command line of a 64 bit process programmatically. I have understood and written this code where I do a process walk of all the currently running processes and get each of their details. But the issue is that this code fails to do the same for a 64 bit process (one that is not running under WOW64).

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <iostream>
#include <cstdio>
#include <fstream>

using namespace std;


BOOL GetProcessList( FILE *f);
BOOL ListProcessModules( DWORD dwPID, FILE *f);
BOOL ListProcessThreads( DWORD dwOwnerPID, FILE *f );
void printError( TCHAR* msg, FILE *f );

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64(HANDLE processHandle)
{
    BOOL bIsWow64 = FALSE;

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

    if(fnIsWow64Process != NULL)
    {
        if (!fnIsWow64Process(processHandle, &bIsWow64))
        {
            //handle error
        }
    }
    return bIsWow64;
}


int main( void )
{
    FILE *f = fopen("file_.txt", "w");
    if (f == NULL)
    {
        printf("Error opening file!\n");
        exit(1);
    }
  GetProcessList(f);
  return 0;
}

BOOL GetProcessList( FILE *f)
{
  HANDLE hProcessSnap;
  HANDLE hProcess;
  PROCESSENTRY32 pe32;
  DWORD dwPriorityClass;


  fprintf(f, "start writing:\n");
  /*
  myfile.open ("example.txt");
  myfile << "writing starts here..." << endl;
  */
  // Take a snapshot of all processes in the system.
  hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
  if( hProcessSnap == INVALID_HANDLE_VALUE )
  {
    printError( TEXT("CreateToolhelp32Snapshot (of processes)"), f);
    return( FALSE );
  }

  // Set the size of the structure before using it.
  pe32.dwSize = sizeof( PROCESSENTRY32 );

  // Retrieve information about the first process,
  // and exit if unsuccessful
  if( !Process32First( hProcessSnap, &pe32 ) )
  {
    printError( TEXT("Process32First"), f ); // show cause of failure
    CloseHandle( hProcessSnap );          // clean the snapshot object
    return( FALSE );
  }

  // Now walk the snapshot of processes, and
  // display information about each process in turn
  do
  {

    _tprintf( TEXT("\n\n=====================================================" ));
    _tprintf( TEXT("\nPROCESS NAME:  %s"), pe32.szExeFile );
    _tprintf( TEXT("\n-------------------------------------------------------" ));


    fprintf(f, "\n\n=====================================================");
    fprintf(f, "\nPROCESS NAME:  %s", pe32.szExeFile );
    fprintf(f, "\n------------------------------------------------------------");
    /*
    myfile << "\n\n=====================================================";
    myfile << "\nPROCESS NAME " << pe32.szExeFile;
    myfile << "\n-----------------------------------------------------------";
    */
    // Retrieve the priority class.
    dwPriorityClass = 0;
    hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
    //is hProcess the handle to the process?
    if( hProcess == NULL )
      printError( TEXT("OpenProcess"), f );
    else
    {
      if(IsWow64(hProcess)){
        _tprintf(TEXT("\nThe process is running under WOW64.\n"));
        fprintf(f, "\nThe process is running under WOW64.\n");
        //myfile << "\nThe process is running under WOW64.\n";
      }
      else{
        _tprintf(TEXT("\nThe process is not running under WOW64.\n"));
        fprintf(f, "\nThe process is not running under WOW64.\n");
        //myfile << "\nThe process is not running under WOW64.\n";
      }




      dwPriorityClass = GetPriorityClass( hProcess );
      if( !dwPriorityClass )
        printError( TEXT("GetPriorityClass"), f );
      CloseHandle( hProcess );
    }

    _tprintf( TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID );
    _tprintf( TEXT("\n  Thread count      = %d"),   pe32.cntThreads );
    _tprintf( TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID );
    _tprintf( TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase );

    fprintf(f, "\n  Process ID        = 0x%08X", pe32.th32ProcessID);
    fprintf(f, "\n  Thread count      = %d",   pe32.cntThreads );
    fprintf(f, "\n  Parent process ID = 0x%08X", pe32.th32ParentProcessID );
    fprintf(f, "\n  Priority base     = %d", pe32.pcPriClassBase );

    if( dwPriorityClass )
      _tprintf( TEXT("\n  Priority class    = %d"), dwPriorityClass );

    // List the modules and threads associated with this process
    ListProcessModules( pe32.th32ProcessID,f );
    ListProcessThreads( pe32.th32ProcessID,f );
    char *cmd_line = NULL;
    //get_cmdline_from_pid(pe32.th32ProcessID, cmd_line);

  } while( Process32Next( hProcessSnap, &pe32 ) );

  CloseHandle( hProcessSnap );
  return( TRUE );
}


BOOL ListProcessModules( DWORD dwPID,FILE *f )
{
  HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
  MODULEENTRY32 me32;

  // Take a snapshot of all modules in the specified process.
  hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
  if( hModuleSnap == INVALID_HANDLE_VALUE )
  {
    printError( TEXT("CreateToolhelp32Snapshot (of modules)"), f );
    return( FALSE );
  }

  // Set the size of the structure before using it.
  me32.dwSize = sizeof( MODULEENTRY32 );

  // Retrieve information about the first module,
  // and exit if unsuccessful
  if( !Module32First( hModuleSnap, &me32 ) )
  {
    printError( TEXT("Module32First"), f );  // show cause of failure
    CloseHandle( hModuleSnap );           // clean the snapshot object
    return( FALSE );
  }

  // Now walk the module list of the process,
  // and display information about each module
  do
  {
    _tprintf( TEXT("\n\n     MODULE NAME:     %s"),   me32.szModule );
    _tprintf( TEXT("\n     Executable     = %s"),     me32.szExePath );
    _tprintf( TEXT("\n     Process ID     = 0x%08X"),         me32.th32ProcessID );
    _tprintf( TEXT("\n     Ref count (g)  = 0x%04X"),     me32.GlblcntUsage );
    _tprintf( TEXT("\n     Ref count (p)  = 0x%04X"),     me32.ProccntUsage );
    _tprintf( TEXT("\n     Base address   = 0x%08X"), (DWORD) me32.modBaseAddr );
    _tprintf( TEXT("\n     Base size      = %d"),             me32.modBaseSize );

    fprintf(f, "\n\n     MODULE NAME:     %s",   me32.szModule );
    fprintf(f, "\n     Executable     = %s",     me32.szExePath );
    fprintf(f, "\n     Process ID     = 0x%08X",         me32.th32ProcessID );
    fprintf(f, "\n     Ref count (g)  = 0x%04X",     me32.GlblcntUsage );
    fprintf(f, "\n     Ref count (p)  = 0x%04X",     me32.ProccntUsage );
    fprintf(f, "\n     Base address   = 0x%08X", (DWORD) me32.modBaseAddr );
    fprintf(f, "\n     Base size      = %d",             me32.modBaseSize );

  } while( Module32Next( hModuleSnap, &me32 ) );

  CloseHandle( hModuleSnap );
  return( TRUE );
}

BOOL ListProcessThreads( DWORD dwOwnerPID,FILE *f )
{
  HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
  THREADENTRY32 te32;

  // Take a snapshot of all running threads
  hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
  if( hThreadSnap == INVALID_HANDLE_VALUE )
    return( FALSE );

  // Fill in the size of the structure before using it.
  te32.dwSize = sizeof(THREADENTRY32);

  // Retrieve information about the first thread,
  // and exit if unsuccessful
  if( !Thread32First( hThreadSnap, &te32 ) )
  {
    printError( TEXT("Thread32First"), f ); // show cause of failure
    CloseHandle( hThreadSnap );          // clean the snapshot object
    return( FALSE );
  }

  // Now walk the thread list of the system,
  // and display information about each thread
  // associated with the specified process
  do
  {
    if( te32.th32OwnerProcessID == dwOwnerPID )
    {
      _tprintf( TEXT("\n\n     THREAD ID      = 0x%08X"), te32.th32ThreadID );
      _tprintf( TEXT("\n     Base priority  = %d"), te32.tpBasePri );
      _tprintf( TEXT("\n     Delta priority = %d"), te32.tpDeltaPri );
      _tprintf( TEXT("\n"));

      fprintf(f, "\n\n     THREAD ID      = 0x%08X", te32.th32ThreadID);
      fprintf(f, "\n     Base priority  = %d", te32.tpBasePri );
      fprintf(f, "\n     Delta priority = %d", te32.tpDeltaPri );
      fprintf(f, "\n");
    }
  } while( Thread32Next(hThreadSnap, &te32 ) );

  CloseHandle( hThreadSnap );
  return( TRUE );
}

void printError( TCHAR* msg, FILE *f )
{
  DWORD eNum;
  TCHAR sysMsg[256];
  TCHAR* p;

  eNum = GetLastError( );
  FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL, eNum,
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
         sysMsg, 256, NULL );

  // Trim the end of the line and terminate it with a null
  p = sysMsg;
  while( ( *p > 31 ) || ( *p == 9 ) )
    ++p;
  do { *p-- = 0; } while( ( p >= sysMsg ) &&
                          ( ( *p == '.' ) || ( *p < 33 ) ) );

  // Display the message
  _tprintf( TEXT("\n  WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
  fprintf(f, "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg);
}

It gives me the ERROR CODE 299, which indicates that it could not read or write memory from the process, and thus does not provide me the executable command for any 64 bit process.

=====================================================
PROCESS NAME:  taskhostex.exe
------------------------------------------------------------
The process is not running under WOW64.

  Process ID        = 0x00001954
  Thread count      = 10
  Parent process ID = 0x000003BC
  Priority base     = 8
 WARNING: CreateToolhelp32Snapshot (of modules) failed with error 299 (Only part of a ReadProcessMemory or WriteProcessMemory request was completed)

Could anyone please help me out with getting around this issue?

Thanks.

Was it helpful?

Solution

This is not possible. From the documentation:

If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).

You need to compile your code as 64-bit.

Here more about this issue: How to enum modules in a 64bit process from a 32bit WOW process.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top