how to dll Inject Topic is solved

Ask for help, how to use AHK_H, etc.
whynotregister
Posts: 94
Joined: 05 Nov 2016, 22:42

how to dll Inject

18 Jan 2017, 13:56

https://github.com/kevrgithub/autohotke ... ectDll.ahk

I tested it with the script in the link above, but it does not work.
Is there a simple way to do dll injection with ahk?
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

18 Jan 2017, 18:42

Is dll injection an 'OK' thing to do?

Like, if I were to say on Stack Overflow, you can change the font size and control colours in legacy programs using dll injection, would there be a problem?

Or similarly if I said you can retrieve the file path and set the three (yes, three) colours in MS Paint (Windows XP) by searching/editing the address space, would there be a problem?

'These are totally hypothetical things that may or may not be possible.'
Last edited by jeeswg on 17 Aug 2017, 15:24, edited 1 time in total.
FanaticGuru
Posts: 1194
Joined: 30 Sep 2013, 22:25

Re: how to dll Inject

18 Jan 2017, 19:46

jeeswg wrote:Is dll injection an OK thing to do?
I am not sure what you mean by is it ok or a problem. Some programs it works fine, some it don't.
Some programs like online games that monitor for tampering especially don't like it.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts

AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon

[Function] Timer - Create and Manage Timers
whynotregister
Posts: 94
Joined: 05 Nov 2016, 22:42

Re: how to dll Inject

19 Jan 2017, 06:03

HotKeyIt wrote:Try InjectAhkDll()

#include _Struct.ahk
#include sizeof.ahk
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;
.
.
.
Process,wait, notepad.exe
winget,pid,pid,ahk_exe notepad.exe
rThread:=InjectAhkDll(PID,A_ScriptDir "\AutoHotkeyMini.dll","#Persistent`nMsgBox % A_WorkingDir")
Sleep 500
rThread.Exec("MsgBox % A_AhkPath")


The program terminates with a crash.
Compiled from x64 to x86 bin.
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject  Topic is solved

19 Jan 2017, 12:35

Try this AHK_H version:

Code: Select all

Process,Exist, notepad.exe
If !PID:=ErrorLevel
  Run notepad.exe,,,PID

rThread:=InjectAhkDll(PID,"C:\Scratch\Program Files\AutoHotkey\AutoHotkey 1\Win32w\AutoHotkeyMini.dll")
rThread.Exec("MsgBox % A_WorkingDir")


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 := 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}
}
whynotregister
Posts: 94
Joined: 05 Nov 2016, 22:42

Re: how to dll Inject

19 Jan 2017, 13:56

HotKeyIt wrote:Try this AHK_H version:

Code: Select all

Process,Exist, notepad.exe
If !PID:=ErrorLevel
  Run notepad.exe,,,PID

rThread:=InjectAhkDll(PID,"C:\Scratch\Program Files\AutoHotkey\AutoHotkey 1\Win32w\AutoHotkeyMini.dll")
rThread.Exec("MsgBox % A_WorkingDir")


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 := 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}
}


It works really well. Thank you. :D :D
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

18 Aug 2017, 20:10

Is it possible to use ComObjCreate and InjectAhkDll() in AutoHotkey_L v1.1?

I'm getting the error message:
An outgoing call cannot be made since the application is dispatching an input-synchronous call.

Code: Select all

;requires: AutoHotkeyMini.dll (either x64 or x32), _Struct.ahk, sizeof.ahk, InjectAhkDll function
;[AutoHotkeyMini.dll]
;GitHub - HotKeyIt/ahkdll-v1-release: AutoHotkey_H v1 release
;https://github.com/HotKeyIt/ahkdll-v1-release
;[_Struct.ahk, sizeof.ahk]
;GitHub - HotKeyIt/_Struct: class to enable easy access to structures
;https://github.com/HotKeyIt/_Struct
;[InjectAhkDll function]
;[SOLVED]get other process's working dir - Page 3 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/85304-solvedget-other-processs-working-dir/page-3#entry544650

;note: AHK, Notepad, and the dll, should all be x64 or x32
vPathDll := "C:\Program Files\AutoHotkey\AutoHotkeyMini.dll"
WinGet, vPID, PID, ahk_class Notepad

vScript = ;continuation section
(%
MsgBox, % "hello"

WinGet, hWnd, ID, ahk_class CabinetWClass

for oWin in ComObjCreate("Shell.Application").Windows
	if (oWin.HWND = hWnd)
		break

oWindows := ComObjCreate("Shell.Application").Windows
Loop, % oWindows.Count()
	if (oWindows.Item[A_Index-1].HWND = hWnd)
	{
		oWin := oWindows.Item[A_Index-1]
		break
	}
)

