记录使用注入的方式为Unity编辑器实现扩展能力

news2024/11/15 16:50:00

使用场景

  1. 当前项目编辑器中不方便存放或者提交扩展代码
  2. 相同的扩展功能需要在多个项目(编辑器)中使用
  3. 项目开发中,偶尔临时需要使用一个功能,想随时使用随时卸载

设计思路

  1. 使用进程注入,将一个c/c++ dll注入到当前运行的unity编辑器中
  2. 使用c/c++ dll调用mono的函数接口,比如mono_get_root_domain去获取unity的domain动态去加载想要加载的外部的扩展c# dll
  3. 在扩展c# dll中调用 EditorUtility.RequestScriptReload();来触发unity编辑器的重新编译,重载编辑器中的domain实现卸载外部c# dll的功能
  4. 在扩展c# dll中绑定EditorApplication.update事件,用来处理主线程的操作,比如AssetDatabase.Refresh();
  5. 使用jsonrpc协议,用来调用c# dll中的部分封装功能函数,可以实现在unity编辑器直接展示扩展窗口,或者将数据传至其他编辑器进行展示

初步实现

  1. 进程注入c/c++ dll
//远程进程插入dll bypid
bool DllInject::nsertDllToProcessByPid(DWORD Pid, const char* pDllName)
{
	// 提升权限
	//ImproveProcessPri();

	// 获取要插入的进程ID
	DWORD dwIDExplorer = Pid;
	if (dwIDExplorer == 0)
	{
		MEMBOX("Get Pro ID Error!\n");
		return false;
	}

	// 打开进程
	HANDLE hProcess = OpenProcess(/*PROCESS_ALL_ACCESS*/0x1F0FFF, FALSE, dwIDExplorer);
	if (hProcess == NULL)
	{
		MEMBOX("Open Process Error!\n");
		return false;
	}

	// 分配空间
	void* pDllPath = VirtualAllocEx(hProcess, 0, strlen(pDllName) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pDllPath)
	{
		MEMBOX("pRemoteThread = NULL!\n");
		return false;
	}
	if (!WriteProcessMemory(hProcess, pDllPath, pDllName, strlen(pDllName) + 1, 0))
	{
		MEMBOX("WriteProcessMemory Fail!\n");
		return false;
	}



	//看有Game.exe 是否打开   .   打开了  GetProcAddress 是不准的  

	/*
	   1. 检测静态 变量是否存储
	   2.

	*/
	

	//卸载保护
	HMODULE h = GetModuleHandle("MessageHis.dat");
	if (h != NULL)
		FreeLibrary(h);


	PROC AdrMyDllDir = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");//(PROC)::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),"LoadLibraryA");

	// 创建远程线程
	HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)AdrMyDllDir, pDllPath, 0, 0);
	if (!hThread)
	{
		MEMBOX("Remote thread faile.");
		//AfxMessageBox("远程线程创建失败");
		return false;
	}
	WaitForSingleObject(hThread, INFINITE); //等待运行完成
	CloseHandle(hThread);//这个CloseHandle是不会关掉远程线程的,TerminateThread能关掉
	VirtualFreeEx(hProcess, pDllPath, strlen(pDllName) + 1, MEM_RELEASE);
	CloseHandle(hProcess);
	MEMBOX("Remote Inject Dll Success");

	//AfxMessageBox("注入成功");
	return true;
}
  1. 调用mono接口加载c# dll
