Page 1 of 1

Copy and run functions from memory

Posted: Sun Jul 19, 2009 12:51 am
by Psych
I'm sure I've seen this mentioned around here, but I just searched and couldn't find it.
Is is possible to load a procedure from a DLL into memory and run that procedure? And get it's return values? Basically, I want to copy a few functions from a lib, then close the lib, but access the functions using prototypes.
I'm thinking I can use the GetFunction to get the address while the library is open, but what about the size?

Posted: Sun Jul 19, 2009 3:19 am
by netmaestro
Probably the closest thing to it would be to use Import and just import the functions you want.

Posted: Sun Jul 19, 2009 9:29 am
by srod
Yes, if the dll function in question accesses static or global variables, for example, then it will invariably attempt to access memory within that part of the address space into which the dll is mapped and given over to one of it's data sections. Such a function, whether copied elsewhere into memory, or not, will thus require access to that memory and thus require the dll to remain mapped into the process' memory space.

With the dll thus in memory, you may as well call the aforementioned function as per normal; with prototypes/CallFunction() etc. or through imports as suggested by netmaestro. There are loads of examples of doing this in these forums.

Posted: Sat Aug 01, 2009 9:40 pm
by Trond
It is not possible because there is really no such thing as a function in a dll. There are only function entry points, which tells you where the functions start. But you don't know where they end and which other functions they may call.

Posted: Sat Aug 01, 2009 11:13 pm
by localmotion34
It actually is possible. There is a tool for the reverser community called Function Replacer 1.0 by Execution.

It replaces one DLL function with another, from entry point to return. So mapping a DLL function to memory is possible, because this tool does it and then realigns the DLL.

Posted: Sun Aug 02, 2009 12:16 am
by netmaestro
Trond wrote:...and which other functions they may call.
It handles this too?

Posted: Sun Aug 02, 2009 10:22 am
by Trond
localmotion34 wrote:It actually is possible. There is a tool for the reverser community called Function Replacer 1.0 by Execution.

It replaces one DLL function with another, from entry point to return. So mapping a DLL function to memory is possible, because this tool does it and then realigns the DLL.
No, this is not the same at all.

It is possible to replace a dll function with another, since you only change the export table to point to the new function (or insert a jump to the new function at the entry point of the old function).

It is not possible to extract the old function, ever.
from entry point to return
There is your problem. There is absolutely no guarantee that the function has only one return.

Example asm:

Code: Select all


SillyFunction:
dostuff
jne path1
path2:
ret

path1:
dostuff
jne path2
jmp path3

BogoFunction:
dostuff
jmp path2

path3:
dostuff
ret

You can't extract SillyFunction because if you run from the function entry point to the first ret, then you don't get the entire function (path3). There is absolutely no way whatsoever to know which ret belongs to which function. Never ever.
In fact, a ret can belong to any number of function. In this case the ret in path2 is also used by BogoFunction. Two functions shares the same code (usually as a compiler optimization or done in hand-written assembly). By physically replacing SillyFunction you'll break BogoFunction. Thus, the replacement must be done by altering the export table or inserting a jump to the new function at the start of SillyFunction. It is not possible to know where SillyFunction extends to, ever. Simply because in asm, there is no concept of functions, and code from various functions can be interleaved (done by compilers for alignment or cache purposes) or even shared, and there is absolutely no way to know.

Posted: Sun Aug 02, 2009 3:20 pm
by SFSxOI
Are you taking about intercepting a function in a .dll and replacing it with your own? Hooking and detouring?

A generic example from the working example by Rings > http://purebasic.fr/english/viewtopic.php?t=22678

Code: Select all

Global Dim Backup.b(5) 

Procedure MyFunction(a.l,b.l,c.l,d.l) 

 < do something in my own function here> 

 ProcedureReturn 

EndProcedure 
  
Procedure Hook(Libname.s,FuncName.s,NewFunctionAddress) 
  