;rThread := InjectAhkDll(vPID, vPathDll, "#Persistent")
rThread := InjectAhkDll(vPID, vPathDll)
rThread.Exec(vScript)
return

Code: Select all

;[SOLVED]get other process's working dir - Page 3 - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/85304-solvedget-other-processs-working-dir/page-3#entry544650

#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}
}
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject

19 Aug 2017, 03:37

Exec works via SendMessage and while this is being processed you cannot use COM calls.
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

19 Aug 2017, 08:01

Thank you HotKeyIt, but this potentially scuppers a lot of things I might want to do with dll injection, is there any workaround?

3 potential uses for dll inject and COM:

[major: drag-and-drop a file to a program when WM_DROPFILES doesn't work]
[COM] Help with the IDropSource and IDropTarget interfaces - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 60#p164860

[middle: Common Item Dialog get folder/file]
get full paths of selected files on Desktop and Common File Dialogs - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 77#p145577

[minor: Explorer get column widths in Windows 7]
Explorer column interaction (get/set: which appear, width, ascending/descending order) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 61#p154461
Last edited by jeeswg on 19 Aug 2017, 08:44, edited 5 times in total.
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject

19 Aug 2017, 08:13

You have to include the script upfront when calling InjectAhkDll and control it using .Exec("SetTimer, ...").
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

19 Aug 2017, 08:48

@HotKeyIt: Many thanks, I had thought that SetTimer might be a way, but I don't really understand InjectAhkDll. Btw when I ran the script, I used SetTimer with '-1', but it appeared to run the subroutine twice simultaneously (I got two MsgBoxes).

Btw also, what is the best way to cleanly withdraw, i.e. 'uninject'. I've been experimenting with .Terminate and ExitApp but I'm still getting crashes regularly. Is there any documentation or advice for this function somewhere? Cheers.
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject

19 Aug 2017, 10:00

Did you include the script with Return in first line when calling InjectAhkDll? .Exec() deletes the script after it ran so you can't use it to create script and SetTimer!
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

19 Aug 2017, 10:21

Haha cheers, I didn't understand what you meant at first, but I worked it out after, helped by your comment, when I checked over the code. My code works now, I get one MsgBox, now that I added 'return' to the top of my vScriptFunc variable.

Re. crashing. If I do q it works, and then I can do w as many times as I like, but if I do e to try and close the thread, and then q to inject again, it crashes.

Code: Select all

;==================================================

#SingleInstance force
ListLines, Off
#KeyHistory 0
Menu, Tray, Click, 1
#NoEnv
AutoTrim, Off
#UseHook

SplitPath, A_ScriptName,,,, vScriptNameNoExt
Menu, Tray, Tip, % vScriptNameNoExt

#Persistent

;==================================================

;if !A_IsAdmin
;	Run, % "*RunAs " (A_IsCompiled ? "" : A_AhkPath " ") """" A_ScriptFullPath """"

vAhkIs64 := (A_PtrSize=8)

;vDir := "C:\Program Files\AutoHotkey"
vDir := A_ScriptDir
;note: I copied and renamed the dlls adding '64' and '32'
if vAhkIs64
	vPathDll := vDir "\AutoHotkeyMini64.dll"
else
	vPathDll := vDir "\AutoHotkeyMini32.dll"

if (vAhkIs64 || !A_Is64bitOS)
	vPathNP := "C:\Windows\System32\notepad.exe"
else
	vPathNP := "C:\Windows\SysWOW64\notepad.exe"

;==================================================

if !vAhkIs64
{
	MsgBox, % "the script must be run with AutoHotkeyU64.exe to inject into a 64-bit process"
	ExitApp
}

q::
WinGet, vPID, PID, A
if !JEE_ProcessIs64Bit(vPID)
{
	MsgBox, % "the window must be 64-bit"
	return
}

vScriptFunc = ;continuation section
(%
return

CountOpenFolders: ;this also counts IE tabs
oWindows := ComObjCreate("Shell.Application").Windows
MsgBox, % oWindows.Count()
return
)

;inject dll, set #Persistent and add some functions/subroutines
rThread := InjectAhkDll(vPID, vPathDll, "#Persistent`n" vScriptFunc)

w::
vScript = ;continuation section
(%
SetTimer, CountOpenFolders, -1
)

rThread.Exec(vScript)
return

;==================================================

e::
rThread.Terminate()
return

;==================================================

JEE_ProcessIs64Bit(vPID)
{
	if !A_Is64bitOS
		return 0
	hProc := DllCall("kernel32\OpenProcess", UInt,0x400, Int,0, UInt,vPID, Ptr)
	DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return !vIsWow64Process
}

;==================================================

#Include, <_Struct>
#Include, InjectAhkDll.ahk

;==================================================
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject

19 Aug 2017, 14:47

Did you rThread:="" before injecting again?
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

19 Aug 2017, 16:35

You're quite right HotKeyIt.
This seems to be invalid:
rThread.Terminate()
I replaced it with this and it's all working:
rThread := ""

All the details for the function are here it turns out:
[SOLVED]get other process's working dir - Page 3 - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/8530 ... ntry544650

A small amount of documentation, but all that's needed.

==================================================

One thing that someone mentioned to me, was that some dll injection techniques require you to latch onto a specific thread, rather than simply to latch onto a process.

Now, I don't actually need to do that, as I have workarounds, however, I'd just like to mention it in case you have any useful links, or anything to say on how to achieve that. Cheers.

[EDIT:] At some point soon I will post some example code for setting the font colour/background colour/font in Notepad, and a prototype window message spy.
HotKeyIt
Posts: 1697
Joined: 29 Sep 2013, 18:35
Contact:

Re: how to dll Inject

19 Aug 2017, 18:03

Here CreateRemoteThread is used so a new thread is created in process, not sure how to latch onto a specific thread and when / why it might be required.
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

19 Aug 2017, 18:15

qwerty12 provided an example of latching onto a specific thread here, using Tiny C Compiler:
[Common Item Dialog get folder/file]
get full paths of selected files on Desktop and Common File Dialogs - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 77#p145577

And mentioned another potential use of it here:
[Explorer get column widths in Windows 7]
Explorer column interaction (get/set: which appear, width, ascending/descending order) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 61#p154461

These two links also appear earlier on this page. Both problems have workarounds, however, maybe one day the approach could be very useful. Cheers.
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

23 Aug 2017, 16:30

I have a prototype window spy, but it seems to crash the program it latched onto when I: reload the script, end the remote thread, or try to close the program.

WARNING: use with caution, *expect* it to crash the program. This will crash your program.

Code: Select all

;prototype window message spy
;currently checks for WM_COMMAND and WM_SYSCOMMAND messages
;this can be changed by editing MyWndProc

#SingleInstance force
ListLines, Off
#KeyHistory 0
Menu, Tray, Click, 1
#NoEnv
AutoTrim, Off
#UseHook

SplitPath, A_ScriptName,,,, vScriptNameNoExt
Menu, Tray, Tip, % vScriptNameNoExt

#Persistent

;==================================================

OnMessage(0x5555, "MsgMonitor")
OnExit("ExitFunc")
return

;==================================================

q::
vAhkIs64 := (A_PtrSize=8)

;vDir := "C:\Program Files\AutoHotkey"
vDir := A_ScriptDir
if vAhkIs64
	vPathDll := vDir "\AutoHotkeyMini64.dll"
else
	vPathDll := vDir "\AutoHotkeyMini32.dll"

;==================================================

DetectHiddenWindows, On
WinGet, hWnd, ID, A
;ControlGet, hWnd, Hwnd,, Edit1, % "ahk_id " hWnd
WinGet, vPID, PID, % "ahk_id " hWnd

if !(vAhkIs64 = JEE_ProcessIs64Bit(vPID))
{
	MsgBox, % "not latched on: AHK and external process must have the same bitness"
	return
}

;==================================================

vScriptFunc = ;continuation section
(% `
#Persistent
DetectHiddenWindows, On
hWnd := hWndX1
pWndProc := RegisterCallback("MyWndProc", "")
;GWL_WNDPROC := -4
vSfx := (A_PtrSize=8) ? "Ptr" : ""
pWndProcOld := DllCall("SetWindowLong" vSfx, Ptr,hWnd, Int,-4, Ptr,pWndProc, Ptr)
vToolTipIsOn := 1

MyWndProc(hWnd, uMsg, wParam, lParam)
{
	global pWndProcOld, vToolTipIsOn
	;WM_COMMAND := 0x111 ;WM_SYSCOMMAND := 0x112
	if vToolTipIsOn
	if (uMsg >= 0x111) && (uMsg <= 0x112)
	if !(wParam = 0xF100) ;61696
	if !(wParam = 0x100000F) ;16777231
	if !(wParam = 0x200000F) ;33554447
	if !(wParam = 0x300000F) ;50331663
	if !(wParam = 0x400000F) ;67108879
		PostMessage, 0x5555, % uMsg, % wParam,, % "ahk_id " hWndX2 ;didn't work
	return DllCall("CallWindowProc", Ptr,pWndProcOld, Ptr,hWnd, UInt,uMsg, UPtr,wParam, Ptr,lParam, Ptr)
}
)

vScriptFunc := StrReplace(vScriptFunc, "hWndX1", hWnd)
vScriptFunc := StrReplace(vScriptFunc, "hWndX2", A_ScriptHwnd)
rThread := InjectAhkDll(vPID, vPathDll, vScriptFunc)
return

;==================================================

e::
rThread := ""
return

;==================================================

MsgMonitor(wParam, lParam, uMsg, hWnd)
{
	ToolTip, % wParam " " lParam "`r`n" Format("0x{:X} 0x{:X}", wParam, lParam)
}

;==================================================

ExitFunc()
{
	global
	ToolTip
	rThread := ""
}

;==================================================

JEE_ProcessIs64Bit(vPID)
{
	if !A_Is64bitOS
		return 0
	hProc := DllCall("kernel32\OpenProcess", UInt,0x400, Int,0, UInt,vPID, Ptr)
	DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return !vIsWow64Process
}

;==================================================

#Include, <_Struct>
#Include, InjectAhkDll.ahk

;==================================================
User avatar
jeeswg
Posts: 5160
Joined: 19 Dec 2016, 01:58
Location: UK

Re: how to dll Inject

23 Aug 2017, 18:50

Here are some examples for interacting with Notepad, which is the last dll injection script I intend to post, unless I can ever get this working:
[COM] Help with the IDropSource and IDropTarget interfaces - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 94#p165994

I'm still having problems relating to dll injection and programs crashing, if anyone can help me with that.

The main aim here is to programmatically set the background colour and font for Notepad's Edit control.

Note: The default system colour for Edit controls can be changed (e.g. on Windows 7) by going to Control Panel\Appearance and Personalization\Personalization and changing the colour for 'Window'. Or you can get/set that colour programmatically by using GetSysColor/SetSysColors (note: 'Color' v. 'Colors').

This script changes the colour for an individual existing Edit control.

Code: Select all

q:: ;get/set Edit control background colour
;[list of RGB values]
;Progress/SplashImage
;https://autohotkey.com/docs/commands/Progress.htm#Object_Colors

;COLOR_WINDOW := 5
vColBGR := DllCall("user32\GetSysColor", Int,5, UInt)
MsgBox, % Format("0x{:06X}", vColBGR)

;COLOR_WINDOW := 5
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0xefcdab) ;BGR
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0x0000ff) ;BGR ;red
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0x00ffff) ;BGR ;yellow
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0x00ff00) ;BGR ;lime
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0xff0000) ;BGR ;blue
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0xc0c0c0) ;BGR ;silver
Sleep 2000
DllCall("user32\SetSysColors", Int,1, IntP,5, UIntP,0xffffff) ;BGR ;white
MsgBox, % "done"
return

Code: Select all

;script to interact with Notepad via dll injection

;warning: this script is likely to crash your Notepad window,
;currently it appears that if Notepad is closed first, that's fine,
;but if the script is closed/reloaded first, it crashes Notepad

#SingleInstance force
ListLines, Off
#KeyHistory 0
Menu, Tray, Click, 1
#NoEnv
AutoTrim, Off
#UseHook

SplitPath, A_ScriptName,,,, vScriptNameNoExt
Menu, Tray, Tip, % vScriptNameNoExt

#Persistent

;==================================================

vAhkIs64 := (A_PtrSize=8)

;vDir := "C:\Program Files\AutoHotkey"
vDir := A_ScriptDir
if vAhkIs64
	vPathDll := vDir "\AutoHotkeyMini64.dll"
else
	vPathDll := vDir "\AutoHotkeyMini32.dll"

if (vAhkIs64 || !A_Is64bitOS)
	vPathNP := "C:\Windows\System32\notepad.exe"
else
	vPathNP := "C:\Windows\SysWOW64\notepad.exe"

;==================================================

;find Notepad window
DetectHiddenWindows, On
WinGet, vWinList, List, ahk_class Notepad
vOutput := ""
WinGet, hWnd, ID, % "ahk_class Notepad ahk_exe " vPathNP
if !hWnd
{
	Run, % vPathNP
	WinWait, % "ahk_class Notepad ahk_exe " vPathNP
	WinGet, hWnd, ID, % "ahk_class Notepad ahk_exe " vPathNP
}
WinGet, vPID, PID, % "ahk_id " hWnd
WinActivate, % "ahk_id " hWnd
MsgBox, % vPID

;==================================================

vScriptFunc = ;continuation section
(
CtlSetColors(hWnd, uMsg, wParam, lParam = 0)
{
	global vColText, vColBk, hBrush, pWndProcOld
	Critical
	;WM_CTLCOLOREDIT := 0x133 ;WM_CTLCOLORSTATIC := 0x138
	if (uMsg >= 0x132) && (uMsg <= 0x138)
	{
		DllCall("SetTextColor", Ptr,wParam, UInt,vColText, UInt)
		DllCall("SetBkColor", Ptr,wParam, UInt,vColBk, UInt)
		return DllCall("CreateSolidBrush", UInt,vColBk, Ptr)
	}
	return DllCall("CallWindowProcA", Ptr,pWndProcOld, Ptr,hWnd, UInt,uMsg, UPtr,wParam, Ptr,lParam, Ptr)
}
)

;inject dll, set #Persistent and add some functions
rThread := InjectAhkDll(vPID, vPathDll, "#Persistent`n" vScriptFunc)

;==================================================

vScript = ;continuation section
(% `
DetectHiddenWindows, On
vPID := DllCall("kernel32\GetCurrentProcessId", UInt)
WinGet, vPName, ProcessName, % "ahk_pid " vPID
vOutput := "process name: " vPName "`r`n"
vOutput .= "working dir: " A_WorkingDir "`r`n"
vOutput .= "path: " A_AhkPath
MsgBox, % vOutput
)
rThread.Exec(vScript)

;==================================================

vScript = ;continuation section
(
Add(vNum1, vNum2)
{
	return vNum1 + vNum2
}
)
rThread.Exec(vScript)

;==================================================

vScript = ;continuation section
(%
MsgBox, % "Add(1, 1) = " Add(1, 1)
)
rThread.Exec(vScript)

;==================================================

vFontName := "Arial", vFontSize := 48, vFontIsBold := 0
vFontHeight := -DllCall("kernel32\MulDiv", Int,vFontSize, Int,A_ScreenDPI, Int,72)
vFontWeight := vFontIsBold ? 700 : 400
ControlGet, hCtl, Hwnd,, Edit1, % "ahk_id " hWnd

vScript = ;continuation section
(
hFont := DllCall("CreateFont", Int,%vFontHeight%, Int,0, Int,0, Int,0
, Int,%vFontWeight%, UInt,0, UInt,0, UInt,0
, UInt,0, UInt,3, UInt,2, UInt,1
, UInt,34, Str,"%vFontName%", Ptr)
PostMessage, 0x30, `% hFont, 1, Edit1, ahk_id %hWnd% ;WM_SETFONT := 0x30
)
rThread.Exec(vScript)

;==================================================

vSfx := (A_PtrSize=8) ? "Ptr" : ""
vScript = ;continuation section
(
hCtl := %hCtl%
hWnd := %hWnd%
vColText := 0xFF0000 ;BGR
vColBk := 0xEFCDAB ;BGR
pWndProcNew := RegisterCallback("CtlSetColors", "", 4)
pWndProcOld := DllCall("SetWindowLong%vSfx%", Ptr,hWnd, Int,-4, Ptr,pWndProcNew, Ptr) ;GWL_WNDPROC := -4
WinSet, Redraw,, ahk_id %hWnd%
)
rThread.Exec(vScript)

;Sleep 5000
;rThread := "" ;this line crashes the script
return

;==================================================

JEE_ProcessIs64Bit(vPID)
{
	if !A_Is64bitOS
		return 0
	hProc := DllCall("kernel32\OpenProcess", UInt,0x400, Int,0, UInt,vPID, Ptr)
	DllCall("kernel32\IsWow64Process", Ptr,hProc, PtrP,vIsWow64Process)
	DllCall("kernel32\CloseHandle", Ptr,hProc)
	return !vIsWow64Process
}

;==================================================

#Include, <_Struct>
#Include, InjectAhkDll.ahk

;==================================================
Note in terms of scripts for setting the colour of an Edit control, there are a tonne of links if you search for 'edit control set colour' or 'Control_Colors', here are some of them:
Spoiler
Last edited by jeeswg on 25 Aug 2017, 11:47, edited 1 time in total.

Return to “Ask For Help”

Who is online

Users browsing this forum: No registered users and 2 guests