UPDATE:
Okay, modified the injection code slightly. After starting to learn C the importance of memory management has become apparent. So, I've now added VirtualFreeEx to free the allocated memory.
Also, I discovered the GetExitCodeThread function, which allows you to get the return value of a specific thread, thereby allowing us to actually return whatever the LoadLibrary function returned (the handle to the module if successful). I've now written a new function "LoadLibraryEx" to tie in with the injection, but also be re-usable.
Here's the updated code:
Imports:
Code:
Imports System.Runtime.InteropServices 'for marshaling unmanaged return types.
API Declarations (Note VirtualFreeEx and GetExitCodeThread)
Code:
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As Integer
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal flAllocationType As Integer, ByVal flProtect As Integer) As Integer
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Integer, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal dwFreeType As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer() As Byte, ByVal nSize As Integer, ByVal lpNumberOfBytesWritten As UInteger) As Boolean
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Integer, ByVal lpProcName As String) As Integer
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Integer
Private Declare Function CreateRemoteThread Lib "kernel32" (ByVal hProcess As Integer, ByVal lpThreadAttributes As Integer, ByVal dwStackSize As Integer, ByVal lpStartAddress As Integer, ByVal lpParameter As Integer, ByVal dwCreationFlags As Integer, ByVal lpThreadId As Integer) As Integer
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Integer, ByVal dwMilliseconds As Integer) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private Declare Function GetExitCodeThread Lib "kernel32" (ByVal hThread As Integer, <Out()> ByRef lpExitCode As UInt32) As <MarshalAs(UnmanagedType.Bool)> Boolean
I've already said what all these API functions do pretty much. VirtualFreeEx is basically the opposite of VirtualAllocEx, except there is a catch with its "dwSize" param:
Originally Posted by
msdn
dwSize [in]
The size of the region of memory to free, in bytes.
If the dwFreeType parameter is MEM_RELEASE, dwSize must be 0 (zero). The function frees the entire region that is reserved in the initial allocation call to VirtualAllocEx.
So basically if we're freeing memory completely (releasing it), you don't put a value for dwSize despite what you might think, leave it at 0 for mem_release. Also, you no longer need the "Die" function at all.
Okay, the LoadLibraryEx function (commented, as usual).
This function is quite long now:
Code:
Public Shared Function LoadLibraryEx(ByVal hProcess As Integer, ByVal lpFileName As String) As UInt32
If Not IO.File.Exists(lpFileName) OrElse IntPtr.Size = 8 Then Return 0 'first thing: Make sure the file exists, and we're compiled in x86
Dim bFileName As Byte() = System.Text.Encoding.ASCII.GetBytes(lpFileName + ControlChars.NullChar) 'convert the string to chars (add a nullbyte)
Dim lpFileAddress As Integer = VirtualAllocEx(hProcess, 0, bFileName.Length, &H1000, &H4) 'allocate the memory to put our char array in.
If lpFileAddress = 0 Then Return 0
Dim writeSuccess As Integer = WriteProcessMemory(hProcess, lpFileAddress, bFileName, bFileName.Length, 0) 'write our chars to the process.
If writeSuccess = 0 Then Return 0
Dim lpLoadLibrary As Integer = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA") 'find where LoadLibrary is located
If lpLoadLibrary = 0 Then Return 0 'if for some reason we couldn't get it.
Dim libThread As Integer = CreateRemoteThread(hProcess, 0, 0, lpLoadLibrary, lpFileAddress, 0, 0) 'execute loadlibrary in the remote process.
If libThread = 0 Then Return False
Dim waitVal As Integer = WaitForSingleObject(libThread, 10000) 'wait up to 10 seconds for the thread to return.
'(be warned, if the target DLL puts a messagebox in DllMain and the user doesn't click it in 10 seconds, this function will return 0 so edit the wait time if you want.
If Not waitVal = &H0UI Then Return CloseHandle(libThread) < Int32.MinValue 'simple trick to close the handle and simultaneously return 0.
Dim hModule As UInt32 = 0 'prepare our hModule holder.
If Not GetExitCodeThread(libThread, hModule) Then Return CloseHandle(libThread) < Int32.MinValue 'try to get the thread return value
VirtualFreeEx(hProcess, lpFileAddress, 0, &H8000) 'dont bother checking the return value of VF, we've successfully injected and if the memory fails to free there's nothing we can do.
CloseHandle(libThread) 'dispose our thread handle, we're done with it.
Return hModule
End Function
Okay, so now we need to refactor our Inject code to work with LoadLibraryEx.
Code:
Public Shared Function InjectDll(ByVal dwProcID As Integer, ByVal lpFileName As String) As Uint32
Dim hProc As Integer = OpenProcess(&H42A, True, dwProcID) 'open the process with a combination of PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_WRITE and PROCESS_QUERY_INFORMATION.
If hProc = 0 Then Return 0 'if unable to obtain a handle, quit.
Dim hModule As UInt32 = LoadLibraryEx(hProc, lpFileName) 'try and load the library
CloseHandle(hProc) 'finished our use with the handle, dispose of it.
Return hModule
End Function
And that's it!
For extra curricular activities, here's my FreeLibraryEx. It functions very much the same as LoadLibraryEx, but those of you who are actually paying attention will notice we didn't write the hModule value to memory! Why not you may ask? The difference is in the param types for LoadLibrary and FreeLibrary.
LoadLibrary = LPCSTR (pointer to C-string)
FreeLibrary = HMODULE (essentially a typedef of unsigned int, which is a value type not a reference!)
So for LoadLibrary, we are required to pass a POINTER to it, rather than a literal value, LoadLibrary then reads from where the pointer points to. For this reason, we had to generate a pointer by allocating some memory, writing a string there and then keeping the pointer to that memory address.
On the other hand, FreeLibrary just takes an unsigned int, which isn't a reference type (i.e, you dont have to pass a pointer to it), so you can simply call CreateRemoteThread and pass the hModule value as the param)
Here's the code:
Code:
Public Shared Function FreeLibraryEx(ByVal hProcess As Integer, ByVal hModule As UInt32) As Boolean
Dim freeLibAddress As Integer = GetProcAddress(GetModuleHandle("kernel32"), "FreeLibrary")
If freeLibAddress = 0 Then Return False
Dim flThread As Integer = CreateRemoteThread(hProcess, 0, 0, freeLibAddress, hModule, 0, 0)
If flThread = 0 Then Return 0
Dim waitVal As Integer = WaitForSingleObject(flThread, 10000)
If Not waitVal = &H0UI Then Return CloseHandle(flThread) < Int32.MinValue
CloseHandle(flThread)
Return True
End Function
Now you just pass the value returned by LoadLibraryEx to FreeLibraryEx to unload the DLL.
Enjoy