I want to access a certain address of a process. But for that i need to get the base address of the process first. I'm using a tool to see if i'm actually doing it right. The tool shows i need the following: "app.exe"+0x011F9B08 = 0x119F8300
I thought i could obtain the base address of a process through OpenProcess(), but that gives me: 0x0000005c as a result. I don't think that is right? Atleast, not what i need.
I think the base address i need is: 0x119F8300 - 0x011F9B08 = 0x107FE7F8 <-- base?
This is my code:
hWindow = FindWindow(NULL, lpWindowName);
if(hWindow)
{
GetWindowThreadProcessId(hWindow, &dwProcId);
if(dwProcId != 0)
{
// hProcHandle -> 0x0000005c
hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcId);
}
else
{
return 0;
}
}
How can i get the base address of the process that i've opened?
If you want to get the virtual address within the other process's address space, you can do that like so:
Open the process using OpenProcess -- if successful, the value returned is a handle to the process, which is just an opaque token used by the kernel to identify a kernel object. Its exact integer value (0x5c in your case) has no meaning to userspace programs, other than to distinguish it from other handles and invalid handles.
Call GetProcessImageFileName to get the name of the main executable module of the process.
Use EnumProcessModules to enumerate the list of all modules in the target process.
For each module, call GetModuleFileNameEx to get the filename, and compare it with the executable's filename.
When you've found the executable's module, call GetModuleInformation to get the raw entry point of the executable.
This will give you the virtual address, but there's not a whole lot you can do with it since it's not mapped into your current process's address space.
I wanted to elaborate a bit on #Adam Rosenfield's answer. I will use League of Legends as an example here.
In order to open the process (Getting a handle) we need it's PID (Process ID). We can do that via a window handle (HWND) because usually the title of the window is known
//You will need to change this the name of the window of the foreign process
HWND WindowHandle = FindWindow(nullptr, L"League of Legends (TM) Client");
DWORD PID;
GetWindowThreadProcessId(WindowHandle, &PID);
PVOID hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, PID);
Now that we are able to get a handle to the process let's continue
HMODULE Module = GetModule();
DWORD BaseAddress = (DWORD)Module;
The GetModule function
HMODULE GetModule()
{
HMODULE hMods[1024];
HANDLE pHandle = GetHandle();
DWORD cbNeeded;
unsigned int i;
if (EnumProcessModules(pHandle, hMods, sizeof(hMods), &cbNeeded))
{
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(pHandle, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
wstring wstrModName = szModName;
//you will need to change this to the name of the exe of the foreign process
wstring wstrModContain = L"League of Legends.exe";
if (wstrModName.find(wstrModContain) != string::npos)
{
CloseHandle(pHandle);
return hMods[i];
}
}
}
}
return nullptr;
}
as for me personally I like to write 2 separate functions one for getting a handle and one for getting the module.
There we go, we have successfully gotten the base address of a foreign process.
Related
I'm trying to hook the DLL onto a notepad process, and then unhook it. When hooked, the DLL should cause the notepad to create a hidden file whenever the user clicks "Save As" (code for this is not shown). When unhooked, that should not be the case.
However, for some reason, while I got the message "DLL unhooking from process", the DLL still is not unhooked from the notepad process, and I know this because the notepad still creates the additional file when it should not have done that.
There are no error messages on the return values whatsover (at least none that I know of), so I removed most return value checks.
Hook
HANDLE hThread;
char * pid = argv[1];
DWORD user_pid = atoi(pid);
LPCSTR Dllpath = "C:\\Users\\xxx\\Desktop....\\MyDll.dll"
LPVOID pDllPath; // Address in remote process where Dllpath will be copied to.
HMODULE hKernel32 = GetModuleHandle("Kernel32");
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, user_pid);
char * command = argv[2];
if (strcmp(command,"hook") == 0){
SIZE_T bytesWritten = 0;
//Allocate memory to target process, and write dll to the allocated memory.
pDllPath = VirtualAllocEx(hProcess, NULL,strlen(DllPath)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
// Write DLL hook name
WriteProcessMemory(hProcess, pDllPath, (LPCVOID)DllPath, strlen(Dllpath)+1,&bytesWritten);
// Load Dll to remote process
hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), pDllPath,0,NULL);
WaitForSingleObject(hThread, INFINITE);
//Clean up
CloseHandle(hThread);
VirtualFreeEx(hProcess, pDllPath, strlen(DllPath+1, MEM_RELEASE);
else if (strcmp(command,"unhook")==0){
InlineUnhook(); //Call unhook inside the dll itself
}
}
Unhook (inside the dll itself)
HANDLE __stdcall InlineUnhook(){
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
LoadLibrary("C:\\Users\\xxx\\Desktop...\\MyDll.dll);
HMODULE hLibModule = GetModuleHandleA ("C:\\Users\\xxx\\Desktop...\\MyDll.dll);
HANDLE hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "FreeLibraryAndExitThread"), (void *)(hLibModule,0),0,NULL);
if (hThread == NULL){
OutputDebugStringA("CreateRemoteThread failed.");
return -1;
}
else{
WaitForSingleObject(hThread, INFINITE);
//Clean up
CloseHandle(hThread);
OutputDebugStringA("DLL unhooking from process...");
return 0;
}
}
Your injector is calling InlineUnhook() directly, so it will act on the instance of the DLL that is loaded in the injector process, not the hooked process.
FreeLibraryAndExitThread() is not compatible with CreateRemoteThread(), so you can't use a remote thread to call it directly, like you can with LoadLibraryA().
Inside of the DLL itself, there is no need for it to call OpenProcess(), LoadLibrary(), or CreateRemoteThread() for itself. The DLL can simply call FreeLibraryAndExitThread() directly, like any other local function.
HINSTANCE hThisInst;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
hThisInst = hinstDLL;
...
return 1;
}
void __stdcall InlineUnhook()
{
FreeLibraryAndExitThread(hThisInst, 0);
}
Your injector will have to use a remote thread to call InlineUnhook() within the context of the hooked process, rather than calling it directly. That means you need to:
export InlineUnhook() from the DLL.
find the address of the loaded DLL within the hooked process. If your DLL is 32bit being loaded into a 32bit target process, that address can be obtained from GetExitCodeThread() when CreateRemoteThread() is done calling LoadLibraryA(). Otherwise, you will have to go hunting for the loaded address afterwards, such as by EnumProcessModules() or CreateToolhelp32Snapshot(TH32CS_SNAPMODULE).
find the address of the exported InlineUnhook() within the hooked process. Use LoadLibrary() and GetProcAddress() inside the injector to calculate the offset of InlineUnhook() within the DLL, and then apply that offset to the address of the loaded DLL within the hooked process.
use CreateRemoteThread() to call InlineUnhook() at that calculated address. You will have to change the signature of InlineUnhook() to be compatible with CreateRemoteThread(), eg:
DWORD __stdcall InlineUnhook(LPVOID)
{
FreeLibraryAndExitThread(hThisInst, 0);
return 1;
}
That's because your InlineUnhook call above calls the copy of the dll that is loaded into your injection process, not the one in the target process.
I want to monitor a process in c++, so I'm using:
std::wstring windowName = TEXT("needle");
HWND windowHandle = FindWindowW(NULL, windowName.c_str());
The FindWindow function, as I understand it, checks the title for all windows (Why did Microsoft name their OS after a core part of it, checking windows in Windows, madness). If a title matches "needle" then it gives me the...
HWND windowHandle
Next I am using:
DWORD* PID;
GetWindowThreadProcessId(windowHandle, PID);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, *PID);
This gives me the processID or PID as I've named it. I can then use that to...
HWND p;
DWORD state;
GetExitCodeProcess(p, &state);
... get the state of the process, I'm going to check for it being "STILL_ACTIVE", like so:
if (state != STILL_ACTIVE) {
std::cout << "excessive profanity\n";
}
else {
std::cout << "sigh of relief\n";
}
Except this doesn't work, "cout-ing" (new verb) the value of state gives me some kind of hexadecimal code. It's never "STILL_ACTIVE" despite having multiple windows with "needle" as the title. The code compiles fine, it's just something to do with conversion, pointers, LPCWSTR's or something I've never come across. Help would be appreciated. Thanks
You have two problems:
1) As PaulMcKenzie points out in his answer, PID points to nothing, and will cause problems. Instead you should declare a DWORD and pass a pointer to it to GetWindowThreadProcessId:
DWORD PID;
// note: &PID instead of just PID
GetWindowThreadProcessId(windowHandle, &PID);
// note: Just PID instead of *PID
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
2) GetExitCodeProcess needs a handle to a process, not an uninitialized HWND. Instead you should give it the handle returned from OpenProcess:
DWORD state;
// note: this is the hProcess returned from OpenProcess
GetExitCodeProcess(hProcess, &state);
Note that this will still only work for one process. If multiple processes have windows with the title "needle" then the result of your FindWindow call will be unpredictable.
One error (and probably not the only error) is that there is no way this can work correctly:
DWORD* PID;
GetWindowThreadProcessId(windowHandle, PID);
You are giving GetWindowThreadProcessId an uninitialized pointer, PID. There is nothing that the function can do with it except dereference it (causing undefined behavior), or at best, check if the value is NULL.
When a function asks for a pointer, it doesn't mean you literally declare a pointer and pass it to the function. The function wants the address of an existing entity:
DWORD PID;
GetWindowThreadProcessId(windowHandle, &PID);
I`m trying to inject a DLL in a process and call a exported function in my DLL.
The DLL is injected alright with that code:
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
HANDLE hThread = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
The module of my DLL is created OK, like you see in that image of Process Hacker (BootstrapDLL.exe):
My exported functions is ok too, like you see in the list of functions exported on Process Hacker (ImplantDotNetAssembly):
The problems, I think, happens on the offset calculation to get the address of the "ImplantDotNetAssembly", because everything above is alright and when I do the calculation I get the address of the "ImplantDotNetAssembly", but when I call CreateRemoteThread again to call it, the window "Has stopped working..." of the windows is showed and the process stoped. What`s happening?
Here is the code of the calculation of the offset:
DWORD_PTR hBootstrap = GetRemoteModuleHandle(ProcId, L"BootstrapDLL.exe");
DWORD_PTR offset = GetFunctionOffset(L"C:\\Users\\Acaz\\Documents\\Visual Studio 2013\\Projects\\Contoso\\Debug\\BootstrapDLL.exe", "ImplantDotNetAssembly");
DWORD_PTR fnImplant = hBootstrap + offset;
HANDLE hThread2 = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)fnImplant, NULL, 0, NULL);
Here are the functions GetRemoteModuleHandle and GetFunctionOffset:
DWORD_PTR GetFunctionOffset(const wstring& library, const char* functionName)
{
// load library into this process
HMODULE hLoaded = LoadLibrary(library.c_str());
// get address of function to invoke
void* lpInject = GetProcAddress(hLoaded, functionName);
// compute the distance between the base address and the function to invoke
DWORD_PTR offset = (DWORD_PTR)lpInject - (DWORD_PTR)hLoaded;
// unload library from this process
FreeLibrary(hLoaded);
// return the offset to the function
return offset;
}
DWORD_PTR GetRemoteModuleHandle(const int processId, const wchar_t* moduleName)
{
MODULEENTRY32 me32;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
// get snapshot of all modules in the remote process
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
// can we start looking?
if (!Module32First(hSnapshot, &me32))
{
CloseHandle(hSnapshot);
return 0;
}
// enumerate all modules till we find the one we are looking for or until every one of them is checked
while (wcscmp(me32.szModule, moduleName) != 0 && Module32Next(hSnapshot, &me32));
// close the handle
CloseHandle(hSnapshot);
// check if module handle was found and return it
if (wcscmp(me32.szModule, moduleName) == 0)
return (DWORD_PTR)me32.modBaseAddr;
return 0;
}
If someone know what is happening, I'll be very grateful!
I cant`t even debug the "has stopped work.." error. When I clik in the DEBUG button on the window, the error throw again and everything stop.
Thank you.
NEVER inject managed assemblies. If for some reason you must inject code into another process, use native code with either NO C library or a STATIC C library.
Using C++, I have an application which creates a remote process and injects a DLL into it. Is there a way to get the remote application to execute a function exported from the DLL, from the application which created it? And is it possible to send parameters to that function? Please note that I am trying to stay away from doing anything within DllMain.
Note:
For a much better answer, please see my update posted below!
Okay so here's how I was able to accomplish this:
BOOL RemoteLibraryFunction( HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID *ppReturn )
{
LPVOID lpRemoteParams = NULL;
LPVOID lpFunctionAddress = GetProcAddress(GetModuleHandleA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) lpFunctionAddress = GetProcAddress(LoadLibraryA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) goto ErrorHandler;
if( lpParameters )
{
lpRemoteParams = VirtualAllocEx( hProcess, NULL, dwParamSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !lpRemoteParams ) goto ErrorHandler;
SIZE_T dwBytesWritten = 0;
BOOL result = WriteProcessMemory( hProcess, lpRemoteParams, lpParameters, dwParamSize, &dwBytesWritten);
if( !result || dwBytesWritten < 1 ) goto ErrorHandler;
}
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunctionAddress, lpRemoteParams, NULL, NULL );
if( !hThread ) goto ErrorHandler;
DWORD dwOut = 0;
while(GetExitCodeThread(hThread, &dwOut)) {
if(dwOut != STILL_ACTIVE) {
*ppReturn = (PVOID)dwOut;
break;
}
}
return TRUE;
ErrorHandler:
if( lpRemoteParams ) VirtualFreeEx( hProcess, lpRemoteParams, dwParamSize, MEM_RELEASE );
return FALSE;
}
//...
CStringA targetDll = "injected.dll"
// Inject the target library into the remote process
PVOID lpReturn = NULL;
RemoteLibraryFunction( hProcess, "kernel32.dll", "LoadLibraryA", targetDll.GetBuffer(MAX_PATH), targetDll.GetLength(), &lpReturn );
HMODULE hInjected = reinterpret_cast<HMODULE>( lpReturn );
// Call our exported function
lpReturn = NULL;
RemoteLibraryFunction( hProcess, targetDll, "Initialize", NULL, 0, &lpReturn );
BOOL RemoteInitialize = reinterpret_cast<BOOL>( lpReturn );
This can also be used to send parameters to a remote function via a pointer to a struct or union, and gets around having to write anything in DllMain.
So after some elaborate testing, it would seem that my previous answer is anything but foolproof(or even 100% functional, for that matter), and is prone to crashes. After giving it some thought, I've decided to take an entirely different approach to this... using Interprocess Communication.
Be aware... this method utilizes code in DllMain.
So don't go overboard, and be sure to follow safe practices when doing this, so that you don't end up in a deadlock...
Most notably, the Win32 API offers the following useful functions:
CreateFileMapping
MapViewOfFile
OpenFileMapping
With the use of these, we can simply tell our Launcher process exactly where our remote init function resides, straight from the injected dll itself...
dllmain.cpp:
// Data struct to be shared between processes
struct TSharedData
{
DWORD dwOffset = 0;
HMODULE hModule = nullptr;
LPDWORD lpInit = nullptr;
};
// Name of the exported function you wish to call from the Launcher process
#define DLL_REMOTEINIT_FUNCNAME "RemoteInit"
// Size (in bytes) of data to be shared
#define SHMEMSIZE sizeof(TSharedData)
// Name of the shared file map (NOTE: Global namespaces must have the SeCreateGlobalPrivilege privilege)
#define SHMEMNAME "Global\\InjectedDllName_SHMEM"
static HANDLE hMapFile;
static LPVOID lpMemFile;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
TSharedData data;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
// Get a handle to our file map
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, SHMEMSIZE, SHMEMNAME);
if (hMapFile == nullptr) {
MessageBoxA(nullptr, "Failed to create file mapping!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}
// Get our shared memory pointer
lpMemFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpMemFile == nullptr) {
MessageBoxA(nullptr, "Failed to map shared memory!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}
// Set shared memory to hold what our remote process needs
memset(lpMemFile, 0, SHMEMSIZE);
data.hModule = hModule;
data.lpInit = LPDWORD(GetProcAddress(hModule, DLL_REMOTEINIT_FUNCNAME));
data.dwOffset = DWORD(data.lpInit) - DWORD(data.hModule);
memcpy(lpMemFile, &data, sizeof(TSharedData));
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// Tie up any loose ends
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
break;
}
return TRUE;
UNREFERENCED_PARAMETER(lpReserved);
}
Then, from our Launcher application, we will do the usual CreateProcess + VirtualAllocEx + CreateRemoteThread trick to inject our Dll, making sure to pass in a pointer to a proper SECURITY_DESCRIPTOR as the 3rd parameter to CreateProcess, as well as passing the CREATE_SUSPENDED flag in the 6th parameter.
This is to help ensure that your child process will have the proper privileges to read and write to a global shared memory namespace, though there are also other ways to achieve this (or you could test without the global path altogether).
The CREATE_SUSPENDED flag will ensure that the dllmain entry point function would have finished writing to our shared memory before other libraries are loaded, which allows easier local hooking later on...
Injector.cpp:
SECURITY_ATTRIBUTES SecAttr, *pSec = nullptr;
SECURITY_DESCRIPTOR SecDesc;
if (InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&SecDesc, TRUE, PACL(nullptr), FALSE))
{
SecAttr.nLength = sizeof(SecAttr);
SecAttr.lpSecurityDescriptor = &SecDesc;
SecAttr.bInheritHandle = TRUE;
pSec = &SecAttr;
}
CreateProcessA(szTargetExe, nullptr, pSec, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi);
After injecting the DLL into the target process, all you need to do is use the same (more or less) file mapping code from your DLL project into your Launcher project (except for the part where you set the shared memory's contents, of course).
Then, calling your remote function is just a simple matter of:
// Copy from shared memory
TSharedData data;
memcpy(&data, lpMemFile, SHMEMSIZE);
// Clean up
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
// Call the remote function
DWORD dwThreadId = 0;
auto hThread = CreateRemoteThread(hProcess, nullptr, 0, LPTHREAD_START_ROUTINE(data.lpInit), nullptr, 0, &dwThreadId);
Then you can ResumeThread on the target process's main thread, or from your remote function.
As an added bonus... Using this form of communication can also open up several doors for our Launcher process, as it can now directly communicate with the target process.
But again, be sure that you don't do too much in DllMain and, if at all possible, simply use your remote init function (where it is also safe to use named mutexes, for example) to create a separate shared memory map and continue communication from there.
Hope this helps someone! =)
I want to call a function in a remote process of an injected DLL that I've made.
I have successfully injected my DLL with:
CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA"), pLibRemote, 0, NULL);
The DllMain is executed and the DLL is running in a stand-by mode. What I would like to do is somehow call the remotely loaded DLL in order to do some work.
I have tried exporting the function like this:
extern "C" __declspec(dllexport) void MyFunc(void)
and then executing the function like this:
CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("mydll"), "MyFunc"), NULL, 0, NULL);
but it results in a crash.
How can I solve this?
Calling GetModuleHandle as you have will get the base of the DLL as it is mapped into your process (if at all). So what you need to do is first make sure to export the function in the DLL. You can do as you have done or create a .def file as shown here. Thereafter:
In Theory
Inject the DLL to the target process and get the base address it was loaded at
Inject the DLL to the current process. Use GetProcAddress to find the offset between the exported function and the base of the DLL.
Add this offset to the base address obtained from step 1. CreateRemoteThread at this location.
In Practice
When doing your DLL injection, it is possible for you to get the base that your DLL is loaded into the target.
HMODULE hInjected;
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)( GetProcAddress( hMod,
"LoadLibraryW" ) ), lpAddress, 0, NULL );
// Locate address our payload was loaded
if( hThread != 0 ) {
WaitForSingleObject( hThread, INFINITE );
GetExitCodeThread( hThread, ( LPDWORD )&hInjected );
CloseHandle( hThread );
}
hInjected will be the base of the injected DLL. I then have another function:
void* GetPayloadExportAddr( LPCWSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName ) {
// Load payload in our own virtual address space
HMODULE hLoaded = LoadLibrary( lpPath );
if( hLoaded == NULL ) {
return NULL;
} else {
void* lpFunc = GetProcAddress( hLoaded, lpFunctionName );
DWORD dwOffset = (char*)lpFunc - (char*)hLoaded;
FreeLibrary( hLoaded );
return (DWORD)hPayloadBase + dwOffset;
}
}
What this does is first load the payload into our own virtual address space. Afterwards,
we can use GetProcAddress to get the address of the exported function. From this, we can get the offset of the function from the base of the DLL. Adding this offset to the hInjected we got earlier will tell us where the CreateRemoteThread call should be made. So you could make a call like so:
BOOL InitPayload( HANDLE hProcess, LPCWSTR lpPath, HMODULE hPayloadBase, HWND hwndDlg ) {
void* lpInit = GetPayloadExportAddr( lpPath, hPayloadBase, "Init" );
if( lpInit == NULL ) {
return FALSE;
} else {
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
lpInit, hwndDlg, 0, NULL );
if( hThread == NULL ) {
return FALSE;
} else {
CloseHandle( hThread );
}
}
return TRUE;
}
This is all code that is ripped out of an old project I have. You're welcome to take the code and do whatever you want with it but I know if I were to rewrite the code now, I would do a lot of things differently.
Mike's answer works if you are injecting a 32bit DLL into a 32bit process.
If you want to inject a 64bit DLL into a 64bit process, you can't get the base address of the DLL from GetExitCodeThread since it will only give you the lower 32bits of the 64bit address.
To get the correct address in this case, you must write a block of code into the process that calls LoadLibrary (storing the result at a specific location in process memory), execute this block of code (using CreateRemoteThread), and then read back the address from that location using ReadProcessMemory.
You can find more details for this here (including PowerShell and ASM code) here:
http://clymb3r.wordpress.com/2013/05/26/implementing-remote-loadlibrary-and-remote-getprocaddress-using-powershell-and-assembly/
You can then compute the offset to your exported function the same way Mike describes, but watch out to store the difference in a 64bit value, and not in a DWORD (which is 32bit).