Jump to content



Photo

_WinAPI_GetCommandLineFromPID() - From any process!


  • Please log in to reply
20 replies to this topic

#1 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 23 January 2009 - 09:58 AM

Hi!

I don't like WMI. It's slow and it only works if the WMI-server can run.

I use this func in my security-app "ModHelper", here: http://www.autoitscript.com/forum/index.php?showtopic=84939
I need to be able to suspend processes so they can't get up to no good... WMI doesn't work if you suspend it... :lmao:

It works on XP sp3 and Vista Home. Hope you will try on others. (pre NT will not work.)
(The structures involved are not publicly disclosed (?) by Microsoft, likely so they can change them whenever they feel like it...)

Thanks to wraithdu for borrowing his GetDebugPrivilege, and also for suggestions!
Also check out his great variant using remote thread execution, further down!
:)

AutoIt         
#include <WinAPI.au3>   ; _GetPrivilege_SEDEBUG() uses this include. My function needs none. #include <array.au3>    ; Needed to display array in example. Not needed by Func. #RequireAdmin ; Reported to be of use on Vista, getting more info from protected processes... ; ############# Needed Constants ################### Global Const $PROCESS_VM_READ=0x10 Global Const $PROCESS_QUERY_INFORMATION = 0x400 ; ############ Example code ####################### _GetPrivilege_SEDEBUG() ; I need this for tricky processes. Not needed for most... $list=ProcessList() Redim $list[ubound($list,1)][3] for $i=1 to ubound($list,1)-1     $list[$i][2]=_WinAPI_GetCommandLineFromPID($list[$i][1]) Next _ArrayDisplay($list) Exit ; ############################################### ; ############ Here be func! #################### Func _WinAPI_GetCommandLineFromPID($PID)     $ret1=DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', $PROCESS_VM_READ+$PROCESS_QUERY_INFORMATION, 'int', False, 'int', $PID)     $tag_PROCESS_BASIC_INFORMATION = "int ExitStatus;" & _                                      "ptr PebBaseAddress;" & _                                      "ptr AffinityMask;" & _                                      "ptr BasePriority;" & _                                      "ulong UniqueProcessId;" & _                                      "ulong InheritedFromUniqueProcessId;"     $PBI=DllStructCreate($tag_PROCESS_BASIC_INFORMATION)     DllCall("ntdll.dll", "int", "ZwQueryInformationProcess", "hwnd", $ret1[0], "int", 0, "ptr", DllStructGetPtr($PBI), "int", _                                                                                                 DllStructGetSize($PBI), "int",0)     $dw=DllStructCreate("ptr")     DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                             "ptr", DllStructGetData($PBI,2)+0x10, _ ; PebBaseAddress+16 bytes <-- ptr _PROCESS_PARAMETERS                             "ptr", DllStructGetPtr($dw), "int", 4, "ptr", 0)     $unicode_string = DllStructCreate("ushort Length;ushort MaxLength;ptr String")     DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                                  "ptr", DllStructGetData($dw, 1)+0x40, _ ; _PROCESS_PARAMETERS+64 bytes <-- ptr CommandLine Offset (UNICODE_STRING struct) - Win XP / Vista.                                  "ptr", DllStructGetPtr($unicode_string), "int", DllStructGetSize($unicode_string), "ptr", 0)     $ret=DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                                  "ptr", DllStructGetData($unicode_string, "String"), _ ; <-- ptr Commandline Unicode String                                  "wstr", 0, "int", DllStructGetData($unicode_string, "Length") + 2, "int*", 0) ; read Length + terminating NULL (2 bytes in unicode)     DllCall("kernel32.dll", 'int', 'CloseHandle', "hwnd", $ret1[0])     If $ret[5] Then Return $ret[3]   ; If bytes returned, return commandline...     Return ""                     ; Getting empty string is correct behaviour when there is no commandline to be had... EndFunc ; ####################### Below Func is Part of example - Needed to get commandline from more processes. ############ ; ####################### Thanks for this function, wraithdu! (Didn't know it was your.) :) ######################### Func _GetPrivilege_SEDEBUG()     Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"     Local $count = 1     Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct     Local $TOKEN_ADJUST_PRIVILEGES = 0x20     Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", _WinAPI_GetCurrentProcess(), "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", "")     Local $hToken = $call[3]     $call = DllCall("advapi32.dll", "int", "LookupPrivilegeValue", "str", Chr(0), "str", "SeDebugPrivilege", "int64*", "")     ;msgbox(0,"",$call[3] & " " & _WinAPI_GetLastErrorMessage())     Local $iLuid = $call[3]     Local $TP = DllStructCreate($tagTOKENPRIVILEGES)     Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))     DllStructSetData($TP, "PrivilegeCount", $count)     DllStructSetData($LUID, "Luid", $iLuid)     DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)     $call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", Chr(0), "ptr", Chr(0))     Return ($call[0] <> 0) ; $call[0] <> 0 is success EndFunc   ;==>_GetPrivilege_SEDEBUG


