.net也能写内存挂
最近在研究.net的内存挂。
写了很久的c++,发现c#写出来的东西实在太香。
折腾c#外挂已经有很长时间了。都是用socket和c++配合。
这个模式其实蛮成功的,用rpc调用的方式加上c#的天生await 非常好写逻辑
类似这样
最近想换个口味。注入托管dll到非托管进程
这样做只是为了解决我目前遇见的一个问题。
在一个多线程的程序上逆向,我挂了很多钩子,导致我读写数据和储存我自己的数据
非常容易出现多线程冲突问题,换到.net里以后
lock 和Monitor 在.net里是同线程不互锁。这样能让我不容易出现互锁现象。
有一段时间正在烦恼那些卖驱动的,只有读写功能为什么还能实现很多功能。
在我的认知里,要调用游戏部分函数才能更方便自己做出更有用的功能
当然这里确实有些外挂是只读取角色顶点就能绘制的。
后来细想一下其实不需要调用功能通过写入代码的方式获取执行就可以了。
就是只要有读写就可以了。
游戏外挂无非就是 读写和调用。 调用是可以通过写来实现。
比如hook某个dx的函数。或者修改虚函数表的地址,然后jmp 到自己的函数里
达到获取执行权限。
好比挂钩了GetTickCount 这个API ,然后目标游戏不断的调用这个API
我们在这里插入自己的调用逻辑就可以了。
想明白了这个,于是我就干起了注入托管dll 到游戏进程里的勾当
当然这个托管dll实在是太大了(因为会用Costura.Fody把第三方库都打包在一起)
想法是这样,注入到游戏进程里以后申请内存空间,然后通过asm编译成bytes
然后写入到内存后,再去调用他就可以了
这里要安利一个asm的库
GitHub - icedland/iced: Blazing fast and correct x86/x64 disassembler, assembler, decoder, encoder for Rust, .NET, Java, Python, Lua
这个库很香
在c#里写asm长这样子,大概就是写好asm以后编译成bytes的过程
然后要介绍在c#内怎么完成thiscall
游戏大部分是thiscall 所以我在内存中申请一段asm
然后通过c#去调用这个段代码就可以了
asm 的作用就是把传入的参数 push到堆栈然后call
之后返回eax 这样就完整的跑通调用了。
用iced把asm生成好,然后通过c#的委托去调用这段asm代码即可
最后实现的效果类是这样
至于读写就更简单了。C#自带Marshal可以直接读写。
而且c#也支持不安全指针 直接 *(int*)(0x123456) = 100;
然后我们无限的包装自己的读写函数,比如byte float int string 之类的读写就可以
至于hook 也可以通过委托回调到自己的c#代码,hook在c#完成编译以后写入到目标地址
至此,完整的c#外挂需要的功能都实现了。
例子分3个工程
TestApp:测试工程模拟调用目标程序比如游戏
InjectionDLL:注入DLL,负责加载.net的dll,如果是远线程注入,就注入这个DLL即可,例子工程是主动loadlibrary
CShareLoadModule : c#的主要工作dll
附上源码一份
netInjection.rar
//以下是补充 2022 10 09
/
因为上面代码是用asm作为Thiscall 调用的,后来发现c#是自带调用约定的可以更优美的实现thiscall 调用
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_0(IntPtr ptr);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_1(IntPtr ptr, IntPtr p1);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_2(IntPtr ptr, IntPtr p1, IntPtr p2);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_3(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_4(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_5(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_6(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_7(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_8(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_9(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_10(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9, IntPtr p10);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_11(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9, IntPtr p10, IntPtr p11);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_12(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9, IntPtr p10, IntPtr p11, IntPtr p12);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_13(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9, IntPtr p10, IntPtr p11, IntPtr p12, IntPtr p13);[UnmanagedFunctionPointer(CallingConvention.ThisCall)]public delegate IntPtr ThisCall_14(IntPtr ptr, IntPtr p1, IntPtr p2, IntPtr p3, IntPtr p4, IntPtr p5, IntPtr p6, IntPtr p7, IntPtr p8, IntPtr p9, IntPtr p10, IntPtr p11, IntPtr p12, IntPtr p13, IntPtr p14);unsafe public static IntPtr ThisCall(IntPtr address, IntPtr dwECX, params object[] args){IntPtr p1 = IntPtr.Zero;IntPtr[] paramPtr = new IntPtr[args.Length*2];int addParamCount = 0;for (int i = 0; i < args.Length; i++){var paramtype = args[i].GetType();if (paramtype == typeof(float)){var v = (float)args[i];paramPtr[addParamCount] = *(IntPtr*)&v;}else if (paramtype == typeof(double)){var v = (double)args[i];paramPtr[addParamCount] = *(IntPtr*)&v;addParamCount++;paramPtr[addParamCount] = *(IntPtr*)((&v) +4);}else if (paramtype == typeof(long)){var v = (long)args[i];paramPtr[addParamCount] = *(IntPtr*)&v;addParamCount++;paramPtr[addParamCount] = *(IntPtr*)((&v) + 4);}else if (paramtype == typeof(IntPtr)){var v = (IntPtr)args[i];paramPtr[addParamCount] = v;}else if (paramtype == typeof(PtrGameUIWindow)){paramPtr[addParamCount] = (args[i] as PtrGameUIWindow).ptr;}else{paramPtr[addParamCount] = (IntPtr)Convert.ToInt32(args[i]);}addParamCount++;}Log.Console($"ThisCall:0x{address.ToString("X8")} ECX:0x{dwECX.ToString("X8")} {paramPtr.ArrayToString(0, addParamCount)}");switch (args.Length){case 0:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_0>(address).Invoke(dwECX);break;case 1:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_1>(address).Invoke(dwECX, paramPtr[0]);break;case 2:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_2>(address).Invoke(dwECX, paramPtr[0], paramPtr[1]);break;case 3:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_3>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2]);break;case 4:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_4>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3]);break;case 5:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_5>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4]);break;case 6:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_6>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5]);break;case 7:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_7>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6]);break;case 8:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_8>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7]);break;case 9:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_9>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8]);break;case 10:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_10>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8], paramPtr[9]);break;case 11:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_11>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8], paramPtr[9], paramPtr[10]);break;case 12:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_12>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8], paramPtr[9], paramPtr[10], paramPtr[11]);break;case 13:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_13>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8], paramPtr[9], paramPtr[10], paramPtr[11], paramPtr[12]);break;case 14:p1 = Marshal.GetDelegateForFunctionPointer<ThisCall_14>(address).Invoke(dwECX, paramPtr[0], paramPtr[1], paramPtr[2], paramPtr[3], paramPtr[4], paramPtr[5], paramPtr[6], paramPtr[7], paramPtr[8], paramPtr[9], paramPtr[10], paramPtr[11], paramPtr[12], paramPtr[13]);break;default:Log.Error(new Exception("ThisCall 参数个数未预测"));p1 = IntPtr.Zero;break;}return p1;}
因为c#会定期GC的问题,导致c#自身函数可能会被GC修改函数位置
所以需要固定住代码位置新增一下函数固定Delegate
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]public delegate IntPtr Delegate_NewStringID2String(IntPtr dwESP);public uint LockDelegate(Delegate func){GCHandleList.Add(GCHandle.Alloc(func));GCHandleList.Add(GCHandle.Alloc(Marshal.GetFunctionPointerForDelegate(func), GCHandleType.Pinned));GCHandleList.Add(GCHandle.Alloc(func.Method.MethodHandle.GetFunctionPointer()));return (uint)Marshal.GetFunctionPointerForDelegate(func);}//使用方法public static IntPtr MyStringID2String(IntPtr dwESP){var ret = IntPtr.IntPtr.Zero;return ret;}public override void Start(){var asm = new Assembler(32);asm.pushad();asm.mov(eax, esp);asm.add(eax, 0x20);asm.push(eax);asm.mov(eax, LockDelegate(new Delegate_NewStringID2String(MyStringID2String)));asm.call(eax);asm.mov(__[esp + 0x1c], eax);asm.popad();asm.ret();var newJmpCode = PatchSelfHelper.AllocMem(0x30);PatchSelfHelper.WriteAssembler(newJmpCode, asm);}
相关文章:

.net也能写内存挂
最近在研究.net的内存挂。 写了很久的c,发现c#写出来的东西实在太香。 折腾c#外挂已经有很长时间了。都是用socket和c配合。 这个模式其实蛮成功的,用rpc调用的方式加上c#的天生await 非常好写逻辑 类似这样 最近想换个口味。注入托管dll到非托管进程 这样做只…...

python学习笔记2-数字转化为String
题目链接 str() 强制转换, sorted() 转换为有序列表,join() 将列表中的元素连接到字符串中,然后奇偶位组合成数字 class Solution:def splitNum(self, num: int) -> int:stnum "".join(sorted(str(num)))num1, num2 int(stn…...

MAC版Gradle构建Spring5.X源码阅读环境
前言: 三年前鄙人有幸在现已几乎报废的Window的DELL中搭建过Spring源码环境,今天,Mac版的搭建,来了。 本篇文章环境搭建:Spring5.2.1 Gradle5.6.3-all jdk8 IDEA2022.3版本 文章目录 1、Spring源码下载2、Gradle下载…...

Linux 常用通配符
通配符是一种特殊语句,主要有星号(*)和问号(?),用来模糊搜索文件。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时&#x…...

Python皮卡丘
系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮爱心https://want…...

【数据结构与算法】三种简单排序算法,包括冒泡排序、选择排序、插入排序算法
冒泡排序算法 冒泡排序他是通过双重循环对每一个值进行比较,将小的值向后移动,以达到最终排序的结果,他的时间复杂度为O(n^2)。 /*** 冒泡排序* param arr*/public static void bubbleSort(int[] arr){int l arr.length;for (int i 0; i <…...

视频太大怎么压缩变小?超过1G的视频这样压缩
视频已经成为了我们日常生活中不可或缺的一部分,然而,很多时候,我们可能会遇到视频文件过大,无法在某些平台上传或保存的问题。那么,如何将过大的视频文件压缩变小呢? 下面就给大家分享三款实用的工具&…...

Edge 无法登录/同步问题【一招搞定】
目录 前言 一、打开 Edge 浏览器显示未同步,点击同步无效 二、Edge 登录报错 0x801901f4 或 0x80190001 解决方法 2.1 报错 0x801901f4 解决方法 2.1.0 Edge 登陆报错图示 2.1.1 添加 Edge 推荐的 DNS 地址 2.1.2 重新登录 Edge 账号成功 2.2 报错 0x801…...

ESP32-S3上手开发
1、搭建开发环境 首先搭建开发环境,这里采用了windows下集成开发环境ide进行开发,具体的安装方法:ESP-IDF安装配置 这里使用的乐鑫的esp32s3,N16R8 2、esp32s3模块 从上面图中可以看到,N16R8这里使用了外扩16M的fl…...

UE4和C++ 开发-编程基础记录(UE4+代码基础知识)
1、UE4基础元素 ①Actor 我们又见面了Actor,Actor是在一个关卡中持续存在的,通常他包含几个Actor组件。支持网络复制和多人游戏。 Actor不包含位置,方向。这些东西在Root Component中存储。对于UE3 中的Pawn也由PlayerCharacter继承了…...

【Unity】【VR】如何让Distance Grab抓取物品时限制物品的Rotation
【背景】 遇到这样的场景,希望抓取Canvas时,Canvas不会沿Z轴旋转。 【问题】 发现Freeze Canvas的Rigid Body没有用。 【分析】 应该是RigidBody的限制仅在物理互动下生效,抓取可能不属于物理互动(比如碰撞),所以不生效。 【思路】 还是得写脚本挂载在Interacta…...

为什么3ds max渲染效果图有噪点?点进来,CG Magic告诉您!
大家在使用3ds max渲染效果图时,可能渲染结果往往会出现的都是不真实,有小伙伴会问如何使3dmax渲染效果图真实呢? 不真实就算了,渲染过程中,会出现3Dmax渲染噪点多这类问题。 什么原因3ds max渲染效果图有噪点呢&a…...

Element UI怎么安装呢?
安装 :::warning 注意 后续演示将会在 Vue CLI 搭建的 Vue 项目上进行操作。如需要请查看 Vue CLI 安装 ::: 通过 YARN 命令安装 $ yarn add element-ui完整引入 代表一次性引入所有组件,比较省心省事,但是项目的打包体积也会跟着变大。 // main.js…...

redis批量删除命令
./redis-cli -h 127.0.0.1 -p 6379 -n 2 KEYS "170*:redisKeyStr" | xargs ./redis-cli -h 127.0.0.1 -p 6379 -n 2 DEL...

kubernetes环境 搭建
1、准备2台机器 2、安装docker环境(参考官网) 1、 sudo apt-get update sudo apt-get install ca-certificates curl gnupg2、 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dea…...

TCP习题总结
1、在采用TCP连接的数据传输阶段,如果发送端的发送窗口值由1000变为2000,那么发送端在收到一个确认之前可以发送()。 A. 2000个TCP报文段 B. 2000B C. 1000B D. 1000 个 TCP 报文 这道题考察的是TCP的基本…...

华为发布LampSite X室内数字化创新解决方案,释放数字世界无限潜能
【阿联酋,迪拜,2023年10月11日】2023全球移动宽带论坛(Global MBB Forum 2022)期间,华为董事、ICT产品与解决方案总裁杨超斌重磅发布了全新一代5G室内数字化产品解决方案LampSite X系列,助力运营商打开商业…...

麒麟操作系统设置QT程序开机自启动有效方法
在麒麟操作系统上设置QT程序开机自启动的两种简单有效的方法。支持请点赞! 一、QT程序打包 1.设置环境变量 设置QT和linuxdeployqt的环境变量,已设置可忽略该步骤。 在/etc/profile文件末尾添加一下内容: export PATH/usr/local/Qt-5.15.…...

Python数组删除元素pop与remove对比
pop()和remove()函数都可以用来删除列表中的函数,pop()是按索引来删除的,remove()是按元素来删除的。 1、pop()默认删除列表中最后一个元素,而且会返回删除的元素。此时的时间复杂度为O(1) 下面的例子中,…...

【Java 进阶篇】Java Web 编写注册页面案例
当涉及到创建一个Java Web注册页面时,你将需要涵盖很多不同的主题,包括HTML、CSS、Java Servlet和数据库连接。在这篇文章中,我们将详细介绍每个步骤,以帮助你创建一个完整的注册页面。 1. 介绍 注册页面是许多Web应用程序的关键…...

7.5 SpringBoot 拦截器Interceptor实战 统一角色权限校验
前言 在【7.1】管理员图书录入和修改API,当时预告过:并没有写【校验是否是管理员】的逻辑,因为是通用逻辑,会单写一篇来细讲,那么今天就来安排! 角色权限校验,是保证接口安全必备的能力:有权限才可以操作!所以,一般对于这种通用逻辑,推荐不与主业务逻辑耦合,那么…...

【原创】ubuntu18修改IP地址
打开网络配置文件 sudo vi /etc/network/interfaces结果发现如下内容: # ifupdown has been replaced by netplan(5) on this system. See # /etc/netplan for current configuration. # To re-enable ifupdown on this system, you can run: # sudo apt inst…...

Vue-2.4sync修饰符
作用:可以实现子组件与父组件数据的双向绑定,简化代码 特点:prop属性名,可以自定义,非固定为value 场景:封装弹框类的基础组件,visible属性 true显示 false隐藏 本质:就是:属性名…...

【RealTek sdk-3.4.14b】RTL8197FH-VG+RTL8367+RTL8812F WiFi to LAN 和WiFi to WAN吞吐量
LAN <----------> 2.4G WiFi Throughput 天线频宽模式协议连接速率TX(Mbps)RX(Mbps)TX&RX(Mbps)2X240MHz802.11nTCP300Mbps2051922112X240MHz802.11nUDP300Mbps224234231 LAN <----------> 5G WiFi Throughput 天线频宽模式协议连接速率TX(Mbps)RX(Mbps)TX&…...

vue 本地上传Excel文件并读取内容
陌路遇见,陌路告别,陌路问好,九月再见,十月重现! 首先我来讲解一下我的思路: 首先,在模板部分,我们有以下元素: <input type“file” change“handleFileUpload” accept“.xlsx…...

京东商品品牌数据采集接口,京东商品详情数据接口,京东API接口
采集京东商品品牌数据的方法如下: 打开网页。在首页【输入框】中输入目标网址批量输入多个关键词并搜索。创建【循环列表】,采集所有商品列表中的数据。编辑字段。创建【循环翻页】,采集多页数据。设置滚动和修改【循环翻页】XPath。启动采集…...

电脑提示Explorer.exe系统错误该怎么办?
平时我们在使用电脑时,系统有时会提示Explorer.exe系统错误,很多用户在遇到这类问题时不知道该怎么办。遇到Explorer.exe系统错误,该怎么办呢?下面我们一起来了解一下。 怎么修复Explorer.exe系统错误? Explorer.exe是…...

Java架构师部署架构设计
目录 1 导学2 部署架构设计和部署架构图2.1 服务器数量和配置2.2 服务器软件配置2.3 网络环境设计2.4 部署架构图2.5 部署说明文档2.6 部署清单2.7 画部署架构图3 实战整体部署架构设计4 节点部署说明列表5 总结1 导学 本章的主要内容是整体架构设计的核心之一,部署架构设计相…...

ubuntu 22.04.3 live server图文安装流程
备注:以下操作全用键盘,tab切换,enter确认,方向键移动; 1、 选择安装,第一个; 2、选择语言,这里只能选择英语,无中文; 3、继续而不更新 4、键盘,…...

基于SVM+TensorFlow+Django的酒店评论打分智能推荐系统——机器学习算法应用(含python工程源码)+数据集+模型(一)
目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境方法一方法二 安装其他模块安装MySQL 数据库 模块实现1. 数据预处理1)数据整合2)文本清洗3)文本分词 相关其它博客工程源代码下载其它资料下载 前言 本项目以支…...