一文带解读C# 动态拦截覆盖第三方进程中的函数(外挂必备)

一、前言

由于项目需要,最近研究了一下跨进程通讯改写第三方程序中的方法(运行中),把自己程序中的目标方法直接覆盖第三方程序中的方法函数;一直没有头绪,通过搜索引擎找了一大堆解决方案,资料甚是稀少,最后功夫不负有心人,经过两天的研究,终于在github 上找到两个开源的代码,通过两个开源代码结合起来即可实现我的需求。下面进一步来分析实践原理,后面会把源代码地址贴上来;通过该文章分享,你会知道怎样通过注入一个dll模块改写第三方运行的程序中的某个方法,在里面实现自己的业务,这个场景在做外挂程序中特别实用!!!

二、场景

假如有一个第三方应用程序,这时候需要对第三方应用程序进行方法拦截,比如第三方应用程序中的某个操作需要用我们的业务覆盖掉他们的业务,那这种情况下我们有什么好的方案解决呢?我们不可能修改第三方程序的代码,那有什么方案可以解决呢?其实我们还是有办法进行”修改“第三方程序的代码的,怎么”修改“呢,请看下面实践原理,下面带你走入不一样的代码世界!!!!

三、实践

原理简化图:

这里实践我就直接写两个客户端程序来进行代码上的演示

3.1. 实现原理

  • Hook 目标方法:需要改写拦截第三方程序的指定的方法,那就得需要Hook 该方法,经过查找资料在github上找到开源代码DotNetDetour,但是开源作者是从.net framework 4.5开始支持,不支持.net framework 4.0, 我的需求需要运行在老爷机xp 上,故必须要支持4.0 的框架,所有我fork了一份把源代码做了修改支持到了.net framework 4.0 框架,fork 源代码地址:https://github.com/a312586670/DotNetDetour

  • Inject 注入dll到目标进程 写好针对目标进程的方法Hooke dll 模块后需要考虑把该dll模块注入到第三方程序进程中,这样才可以实现完全的hook成功,改写目标进程的方法,我这里使用fastWin32 开源代码,代码地址如下:https://github.com/a312586670/FastWin32

3.2 创建第三方程序Demo

这里为了演示,我自己创建了一个目标客户端程序,主要有如下核心代码方法:

public class ProcessService
{public string GetProcessInfo(){return "这是TargetClient 客户端(第三方程序)";}public ProcessResponse GetProcessInfo(ProcessRequest request){return new ProcessResponse(){Name = "这是TargetClient 客户端(第三方程序)",Version = request.Version};}
}

UI界面交互代码如下:

 /// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void btnInfo_Click(object sender, RoutedEventArgs e){var service = new ProcessService();this.txtInfo.Text = service.GetProcessInfo();}private void btnComplateInfo_Click(object sender, RoutedEventArgs e){var service = new ProcessService();var response = service.GetProcessInfo(new ProcessRequest() { Version = "v-Demo 1.0 版本" });this.txtInfo.Text = response.Name + response.Version;}}

上面代码中有两个按钮事件,分别调用了ProcessService 的两个方法,我们先来运行目标客户端Demo程序,分别点击两个按钮运行结果如下:

3.3 创建核心Hook类库

好了,上面我们的目标第三方Demo程序已经写好了,接下来我们需要写一个核心的Jlion.Process.HookCore类库 改写目标的ProcessService 的两个方法。我这里建了一个Jlion.Process.HookCore类库,通过nuget包引用我fork 后的DotNetDetour 类库,如下图:应用成功后我们建立核心的hook 方法,代码如下:

  public class ProcessHookService : IMethodHook{[HookMethod("Jlion.Process.Target.Client.ProcessService", null, null)]public string GetProcessInfo(){TextHelper.LogInfo($"这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端 的GetProcessInfo 方法后得到的结果");return "这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端 的GetProcessInfo 方法后得到的结果";}[OriginalMethod]public string GetProcessInfo_Original(){return null;}[HookMethod("Jlion.Process.Target.Client.ProcessService", null, null)]public object GetProcessInfo([RememberType("Jlion.Process.Target.Client.Model.ProcessRequest", false)] object request){var json = JsonConvert.SerializeObject(request);TextHelper.LogInfo($"json:{json}");var name = "这是Jlion.Process.HookCore.HookService dll. 改写TargetClient 客户端的GetProcessInfo(obj)后得到的结果";return new ProcessResponse(){Name = name,Version = "改写的dll 版本"};}[OriginalMethod]public object GetProcessInfo_Original([RememberType("Jlion.Process.Target.Client.Model.ProcessRequest", false)] object request){return null;}}

