有点背景,这是我第一个关于堆栈溢出的问题,所以如果这是很难回答的,因为我的问题的质量,我很抱歉。
运行在:Windows1110.0.22000Build 22000,Intel x64,C++20,Mono4.5,VisualStudio2022(如果你需要知道别的什么,那就问)
我在这个问题上挣扎了几天。我一直在使用C++ Mono尝试将一个方法从C#类库(C#类库)注入到另一个进程。已经有一段时间了,我从要注入的方法中获得了MonoMethod对象,并且找到了多种执行它的方法,例如:
mono_runtime_invoke(MonoMethod *method, void *obj, void **params, MonoObject **exc)
mono_method_get_unmanaged_thunk(MonoMethod* method)
(返回C/C++函数指针)
mono_compile_method(MonoMethod* method)
(我一会儿再谈这个)
但问题是,所有这些都没有让我远程执行。我认为我最擅长的就是mono_compile_method(MonoMethod* method)
,因为文档告诉我This JIT-compiles the method, and returns the pointer to the native code produced.
mono_runtime_invoke和mono_method_get_unmanaged_thunk:http://docs.go-mono.com/?link=xhtml%3Adeploy%2Fmono-api-methods.html (向下滚动)
mono_compile_method位于左侧的“未排序”部分。
我想我可以在目标进程中分配一些内存,使用VirtualAllocEx
和WriteProcessMemory
将代码放入目标程序的地址空间,然后使用CreateRemoteThread
执行它。
VirtualAllocEx
和WriteProcessMemory
总是成功的,就像CreateRemoteThread
一样,不会抛出错误,但是它只做了一件事,那就是由于访问冲突而使目标进程崩溃。
这是我的尝试(注入代码):
MonoAssembly* Manager::Inject(const char* dllpath, char *ass, UINT len)
{
MonoClass* classs;
MonoMethod* method;
MonoDomain* domain = mono_jit_init("ass");
MonoAssembly* asse = mono_domain_assembly_open(domain, dllpath);
if (!asse)
{
std::cout << "Failed to open assembly.";
return NULL;
}
MonoImage* monoImage = mono_assembly_get_image(asse);
if (!monoImage)
{
std::cout << "Failed to get image from assembly.";
return NULL;
}
classs = mono_class_from_name(monoImage, this->namespaceName.c_str(), this->className.c_str());
if (!classs)
{
std::cout << "Failed to get class from name.";
return NULL;
}
method = mono_class_get_method_from_name(classs, this->method.c_str(), -1);
if (!method)
{
std::cout << "Failed to get method from name.";
return NULL;
}
MonoObject* excPtr = nullptr;
int size = 1024 * 8;
void* code;
code = mono_compile_method(method);
if (handle)
{
void* loc = VirtualAllocEx(handle, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!loc)
{
std::cout << "VirtualAllocEx failed # " << GetLastError();
return NULL;
}
SIZE_T written = 0;
if (!WriteProcessMemory(handle, loc, code, size, &written))
{
std::cout << "WriteProcessMemory failed # " << GetLastError();
return NULL;
}
std::cout << written << " bytes written.\n";
HANDLE h = CreateRemoteThread(handle, NULL, 0, (LPTHREAD_START_ROUTINE)loc, NULL, 0, NULL);
if (!h)
{
std::cout << "Failed to create remote thread # " << GetLastError();
return NULL;
}
DWORD waitResult = WaitForSingleObject(h, -1);
if (waitResult == WAIT_FAILED)
{
std::cout << "Failed to wait for remote thread. # " << GetLastError();
return NULL;
}
DWORD error;
if (!GetExitCodeThread(h, &error))
{
std::cout << "Failed to get thread exit code. # " << GetLastError();
return NULL;
}
if (error == 3221225477)
{
std::cout << "An access violation occurred while executing.";
return NULL;
}
}
else
{
std::cout << "Invalid handle! # " << GetLastError();
return NULL;
}
CloseHandle(handle);
return asse;
}
这是我的Dll,它包含将被注入的方法:
using System;
namespace TestDll
{
public class Class1
{
static void PrintText()
{
Console.WriteLine("HELLO FROM DLL");
}
}
}
这是我的测试目标应用程序的代码:
using System;
namespace TestTarget
{
class Program
{
static void Main(string[] args)
{
string s = "";
while(true)
{
s = Console.ReadLine();
if(s == "stop")
{
break;
}
}
}
}
}
这是TestTarget在尝试注入时抛出的消息:
The program '[9636] TestTarget.exe' has exited with code 3221225477 (0xc0000005) 'Access violation'.
我知道mono_compile_method可以工作,因为如果我尝试将返回值转换为函数指针并调用它:
void (*code)() = (void(*)())mono_compile_method(method);
code();
它按预期工作,并打印
HELLO FROM DLL
因此,它返回一个指向本机代码的指针(如果我是对的,它应该由CPU直接执行)。我想知道当我在CreateRemoteThread上使用它时,它为什么不能工作,因为我可以将它称为函数指针。我认为这是错误的/我写了指向内存的本机代码的指针,它指向我进程中的本机代码,但是天知道目标进程中有什么,因为进程有自己的地址空间。
如果我试图做的事情(将方法注入远程进程)是不可能的,那么请尝试并提供相应的技术。谢谢,如果你对我的问题(:D)有什么疑问,请问。
发布于 2022-07-14 02:02:22
您需要编写注入的数据和代码(而不是您指出的函数指针)到远程进程。三种注射方式的There is an example。值得注意的是CreateRemoteThread & WriteProcessMemory技术。
https://stackoverflow.com/questions/72970547
复制相似问题