external process: get working directory (current directory)

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

external process: get working directory (current directory)

18 Oct 2017, 14:02

Can somebody help me get this to work? I.e. if possible so that x64/x32 AHK can get the working directory from x64/x32 external processes. Thanks.

I tried it with AHK x32, on Notepad x64/x32, but it didn't work.

[SOLVED]get other process's working dir - Page 2 - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/8530 ... ntry544320

I used this MCode function:

Machine code functions: Bit Wizardry - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/1948 ... dry/page-1

There is an alternative MCode function here. I'm not sure if there is a newer version.

MCode function + onlinegenerator (x86 and x64) - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/8928 ... 6-and-x64/
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

18 Oct 2017, 19:15

Sometime I wrote the function to get process' comandline. It reads CommandLine from RTL_USER_PROCESS_PARAMETERS structure. Also RUPP contains process' current directory.

Code: Select all

IsAdminChecking(), SetDebugPrivilege()  ; only for system processes on Windows 10 (and on Windows 8, maybe), else may by commented out

Process, Exist, winlogon.exe
PID := ErrorLevel
MsgBox, % GetProcessCurrentDirectory(PID)

GetProcessCurrentDirectory(PID)  {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0
   
   hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, Int, 0, UInt, PID, Ptr)
   (A_Is64bitOS && DllCall("IsWow64Process", Ptr, hProc, UIntP, IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, PtrType := "UInt", pPtr := "UIntP"
   else
      PtrSize := 8, PtrType := "Int64", pPtr := "Int64P"
   offsetCURDIR := 4*4 + PtrSize*5
   
   hModule := DllCall("GetModuleHandle", "str", "Ntdll", Ptr)
   if (A_PtrSize < PtrSize)  {            ; <<—— script 32, target process 64
      if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64QueryInformationProcess64", Ptr)
         failed := "NtWow64QueryInformationProcess64"
      if !ReadProcessMemory := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtWow64ReadVirtualMemory64", Ptr)
         failed := "NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else  {
      if !QueryInformationProcess := DllCall("GetProcAddress", Ptr, hModule, AStr, "NtQueryInformationProcess", Ptr)
         failed := "NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)            ; <<—— script 64, target process 32
         info := 26, szPBI := 8, offsetPEB := 0
      else                                ; <<—— script and target process have the same bitness
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   if failed  {
      DllCall("CloseHandle", Ptr, hProc)
      MsgBox, Failed to get pointer to %failed%
      Return
   }
   VarSetCapacity(PBI, 48, 0)
   if DllCall(QueryInformationProcess, Ptr, hProc, UInt, info, Ptr, &PBI, UInt, szPBI, UIntP, bytes) != STATUS_SUCCESS  {
      DllCall("CloseHandle", Ptr, hProc)
      Return
   }
   pPEB := NumGet(&PBI + offsetPEB, PtrType)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, UIntP, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCURDIR, UShortP, szBuff, PtrType, 2, UIntP, bytes)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pRUPP + offsetCURDIR + PtrSize, pPtr, pCURDIR, PtrType, PtrSize, UIntP, bytes)
   
   VarSetCapacity(buff, szBuff, 0)
   DllCall(ReadProcessMemory, Ptr, hProc, PtrType, pCURDIR, Ptr, &buff, PtrType, szBuff, UIntP, bytes)
   DllCall("CloseHandle", Ptr, hProc)
   Return currentDirPath := StrGet(&buff, "UTF-16")
}

IsAdminChecking()  {
   if !( A_IsAdmin || RegExMatch( DllCall("GetCommandLine", "str"), " /restart(?!\S)" ) )  {
      try  {
         if A_IsCompiled
            Run *RunAs "%A_ScriptFullPath%" /restart
         else
            Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
      }
      ExitApp
   }
}

SetDebugPrivilege()  {
   static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2
   
   hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, Int, false, UInt, DllCall("GetCurrentProcessId"), Ptr)
   DllCall("Advapi32\OpenProcessToken", Ptr, hProc, UInt, TOKEN_ADJUST_PRIVILEGES, PtrP, token)
   
   DllCall("Advapi32\LookupPrivilegeValue", Ptr, 0, Str, "SeDebugPrivilege", Int64P, luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", Ptr, token, Int, false, Ptr, &TOKEN_PRIVILEGES, UInt, 0, Ptr, 0, Ptr, 0)
   res := A_LastError
   DllCall("CloseHandle", Ptr, token)
   DllCall("CloseHandle", Ptr, hProc)
   Return res  ; success 0
}
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: external process: get working directory (current directory)

