I used this repository for injecting my code to a specific method in another running process (c++). Everything is okay and I can run the samples, but when I change the situation to a managed library (a console application (c#) which is using a managed class library (c#)), It's not successful.
First Situation: (works properly)
Target: "B - Target With Free Function From DLL"
#include <stdio.h>
#include <Windows.h>
#include <Psapi.h>
#define DLL_NAME "B2 - GetNum-DLL.dll"
#define DLL_FUNC_NAME "GetNum"
void GetPathToDLL(char* outPath, size_t outPathSize)
{
char relPath[1024];
char thisAppName[1024];
GetModuleFileName(NULL, relPath, 1024);
GetModuleBaseName(GetCurrentProcess(), NULL, thisAppName, 1024);
char* replaceStart = strstr(relPath, thisAppName);
const char* dllName = DLL_NAME;
memcpy(replaceStart, dllName, strlen(dllName));
memset(replaceStart + strlen(dllName), '\0', &relPath[1024] - (replaceStart + strlen(dllName)));
_fullpath(outPath, relPath, outPathSize);
}
int main()
{
char dllPath[1024];
GetPathToDLL(dllPath, 1024);
HMODULE sharedLib = LoadLibrary(dllPath);
int(*getNum)() = (int(*)()) GetProcAddress(sharedLib, DLL_FUNC_NAME);
while (1)
{
printf("GetNum: %i\n", getNum());
Sleep(5000);
}
return 0;
}
Target imported dll: "B2 - GetNum-DLL"
#include "getnum-dll.h"
int GetNum()
{
return 1;
}
Injector: "13 - Trampoline Imported Func With DLL Injection"
#include "..\hooking_common.h"
#define TARGET_APP_NAME "B - Target With Free Function From DLL.exe"
#define PAYLOAD_DLL_NAME "13B - Trampoline Imported Func DLL Payload.dll"
#define PAYLOAD_FUNC_NAME "GetNumPayload"
void InjectPayload(HANDLE process, const char* pathToPayloadDLL)
{
//write the name of our dll to the target process' memory
size_t dllPathLen = strlen(pathToPayloadDLL);
void* dllPathRemote = VirtualAllocEx(
process,
NULL, //let the system decide where to allocate the memory
dllPathLen,
MEM_COMMIT, //actually commit the virtual memory
PAGE_READWRITE); //mem access for committed page
check(dllPathRemote);
BOOL writeSucceeded = WriteProcessMemory(
process,
dllPathRemote,
pathToPayloadDLL,
dllPathLen,
NULL);
check(writeSucceeded);
PTHREAD_START_ROUTINE loadLibraryFunc = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "LoadLibraryA");
check(loadLibraryFunc);
//create a thread in remote process that loads our target dll using LoadLibraryA
HANDLE remoteThread = CreateRemoteThread(
process,
NULL, //default thread security
0, //stack size for thread
loadLibraryFunc, //pointer to start of thread function (for us, LoadLibraryA)
dllPathRemote, //pointer to variable being passed to thread function
0, //0 means the thread runs immediately after creation
NULL); //we don't care about getting back the thread identifier
check(remoteThread);
// Wait for the remote thread to terminate
WaitForSingleObject(remoteThread, INFINITE);
//once we're done, free the memory we allocated in the remote process for the dllPathname, and shut down
VirtualFreeEx(process, dllPathRemote, 0, MEM_RELEASE);
CloseHandle(remoteThread);
}
//hacky way to get the path to the correct payload for
//whatever the active build config is... saves having to
//provide the path on the command line, but is otherwise
//not particularly important
void GetPathToPayloadDLL(char* outBuff)
{
char relPath[1024];
char thisAppName[1024];
GetModuleFileName(NULL, relPath, 1024);
GetModuleBaseName(GetCurrentProcess(), NULL, thisAppName, 1024);
char* replaceStart = strstr(relPath, thisAppName);
const char* payloadDLLName = PAYLOAD_DLL_NAME;
memcpy(replaceStart, payloadDLLName, strlen(payloadDLLName));
memset(replaceStart + strlen(payloadDLLName), '\0', &relPath[1024] - (replaceStart + strlen(payloadDLLName)));
_fullpath(outBuff, relPath, 1024);
}
int main(int argc, const char** argv)
{
//5 check(argc == 2);
DWORD processID = FindPidByName(TARGET_APP_NAME);
check(processID);
HANDLE remoteProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
check(remoteProcessHandle);
char fullPath[1024];
GetPathToPayloadDLL(fullPath);
HMODULE mod = FindModuleBaseAddress(remoteProcessHandle, fullPath);
InjectPayload(remoteProcessHandle, fullPath);
return 0;
}
Injected Payload: "13B - Trampoline Imported Func DLL Payload"
#include "trampoline-imported-func-payload.h"
#include <stdio.h>
#include <stack>
#include <vector>
#include "capstone/x86.h"
#include "../hooking_common.h"
#include "../trampoline_common.h"
#include "capstone/capstone.h"
#define TARGET_APP_NAME "B - Target With Free Function From DLL.exe"
#define TARGET_DLL_NAME "B2 - GetNum-DLL.dll"
#define FUNC2HOOK_NAME "GetNum"
/**************************
* HOOKING CODE *
**************************/
thread_local std::stack<uint64_t> hookJumpAddresses;
void PushAddress(uint64_t addr) //push the address of the jump target
{
hookJumpAddresses.push(addr);
}
//we absolutely don't want this inlined
__declspec(noinline) void PopAddress(uint64_t trampolinePtr)
{
uint64_t addr = hookJumpAddresses.top();
hookJumpAddresses.pop();
memcpy((void*)trampolinePtr, &addr, sizeof(uint64_t));
}
void InstallHook(void* func2hook, void* payloadFunc)
{
SetOtherThreadsSuspended(true);
DWORD oldProtect;
VirtualProtect(func2hook, 1024, PAGE_EXECUTE_READWRITE, &oldProtect);
//102 is the size of the "pre-payload" instructions that are written below
//the trampoline will be located after these instructions in memory
void* hookMemory = AllocatePageNearAddress(func2hook);
uint32_t trampolineSize = BuildTrampoline(func2hook, (void*)((char*)hookMemory + 102));
uint8_t* memoryIter = (uint8_t*)hookMemory;
uint64_t trampolineAddress = (uint64_t)(memoryIter)+102;
memoryIter += WriteSaveArgumentRegisters(memoryIter);
memoryIter += WriteMovToRCX(memoryIter, trampolineAddress);
memoryIter += WriteSubRSP32(memoryIter); //allocate home space for function call
memoryIter += WriteAbsoluteCall64(memoryIter, &PushAddress);
memoryIter += WriteAddRSP32(memoryIter);
memoryIter += WriteRestoreArgumentRegisters(memoryIter);
memoryIter += WriteAbsoluteJump64(memoryIter, payloadFunc);
//create the relay function
void* relayFuncMemory = memoryIter + trampolineSize;
WriteAbsoluteJump64(relayFuncMemory, hookMemory); //write relay func instructions
//install the hook
uint8_t jmpInstruction[5] = { 0xE9, 0x0, 0x0, 0x0, 0x0 };
const int32_t relAddr = int32_t((int64_t)relayFuncMemory - ((int64_t)func2hook + sizeof(jmpInstruction)));
memcpy(jmpInstruction + 1, &relAddr, 4);
memcpy(func2hook, jmpInstruction, sizeof(jmpInstruction));
SetOtherThreadsSuspended(false);
}
/**************************
* PAYLOAD CODE *
**************************/
int(*target)();// = nullptr;
int GetNumPayload()
{
//this payload is used with the demo program "trampoline-imported-func-with-dll-injection
//and is meant to be injected into the target app "target-with-functions-from-dll"
//this payload hooks the "getNum" function found in the "getnum-dll" project
printf("Trampoline Executed\n");
PopAddress(uint64_t(&target));
return target();
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpvReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
printf("Function Payload Injected Successfully \n");
HMODULE mod = FindModuleInProcess(GetCurrentProcess(), TARGET_DLL_NAME);
void* localHookFunc = GetProcAddress(mod, FUNC2HOOK_NAME);
InstallHook(localHookFunc, GetNumPayload);
}
return true;
}
Output: after each target method call, injected method executed.
Second Situation: (doesn't work)
I changed target to a simple console application which using a imported lib. I changed TARGET_APP_NAME, TARGET_DLL_NAME,FUNC2HOOK_NAME in payload and injector and execute injector again.
Target: "TargetConsole.exe"
using System;
using System.Runtime.InteropServices;
using ImportedLib;
namespace TargetConsole
{
class Program
{
static void Main(string[] args)
{
ImportedLib.Class1 cl = new Class1();
while (true)
{
Console.WriteLine(cl.MyMethod().ToString());
System.Threading.Thread.Sleep(2000);
}
}
}
}
Target Imported dll: "ImportedLib.dll"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ImportedLib
{
public class Class1
{
public int MyMethod()
{
return 17;
}
}
}
Output: Injection is successful but hooking is not.