2020年5月18日星期一

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

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


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

一、前言

由于项目需要,最近研究了一下跨进程通讯改写第三方程序中的方法(运行中),把自己程序中的目标方法直接覆盖第三方程序中的方法函数;一直没有头绪,通过搜索引擎找了一大堆解决方案,资料甚是稀少,最后功夫不负有心人,经过两天的研究,终于在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程序,分别点击两个按钮运行结果如下:
按钮事件结果1
按钮事件结果2

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)			{			}		}				

没有评论:

发表评论