18 Oct 2017, 19:47

This is really great, many thanks, and it doesn't need a machine code function.

You've been posting a lot of good stuff the last few months.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: external process: get working directory (current directory)

18 Oct 2017, 20:14

Haha you're here to practise your English, classic.

Hmm, the comment about system processes, reminded me, I wanted a way to get the user name for a process. I've started a new thread here:

process: get user name (like Task Manager) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=38546
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 06:57

teadrinker wrote:
18 Oct 2017, 19:15
Sometime I wrote the function to get process' comandline. It reads CommandLine from RTL_USER_PROCESS_PARAMETERS structure. Also RUPP contains process' current directory.
IsAdminChecking(), SetDebugPrivilege() ; only for system processes on Windows 10 (and on Windows 8, maybe), else may by commented out
could you point out how to also get the command line?
all this info is possible to read with your previous function?
Spoiler
the struct above isn't this one?
https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

28 May 2022, 09:36

logan9 wrote: the struct above isn't this one?
Yep, but most items are undocumented.
logan9 wrote: all this info is possible to read with your previous function?
Of course.
logan9 wrote: could you point out how to also get the command line?
Like this:

Code: Select all

Process, Exist, svchost.exe
PID := ErrorLevel
cmd := GetCommandLine(PID, true, imagePath)
MsgBox, % cmd . "`n" . imagePath

GetCommandLine(PID, setDebugPrivilege := false, ByRef imagePath := "") {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0
        , TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2, setDebug := 0
   
   if (setDebugPrivilege && !setDebug) {
      RunAsAdmin()
      if SetPrivilege("SeDebugPrivilege") != 0
         MsgBox, Failed to set debug privelege
   }
   hProc := DllCall("OpenProcess", "UInt", PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, "Int", 0, "UInt", PID, "Ptr")
   (A_Is64bitOS && DllCall("IsWow64Process", "Ptr", hProc, "UIntP", IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
   else
      PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70

   hModule := DllCall("GetModuleHandle", "str", "Ntdll", "Ptr")
   if (A_PtrSize < PtrSize) {            ; script 32, dest proc 64
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64QueryInformationProcess64", "Ptr")
         failed := "NtWow64QueryInformationProcess64"
      if !ReadProcessMemory := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64ReadVirtualMemory64", "Ptr")
         failed := "NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else {
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtQueryInformationProcess", "Ptr")
         failed := "NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)            ; script 64, dest proc 32
         info := 26, szPBI := 8, offsetPEB := 0
      else                                ; script and dest proc the same bitness
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   if failed {
      DllCall("CloseHandle", "Ptr", hProc)
      MsgBox, Failed to get pointer to %failed%
      Return
   }
   VarSetCapacity(PBI, 48, 0)
   if DllCall(QueryInformationProcess, "Ptr", hProc, "UInt", info, "Ptr", &PBI, "UInt", szPBI, "UIntP", bytes) != STATUS_SUCCESS {
      DllCall("CloseHandle", "Ptr", hProc)
      Return
   }
   pPEB := NumGet(&PBI + offsetPEB, PtrType)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, "UIntP", bytes)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pRUPP + offsetCMD, "UShortP", szCMD, PtrType, 2, "UIntP", bytes)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pRUPP + offsetCMD + PtrSize, pPtr, pCMD, PtrType, PtrSize, "UIntP", bytes)
   
   VarSetCapacity(buff, szCMD, 0)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pCMD, "Ptr", &buff, PtrType, szCMD, "UIntP", bytes)
   CMD := StrGet(&buff, "UTF-16")
   
   if IsByRef(imagePath) {
      DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pRUPP + offsetCMD - PtrSize*2, "UShortP", szPATH, PtrType, 2, "UIntP", bytes)
      DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pRUPP + offsetCMD - PtrSize, pPtr, pPATH, PtrType, PtrSize, "UIntP", bytes)
      
      VarSetCapacity(buff, szPATH, 0)
      DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pPATH, "Ptr", &buff, PtrType, szPATH, "UIntP", bytes)
      imagePath := StrGet(&buff, "UTF-16") . (IsWow64 ? " *32" : "")
   }
   DllCall("CloseHandle", "Ptr", hProc)
   Return CMD
}

