Jump to content

_WinAPI_GetCommandLineFromPID() - From any process!


Manko
 Share

Recommended Posts

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! :)

#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.

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
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...
Link to comment
Share on other sites

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

Contributions

CheckUpdate - SelfUpdating script ------- Self updating script

Dynamic input validation ------------------- Use a Input masks can make your life easier and Validation can be as simple

MsgBox with CountDown ------------------- MsgBox with visual countdown

Display Multiline text cells in ListView ---- Example of pop-up or ToolTip for multiline text items in ListView

Presentation Manager ---------------------- Program to display and refresh different Border-less GUI's on a Display (large screen TV)

USB Drive Tools ------------------------------ Tool to help you with your USB drive management

Input Period udf ------------------------------ GUI for a period input

Excel ColorPicker ---------------------------- Color pickup tool will allow you to select a color from the standard Excel color palette

Excel Chart UDF ----------------------------- Collaboration project with water 

GetDateInString ------------------------------ Find date/time in a string using a date format notation like DD Mon YYYY hh:mm

TaskListAllDetailed --------------------------- List All Scheduled Tasks

Computer Info --------------------------------- A collection of information for helpdesk

Shared memory Demo ----------------------- Demo: Two applications communicate with each other through means of a memory share (using Nomad function, 32bit only)

Universal Date Format Conversion -------- Universal date converter from your PC local date format to any format

Disable Windows DetailsPane -------------- Disable Windows Explorer Details Pane

Oracle SQL Report Generator -------------  Oracle Report generator using SQL

SQLite Report Generator -------------------  SQLite Report generator using SQL

SQLite ListView and BLOB demo ---------- Demo: shows how binary (image) objects can be recognized natively in a database BLOB field

DSN-Less Database connection demo --- Demo: ActiveX Data Objects DSN-Less Database access

Animated animals ----------------------------- Fun: Moving animated objects

Perforated image in GUI --------------------- Fun: Perforate your image with image objects

UEZ's Perforator major update ------------- Fun: Pro version of Perforator by UEZ

Visual Crop Tool (GUI) ----------------------- Easy to use Visual Image Crop tool

Visual Image effect (GUI) -------------------- Visually apply effects on an image

 

 

 

Link to comment
Share on other sites

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

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

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
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...
Link to comment
Share on other sites

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
Link to comment
Share on other sites

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...
Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.

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
Link to comment
Share on other sites

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
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...
Link to comment
Share on other sites

  • 3 weeks later...

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.

#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
Link to comment
Share on other sites

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...
Link to comment
Share on other sites

  • 1 year later...

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?

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
Link to comment
Share on other sites

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:

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

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

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...
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...