bool MonoInjecter::InjectMonoAssembly()
{
    //GetProcAddress
    /* grab the root domain */
   // domain = fnGetRootDomain();
   // fnThreadAttach(domain);

    log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
    log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());

    //----------------------------
    domain = fnGetDomainById(1);
    log_trace("Hello %s %ld", "fnGetRootDomain", domain);
    fnThreadAttach(domain);

    log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
    log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());
    //----------------------------

    /* open payload assembly */
    std::string assemblyDir;
    /* Grab our root directory*/
    assemblyDir.append(fnGetRootDir());
    assemblyDir.append(ASSEMBLY_PATH);
    assembly = fnAssemblyOpen(assemblyDir.c_str(), NULL);
    if (assembly == NULL) return false;
    log_trace("Hello %s %ld", "fnAssemblyOpen", assembly);
    image = fnAssemblyGetImage(assembly);
    if (image == NULL) return false;
    log_trace("Hello %s %ld", "fnAssemblyGetImage", image);
    klass = fnClassFromName(image, PAYLOAD_NAMESPACE, PAYLOAD_CLASS);
    if (klass == NULL) return false;
    log_trace("Hello %s %ld", "fnClassFromName", klass);
    /* grab the hack entrypoint */
    method = fnMethodFromName(klass, PAYLOAD_MAIN, 0);
    if (method == NULL) return false;
    log_trace("Hello %s %ld", "fnMethodFromName", method);
    /* call our entrypoint */
    fnRuntimeInvoke(method, NULL, NULL, NULL);
    log_trace("\nHello %s", "run mono dll!\n\n");

    return true;
}
  1. 简单实现一个编辑器工具用来查找当前已经打开的unity编辑器进程,然后进行注入
    在这里插入图片描述
  2. 由注入的c# dll调用的测试输出, 当前编辑器中是没有任何代码的
    在这里插入图片描述