RunAsAdmin(exitIfNotAdmin := false) {
   commandLine := DllCall("GetCommandLine", "str")
   isRestarted := !!RegExMatch(commandLine, " /restart(?!\S)")
   
   while !( A_IsAdmin || isRestarted ) {
      try Run, % "*RunAs " . (A_IsCompiled ? """" . A_ScriptFullPath . """ /restart"
                                           : """" . A_AhkPath . """ /restart """ . A_ScriptFullPath . """")
      catch
         break 
      ExitApp
   }
   if !A_IsAdmin  {
      MsgBox, Failed to run the script as admin!
      if exitIfNotAdmin
         ExitApp
   }
}

SetPrivilege(privilege, enable := true) {
   static TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2, SE_PRIVILEGE_REMOVED := 0x4
   
   DllCall("Advapi32\OpenProcessToken", "Ptr", -1, "UInt", TOKEN_ADJUST_PRIVILEGES, "PtrP", token)
   DllCall("Advapi32\LookupPrivilegeValue", "Ptr", 0, "Str", privilege, "Int64P", luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(enable ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", "Ptr", token, "Int", !enable, "Ptr", &TOKEN_PRIVILEGES, "UInt", 0, "Ptr", 0, "Ptr", 0)
   res := A_LastError
   DllCall("CloseHandle", "Ptr", token)
   DllCall("CloseHandle", "Ptr", hProc)
   Return res  ; success — 0
}
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 09:54

teadrinker wrote:
28 May 2022, 09:36
Yep, but most items are undocumented.
your code is a bit hard for me to understand, I thought I would need just to increment a count in some of these ReadProcessMemory call
to get the values of these next items

UNICODE_STRING WindowTitle; is the same title you get by calling ahk "Wingettitle"?
if so, could you also point out how to get it?
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

28 May 2022, 11:00

This is all in one:

Code: Select all

WinGet, PID, PID, ahk_exe explorer.exe
Info := GetProcessInfo(PID)
MsgBox, % "Current Directory: " . Info.currentDir  . "`n`n"
        . "Dll Path: "          . Info.DllPath     . "`n`n"
        . "Image Path: "        . Info.ImagePath   . "`n"
        . "Command Line: "      . Info.CMD         . "`n"
        . "Window Title: "      . Info.WindowTitle . "`n"
        . "Desktop Info: "      . Info.DesktopInfo . "`n"
        . "Shell Info: "        . Info.ShellInfo   . "`n"
        . "Runtime Data: "      . Info.RuntimeData

GetProcessInfo(PID, setDebugPrivilege := false) {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0, setDebug := 0
   
   if (setDebugPrivilege && !setDebug) {
      RunAsAdmin()
      if SetPrivilege("SeDebugPrivilege") != 0
         throw "Failed to set debug privelege"
   }
   hProc := DllCall("OpenProcess", "UInt", PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, "Int", 0, "UInt", PID, "Ptr")
   (A_Is64bitOS && DllCall("IsWow64Process", "Ptr", hProc, "UIntP", IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
   else
      PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70

   hModule := DllCall("GetModuleHandle", "str", "Ntdll", "Ptr")
   if (A_PtrSize < PtrSize) {            ; script 32, dest proc 64
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64QueryInformationProcess64", "Ptr")
         failed := "NtWow64QueryInformationProcess64"
      if !ReadProcessMemory := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64ReadVirtualMemory64", "Ptr")
         failed := "NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else {
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtQueryInformationProcess", "Ptr")
         failed := "NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)            ; script 64, dest proc 32
         info := 26, szPBI := 8, offsetPEB := 0
      else                                ; script and dest proc the same bitness
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   if failed {
      DllCall("CloseHandle", "Ptr", hProc)
      MsgBox, Failed to get pointer to %failed%
      Return
   }
   VarSetCapacity(PBI, 48, 0)
   if DllCall(QueryInformationProcess, "Ptr", hProc, "UInt", info, "Ptr", &PBI, "UInt", szPBI, "UIntP", bytes) != STATUS_SUCCESS {
      DllCall("CloseHandle", "Ptr", hProc)
      Return
   }
   pPEB := NumGet(&PBI + offsetPEB, PtrType)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, "UIntP", bytes)
   Info := {}
   BoundFunc := Func("DllCall").Bind(ReadProcessMemory, "Ptr", hProc, PtrType), params := [pPtr, PtrType, PtrSize]
   Info.currentDir  := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize* 5, params*)
   Info.DllPath     := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize* 8, params*)
   Info.ImagePath   := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize*10, params*)
   Info.CMD         := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize*12, params*)
   Info.WindowTitle := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*15, params*)
   Info.DesktopInfo := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*17, params*)
   Info.ShellInfo   := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*19, params*)
   Info.RuntimeData := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*21, params*)
   DllCall("CloseHandle", "Ptr", hProc)
   Return Info
}

