[SOLVED]get other process's working dir
For your code last time, if don't use machine code, how can I pass the ThreadProc function's code to object process? Is it possible?
I want to learn to do it and ahk code is intuitive for me (I know machine code is better in practice).
Click to download Chinese resource for AutoHotkey.
Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.
That won't be possible as far as I understand
I have put together InjectAhkDll(), now you can inject AutoHotkey.dll in another process and execute ahk code as much as you like
requires latest AutoHotkey.dll (07.10.12)
EDIT 08.11.2015: Fixed bugs for 64-bit
EDIT 12.11.2012: updated to support 64-bit (requires _Struct now)
EDIT 25.12.2012: you can now pass a script to be used instead of starting an empty script.
Example, display working directory of notepad.exe process:
Process,Exist, notepad.exe If !PID:=ErrorLevel Run notepad.exe,,,PID rThread:=InjectAhkDll(PID,A_ScriptDir "\AutoHotkeyMini.dll","#Persistent`nMsgBox % A_WorkingDir") Sleep 500 rThread.Exec("MsgBox % A_AhkPath")
)']- PID - must be a PID of existing process.- dll - path to AutoHotkey.dll or AutoHotkeyMini.dll
- script - this parameter is used when code needs to be executed, see Exec method.
METHODS:
- Exec(Script) - execute AHK code, Script must be text containing AutoHotkey script to execute
CLEANUP
- AutoHotkey dll is unloaded from remote process when object is deleted.
#Include <_Struct> InjectAhkDll(PID,dll="AutoHotkey.dll",script=0){ static PROCESS_ALL_ACCESS:=0x1F0FFF,MEM_COMMIT := 0x1000,MEM_RELEASE:=0x8000,PAGE_EXECUTE_READWRITE:=64 ,hKernel32:=DllCall("LoadLibrary","Str","kernel32.dll","PTR"),LoadLibraryA:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","LoadLibraryA","PTR") ,base:={__Call:"InjectAhkDll",__Delete:"InjectAhkDll"},FreeLibrary:=DllCall("GetProcAddress","PTR",hKernel32,"AStr","FreeLibrary","PTR") static TH32CS_SNAPMODULE:=0x00000008,INVALID_HANDLE_VALUE:=-1 ,MAX_PATH:=260,MAX_MODULE_NAME32:=255,ModuleName:="",init:=VarSetCapacity(ModuleName,MAX_PATH*(A_IsUnicode?2:1)) ,_MODULEENTRY32:=" ( DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize; HMODULE hModule; TCHAR szModule[" MAX_MODULE_NAME32 + 1 "]; TCHAR szExePath[" MAX_PATH "]; )" If IsObject(PID){ If (dll!="Exec" && script) return DllCall("MessageBox","PTR",0,"Str","Only Exec method can be used here!","STR","Error","UInt",0) hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID.PID,"PTR") If !hProc return DllCall("MessageBox","PTR",0,"Str","Could not open process for PID: " PID.PID,"STR","Error","UInt",0) if (!script) ; Free Library in remote process (object is being deleted) { ; Terminate the thread in ahkdll hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkTerminate, "PTR", 0, "UInt", 0, "PTR", 0,"PTR") DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF) ,DllCall("CloseHandle", "PTR", hThread) ; Free library in remote process hThread := DllCall("CreateRemoteThread", "PTR", hProc, "UInt", 0, "UInt", 0, "PTR", FreeLibrary, "PTR", PID.hModule, "UInt", 0, "UInt", 0,"PTR") DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF) ,DllCall("CloseHandle", "PTR", hThread),DllCall("CloseHandle", "PTR", hProc) return } nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0) ,StrPut(script,&nScript) ; Reserve memory in remote process where our script will be saved If !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr") return DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0) ,DllCall("CloseHandle", "PTR", hProc) ; Write script to remote process memory DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0) ; Start execution of code hThread := DllCall("CreateRemoteThread", "PTR", hProc, "PTR", 0, "PTR", 0, "PTR", PID.ahkExec, "PTR", pBufferRemote, "UInt", 0, "PTR", 0,"PTR") If !hThread { DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE) ,DllCall("CloseHandle", "PTR", hProc) return DllCall("MessageBox","PTR",0,"Str","Could not execute script in remote process.","STR","Error","UInt",0) } ; Wait for thread to finish DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF) ; Get Exit code returned by ahkExec (1 = script could be executed / 0 = script could not be executed) DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode) If !lpExitCode return DllCall("MessageBox","PTR",0,"Str","Could not execute script in remote process.","STR","Error","UInt",0) DllCall("CloseHandle", "PTR", hThread) ,DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nScriptLength,MEM_RELEASE) ,DllCall("CloseHandle", "PTR", hProc) return } else if !hDll:=DllCall("LoadLibrary","Str",dll,"PTR") return DllCall("MessageBox","PTR",0,"Str","Could not find " dll " library.","STR","Error","UInt",0),DllCall("CloseHandle", "PTR", hProc) else { hProc := DllCall("OpenProcess","UInt", PROCESS_ALL_ACCESS, "Int",0,"UInt", DllCall("GetCurrentProcessId"),"PTR") DllCall("GetModuleFileName","PTR",hDll,"PTR",&ModuleName,"UInt",MAX_PATH) DllCall("CloseHandle","PTR",hProc) } ; Open Process to PID hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int",0, "UInt", PID,"PTR") If !hProc return DllCall("MessageBox","PTR",0,"Str","Could not open process for PID: " PID,"STR","Error","UInt",0) ; Reserve some memory and write dll path (ANSI) nDirLength := VarSetCapacity(nDir, StrLen(dll)+1, 0) ,StrPut(dll,&nDir,"CP0") ; Reserve memory in remote process If !pBufferRemote := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nDirLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr") return DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0),DllCall("CloseHandle", "PTR", hProc) ; Write dll path to remote process memory DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferRemote, "Ptr", &nDir, "PTR", nDirLength, "Ptr", 0) ; Start new thread loading our dll hThread:=DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",LoadLibraryA,"PTR",pBufferRemote,"UInt",0,"PTR",0,"PTR") If !hThread { DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,"Uint",MEM_RELEASE) ,DllCall("CloseHandle", "PTR", hProc) return DllCall("MessageBox","PTR",0,"Str","Could not load " dll " in remote process.","STR","Error","UInt",0) } ; Wait for thread to finish DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF) ; Get Exit code returned by thread (HMODULE for our dll) DllCall("GetExitCodeThread", "PTR", hThread, "UInt*", hModule) ; Close Thread DllCall("CloseHandle", "PTR", hThread) If (A_PtrSize=8){ ; use different method to retrieve base address because GetExitCodeThread returns DWORD only hModule:=0,me32 := new _Struct(_MODULEENTRY32) ; Take a snapshot of all modules in the specified process. hModuleSnap := DllCall("CreateToolhelp32Snapshot","UInt", TH32CS_SNAPMODULE,"UInt", PID, "PTR" ) if( hModuleSnap != INVALID_HANDLE_VALUE ){ ; reset hModule and set the size of the structure before using it. me32.dwSize := sizeof(_MODULEENTRY32) ; Retrieve information about the first module, ; and exit if unsuccessful if( !DllCall("Module32First" (A_IsUnicode?"W":""),"PTR", hModuleSnap,"PTR", me32[] ) ) { ; Free memory used for passing dll path to remote thread DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE) ,DllCall("CloseHandle","PTR", hModuleSnap ) ; Must clean up the snapshot object! return false } ; Now walk the module list of the process,and display information about each module while(A_Index=1 || DllCall("Module32Next" (A_IsUnicode?"W":""),"PTR",hModuleSnap,"PTR", me32[] ) ) If (StrGet(me32.szExePath[""])=dll){ hModule := me32.modBaseAddr["",""] break } DllCall("CloseHandle","PTR",hModuleSnap) ; clean up } } hDll:=DllCall("LoadLibrary","Str",dll,"PTR") ; Calculate pointer to ahkdll and ahkExec functions ahktextdll:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahktextdll","PTR")-hDll ahkExec:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkExec","PTR")-hDll ahkTerminate:=hModule+DllCall("GetProcAddress","PTR",hDll,"AStr","ahkTerminate","PTR")-hDll If script { nScriptLength := VarSetCapacity(nScript, (StrLen(script)+1)*(A_IsUnicode?2:1), 0) ,StrPut(script,&nScript) ; Reserve memory in remote process where our script will be saved If !pBufferScript := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "PTR", nScriptLength, "UInt", MEM_COMMIT, "UInt", PAGE_EXECUTE_READWRITE, "Ptr") return DllCall("MessageBox","PTR",0,"Str","Could not reseve memory for process.","STR","Error","UInt",0) ,DllCall("CloseHandle", "PTR", hProc) ; Write script to remote process memory DllCall("WriteProcessMemory", "Ptr", hProc, "Ptr", pBufferScript, "Ptr", &nScript, "PTR", nScriptLength, "Ptr", 0) } else pBufferScript:=0 ; Run ahkdll function in remote thread hThread := DllCall("CreateRemoteThread","PTR",hProc,"PTR",0,"PTR",0,"PTR",ahktextdll,"PTR",pBufferScript,"PTR",0,"UInt",0,"PTR") If !hThread { ; could not start ahkdll in remote process ; Free memory used for passing dll path to remote thread DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE) DllCall("CloseHandle", "PTR", hProc) return DllCall("MessageBox","PTR",0,"Str","Could not start ahkdll in remote process","STR","Error","UInt",0) } DllCall("WaitForSingleObject", "PTR", hThread, "UInt", 0xFFFFFFFF) DllCall("GetExitCodeThread", "PTR", hThread, "UIntP", lpExitCode) ; Release memory and handles DllCall("VirtualFreeEx","PTR",hProc,"PTR",pBufferRemote,"PTR",nDirLength,MEM_RELEASE) DllCall("CloseHandle", "PTR", hThread) DllCall("CloseHandle", "PTR", hProc) If !lpExitCode ; thread could not be created. return DllCall("MessageBox","PTR",0,"Str","Could not create a thread in remote process","STR","Error","UInt",0) return {PID:PID,hModule:hModule,ahkExec:ahkExec,ahkTerminate:ahkTerminate,base:base} }
Wouldn't it be 'safer' to search default paths ( ie working dir, sys dir, lib dir etc ) for the dll rather than the user having to specify it?
Just a thought..
don't duplicate, iterate!
Now many thinks are so simple, e.g. show path of executable for current window
^!+a:: WinGet,PID,PID,A rThread:=InjectAhkDll(PID,A_ScriptDir "\AutoHotkeyMini.dll") rThread.Exec("MsgBox % A_AhkPath") rThread:="" return
That wouldn't probably load the right dll, there are 10 AutoHotkey[Mini].dlls for 32-bit and another 6 for 64-bitWouldn't it be 'safer' to search default paths ( ie working dir, sys dir, lib dir etc ) for the dll rather than the user having to specify it?
thanks again!!
don't duplicate, iterate!
I use your code (with getworkingdir) in Win7 64 bit. Notepad and Wordpad (64 bit) are normal, but Scite4AutoHotkey (32 bit) crash.
Why?
Click to download Chinese resource for AutoHotkey.
Recommended: AutoHotkey_L My code is based on it or similar versions, e.g. AutoHotkey_H.
Together with AutoHotkey, we grow and march forward. No matter how the future will be, this period of days is still epic.
Also it killed my notepad windows when I tested it. I'd kind of like to get this working though, do I have to uninstall my version of AHK_L? Or is it possible to have this work with AHK_L? If someone could dumb this down for me it'd be helpful :3
I'm on Windows 7 x64. I tried the latest Autohotkey_H (1.1.9.0 built on Nov 8th 2012), tried both the 32 bit w and the 64 bit w version.
Any help would be greatly appreciated.
Cheers, tw
don't duplicate, iterate!
Try this
The MCode hex string is original 32-bit GetCurrentDirectoryW function with swapped parameters.,GetCurrentDirectoryW,init:=MCode(GetCurrentDirectoryW,"8BFF558BECFF750[color=#FF0000]8[/color]8B450803C050FF15A810807CD1E85DC20800")
-----------------------------
HotKeyIt,
i dont understand the need/purpose of the MCode. how/why did you generate it and what is it for?
CreateRemoteThread can pass one parameter only to the called function in remote thread.
GetCurrentDirectory requires 2 parameters, but when we swap these parameters it seems to work, at least on XP.
hrmmm..ok..
now suppose you wanted to hook msdn MessageBox from a remote process and append your own string to the end of every msgbox the remote process displays. how would that be done?