测试环境

  1. 操作系统系统: windows 11 64位`, (不兼容32位)
  2. unity版本: 2021.3.15f1
  3. .NET6.0(第三方编辑器的实现)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式搜索 (二)

一、DSL 查询文档 1. DSL Query 的分类 Elasticsearch 提供了基于 JSON 的 DSL (Domain Specific Language) 来定义查询 常见的查询类型包括: ① 查询所有:查询出所有数据,一般测 试用 例如:match_all ② 全文检索 (full text) …

C++数据结构笔记(8)循环链表实现

1.循环链表与单链表的区别在于尾部结点存在指向头结点的指针 2.无论尾部结点指向第一个结点(头结点)还是第二个结点(第一个有效结点),都可以被称为循环链表 3.判断循环结束的两种方式:遍历次数等于size;或…

《深度探索c++对象模型》笔记

非原创,在学习 1 关于对象(Object Lessons) 这里最开始从C语言的结构体引出C中的”抽象数据类型(ADT)“。 而加上封装之后,布局成本没有增加,三个data member直接内含在每一个class object之中…

深入选择屏幕

2.3.4.4 屏幕输入报表筛选条件等 &--------------------------------------------------------------------- *& selection-screen /option/parameter:屏幕输入报表赛选条件 *& TABLES . *selection-screen begin of block test select-options: selection-screen…

PHY芯片快速深度理解

摘要: 什么是phy 为什么要熟悉RJ45网口 网络七层协议 两个模块进行通信 什么是MDIO协议 MDIO的作用 MDIO没那么重要 MDIO读写时序 为什么说读取的phy最多32个 什么是phy 物理层芯片称为PHY、数据链路层芯片称为MAC。 可以看到PHY的数据是RJ45网络接口&am…

linux常见指令下

接下来我们就聊聊linux的后面十条指令。 一:echo 作用是往显示器输出内容,和printf类型,但是该指令最核心的是与之相关的一些概念 概念1.输出重定向: echo不仅可以向显示打印内容,还可以向文件输出内容,本应该输出到…

在服务器上启动springboot项目

环境搭建:要在服务器上运行SpringBoot Web项目,需要先在服务器上安装JDK(CentOS系统安装JDK参考:http://t.csdn.cn/0zYml) 第一步:创建项目 创建一个简单的springboot项目,并通过测试&#xf…

Java Web Servlet (2)23.7.8

1.7 urlPattern配置 Servlet类编写好后,要想被访问到,就需要配置其访问路径(urlPattern) 一个Servlet,可以配置多个urlPattern package com.itheima.web;import javax.servlet.ServletRequest; import javax.servlet.ServletRes…

嵌入式基础知识-流水线

提到流水线,最先想到的可能是流水线车间中的产品制造过程。 工业上的流水线,又称装配线,指每一个生产单位只专注处理某一个片段的工作,以提高工作效率及产量。 在计算机领域中,也有流水线的概念,其核心原理…

互联网医院系统定制|互联网医院在线诊疗平台

互联网医院系统对医院有以下几个方面的帮助:   提升医疗服务效率:互联网医院系统可以为医院提供在线挂号、在线问诊、远程会诊等功能,减少患者排队等待时间,提高医疗服务效率。   扩大服务范围:互联网医院系统可以…

【数据结构二叉树OJ系列】6、平衡二叉树

目录 题述: 思路: 正确代码如下: 时间复杂度分析: 现让你把代码优化时间复杂度为O(N) 思路: 题述: 给定一个二叉树,判断他是否是高度平衡的二叉树。 本题中&#xf…

HttpRunner自动化之接口关联和常用断言

接口关联 第一个test接口获取token,并提取出存储到变量中,在第二个test接口中直接调用该变量,如下图 # 接口关联 - config:name: 微信接口base_url: https://api.weixin.qq.com - test:name: 获取tokenrequest:url: /cgi-bin/tokenmethod: GETparams:g…

在vue3项目中加载Cesium立体地形信息并调整初始化角度

在vue3项目中加载Cesium立体地形信息并调整初始化角度 使用vite创建vue3项目 npm create vitelatestcd到创建的项目文件夹中 npm install安装Cesium npm i cesium vite-plugin-cesium vite -D配置 (1)在项目的vite.config.js文件中添加: impo…

Java模拟cookie登陆操作

Java模拟cookie登陆操作 在使用java访问URL时,如果该URL需要身份验证,那么就不能够直接访问,因为没有登陆。那么,如何解决这个问题呢? 方法是使用java模拟登陆,登陆后记录下cookie信息,在下次发…

【算法集训之线性表篇】Day 07

文章目录 题目基本设计思想代码实现效果 题目 一个长度为L(L>1)的升序序列S,处在第[L/2]个位置的数称为S的中位数。例如,若序列S1{11,13,15,17,19},则S1的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数,例如…

使用ida pro反编译并修改so库

快速搜索 图表视图 找到需要修改的行 Edit -> Patch program -> change byte… 复制指令 到这个网站Online ARM to HEX 点击可以切换为HEX to ARM 构造待修改的指令 修改好后复制HEX字符串 Edit -> Patch program -> Apply patches to input file

测试工程师的个人年终总结报告模板

目录 正文之前的思考: 年终总结报告 开篇语 1.  项目概述 1.1  项目情况 1.2  工作流程 1.3  个人角色 1.4  完成情况 2.  工作业绩 3.  亮点和不足 4.  未来展望 总结: 正文之前的思考: 开始编排文档之前来做一个…

FAM NHS ester,5-FAM azide,两者用于标记核苷酸的荧光试剂

一、FAM NHS ester,6-isomer,92557-81-8 理论分析: 中文名:羧基荧光素-活性酯,6-异构体,6-羧基荧光素琥珀酰亚胺酯,6-羧基荧光素-活性酯 英文名:FAM NHS ester,6-isomer,6-FAM-NHS,…

D. Survey in Class

D. Survey in Class Problem - D - Codeforces 思路:题目要求的是最大值与最小值的差值最大,那么我们能够想到,一定是两个人比较得到的最大的差值,假设a与b比较得到的最大的差值,因为如果提问了这两个区间都不包含的&…

单个电源模块带电感的直流压降仿真(二)

单个电源模块带电感的直流压降仿真(二) 接 单个电源模块带电感的直流压降仿真(一) 在右侧net manager disable all nets鼠标移动到需要仿真的电感前后两端的铜皮上,select net and enable net并且把GND也select和enable上