ReadUnicodeString(BoundFunc, addr, pPtr, PtrType, PtrSize) {
   BoundFunc.Call(addr, "UShortP", stringSize, PtrType, 2, "UIntP", bytes)
   BoundFunc.Call(addr + PtrSize, pPtr, pString, PtrType, PtrSize, "UIntP", bytes)
   VarSetCapacity(buff, stringSize, 0)
   BoundFunc.Call(pString, "Ptr", &buff, PtrType, stringSize, "UIntP", bytes)
   Return StrGet(&buff, "UTF-16")
}

RunAsAdmin(exitIfNotAdmin := false) {
   commandLine := DllCall("GetCommandLine", "str")
   isRestarted := !!RegExMatch(commandLine, " /restart(?!\S)")
   
   while !( A_IsAdmin || isRestarted ) {
      try Run, % "*RunAs " . (A_IsCompiled ? """" . A_ScriptFullPath . """ /restart"
                                           : """" . A_AhkPath . """ /restart """ . A_ScriptFullPath . """")
      catch
         break 
      ExitApp
   }
   if !A_IsAdmin  {
      MsgBox, Failed to run the script as admin!
      if exitIfNotAdmin
         ExitApp
   }
}

SetPrivilege(privilege, enable := true) {
   static TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2, SE_PRIVILEGE_REMOVED := 0x4
   
   DllCall("Advapi32\OpenProcessToken", "Ptr", -1, "UInt", TOKEN_ADJUST_PRIVILEGES, "PtrP", token)
   DllCall("Advapi32\LookupPrivilegeValue", "Ptr", 0, "Str", privilege, "Int64P", luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(enable ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", "Ptr", token, "Int", !enable, "Ptr", &TOKEN_PRIVILEGES, "UInt", 0, "Ptr", 0, "Ptr", 0)
   res := A_LastError
   DllCall("CloseHandle", "Ptr", token)
   DllCall("CloseHandle", "Ptr", hProc)
   Return res  ; success — 0
}
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 12:28

thank you!! when the process contains multiple windows, with this API is possible to get the wintitle of all windows?

iirc using wingettitle, If you script contain multiple guis, it get the title of the last active/focused window
BoBo
Posts: 6528
Joined: 13 May 2014, 17:15

Re: external process: get working directory (current directory)

28 May 2022, 14:11

@teadrinker - typo? :)

if SetPrivilege("SeDebugPrivilege") != 0
vs.
if SetPrivilege("SetDebugPrivilege") != 0
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

28 May 2022, 15:27

logan9 wrote: with this API is possible to get the wintitle of all windows?
I think this code returns the title of the very first window wihch the process was created with.
BoBo wrote: typo?
Nope.
SE_DEBUG_NAME
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 15:39

teadrinker wrote:
28 May 2022, 11:00
This is all in one:

Code: Select all

WinGet, PID, PID, ahk_exe explorer.exe
Info := GetProcessInfo(PID)
MsgBox, % "Current Directory: " . Info.currentDir  . "`n`n"
        . "Dll Path: "          . Info.DllPath     . "`n`n"
        . "Image Path: "        . Info.ImagePath   . "`n"
        . "Command Line: "      . Info.CMD         . "`n"
        . "Window Title: "      . Info.WindowTitle . "`n"
        . "Desktop Info: "      . Info.DesktopInfo . "`n"
        . "Shell Info: "        . Info.ShellInfo   . "`n"
        . "Runtime Data: "      . Info.RuntimeData

GetProcessInfo(PID, setDebugPrivilege := false) {
   static PROCESS_QUERY_INFORMATION := 0x400, PROCESS_VM_READ := 0x10, STATUS_SUCCESS := 0, setDebug := 0
   
   if (setDebugPrivilege && !setDebug) {
      RunAsAdmin()
      if SetPrivilege("SeDebugPrivilege") != 0
         throw "Failed to set debug privelege"
   }
   hProc := DllCall("OpenProcess", "UInt", PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, "Int", 0, "UInt", PID, "Ptr")
   (A_Is64bitOS && DllCall("IsWow64Process", "Ptr", hProc, "UIntP", IsWow64))
   if (!A_Is64bitOS || IsWow64)
      PtrSize := 4, PtrType := "UInt", pPtr := "UIntP", offsetCMD := 0x40
   else
      PtrSize := 8, PtrType := "Int64", pPtr := "Int64P", offsetCMD := 0x70

   hModule := DllCall("GetModuleHandle", "str", "Ntdll", "Ptr")
   if (A_PtrSize < PtrSize) {            ; script 32, dest proc 64
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64QueryInformationProcess64", "Ptr")
         failed := "NtWow64QueryInformationProcess64"
      if !ReadProcessMemory := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtWow64ReadVirtualMemory64", "Ptr")
         failed := "NtWow64ReadVirtualMemory64"
      info := 0, szPBI := 48, offsetPEB := 8
   }
   else {
      if !QueryInformationProcess := DllCall("GetProcAddress", "Ptr", hModule, "AStr", "NtQueryInformationProcess", "Ptr")
         failed := "NtQueryInformationProcess"
      ReadProcessMemory := "ReadProcessMemory"
      if (A_PtrSize > PtrSize)            ; script 64, dest proc 32
         info := 26, szPBI := 8, offsetPEB := 0
      else                                ; script and dest proc the same bitness
         info := 0, szPBI := PtrSize * 6, offsetPEB := PtrSize
   }
   if failed {
      DllCall("CloseHandle", "Ptr", hProc)
      MsgBox, Failed to get pointer to %failed%
      Return
   }
   VarSetCapacity(PBI, 48, 0)
   if DllCall(QueryInformationProcess, "Ptr", hProc, "UInt", info, "Ptr", &PBI, "UInt", szPBI, "UIntP", bytes) != STATUS_SUCCESS {
      DllCall("CloseHandle", "Ptr", hProc)
      Return
   }
   pPEB := NumGet(&PBI + offsetPEB, PtrType)
   DllCall(ReadProcessMemory, "Ptr", hProc, PtrType, pPEB + PtrSize * 4, pPtr, pRUPP, PtrType, PtrSize, "UIntP", bytes)
   Info := {}
   BoundFunc := Func("DllCall").Bind(ReadProcessMemory, "Ptr", hProc, PtrType), params := [pPtr, PtrType, PtrSize]
   Info.currentDir  := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize* 5, params*)
   Info.DllPath     := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize* 8, params*)
   Info.ImagePath   := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize*10, params*)
   Info.CMD         := ReadUnicodeString(BoundFunc, pRUPP + 16 + PtrSize*12, params*)
   Info.WindowTitle := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*15, params*)
   Info.DesktopInfo := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*17, params*)
   Info.ShellInfo   := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*19, params*)
   Info.RuntimeData := ReadUnicodeString(BoundFunc, pRUPP + 52 + PtrSize*21, params*)
   DllCall("CloseHandle", "Ptr", hProc)
   Return Info
}

