Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

GetCommandLine


  • Please log in to reply
20 replies to this topic
Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
This retrieves a start-up command-line of an application, once getting PID of it. If an application is an interactive service, then need an Debug privilege which I omitted for simplicity. If an application is a non-interactive service, then have to rely on other means.

/*
Process, Exist, myprog.exe
pid := ErrorLevel
*/

; Replace the WinTitle with the correct one
WinGet, pid, PID, ahk_class TTOTAL_CMD

VarSetCapacity(sFilePath, 260)
VarSetCapacity(sCmdLine, 512)

pFunc := DllCall("GetProcAddress"
	, "Uint", DllCall("GetModuleHandle", "str", "kernel32.dll")
	, "str", "GetCommandLineA")

hProc := DllCall("OpenProcess", "Uint", 0x043A, "int", 0, "Uint", pid)

hThrd := DllCall("CreateRemoteThread", "Uint", hProc, "Uint", 0, "Uint", 0
	, "Uint", pFunc, "Uint", 0, "Uint", 0, "Uint", 0)

DllCall("WaitForSingleObject", "Uint", hThrd, "Uint", 0xFFFFFFFF)
DllCall("GetExitCodeThread", "Uint", hThrd, "UintP", pcl)
DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pcl, "str", sCmdLine, "Uint", 512, "Uint", 0)

DllCall("psapi\GetModuleFileNameExA", "Uint", hProc, "Uint", 0, "str", sFilePath, "Uint", 260)
; DllCall("psapi\GetProcessImageFileNameA", "Uint", hProc, "str", sFilePath, "Uint", 281)

DllCall("CloseHandle", "Uint", hThrd)
DllCall("CloseHandle", "Uint", hProc)

MsgBox % sFilePath . " | " . sCmdLine



Grumpy
  • Guests
  • Last active:
  • Joined: --
Mmm, it was already there: process list+file names+command lines but it has other features there that might not be wanted, so it is nice to have it isolated. Thanks.

carsong
  • Members
  • 18 posts
  • Last active: Feb 15 2007 12:28 PM
  • Joined: 14 Oct 2006

This retrieves a start-up command-line of an application, once getting PID of it.


This helps a lot! Thanks!

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Sean, :)

If an application is an interactive service, then need an Debug privilege which I omitted for simplicity.


What happens to script/sCmdLine if my script unknowingly uses the PID of a Service ?

:)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

What happens to script/sCmdLine if my script unknowingly uses the PID of a Service ?

Most of the DllCall()'s in the code will (silently) fail, without Debug privilege.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Thank you Sean :)

One more help please. Have I wrapped it right?

GetCommandLine( PID ) { ;  by Sean          www.autohotkey.com/forum/viewtopic.php?t=16575 
 Static pFunc 
 If ! ( hProcess := DllCall( "OpenProcess", UInt,0x043A, Int,0, UInt, PID ) ) 
        Return  
 If pFunc= 
    pFunc := DllCall( "GetProcAddress", UInt 
           , DllCall( "GetModuleHandle", Str,"kernel32.dll" ), Str,"GetCommandLineA" ) 
 hThrd := DllCall( "CreateRemoteThread", UInt,hProcess, UInt,0, UInt,0, UInt,pFunc, UInt,0 
        , UInt,0, UInt,0 ),  DllCall( "WaitForSingleObject", UInt,hThrd, UInt,0xFFFFFFFF ) 
 DllCall( "GetExitCodeThread", UInt,hThrd, UIntP,pcl ), VarSetCapacity( sCmdLine,512 ) 
 DllCall( "ReadProcessMemory", UInt,hProcess, UInt,pcl, Str,sCmdLine, UInt,512, UInt,0 ) 
 DllCall( "CloseHandle", UInt,hThrd ), DllCall( "CloseHandle", UInt,hProcess ) 
Return sCmdLine 
} 