trancexx fixed 64-bit support and fleshed out structs.

AutoIt         
Func _WinAPI_GetCommandLineFromPID($iPID)     Local $aCall = DllCall("kernel32.dll", "handle", "OpenProcess", _             "dword", 1040, _ ; PROCESS_VM_READ | PROCESS_QUERY_INFORMATION             "bool", 0, _             "dword", $iPID)     If @error Or Not $aCall[0] Then         Return SetError(1, 0, "")     EndIf     Local $hProcess = $aCall[0]     Local $tPROCESS_BASIC_INFORMATION = DllStructCreate("dword_ptr ExitStatus;" & _             "ptr PebBaseAddress;" & _             "dword_ptr AffinityMask;" & _             "dword_ptr BasePriority;" & _             "dword_ptr UniqueProcessId;" & _             "dword_ptr InheritedFromUniqueProcessId")     $aCall = DllCall("ntdll.dll", "int", "NtQueryInformationProcess", _             "handle", $hProcess, _             "dword", 0, _ ; ProcessBasicInformation             "ptr", DllStructGetPtr($tPROCESS_BASIC_INFORMATION), _             "dword", DllStructGetSize($tPROCESS_BASIC_INFORMATION), _             "dword*", 0)     If @error Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(2, 0, "")     EndIf     Local $tPEB = DllStructCreate("byte InheritedAddressSpace;" & _             "byte ReadImageFileExecOptions;" & _             "byte BeingDebugged;" & _             "byte Spare;" & _             "ptr Mutant;" & _             "ptr ImageBaseAddress;" & _             "ptr LoaderData;" & _             "ptr ProcessParameters;" & _             "ptr SubSystemData;" & _             "ptr ProcessHeap;" & _             "ptr FastPebLock;" & _             "ptr FastPebLockRoutine;" & _             "ptr FastPebUnlockRoutine;" & _             "dword EnvironmentUpdateCount;" & _             "ptr KernelCallbackTable;" & _             "ptr EventLogSection;" & _             "ptr EventLog;" & _             "ptr FreeList;" & _             "dword TlsExpansionCounter;" & _             "ptr TlsBitmap;" & _             "dword TlsBitmapBits[2];" & _             "ptr ReadOnlySharedMemoryBase;" & _             "ptr ReadOnlySharedMemoryHeap;" & _             "ptr ReadOnlyStaticServerData;" & _             "ptr AnsiCodePageData;" & _             "ptr OemCodePageData;" & _             "ptr UnicodeCaseTableData;" & _             "dword NumberOfProcessors;" & _             "dword NtGlobalFlag;" & _             "ubyte Spare2[4];" & _             "int64 CriticalSectionTimeout;" & _             "dword HeapSegmentReserve;" & _             "dword HeapSegmentCommit;" & _             "dword HeapDeCommitTotalFreeThreshold;" & _             "dword HeapDeCommitFreeBlockThreshold;" & _             "dword NumberOfHeaps;" & _             "dword MaximumNumberOfHeaps;" & _             "ptr ProcessHeaps;" & _             "ptr GdiSharedHandleTable;" & _             "ptr ProcessStarterHelper;" & _             "ptr GdiDCAttributeList;" & _             "ptr LoaderLock;" & _             "dword OSMajorVersion;" & _             "dword OSMinorVersion;" & _             "dword OSBuildNumber;" & _             "dword OSPlatformId;" & _             "dword ImageSubSystem;" & _             "dword ImageSubSystemMajorVersion;" & _             "dword ImageSubSystemMinorVersion;" & _             "dword GdiHandleBuffer[34];" & _             "dword PostProcessInitRoutine;" & _             "dword TlsExpansionBitmap;" & _             "byte TlsExpansionBitmapBits[128];" & _             "dword SessionId")     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPROCESS_BASIC_INFORMATION, "PebBaseAddress"), _             "ptr", DllStructGetPtr($tPEB), _             "dword", DllStructGetSize($tPEB), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(3, 0, "")     EndIf     Local $tPROCESS_PARAMETERS = DllStructCreate("dword AllocationSize;" & _             "dword ActualSize;" & _             "dword Flags;" & _             "dword Unknown1;" & _             "word LengthUnknown2;" & _             "word MaxLengthUnknown2;" & _             "ptr Unknown2;" & _             "handle InputHandle;" & _             "handle OutputHandle;" & _             "handle ErrorHandle;" & _             "word LengthCurrentDirectory;" & _             "word MaxLengthCurrentDirectory;" & _             "ptr CurrentDirectory;" & _             "handle CurrentDirectoryHandle;" & _             "word LengthSearchPaths;" & _             "word MaxLengthSearchPaths;" & _             "ptr SearchPaths;" & _             "word LengthApplicationName;" & _             "word MaxLengthApplicationName;" & _             "ptr ApplicationName;" & _             "word LengthCommandLine;" & _             "word MaxLengthCommandLine;" & _             "ptr CommandLine;" & _             "ptr EnvironmentBlock;" & _             "dword Unknown[9];" & _             "word LengthUnknown3;" & _             "word MaxLengthUnknown3;" & _             "ptr Unknown3;" & _             "word LengthUnknown4;" & _             "word MaxLengthUnknown4;" & _             "ptr Unknown4;" & _             "word LengthUnknown5;" & _             "word MaxLengthUnknown5;" & _             "ptr Unknown5;")     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPEB, "ProcessParameters"), _             "ptr", DllStructGetPtr($tPROCESS_PARAMETERS), _             "dword", DllStructGetSize($tPROCESS_PARAMETERS), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(4, 0, "")     EndIf     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPROCESS_PARAMETERS, "CommandLine"), _             "wstr", "", _             "dword", DllStructGetData($tPROCESS_PARAMETERS, "MaxLengthCommandLine"), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(5, 0, "")     EndIf     DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)     Return $aCall[3] EndFunc  