ReadUnicodeString(BoundFunc, addr, pPtr, PtrType, PtrSize) {
   BoundFunc.Call(addr, "UShortP", stringSize, PtrType, 2, "UIntP", bytes)
   BoundFunc.Call(addr + PtrSize, pPtr, pString, PtrType, PtrSize, "UIntP", bytes)
   VarSetCapacity(buff, stringSize, 0)
   BoundFunc.Call(pString, "Ptr", &buff, PtrType, stringSize, "UIntP", bytes)
   Return StrGet(&buff, "UTF-16")
}

RunAsAdmin(exitIfNotAdmin := false) {
   commandLine := DllCall("GetCommandLine", "str")
   isRestarted := !!RegExMatch(commandLine, " /restart(?!\S)")
   
   while !( A_IsAdmin || isRestarted ) {
      try Run, % "*RunAs " . (A_IsCompiled ? """" . A_ScriptFullPath . """ /restart"
                                           : """" . A_AhkPath . """ /restart """ . A_ScriptFullPath . """")
      catch
         break 
      ExitApp
   }
   if !A_IsAdmin  {
      MsgBox, Failed to run the script as admin!
      if exitIfNotAdmin
         ExitApp
   }
}

SetPrivilege(privilege, enable := true) {
   static TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2, SE_PRIVILEGE_REMOVED := 0x4
   
   DllCall("Advapi32\OpenProcessToken", "Ptr", -1, "UInt", TOKEN_ADJUST_PRIVILEGES, "PtrP", token)
   DllCall("Advapi32\LookupPrivilegeValue", "Ptr", 0, "Str", privilege, "Int64P", luid)
   VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
   NumPut(1, TOKEN_PRIVILEGES, "UInt")
   NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
   NumPut(enable ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED, TOKEN_PRIVILEGES, 12, "UInt")
   DllCall("Advapi32\AdjustTokenPrivileges", "Ptr", token, "Int", !enable, "Ptr", &TOKEN_PRIVILEGES, "UInt", 0, "Ptr", 0, "Ptr", 0)
   res := A_LastError
   DllCall("CloseHandle", "Ptr", token)
   DllCall("CloseHandle", "Ptr", hProc)
   Return res  ; success — 0
}
I tested with some different processes, only Current Directory, ImagePath, Command Line has a value all others are blank
I'm on win10, I also tried running the script as admin, and setting setDebugPrivilege to true
the processes tested were not running with admin privilege
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

28 May 2022, 15:54

For me it returns for the Skype window on Windows 10:
Image
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 15:56

What's your win version?
I don't have skype, could you try with Microsoft edge?
C:\Program Files (x86)\Microsoft\Edge\Application
Spoiler
Last edited by logan9 on 28 May 2022, 16:12, edited 1 time in total.
teadrinker
Posts: 3512
Joined: 29 Mar 2015, 09:41
Contact:

Re: external process: get working directory (current directory)

28 May 2022, 15:58

For the Calculator.exe process:
Current Directory: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\

Dll Path: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe;C:\Program Files\WindowsApps\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe;C:\Program Files\WindowsApps\Microsoft.VCLibs.140.00_14.0.30704.0_x64__8wekyb3d8bbwe;

Image Path: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\Calculator.exe
Command Line: "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\Calculator.exe" -ServerName:App.AppXsm3pg4n7er43kdh1qp4e79f1j7am68r8.mca
Window Title:
Desktop Info:
Shell Info:
Runtime Data:
logan9
Posts: 33
Joined: 22 Feb 2022, 12:48

Re: external process: get working directory (current directory)

28 May 2022, 16:34

teadrinker wrote:
28 May 2022, 15:58
For the Calculator.exe process:
Current Directory: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\

Dll Path: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe;C:\Program Files\WindowsApps\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe;C:\Program Files\WindowsApps\Microsoft.VCLibs.140.00_14.0.30704.0_x64__8wekyb3d8bbwe;

Image Path: C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\Calculator.exe
Command Line: "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.2103.8.0_x64__8wekyb3d8bbwe\Calculator.exe" -ServerName:App.AppXsm3pg4n7er43kdh1qp4e79f1j7am68r8.mca
Window Title:
Desktop Info:
Shell Info:
Runtime Data:
the window title is blank, is it not a script error?

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], Deepmojoman, wer and 42 guests