SetDebugPrivilege() {
 ;PROCESS_QUERY_INFORMATION=[color=red]0x400[/color], TOKEN_ADJUST_PRIVILEGES=[color=red]0x20[/color], SE_PRIVILEGE_ENABLED:=[color=red]0x2[/color]
 hProcess := DllCall( "OpenProcess", UInt,[color=red]0x400[/color],Int,0,UInt,DllCall("GetCurrentProcessId"))
 DllCall( "Advapi32.dll\LookupPrivilegeValueA", UInt,0, Str,"[color=red]SeDebugPrivilege[/color]", UIntP,lu )
  ; TOKEN_PRIVILEGES Structure : www.msdn.microsoft.com/en-us/library/aa379630(VS.85).aspx
 VarSetCapacity( TP,16,0), NumPut( 1,TP,0,4 ),  NumPut( lu,TP,4,8 ), NumPut( [color=red]0x2[/color],TP,12,4 ) 
 DllCall( "Advapi32.dll\OpenProcessToken", UInt,hProcess, UInt,[color=red]0x20[/color], UIntP,hToken )
 Result :=  DllCall( "Advapi32.dll\AdjustTokenPrivileges"
                 , UInt,hToken, UInt,0, UInt,&TP, UInt,0, UInt,0, UInt,0 )
 DllCall( "CloseHandle", UInt,hProcess ), DllCall( "CloseHandle", UInt,hToken )
Return Result 
}

SetDebugPrivilege() 
MsgBox, % GetCommandLine( DllCall( "GetCurrentProcessId" ) ) 
Process, Exist, svchost.exe 
MsgBox,0, %errorLevel%, % GetCommandLine( errorLevel )

Edit 2009-06-22: Added DelimitParameters()

The following function can convert the obtained command line into pipe delimited string to ease Loop, Parse or StringSplit

DelimitParameters( CommandLine,D="|" ) {     ; Supplementary function for GetCommandLine()
 tempVar := CommandLine           ; www.autohotkey.com/forum/viewtopic.php?p=232199#232199
 Loop {
 StringReplace,tempVar,tempVar,%Param%
 CommandLine := DllCall( "shlwapi\PathGetArgsA", Str,CommandLine,Str )
 StringReplace,Param,tempVar,%CommandLine%
 DllCall( "shlwapi\PathUnquoteSpacesA", Str,Param )
 IfEqual,Param,,Return SubStr(DelimitedString,2)
 DelimitedString = %DelimitedString%%D%%Param%
}}


Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Have I wrapped it right?

Yes, looks fine to me.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
I could not grasp much from shimanov's GetRemoteCommandLine() and then saw your comment.
Thanks for sharing this wonderful code Sean.

:)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

I could not grasp much from shimanov's GetRemoteCommandLine() and then saw your comment.

Oh, my comment there was not correct. Looks like he tracked down the procedures of GetCommandLineA in the Debugger. As it's an implementation detail, relying on it should be the last choice.
BTW, my preferred method is indeed utilizing PEB, but it relies on the undocumented features unfortunately.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

As it's an implementation detail, relying on it should be the last choice.


er.. I intend to use this only on all running AHK instances.. Is there a way to ascertain if compiled AHK is running as a service ?

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

As it's an implementation detail, relying on it should be the last choice.

er.. I intend to use this only on all running AHK instances..

I meant it only for GetRemoteCommandLine function. APIs and features my code used are all well-documented (although there is one loop-hole in the code: stack-mismatch after the call in the remote thread).

Is there a way to ascertain if compiled AHK is running as a service?

The first one hitting me is retrieving the parent process (identifier) of the target process and checking if it's services.exe, if it's what you meant by service. It can be done using CreateToolhelp32Snapshot and Process32First/Process32Next, with Debug privilege enabled.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

The first one hitting me is retrieving the parent process (identifier) of the target process and checking if it's services.exe, if it's what you meant by service. It can be done using CreateToolhelp32Snapshot and Process32First/Process32Next, with Debug privilege enabled.


Search reveals there are example calls already posted. Thank you very much for the pointer.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Search reveals there are example calls already posted. Thank you very much for the pointer.

After reading your post more carefully, I now noticed this:

only on all running AHK instances

As AHK can't be started as a service by itself, meaning that AHK can't be a (direct) child process of services.exe, I guess what you're really after is obtaining the user's name of a process and checking if it's NT AUTHORITY/SYSTEM. If turned out so, may use OpenProcess -> OpenProcessToken -> GetTokenInformation -> LookupAccountSid.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

what you're really after is obtaining the user's name of a process and checking if it's NT AUTHORITY/SYSTEM.


Almost exactly, except I thought of comparing it to A_Username. Would it not work? :roll:

may use OpenProcess -> OpenProcessToken -> GetTokenInformation -> LookupAccountSid.


Thank you.. That looks simple.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Almost exactly, except I thought of comparing it to A_Username. Would it not work? :roll:

It depends. If want to rule out not only services but also all ones run as other accounts than the current user, then A_UserName should be used than SYSTEM.