/Manko [EDIT: trancexx corrections!]

Edited by Manko, 11 March 2010 - 02:29 PM.

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...







#2 trancexx

trancexx

    Hm, I really shouldn't.

  • Active Members
  • PipPipPipPipPipPip
  • 5,194 posts

Posted 23 January 2009 - 12:53 PM

Nice, nice, nice...

eMyvnE


#3 UEZ

UEZ

    Never say never

  • MVPs
  • 3,619 posts

Posted 23 January 2009 - 02:01 PM

Nice work Manko and very useful.


THANKS!

UEZ

 
The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯


#4 GreenCan

GreenCan

    Polymath

  • Active Members
  • PipPipPipPip
  • 240 posts

Posted 23 January 2009 - 05:04 PM

Nicely done UEZ.

Your udf seems to find process paths that Alzo Process Management doesn't find and sometimes V.V. Interesting.

Thanks for sharing,

GreenCan

#5 Paulchen

Paulchen

    Wayfarer

  • Active Members
  • Pip
  • 63 posts

Posted 23 January 2009 - 05:55 PM

Nice work.

Note:When you start this program with #RequireAdmin you get also information over the process with higher integritylevel

#6 UEZ

UEZ

    Never say never

  • MVPs
  • 3,619 posts

Posted 23 January 2009 - 05:56 PM

Nicely done UEZ.

Your udf seems to find process paths that Alzo Process Management doesn't find and sometimes V.V. Interesting.

Thanks for sharing,

GreenCan


The credits must go to Manko not to me :)

UEZ

 
The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯


#7 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 23 January 2009 - 06:18 PM

The credits must go to Manko not to me :think:

UEZ


Thanks UEZ, and all of you!

Paulchen: Is that in Vista??! Never new "#RequireAdmin" did anything but stop code from running if you're not admin. Can't wait to try it on Vista! Or did you mean I forgot to mention that running in admin would reveal more commandlines on xp? Never thought of that... Always in admin. Always doing stuff that require it... :)

If you have Vista, can you confirm this? :lmao: (That "#RequireAdmin" gives access to more commandlines.)
Can't get to a vista system before Sunday.

/Manko

Edited by Manko, 23 January 2009 - 06:21 PM.

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...

#8 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 23 January 2009 - 06:31 PM

I'll check this out tonight. In my little app I use WMI for the commandline. It would be nice to not have to use it.

One other option is to inject a small DLL that calls the GetCommandLine function and returns the info to your app.

#9 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 23 January 2009 - 11:37 PM

Vista Ultimate SP1 32-bit

Alrighty, good function! Few things -

1) #RequireAdmin would be useful for users with UAC enabled only. I'm not sure if getting SEDEBUG will work without this on UAC systems. UAC or not, in Vista SEDEBUG is REQUIRED to get info from system processes.

2) ReadProcessMemory() will always read the specified number of bytes, assuming you're not trying to read outside of the process's address space. So it will return either 0 or 1024, so testing $ret[5]>2 is kinda pointless. Rather -
If Not @error And $ret[5] Then Return $ret[3]ƒo݊÷ ÛpèŸm~ŠàzÛh Z,xv§vW­…êk¡Ç¬³*.ßÛÞ¢—§yÝ÷jëhŠ×6DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $ret1[0])


I get the same results as the WMI version, so that's good. Only other suggestion would be to credit the authors of functions you've borrowed in your source :)

Edited by wraithdu, 23 January 2009 - 11:40 PM.


#10 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 24 January 2009 - 06:16 PM