dwAddr =GetProcAddress_(GetModuleHandle_(LibName), FuncName) 
OriginalAdress=dwAddr 
Result=ReadProcessMemory_(GetCurrentProcess_(), dwAddr, @Backup(0), 6, @readbytes)
  
  
 Dim a.b(6) 
 a(0)=$e9 
 a(5)=$C3 
  
 dwCalc = NewFunctionAddress - dwAddr - 5
  
 CopyMemory(@dwCalc,@a(1),4) 
  
 Result = WriteProcessMemory_(GetCurrentProcess_(), dwAddr, @a(0), 6, @written); 
  
EndProcedure 
  
Procedure UnHook(Libname.s,FuncName.s) 
  
dwAddr = GetProcAddress_(GetModuleHandle_(LibName), FuncName) 
Result= WriteProcessMemory_(GetCurrentProcess_(), dwAddr, @Backup(0), 6, @written); 

EndProcedure 
  

; Hook("<the dll here>, "<the function in the dll to hook>, "< call our own function instead >"
  
Hook("Some.dll", "Dll_Function", @MyFunction()); 

UnHook("Some.dll", "Dll_Function")

Or maybe more in line with your question regarding using prototypes, heres something I use for getting the Process ID (PID) of a running executable (which is in memory), you can see the use of getting the library and calling its functions and setting up the prototypes for those functions:

Code: Select all

Prototype.i PFNCreateToolhelp32Snapshot(dwFlags.i, th32ProcessID.i) ;
Prototype.b PFNProcess32First(hSnapshot.i, *lppe.PROCESSENTRY32) ;
Prototype.b PFNProcess32Next(hSnapshot.i, *lppe.PROCESSENTRY32) ;
 
Procedure GetPidByName(p_name$) 
    Protected hDLL.i, process_name$ 
    Protected PEntry.PROCESSENTRY32, hTool32.i 
    Protected pCreateToolhelp32Snapshot.PFNCreateToolhelp32Snapshot 
    Protected pProcess32First.PFNProcess32First 
    Protected pProcess32Next.PFNProcess32Next 
    Protected pid.i 
    
    hDLL = OpenLibrary(#PB_Any,"kernel32.dll") 
    
    If hDLL 
        pCreateToolhelp32Snapshot = GetFunction(hDLL,"CreateToolhelp32Snapshot") 
        pProcess32First = GetFunction(hDLL,"Process32First") 
        pProcess32Next = GetFunction(hDLL,"Process32Next") 
    Else 
        ProcedureReturn 0 
    EndIf 
    
    PEntry\dwSize = SizeOf(PROCESSENTRY32) 
    hTool32 = pCreateToolhelp32Snapshot(#TH32CS_SNAPPROCESS, 0) 
    pProcess32First(hTool32, @PEntry) 
    process_name$ = Space(#MAX_PATH) 
    CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
    
    If  UCase(process_name$) = UCase(p_name$) 
        ProcedureReturn PEntry\th32ProcessID 
    EndIf 
    
    While pProcess32Next(hTool32, @PEntry) > 0 
        process_name$ = Space(#MAX_PATH) 
        CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
        
        If  UCase(process_name$) = UCase(p_name$) 
            ProcedureReturn PEntry\th32ProcessID 
        EndIf 
    
    Wend 
    
    CloseLibrary(hDLL) 
    
    ProcedureReturn 0 
EndProcedure

Or maybe more generically:

Code: Select all

Lib_Mine = LoadLibrary_("My.dll")
If Lib_Mine
*h_Lib_Mine_Func1 = GetProcAddress_(Lib_Mine, "DLL_First_Function")
*h_Lib_Mine_Func2 = GetProcAddress_(Lib_Mine, "DLL_Second_Function")
*h_Lib_Mine_Func3 = GetProcAddress_(Lib_Mine, "DLL_Third_Function")
*h_Lib_Mine_Func4 = GetProcAddress_(Lib_Mine, "DLL_Fourth_Function")

FreeLibrary_(Lib_Mine)
EndIf

CallFunctionFast(*h_Lib_Mine_Func1,a, b)
CallFunctionFast(*h_Lib_Mine_Func2,a, b)
CallFunctionFast(*h_Lib_Mine_Func3,a, b)
CallFunctionFast(*h_Lib_Mine_Func4,a, b)


or....maybe like this:


Lib_Mine = LoadLibrary_("My.dll")
If Lib_Mine
*h_Lib_Mine_Func1 = GetProcAddress_(Lib_Mine, "DLL_First_Function")
*h_Lib_Mine_Func2 = GetProcAddress_(Lib_Mine, "DLL_Second_Function")
*h_Lib_Mine_Func3 = GetProcAddress_(Lib_Mine, "DLL_Third_Function")
*h_Lib_Mine_Func4 = GetProcAddress_(Lib_Mine, "DLL_Fourth_Function")
CallFunctionFast(*h_Lib_Mine_Func1,a, b)
CallFunctionFast(*h_Lib_Mine_Func2,a, b)
CallFunctionFast(*h_Lib_Mine_Func3,a, b)
CallFunctionFast(*h_Lib_Mine_Func4,a, b)

FreeLibrary_(Lib_Mine)
EndIf

And to show an example of use in a current project I'm using to show FPS differences between Graphics cards in the same environment in Windows Vista:

Code: Select all


; gpcomms.dll - proxy dll project from > http://www.mikoweb.eu/index.php?node=28
; injector part from hipy001 at > http://www.purebasic.fr/english/viewtopic.php?t=37607
; other parts in PureBasic form and credit goes to their original authors

Prototype.i PFNCreateToolhelp32Snapshot(dwFlags.i, th32ProcessID.i) ;
Prototype.b PFNProcess32First(hSnapshot.i, *lppe.PROCESSENTRY32) ;
Prototype.b PFNProcess32Next(hSnapshot.i, *lppe.PROCESSENTRY32) ;


Procedure GPSI_ShowFPS(bShowFPS.i)
Lib_gpcomms = LoadLibrary_("gpcomms.dll")
If Lib_gpcomms
*h_GPSI_ShowFPS = GetProcAddress_(Lib_gpcomms, "GPSI_ShowFPS")
ret.i = CallFunctionFast(*h_GPSI_ShowFPS, bShowFPS)
FreeLibrary_(Lib_gpcomms)
EndIf
ProcedureReturn ret
EndProcedure

Procedure.b CheckRunningExe(FileName.s) 
  Protected snap.i , Proc32.PROCESSENTRY32 , dll_kernel32.i 
  FileName = GetFilePart(FileName) 
  dll_kernel32 = OpenLibrary(#PB_Any, "kernel32.dll") 
  If dll_kernel32 
    snap = CallFunction(dll_kernel32, "CreateToolhelp32Snapshot",$2, 0) 
    If snap 
      Proc32\dwSize = SizeOf(PROCESSENTRY32) 
      If CallFunction(dll_kernel32, "Process32First", snap, @Proc32) 
        While CallFunction(dll_kernel32, "Process32Next", snap, @Proc32) 
          If PeekS(@Proc32\szExeFile)=FileName 
            CloseHandle_(snap) 
            CloseLibrary(dll_kernel32) 
            ProcedureReturn #True 
          EndIf 
        Wend 
      EndIf    
      CloseHandle_(snap) 
    EndIf 
    CloseLibrary(dll_kernel32) 
  EndIf 
  ProcedureReturn #False 
EndProcedure

Procedure Elevated_Cmd(app_dir.s, app_name.s)
AppVerb$ = "runas"
AppName$ = app_name
AppDir$ = app_dir

shExecInfo.SHELLEXECUTEINFO 
shExecInfo\cbSize=SizeOf(SHELLEXECUTEINFO) 
shExecInfo\fMask=#Null 
shExecInfo\hwnd=#Null 
shExecInfo\lpVerb=@AppVerb$
shExecInfo\lpFile=@AppName$ 
shExecInfo\lpDirectory=@AppDir$
shExecInfo\nShow=#SW_NORMAL

exe.i = ShellExecuteEx_(shExecInfo)
Delay(3000)

If CheckRunningExe(app_name) = #True
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf

EndProcedure

Procedure GetPidByName(p_name$) 
    Protected hDLL.i, process_name$ 
    Protected PEntry.PROCESSENTRY32, hTool32.i 
    Protected pCreateToolhelp32Snapshot.PFNCreateToolhelp32Snapshot 
    Protected pProcess32First.PFNProcess32First 
    Protected pProcess32Next.PFNProcess32Next 
    Protected pid.i 
    
    hDLL = OpenLibrary(#PB_Any,"kernel32.dll") 
    
    If hDLL 
        pCreateToolhelp32Snapshot = GetFunction(hDLL,"CreateToolhelp32Snapshot") 
        pProcess32First = GetFunction(hDLL,"Process32First") 
        pProcess32Next = GetFunction(hDLL,"Process32Next") 
    Else 
        ProcedureReturn 0 
    EndIf 
    
    PEntry\dwSize = SizeOf(PROCESSENTRY32) 
    hTool32 = pCreateToolhelp32Snapshot(#TH32CS_SNAPPROCESS, 0) 
    pProcess32First(hTool32, @PEntry) 
    process_name$ = Space(#MAX_PATH) 
    CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
    
    If  UCase(process_name$) = UCase(p_name$) 
        ProcedureReturn PEntry\th32ProcessID 
    EndIf 
    
    While pProcess32Next(hTool32, @PEntry) > 0 
        process_name$ = Space(#MAX_PATH) 
        CopyMemory(@PEntry\szExeFile,@process_name$,#MAX_PATH) 
        
        If  UCase(process_name$) = UCase(p_name$) 
            ProcedureReturn PEntry\th32ProcessID 
        EndIf 
    
    Wend 
    
    CloseLibrary(hDLL) 
    
    ProcedureReturn 0 
EndProcedure

Procedure InjectLibA(dwProcessId.i, pszLibFile$) 
  hProcess.i 
  hThread.i 
  lzLibFileRemote.i 
  lSize.i 
  endSize.i 
  lsThreadRtn.i 
  
  hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_CREATE_THREAD | #PROCESS_VM_OPERATION | #PROCESS_VM_WRITE, 0, dwProcessId) 
  
  If hProcess = 0 : Goto ErrHandle : EndIf 
  lSize = 1 + Len(pszLibFile$) 
  endSize = lSize 
  
  lzLibFileRemote = VirtualAllocEx_(hProcess, #Null, endSize, #MEM_COMMIT, #PAGE_READWRITE) 
  
  If lzLibFileRemote = 0 : Goto ErrHandle : EndIf 
  
  If (WriteProcessMemory_(hProcess, lzLibFileRemote, pszLibFile$, endSize, #Null) = 0) : Goto ErrHandle : EndIf 
  
  OpenLibrary(0, "Kernel32.dll") : lsThreadRtn = GetFunction(0, "LoadLibraryA") : CloseLibrary(0) 
  
  If lsThreadRtn = 0 : Goto ErrHandle : EndIf 
  
  hThread = CreateRemoteThread_(hProcess, #Null, #Null, lsThreadRtn, lzLibFileRemote, #Null, #Null) 
  
  If (hThread = 0) : Goto ErrHandle : EndIf 
  
  WaitForSingleObject_(hThread, #INFINITE) 
  
  If lzLibFileRemote<>0 
    VirtualFreeEx_(hProcess, lzLibFileRemote, 0, #MEM_RELEASE) 
    MessageRequester("Inject Status", "Injection Suceeded", 0)
    Else
    VirtualFreeEx_(hProcess, lzLibFileRemote, 0, #MEM_RELEASE) 
    MessageRequester("Inject Status", "Injection Failed !!!", 0)
  EndIf 
  End 
  
  ErrHandle: 
      CloseHandle_(hThread) 
      CloseHandle_(hProcess)
      MessageRequester("Inject Status", "Injection Failed !!!", 0) 
EndProcedure

path_game$ = "C:\Program Files\SomeApp-Game\My_App_Game\"
file_game$ = "MyApp.exe"

apprun = Elevated_Cmd(path_game$, file_game$)
Delay(10000)

dll_dir$ = GetCurrentDirectory() + "d3d9.dll"

val_pid.i = GetPidByName(file_game$)
Delay(10)
File_dll$ = dll_dir$
Delay(10)
InjectLibA(val_pid, dll_dir$)

Delay(10000)

Debug GPSI_ShowFPS(1)
Does this help at all or am I not understanding what your after? (I'm probably not understanding - I can be that way sometimes :) )

Hope it helps.