22 #include "../config.h"
24 #include "RMonoAPIBackend_Def.h"
41 template <
typename ABI>
42 RMonoAPIBackend<ABI>::RMonoAPIBackend(ABI* abi)
43 : abi(abi), process(nullptr), worker(nullptr), injected(false)
48 template <
typename ABI>
49 RMonoAPIBackend<ABI>::~RMonoAPIBackend()
54 template <
typename ABI>
57 using namespace blackbone;
63 this->process = &process;
64 this->worker = workerThread;
68 bool x64 = (
sizeof(irmono_voidp) == 8);
70 RemoteExec& rem = process.remote();
71 ProcessMemory& mem = process.memory();
72 ProcessModules& modules = process.modules();
74 ipcVec.inject(&process);
76 ModuleDataPtr monoDll = modules.GetModule(L
"mono.dll");
79 auto loadedModules = modules.GetAllModules();
81 for (
auto it = loadedModules.begin() ; it != loadedModules.end() ; it++) {
82 auto& modName = it->first.first;
83 auto& mod = it->second;
85 if (process.modules().GetExport(mod,
"mono_get_root_domain")) {
93 RMonoLogInfo(
"Found Mono Embedded API in '%ls'", monoDll->name.data());
95 throw std::runtime_error(
"Couldn't find module containing Mono Embedded API in remote process.");
102 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
103 std::string exportName(
"mono_");
104 exportName.append(name);
105 auto res = process.modules().GetExport(monoDll, exportName.data());
107 func.init(abi, mono, exportName, res->procAddress);
109 RMonoLogDebug(
"API function not found in remote process: %s", exportName.data());
110 func.initInvalid(exportName);
111 if constexpr (func.isRequired()) {
112 throw std::runtime_error(std::string(
"Required export not found in mono.dll: ").append(exportName));
117 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
118 auto res = process.modules().GetExport(monoDll, name);
120 func.init(abi, mono, name, res->procAddress);
122 RMonoLogDebug(
"API function not found in remote process: %s", name);
123 func.initInvalid(name);
124 if constexpr (func.isRequired()) {
125 throw std::runtime_error(std::string(
"Required export not found in mono.dll: ").append(name));
134 std::string monoAPIWrapperCode;
135 std::string miscAPIWrapperCode;
137 struct APIWrapperInfo
139 asmjit::Label startLabel;
140 asmjit::Label endLabel;
145 std::map<std::string, APIWrapperInfo> monoAPIWrapperInfo;
146 std::map<std::string, APIWrapperInfo> miscAPIWrapperInfo;
149 auto asmPtr = AsmFactory::GetAssembler(!x64);
152 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
156 info.startLabel = func.compile(a);
157 info.endLabel = a->newLabel();
158 a->bind(info.endLabel);
160 monoAPIWrapperInfo.insert(std::pair<std::string, APIWrapperInfo>(name, info));
164 void* code = a->make();
166 if (!code && a->getCodeSize() != 0) {
167 RMonoLogError(
"Error assembling MonoAPI wrapper code: %d", (
int) a->getError());
168 throw RMonoException(
"Error assembling MonoAPI wrapper code.");
171 monoAPIWrapperCode = std::string((
const char*) code, a->getCodeSize());
173 for (
auto& p : monoAPIWrapperInfo) {
174 p.second.offset = a->getLabelOffset(p.second.startLabel);
175 p.second.size = a->getLabelOffset(p.second.endLabel) - p.second.offset;
180 auto asmPtr = AsmFactory::GetAssembler(!x64);
183 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
187 info.startLabel = func.compile(a);
188 info.endLabel = a->newLabel();
189 a->bind(info.endLabel);
191 miscAPIWrapperInfo.insert(std::pair<std::string, APIWrapperInfo>(name, info));
195 void* code = a->make();
197 if (!code && a->getCodeSize() != 0) {
198 RMonoLogError(
"Error assembling MiscAPI wrapper code: %d", (
int) a->getError());
199 throw RMonoException(
"Error assembling MiscAPI wrapper code.");
202 miscAPIWrapperCode = std::string((
const char*) code, a->getCodeSize());
204 for (
auto& p : miscAPIWrapperInfo) {
205 p.second.offset = a->getLabelOffset(p.second.startLabel);
206 p.second.size = a->getLabelOffset(p.second.endLabel) - p.second.offset;
214 std::string boilerplateCode = assembleBoilerplateCode();
220 if (RMonoLogger::getInstance().isLogLevelActive(RMonoLogger::LOG_LEVEL_VERBOSE)) {
221 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
223 func.debugDumpSignatures();
226 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
228 func.debugDumpSignatures();
237 this->remDataBlock = std::move(mem.Allocate(monoAPIWrapperCode.size() + boilerplateCode.size(), PAGE_EXECUTE_READWRITE).result());
239 size_t monoAPIWrapperCodeOffs = 0;
240 size_t miscAPIWrapperCodeOffs = monoAPIWrapperCodeOffs + monoAPIWrapperCode.size();
241 size_t boilerplateCodeOffs = miscAPIWrapperCodeOffs + miscAPIWrapperCode.size();
243 remDataBlock.Write(monoAPIWrapperCodeOffs, monoAPIWrapperCode.size(), monoAPIWrapperCode.data());
244 remDataBlock.Write(miscAPIWrapperCodeOffs, miscAPIWrapperCode.size(), miscAPIWrapperCode.data());
245 remDataBlock.Write(boilerplateCodeOffs, boilerplateCode.size(), boilerplateCode.data());
247 RMonoLogDebug(
"Remote Data Block: %llu bytes", (
long long unsigned) remDataBlock.size());
253 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
255 const APIWrapperInfo& info = monoAPIWrapperInfo[name];
257 func.link(remDataBlock.ptr() + monoAPIWrapperCodeOffs + info.offset);
259 if constexpr (func.needsWrapFunc()) {
260 RMonoLogDebug(
"Wrapper for '%s' is at %llX (size: %llu)", func.getName().data(),
261 (long long unsigned) (remDataBlock.ptr() + monoAPIWrapperCodeOffs + info.offset), (long long unsigned) info.size);
263 RMonoLogVerbose(
"No wrapper required for '%s'", func.getName().data());
268 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
270 const APIWrapperInfo& info = miscAPIWrapperInfo[name];
272 func.link(remDataBlock.ptr() + miscAPIWrapperCodeOffs + info.offset);
274 if constexpr (func.needsWrapFunc()) {
275 RMonoLogDebug(
"Wrapper for '%s' is at %llX (size: %llu)", func.getName().data(),
276 (long long unsigned) (remDataBlock.ptr() + miscAPIWrapperCodeOffs + info.offset), (long long unsigned) info.size);
278 RMonoLogVerbose(
"No wrapper required for '%s'", func.getName().data());
283 foreachAPI(*
dynamic_cast<BoilerplateAPI*
>(
this), [&](
const char* name,
auto& func) {
285 func.rebuild(process, remDataBlock.ptr() + boilerplateCodeOffs + func.getAddress(), worker);
293 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
295 validAPIFuncNames.insert(func.getName());
298 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
300 validAPIFuncNames.insert(func.getName());
308 template <
typename ABI>
311 using namespace blackbone;
318 remDataBlock = MemBlock();
320 ipcVec.vectorFree(ipcVecPtr);
322 foreachAPI(*
dynamic_cast<BoilerplateAPI*
>(
this), [&](
const char* name,
auto& func) {
325 foreachAPI(*
dynamic_cast<MiscAPI*
>(
this), [&](
const char* name,
auto& func) {
328 foreachAPI(*
dynamic_cast<MonoAPI*
>(
this), [&](
const char* name,
auto& func) {
338 template <
typename ABI>
341 using namespace asmjit;
342 using namespace asmjit::host;
344 ipcVecPtr = ipcVec.vectorNew();
346 bool x64 = (
sizeof(irmono_voidp) == 8);
348 RMonoLogVerbose(
"Assembling BoilerplateAPI functions for %s", x64 ?
"x64" :
"x86");
350 auto asmPtr = AsmFactory::GetAssembler(!x64);
353 asmjit::Label lForeachIPCVecAdapter = a->newLabel();
354 asmjit::Label lGchandlePin = a->newLabel();
355 asmjit::Label lArraySetref = a->newLabel();
359 a->bind(lForeachIPCVecAdapter);
364 a->xchg(a->zcx, a->zdx);
365 a->mov(a->zax, (uint64_t) ipcVec.getAPI().vectorAdd);
371 a->mov(a->zcx, ptr(a->zsp, 8));
372 a->mov(a->zdx, ptr(a->zsp, 4));
373 a->mov(a->zax, (uint32_t) (uintptr_t) ipcVec.getAPI().vectorAdd);
382 a->bind(lGchandlePin);
388 a->mov(a->zax, gchandle_get_target.getRawFuncAddress());
394 a->mov(a->zcx, a->zax);
396 a->mov(a->zax, gchandle_new.getRawFuncAddress());
404 a->push(dword_ptr(a->zsp, 4));
405 a->mov(a->zax, gchandle_get_target.getRawFuncAddress());
412 a->mov(a->zax, gchandle_new.getRawFuncAddress());
420 if (array_addr_with_size && gc_wbarrier_set_arrayref) {
422 a->bind(lArraySetref);
428 a->mov(a->zsi, a->zdx);
431 a->mov(a->zbx, ptr(a->zsp, 16));
432 a->mov(a->zsi, ptr(a->zsp, 20));
433 a->mov(a->zdi, ptr(a->zsp, 24));
434 a->mov(a->zcx, a->zbx);
438 AsmGenGchandleGetTargetChecked(a, gchandle_get_target.getRawFuncAddress(), x64);
439 a->mov(a->zbx, a->zax);
442 a->mov(a->zcx, a->zdi);
443 AsmGenGchandleGetTargetChecked(a, gchandle_get_target.getRawFuncAddress(), x64);
444 a->mov(a->zdi, a->zax);
448 a->mov(a->zcx, a->zbx);
449 a->mov(a->zdx,
sizeof(IRMonoObjectPtrRaw));
450 a->mov(asmjit::host::r8, a->zsi);
451 a->mov(a->zax, array_addr_with_size.getRawFuncAddress());
457 a->push(
sizeof(IRMonoObjectPtrRaw));
459 a->mov(a->zax, array_addr_with_size.getRawFuncAddress());
463 a->mov(a->zsi, a->zax);
467 a->mov(a->zcx, a->zbx);
468 a->mov(a->zdx, a->zsi);
469 a->mov(asmjit::host::r8, a->zdi);
470 a->mov(a->zax, gc_wbarrier_set_arrayref.getRawFuncAddress());
478 a->mov(a->zax, gc_wbarrier_set_arrayref.getRawFuncAddress());
489 std::string boilerplateCode((
const char*) a->make(), a->getCodeSize());
491 if (a->isLabelBound(lForeachIPCVecAdapter)) {
492 rmono_foreach_ipcvec_adapter.rebuild(*process, (ptr_t) a->getLabelOffset(lForeachIPCVecAdapter), worker);
494 if (a->isLabelBound(lGchandlePin)) {
495 rmono_gchandle_pin.rebuild(*process, (ptr_t) a->getLabelOffset(lGchandlePin), worker);
497 if (a->isLabelBound(lArraySetref)) {
498 rmono_array_setref.rebuild(*process, (ptr_t) a->getLabelOffset(lArraySetref), worker);
501 return boilerplateCode;
510 template <
typename ABI>
511 template <
typename FuncT,
typename MainT,
typename... PartialT>
512 void RMonoAPIBackend<ABI>::foreachAPIPacked(MainT& main, FuncT func, PackHelper<PartialT...>)
514 foreachAPIRecurse(func, *
dynamic_cast<PartialT*
>(&main)...);
518 template <
typename ABI>
519 template <
typename FuncT,
typename FirstT,
typename... OtherT>
520 void RMonoAPIBackend<ABI>::foreachAPIRecurse(FuncT func, FirstT& part, OtherT&... other)
522 visit_struct::for_each(part, func);
524 if constexpr (
sizeof...(other) != 0) {
525 foreachAPIRecurse(func, other...);
530 template <
typename ABI>
531 template <
typename MainAPIT,
typename FuncT>
532 void RMonoAPIBackend<ABI>::foreachAPI(MainAPIT& api, FuncT func)
534 foreachAPIPacked(api, func,
typename MainAPIT::internal_api_parts());