Vista Ultimate SP1 32-bit
Alrighty, good function! Few things -
1) #RequireAdmin would be useful for users with UAC enabled only. I'm not sure if getting SEDEBUG will work without this on UAC systems. UAC or not, in Vista SEDEBUG is REQUIRED to get info from system processes.
2) ReadProcessMemory() will always read the specified number of bytes, assuming you're not trying to read outside of the process's address space. So it will return either 0 or 1024, so testing $ret[5]>2 is kinda pointless. Rather -

If Not @error And $ret[5] Then Return $ret[3]ƒo݊÷ ÛpèŸm~ŠàzÛh Z,xv§vW­…êk¡Ç¬³*.ßÛÞ¢—§yÝ÷jëhŠ×6DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $ret1[0])
I get the same results as the WMI version, so that's good. Only other suggestion would be to credit the authors of functions you've borrowed in your source :)

Thanks for being a sport about me borrowing your "GetDebugPrivilege" Func! (Didn't know it was yours, I promise!) (Bad excuse! Coulda checked.)

1. I'm putting it in there. Hope this helps yall getting this commandlines on Vista!
2. Another good sugestion.
3. Yeah! You are SO right! Thanks for the borrowed Func! Before I realised that you didn't mean anything in my "UDF", I was going to make a smartass remark about thanking Microsoft for their APIs and structs... Glad I only thought that, and didn't post it on this board... .. . . . .

/Manko
Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...

#11 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 24 January 2009 - 08:20 PM

No problem. Keep up the good work (this one and ModHelper)!

I think I'm going to do up a small C++ example and give it to the author of Daphne process explorer, since he seems to be having problems getting commandlines in Vista. All credit to you for the method!

#12 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 25 January 2009 - 08:13 AM

After doing the C++ version of this, I have a minor update to your function. The commandline is stored as a UNICODE_STRING structure so it's better to read the given length of the string instead of a generic 1024 bytes. If for some reason the full 1024 bytes is not accessible by the ReadProcessMemory function, then the function fails and reads nothing. By reading the actual length of the string, we avoid this potential problem. To do this, we back up the second ReadProcessMemory call by 4 bytes to the beginning of the UNICODE_STRING struct, and read 8 bytes, the size of the struct.

AutoIt         
Func _GetCommandLineFromPID($PID)     $ret1=DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', $PROCESS_VM_READ+$PROCESS_QUERY_INFORMATION, 'int', False, 'int', $PID)     $tag_PROCESS_BASIC_INFORMATION = "int ExitStatus;" & _                                      "ptr PebBaseAddress;" & _                                      "ptr AffinityMask;" & _                                      "ptr BasePriority;" & _                                      "ulong UniqueProcessId;" & _                                      "ulong InheritedFromUniqueProcessId;"     $PBI=DllStructCreate($tag_PROCESS_BASIC_INFORMATION)     DllCall("ntdll.dll", "int", "ZwQueryInformationProcess", "hwnd", $ret1[0], "int", 0, "ptr", DllStructGetPtr($PBI), "int", _                                                                                                 DllStructGetSize($PBI), "int",0)     $dw=DllStructCreate("ptr")     DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                             "ptr", DllStructGetData($PBI,2)+0x10, _ ; PebBaseAddress+16 bytes <-- ptr _PROCESS_PARAMETERS                             "ptr", DllStructGetPtr($dw), "int", 4, "ptr", 0)     $unicode_string = DllStructCreate("ushort Length;ushort MaxLength;ptr String")     DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                                  "ptr", DllStructGetData($dw, 1)+0x40, _ ; _PROCESS_PARAMETERS+64 bytes <-- ptr CommandLine Offset (UNICODE_STRING struct) - Win XP / Vista.                                  "ptr", DllStructGetPtr($unicode_string), "int", DllStructGetSize($unicode_string), "ptr", 0)     $ret=DllCall("kernel32.dll", "int", "ReadProcessMemory", "hwnd", $ret1[0], _                                  "ptr", DllStructGetData($unicode_string, "String"), _ ; <-- ptr Commandline Unicode String                                  "wstr", 0, "int", DllStructGetData($unicode_string, "Length") + 2, "int*", 0) ; read Length + terminating NULL (2 bytes in unicode)     DllCall("kernel32.dll", 'int', 'CloseHandle', "hwnd", $ret1[0])     If $ret[5] Then Return $ret[3]   ; If bytes returned, return commandline...     Return ""                     ; Getting empty string is correct behaviour when there is no commandline to be had... EndFunc         ; ...or if we're not allowed for some reason.... vista...

Edited by wraithdu, 25 January 2009 - 08:15 AM.


#13 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 25 January 2009 - 01:00 PM

Thanks, wraithdu!

I must admit, I had not grasped the UNICODE_STRING struct. Ushort... That explains things... :)
Yes, that is exactly the way to go. (When one knows to get that info... I rushed things as usual...)