我这里就不详细的写DotNetDetour 的使用,需要知道它的使用可以访问 https://github.com/a312586670/DotNetDetour 查看具体的文档

核心的Jlion.Process.HookCore hook 类库 也已经创建完了,接下来还需要创建一个初始化Hook的服务类(特别重要),并且还必须是静态方法,代码如下:

 public class HookService{/// <summary>/// Hook 初始化/// </summary>/// <param name="msg"></param>/// <returns></returns>public static int Start(string msg){try{TextHelper.LogInfo("开始"+msg);MethodHook.Install();}catch{return -1;}return 1;}}

到这一步基本上Jlion.Process.HookCore Hook 核心的类库已经创建完了

3.4 模块注入客户端程序

创建客户端后需要引用FastWin32类库,如下图:

客户端注入Dll核心代码如下:

public class InjectService
{//注入的核心dll 路径public static string path = AppDomain.CurrentDomain.BaseDirectory+ "Jlion.Process.HookCore.dll";/// <summary>/// 进程id/// </summary>public static uint pid = 0;/// <summary>/// 启动/// </summary>public static void Start(){Inject();}#region 私有方法private static void Inject(){try{Injector.InjectManaged(pid, path, "Jlion.Process.HookCore.HookService", "Start", "ss", out int returnValue);}catch (Exception ex){}}#endregion}

代码中核心的代码是Injector.InjectManaged(),该方法有如下两个重构方法:

参数说明:

  • processId:目标进程的进程id ->pid

  • assemblyPath:核心Hook 注入的dll 绝对路径

  • typeName:Hook 初始化方法的命名空间,一般注入一个模块dll后需要执行的入口初始化方法,这里是Hook 核心dll 中的HookService.Start 方法的命名空间(Jlion.Process.HookCore.HookService)

  • methodName : 注入后执行的方法名称

  • argument : 方法所需要的参数

  • returnValue:返回注入后运行的方法返回值

客户端UI 核心代码如下:
/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void btnInject_Click(object sender, RoutedEventArgs e){InjectService.pid = Convert.ToUInt32(txbPid.Text.Trim());InjectService.Start();}}

这里核心的注入Client Demo 也写完了,我们把注入的客户端也运行起来,输入目标的进程pid(也可以程序中查找目标进程Id),运行后再来执行上面创建的第三方程序的两个按钮,结果如下:通过编写客户端程序点击注入dll后,再点击第三方程序的两个按钮事件,结果如下:可以看到点击后,运行的结果已经被动态注入的Jlion.Process.HookCore.dll改写了,不过上面的代码也可以改写后同时还运行原有目标的方法就是通过调用'_Original'后缀结尾的方法,方法体返回null即可。

四、总结

通过DotNetDetour 框架可以编写对目标进程的方法进行Hook 重写,使用新的方法覆盖第三方进程的方法,也可以继续执行第三方的方法。通过FastWin32调用Win32 API 把开发的dll模块注入到第三方进程中,同时注入后执行初始化方法,可以进行原有的Hook方法进行覆盖。到这里是不是感觉很神奇,它可以在以下场景中使用:

  • 想必大家想到的就是外挂程序,通过改写目标程序的方法进行外挂处理,写上自己的覆盖业务

  • 灰产地带比较实用

  • 破解第三方收费软件等等用途

感兴趣的朋友可以下载Demo 源代码玩一玩:github 源代码地址:https://github.com/a312586670/processClientDemo

往期精彩回顾



  • 【.net core】电商平台升级之微服务架构应用实战

  • .Net Core微服务架构技术栈的那些事

  • Asp.Net Core 中IdentityServer4 授权中心之应用实战

  • Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式

  • Asp.Net Core 中IdentityServer4 授权流程及刷新Token

  • Asp.Net Core 中IdentityServer4 实战之 Claim详解

  • Asp.Net Core 中IdentityServer4 实战之角色授权详解

  • Asp.Net Core 中间件应用实战中你不知道的那些事

  • Asp.Net Core Filter 深入浅出的那些事-AOP

  • Asp.Net Core EndPoint 终结点路由工作原理解读

  • ASP.NET CORE 内置的IOC解读及使用

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

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

相关文章

JAVA JFrame编程

JFrame编程 最基础的窗口 public test1() {setTitle("test1");setSize(300,300); //设置窗口大小setLocation(300,300); //设置窗口的位置jp new JPanel();JButton jbnew JButton("button");add(jb); //整个窗口可以增加一个按钮setDefaultCloseOpera…

linux卸载docker redis,【Docker】Redis在docker上的安装、启动、停止、删除操作

查找镜像按名称搜索图像docker search redis按名称搜索并显示非截断描述(--no-trunc)docker search --stars3 --no-trunc redis按名称redis搜索出星数至少为3颗星的镜像docker search --filter stars3 redis显示名称中包含“redis”的图像&#xff0c;并且是自动构建docker sea…

[C++11]override关键字的使用

override关键字确保在派生类中声明的重写函数与基类的虚函数有相同的签名&#xff0c;同时也明确表明将会重写基类的虚函数&#xff0c;这样就可以保证重写的虚函数的正确性&#xff0c;也提高了代码的可读性&#xff0c;和final一样&#xff0c;这个关键字要写到方法的后面。 …

Sql Server之旅——第二站 理解讨厌的表扫描

很久以前我们在写sql的时候&#xff0c;最怕的一件事情就是sql莫名奇妙的超级慢&#xff0c;慢的是几根烟抽完&#xff0c;那个小球还在一直转。。。这个着急也只有当事人才明白&#xff0c;后来听说有个什么“评估执行计划“&#xff0c;后来的后来才明白应该避免表扫描。。。…

JAVA JFrame画图基础和事件监听

JFrame画图基础和事件监听 消息框 JOptionPane.showMessageDialog(mine.this, "删除不成功!");画图 class MyJPanel extends JPanel //继承面板类 {public void paint(Graphics g) //覆盖父类的方法,paint相当于画图{g.drawOval(30, 30, 80, 80); //画圆g.drawLi…

[C++11]final关键字的使用

C中增加了final关键字来限制某个类不能被继承&#xff0c;或者或个虚函数不能被重写&#xff0c;和java的final关键字的功能是类似的。如果使用final修饰函数&#xff0c;只能修饰虚函数&#xff0c;并且要把final关键字放到类或者函数的后面。 1.如果使用final修饰函数&#…

Sql Server之旅——第一站 那些给我们带来福利的系统视图

本来想这个系列写点什么好呢&#xff0c;后来想想大家作为程序员&#xff0c;用的最多的莫过于数据库了&#xff0c;但是事实上很多像我这样工作在一线的码农&#xff0c;对sql 都一知半解&#xff0c;别谈优化和对数据库底层的认识了&#xff0c;我也是这样。。。一&#xff1…

c语言case怎么输入字母,如何使用switch case语句将字母转换为数字

我正在制作黑色插口游戏&#xff0c;并且需要使用switch case语句将A转换为11&#xff0c;将T&#xff0c;Q&#xff0c;J和K转换为10&#xff0c;但是我不确定如何执行代码。有人会帮助我解决这个问题吗&#xff1f;如何使用switch case语句将字母转换为数字到目前为止&#x…

JAVA JDBC连接mysql编程

JDBC连接mysql编程 基本操作 package jdbc;import java.sql.Statement; import java.util.Scanner; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet;public class test {public static void main(String[] args) throws Exception {…

[C++11]继承构造函数

C11中提供的继承构造函数可以让派生类直接使用基类的构造函数&#xff0c;而无需自己再写构造函数&#xff0c;尤其是在基类有很多构造函数的情况下&#xff0c;可以极大地简化派生类构造函数的编写。 先来看没有继承构造函数之前的处理方式: 代码如下: #include <iostrea…

.NET 程序员的 Playground :LINQPad

如果想执行一个简单的 C# 语句并获得运行结果&#xff0c;通常我们需要做几个步骤才能达成&#xff1a;打开 Visual Studio 并新建一个控制台项目。在 Program.cs 中编写代码并保存。点击运行按钮或者 F5 运行程序并查看结果。通常来说这并不会产生问题。但如果你和笔者一样为 …

c语言表达式5 gt 3 gt 1,C语言题目谁会做?

1.为表示关系X>y>z&#xff0c;应使用C语言表达式________2.选择题&#xff1a;C语言中&#xff0c;函数返回值的类型是&#xff1a;_____A。return语句中的表达式的类型。B。主调函数中指定的类型。C。定义函数时所指定的函数类型。D。函数调用时系统随机指定的类型3.1.…

JAVA 点菜系统数据库课程设计

点菜系统数据库课程设计 效果图 数据库建表 CREATE TABLE OrderDish (orderid int not null,money int,primary key(orderid) );CREATE TABLE Dish (id varchar(20) not null,name nchar(10),price int,type nchar(10),primary key(id) ); insert into Dish values(zhushi0,水…

[C++11]委托构造函数

委托构造函数允许使用同一个类中的一个构造函数调用其他的构造函数&#xff0c;从而简化相关变量的初始化。 注意点: 1.这种链式的构造函数调用不能形成一个闭环(死循环)&#xff0c;否则会在运行期抛异常。 2.如果要进行多层构造函数的链式调用&#xff0c;建议将构造函数的…

基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目

首先&#xff0c;默认咱们已经有了.net core 3.1的开发环境&#xff0c;如果你没有&#xff0c;快去下载... https://dotnet.microsoft.com/download由于项目是基于abp vNext开发的&#xff0c;所以开发之前建议去撸一遍abp官方文档&#xff0c;https://docs.abp.io/en/abp/lat…

c语言常见错误代码释义,C语言常见错误代码释义解析.doc

C语言常见错误代码释义解析C语言常见错误代码释义错误代码及错误信息 错误释义error 1: Out of memory 内存溢出error 2: Identifier expected 缺标识符error 3: Unknown identifier 未定义的标识符error 4: Duplicate identifier 重复定义的标识符error 5: Syntax error 语法错…

JAVA Java多线程与并发库

Java多线程与并发库 同步方式 import javax.xml.stream.events.StartDocument;public class TestSynchronized {public static void main(String[] args) {// TODO Auto-generated method stubTestSynchronized test new TestSynchronized();test.init();}void init() {fina…

[C++11]统一的数据初始化方式 - 初始化列表

关于C中的变量&#xff0c;数组&#xff0c;对象等都有不同的初始化方法&#xff0c;在这些繁琐的初始化方法中没有任何一种方式适用于所有的情况。为了统一初始化方式&#xff0c;并且让初始化行为具有确定的效果&#xff0c;在C11中提出了列表初始化的概念。 代码如下: #in…

ffmpeg为何用c语言编译,如何使用ffmpeg的c语言sdk实现对文件夹的操作

重要函数打开文件夹&#xff1a;avio_open_dir()读取文件夹&#xff1a;avio_read_dir()关闭文件夹&#xff1a;avio_close_dir()结构体, 操作目录的上下文&#xff1a;AVIODirContext()目录项&#xff0c;用于存放文件名&#xff0c;文件大小等信息&#xff1a;AVIODirEntry()…

Sql Server之旅——第三站 解惑那些背了多年聚集索引的人

说到聚集索引&#xff0c;我想每个码农都明白&#xff0c;但是也有很多像我这样的伪程序员&#xff0c;只能用死记硬背来解决这个问题&#xff0c;什么表中只能建一个聚集索引&#xff0c;然后又扯到了目录查找来帮助读者记忆。。。。问题就在这里&#xff0c;我们不是学文科&a…