c# - 如何在另一个进程中挂钩托管库中的方法而不通过 dll 注入修改它们?
问题描述
我使用这个存储库将我的代码注入到另一个正在运行的进程 (c++) 中的特定方法中。一切正常,我可以运行示例,但是当我将情况更改为托管库(使用托管类库 (c#) 的控制台应用程序 (c#))时,它并不成功。
第一种情况:(正常工作)
目标:“B - 来自 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;
}
目标导入的 dll:“B2 - GetNum-DLL”
#include "getnum-dll.h"
int GetNum()
{
return 1;
}
注射器:“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;
}
注入的有效负载:“13B - Trampoline 导入的 Func DLL 有效负载”
#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;
}
输出:在每个目标方法调用之后,注入的方法被执行。
第二种情况:(不起作用)
我将目标更改为使用导入库的简单控制台应用程序。我在有效载荷和注入器中更改了 TARGET_APP_NAME、TARGET_DLL_NAME、FUNC2HOOK_NAME 并再次执行注入器。
目标:“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);
}
}
}
}
目标导入的 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;
}
}
}
输出:注入成功,但挂钩不成功。
解决方案
推荐阅读
- python - 如何防止未定义数量的文本超出 tkinter 窗口?
- c# - 从 WinUI 3.0 Preview 3 Desktop App 中 WebView2 中的帖子获取响应
- java - 如何在 Java 中为 SQLITE 数据库的不同行实例化多个对象?
- c++ - 为什么 std::pow(int, int) 比带有整数值的 for 循环更快?
- php - 重构 Laravel 上的重复查询
- javascript - 您可以强制从 GitHub 拉取请求安装 npm 子依赖项吗?
- c - ./ 处的分段错误
- asp.net-mvc - 在同步融合“假列”MVC 中为 Grid 创建数据库中没有记录的列
- javascript - JS 闭包 - 重新初始化混乱
- angular - 有什么方法可以在同一端口上的 nginx 上部署 2 个 Angular 应用程序?