Will update!

btw, please relay the mentioned authors response!

/Manko

Edited by Manko, 25 January 2009 - 01:09 PM.

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...

#14 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 25 January 2009 - 05:18 PM

I will when I get one. He seems to visit his board fairly infrequently. Here's the thread -

http://forum.drk.com.ar/viewtopic.php?f=10...=27&start=0

#15 wraithdu

wraithdu

    I am less fun than a twisted ankle.

  • MVPs
  • 2,137 posts

Posted 10 February 2009 - 06:43 PM

I was doing some research regarding remote thread execution for ModuleSpy, and came up with this option for getting the commandline. It creates a thread in the target process which calls the GetCommandLine() function, then retrieves the pointer and reads the memory. There are 2 different functions for creating the remote threads depending if you're using Vista/2008 or not. The reasons are noted in the comments.

AutoIt         
#AutoIt3Wrapper_Change2CUI=y #include <WinAPI.au3> _GetPrivilege_SEDEBUG() $ISVISTA = (@OSVersion == "WIN_VISTA") Or (@OSVersion == "WIN_2008") $pGetCommandLineW = _GetProcAddress(_WinAPI_GetModuleHandle("kernel32.dll"), "GetCommandLineW") $pExitThread = _GetProcAddress(_WinAPI_GetModuleHandle("kernel32.dll"), "ExitThread") $szCmdLine = DllStructCreate("wchar[520]") If $pGetCommandLineW Then     $aList = ProcessList()     For $i = 1 To $aList[0][0]         $hProc = _GetProcHandle($aList[$i][1])         ConsoleWrite("-------------------" & @CRLF)         ConsoleWrite("PID: " & $aList[$i][1] & @CRLF & "hProc: " & $hProc & @CRLF)         If $hProc Then             If $ISVISTA Then                 $hThread = NtCreateThreadEx($hProc, $pGetCommandLineW, 0)             Else                 $hThread = CreateRemoteThread($hProc, $pGetCommandLineW, 0)             EndIf             ConsoleWrite("hThread: " & $hThread & @CRLF)             If $hThread Then                 _WinAPI_WaitForSingleObject($hThread) ; wait for thread to finish                 ; get thread return value, which is the ptr to commandline string                 $ret = DllCall("kernel32.dll", "int", "GetExitCodeThread", "ptr", $hThread, "dword*", 0)                 $pszCmdLine = Ptr($ret[2])                 ConsoleWrite("pszCmdLine: " & $pszCmdLine & @CRLF)                 _WinAPI_CloseHandle($hThread) ; close thread handle                 If $pszCmdLine Then                     ; read the commandline from the remote process                     $ret = DllCall("kernel32.dll", "int", "ReadProcessMemory", "ptr", $hProc, "ptr", $pszCmdLine, "ptr", DllStructGetPtr($szCmdLine), _                                                     "ulong", DllStructGetSize($szCmdLine), "ulong*", 0)                     If $ret[5] Then                         ConsoleWrite("CmdLine: " & DllStructGetData($szCmdLine, 1) & @CRLF)                     EndIf                 EndIf             EndIf             _WinAPI_CloseHandle($hProc)         EndIf     Next EndIf If @Compiled Then MsgBox(0, "GetCommandLineW", "Done.") Func NtCreateThreadEx($hProcess, $pCode, $pParameter)     ; this is a largely undocumented function, so don't ask what the structure is...I don't know either :)     Local $return = 0     Local $tagUNKNOWN = "ulong Length;ulong Unknown1;ulong Unknown2;ptr Unknown3;ulong Unknown4;ulong Unknown5;ulong Unknown6;ptr Unknown7;ulong Unknown8"     Local $dw0 = DllStructCreate("dword")     Local $dw1 = DllStructCreate("dword")     DllStructSetData($dw0, 1, 0)     DllStructSetData($dw1, 1, 0)     Local $buffer = DllStructCreate($tagUNKNOWN)     DllStructSetData($buffer, 1, DllStructGetSize($buffer))     DllStructSetData($buffer, 2, 0x10003)     DllStructSetData($buffer, 3, 0x8)     DllStructSetData($buffer, 4, DllStructGetPtr($dw1))     DllStructSetData($buffer, 5, 0)     DllStructSetData($buffer, 6, 0x10004)     DllStructSetData($buffer, 7, 4)     DllStructSetData($buffer, 8, DllStructGetPtr($dw0))     DllStructSetData($buffer, 9, 0)     ; create the remote thread     ; NtCreateThreadEx is only availale in Vista+ and allows creating threads in sessions other than the calling app's     ; this is necessary versus XP, because a good portion of Vista's processes run in a different session     Local $ret = DllCall("ntdll.dll", "dword", "NtCreateThreadEx", "ptr*", 0, "dword", 0x1FFFFF, "ptr", 0, "ptr", $hProcess, "ptr", $pCode, "ptr", $pParameter, _                                         "int", 0, "dword", 0, "dword", 0, "dword", 0, "ptr", DllStructGetPtr($buffer))     If $ret[1] Then $return = $ret[1]     Return $return EndFunc Func CreateRemoteThread($hProcess, $pCode, $pParameter)     Local $return = 0     ; create remote thread     ; CreateRemoteThread cannot create threads in processes that are not in the calling app's session     ; however in XP, pretty much everything runs in the same session, so we're OK using this function     Local $ret = DllCall("kernel32.dll", "ptr", "CreateRemoteThread", "ptr", $hProcess, "ptr", 0, "uint", 0, "ptr", $pCode, "ptr", $pParameter, "dword", 0, "ptr", 0)     If $ret[0] Then $return = $ret[0]     Return $return EndFunc ; this is another option that allows us to create remote threads in other sessions in XP ; however the return value of our thread is lost (which may be very important, such as the return from LoadLibrary or GetCommandLine) Func RtlCreateUserThread($hProcess, $pCode, $pParameter)     Local $return = 0     ; create a suspended thread at kernel32!ExitThread     Local $ret = DllCall("ntdll.dll", "dword", "RtlCreateUserThread", "ptr", $hProcess, "ptr", 0, "int", 1, "ulong", 0, "ulong*", 0, "ulong*", 0, _                                         "ptr", $pExitThread, "dword*", 0, "ptr*", 0, "ptr*", 0)     If $ret[9] Then         ; schedule an asynchronous procedure call (APC) at the code to be executed         DllCall("ntdll.dll", "dword", "NtQueueApcThread", "ptr", $ret[9], "ptr", $pCode, "ptr", $pParameter, "ptr", 0, "ulong", 0)         ; resume the thread, executing the APC         DllCall("kernel32.dll", "dword", "ResumeThread", "ptr", $ret[9])         $return = $ret[9]     EndIf     ; NOTE: the return value of the APC is lost     Return $return EndFunc Func _GetProcAddress($module, $function)     Local $call = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", $module, "str", $function)     Return $call[0] EndFunc Func _GetProcHandle($process)     Local $hProcess = 0     Local $PERMISSION = BitOR(0x0002, 0x0400, 0x0008, 0x0010, 0x0020) ; CREATE_THREAD, QUERY_INFORMATION, VM_OPERATION, VM_READ, VM_WRITE         If IsInt($process) Then         If $process > 0 Then             Local $ret = DllCall("kernel32.dll", "ptr", "OpenProcess", "dword", $PERMISSION, "int", 0, "dword", $process)             If $ret[0] Then                 $hProcess = $ret[0]             EndIf         EndIf     EndIf         Return $hProcess EndFunc Func _GetPrivilege_SEDEBUG()     Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"     Local $count = 1     Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct     Local $TOKEN_ADJUST_PRIVILEGES = 0x20     Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", _WinAPI_GetCurrentProcess(), "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", "")     Local $hToken = $call[3]     $call = DllCall("advapi32.dll", "int", "LookupPrivilegeValue", "str", Chr(0), "str", "SeDebugPrivilege", "int64*", "")     Local $iLuid = $call[3]     Local $TP = DllStructCreate($tagTOKENPRIVILEGES)     Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))     DllStructSetData($TP, "PrivilegeCount", $count)     DllStructSetData($LUID, "Luid", $iLuid)     DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)     $call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", Chr(0), "ptr", Chr(0))     Return ($call[0] <> 0) ; $call[0] <> 0 is success EndFunc   ;==>_GetPrivilege_SEDEBUG


#16 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 10 February 2009 - 07:40 PM

I was doing some research regarding remote thread execution for ModuleSpy, and came up with this option for getting the commandline. It creates a thread in the target process which calls the GetCommandLine() function, then retrieves the pointer and reads the memory.

Hi, wraithdu!
Great work!
Remote thread execution... Brings back memories from my reversing days...
Thanks for posting in my thread! :)

/Manko
Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...

#17 rexx

rexx

    Wayfarer

  • Active Members
  • Pip
  • 65 posts

Posted 09 March 2010 - 03:00 PM

Hi,
I found this is not working under x64.
I tried to make some modifications but still not working.
Maybe it's the problem of the PEB structure.
http://msdn.microsoft.com/en-us/library/aa813706(VS.85).aspx
But I don't know how to fix it.
Any idea?

AutoIt         
Func _WinAPI_GetCommandLineFromPID($PID)     Local $ret1 = DllCall("kernel32.dll", 'handle', 'OpenProcess', 'dword', $PROCESS_VM_READ+$PROCESS_QUERY_INFORMATION, 'bool', False, 'dword', $PID)     Local $tag_PROCESS_BASIC_INFORMATION = "int ExitStatus;" & _                                            "ptr PebBaseAddress;" & _                                            "ptr AffinityMask;" & _                                            "ptr BasePriority;" & _                                            "ulong_ptr UniqueProcessId;" & _                                            "ulong InheritedFromUniqueProcessId;"     Local $PBI=DllStructCreate($tag_PROCESS_BASIC_INFORMATION)     DllCall("ntdll.dll", "int", "ZwQueryInformationProcess", "hwnd", $ret1[0], "int", 0, "ptr", DllStructGetPtr($PBI), "int", _                                                                                                 DllStructGetSize($PBI), "int",0)     Local $dw=DllStructCreate("ptr")     DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $ret1[0], _                             "ptr", DllStructGetData($PBI,2)+0x10, _ ; PebBaseAddress+16 bytes <-- ptr _PROCESS_PARAMETERS                             "ptr", DllStructGetPtr($dw), "ulong_ptr", 4, "ulong_ptr*", 0)     Local $unicode_string = DllStructCreate("ushort Length;ushort MaxLength;ptr String")     DllCall("kernel32.dll", "bool", "ReadProcessMemory", "handle", $ret1[0], _                             "ptr", DllStructGetData($dw, 1)+0x40, _ ; _PROCESS_PARAMETERS+64 bytes <-- ptr CommandLine Offset (UNICODE_STRING struct) - Win XP / Vista.                             "ptr", DllStructGetPtr($unicode_string), "ulong_ptr", DllStructGetSize($unicode_string), "ulong_ptr*", 0)     Local $ret = DllCall("kernel32.dll", "int", "ReadProcessMemory", "handle", $ret1[0], _                                          "ptr", DllStructGetData($unicode_string, "String"), _ ; <-- ptr Commandline Unicode String                                          "wstr", 0, "ulong_ptr", DllStructGetData($unicode_string, "Length") + 2, "ulong_ptr*", 0) ; read Length + terminating NULL (2 bytes in unicode)     DllCall("kernel32.dll", 'int', 'CloseHandle', "hwnd", $ret1[0])     If $ret[5] Then Return $ret[3] ; If bytes returned, return commandline...     Return "" ; Getting empty string is correct behaviour when there is no commandline to be had... EndFunc

Edited by rexx, 09 March 2010 - 03:01 PM.


#18 trancexx

trancexx

    Hm, I really shouldn't.

  • Active Members
  • PipPipPipPipPipPip
  • 5,194 posts

Posted 09 March 2010 - 05:03 PM

That's because of the coding style Manko uses (check his profile). That's not bad, usually it's efficient enough.
That function should look something like this:
AutoIt         
Func _WinAPI_GetCommandLineFromPID($iPID)     Local $aCall = DllCall("kernel32.dll", "handle", "OpenProcess", _             "dword", 1040, _ ; PROCESS_VM_READ | PROCESS_QUERY_INFORMATION             "bool", 0, _             "dword", $iPID)     If @error Or Not $aCall[0] Then         Return SetError(1, 0, "")     EndIf     Local $hProcess = $aCall[0]     Local $tPROCESS_BASIC_INFORMATION = DllStructCreate("dword_ptr ExitStatus;" & _             "ptr PebBaseAddress;" & _             "dword_ptr AffinityMask;" & _             "dword_ptr BasePriority;" & _             "dword_ptr UniqueProcessId;" & _             "dword_ptr InheritedFromUniqueProcessId")     $aCall = DllCall("ntdll.dll", "int", "NtQueryInformationProcess", _             "handle", $hProcess, _             "dword", 0, _ ; ProcessBasicInformation             "ptr", DllStructGetPtr($tPROCESS_BASIC_INFORMATION), _             "dword", DllStructGetSize($tPROCESS_BASIC_INFORMATION), _             "dword*", 0)     If @error Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(2, 0, "")     EndIf     Local $tPEB = DllStructCreate("byte InheritedAddressSpace;" & _             "byte ReadImageFileExecOptions;" & _             "byte BeingDebugged;" & _             "byte Spare;" & _             "ptr Mutant;" & _             "ptr ImageBaseAddress;" & _             "ptr LoaderData;" & _             "ptr ProcessParameters;" & _             "ptr SubSystemData;" & _             "ptr ProcessHeap;" & _             "ptr FastPebLock;" & _             "ptr FastPebLockRoutine;" & _             "ptr FastPebUnlockRoutine;" & _             "dword EnvironmentUpdateCount;" & _             "ptr KernelCallbackTable;" & _             "ptr EventLogSection;" & _             "ptr EventLog;" & _             "ptr FreeList;" & _             "dword TlsExpansionCounter;" & _             "ptr TlsBitmap;" & _             "dword TlsBitmapBits[2];" & _             "ptr ReadOnlySharedMemoryBase;" & _             "ptr ReadOnlySharedMemoryHeap;" & _             "ptr ReadOnlyStaticServerData;" & _             "ptr AnsiCodePageData;" & _             "ptr OemCodePageData;" & _             "ptr UnicodeCaseTableData;" & _             "dword NumberOfProcessors;" & _             "dword NtGlobalFlag;" & _             "ubyte Spare2[4];" & _             "int64 CriticalSectionTimeout;" & _             "dword HeapSegmentReserve;" & _             "dword HeapSegmentCommit;" & _             "dword HeapDeCommitTotalFreeThreshold;" & _             "dword HeapDeCommitFreeBlockThreshold;" & _             "dword NumberOfHeaps;" & _             "dword MaximumNumberOfHeaps;" & _             "ptr ProcessHeaps;" & _             "ptr GdiSharedHandleTable;" & _             "ptr ProcessStarterHelper;" & _             "ptr GdiDCAttributeList;" & _             "ptr LoaderLock;" & _             "dword OSMajorVersion;" & _             "dword OSMinorVersion;" & _             "dword OSBuildNumber;" & _             "dword OSPlatformId;" & _             "dword ImageSubSystem;" & _             "dword ImageSubSystemMajorVersion;" & _             "dword ImageSubSystemMinorVersion;" & _             "dword GdiHandleBuffer[34];" & _             "dword PostProcessInitRoutine;" & _             "dword TlsExpansionBitmap;" & _             "byte TlsExpansionBitmapBits[128];" & _             "dword SessionId")     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPROCESS_BASIC_INFORMATION, "PebBaseAddress"), _             "ptr", DllStructGetPtr($tPEB), _             "dword", DllStructGetSize($tPEB), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(3, 0, "")     EndIf     Local $tPROCESS_PARAMETERS = DllStructCreate("dword AllocationSize;" & _             "dword ActualSize;" & _             "dword Flags;" & _             "dword Unknown1;" & _             "word LengthUnknown2;" & _             "word MaxLengthUnknown2;" & _             "ptr Unknown2;" & _             "handle InputHandle;" & _             "handle OutputHandle;" & _             "handle ErrorHandle;" & _             "word LengthCurrentDirectory;" & _             "word MaxLengthCurrentDirectory;" & _             "ptr CurrentDirectory;" & _             "handle CurrentDirectoryHandle;" & _             "word LengthSearchPaths;" & _             "word MaxLengthSearchPaths;" & _             "ptr SearchPaths;" & _             "word LengthApplicationName;" & _             "word MaxLengthApplicationName;" & _             "ptr ApplicationName;" & _             "word LengthCommandLine;" & _             "word MaxLengthCommandLine;" & _             "ptr CommandLine;" & _             "ptr EnvironmentBlock;" & _             "dword Unknown[9];" & _             "word LengthUnknown3;" & _             "word MaxLengthUnknown3;" & _             "ptr Unknown3;" & _             "word LengthUnknown4;" & _             "word MaxLengthUnknown4;" & _             "ptr Unknown4;" & _             "word LengthUnknown5;" & _             "word MaxLengthUnknown5;" & _             "ptr Unknown5;")     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPEB, "ProcessParameters"), _             "ptr", DllStructGetPtr($tPROCESS_PARAMETERS), _             "dword", DllStructGetSize($tPROCESS_PARAMETERS), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(4, 0, "")     EndIf     $aCall = DllCall("kernel32.dll", "bool", "ReadProcessMemory", _             "ptr", $hProcess, _             "ptr", DllStructGetData($tPROCESS_PARAMETERS, "CommandLine"), _             "wstr", "", _             "dword", DllStructGetData($tPROCESS_PARAMETERS, "MaxLengthCommandLine"), _             "dword*", 0)     If @error Or Not $aCall[0] Then         DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)         Return SetError(5, 0, "")     EndIf     DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess)     Return $aCall[3] EndFunc

Obviously now you can use it to get other informations also. You just have to pick what you want from $tPROCESS_PARAMETERS structure.
Test it. I know it works as 32bit. To make it bullet-proof someone with experience with these structures might help.

edit:
But maybe it's bullet-proof already.

Edited by trancexx, 09 March 2010 - 05:47 PM.

eMyvnE


#19 rexx

rexx

    Wayfarer

  • Active Members
  • Pip
  • 65 posts

Posted 10 March 2010 - 02:59 AM

Thanks!
Works fine both 32 and 64 bit.

#20 Manko

Manko

    Polymath

  • Active Members
  • PipPipPipPip
  • 229 posts

Posted 11 March 2010 - 02:21 PM

Thanks, trancexx, for tidying up my code...
Didn't know autoit did this for us... :mellow:
Haven't analysed your corrections, but am i correct in assuming "ptr" gets retranslated to 64 bits in 64-bit systems?
Thanks also for contributing more fleshed-out structs!

/Manko
Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users