C# dynamically intercepts and overwrites functions of third-party processes to implement function tampering (plug-ins)

Today I was reading a pdf document that I had collected before (introducing the relevant knowledge of C# plug-ins), and combined with the things on the Internet and personal understanding, I came up with this article.

Reference article:

[Selected] An article with an explanation of C# dynamic interception covering functions in third-party processes (essential for plug-ins)_zls365365’s blog-CSDN blog

DotNetDetour – a versatile open source .NET code Hook artifact

test environment:

visual studio 2017

.net framework 4.0

The test steps are as follows:

1. Writing a third-party client program (that is, the client whose function is to be tampered with)

1.1 Create a new winform form application named TargetClient, select .net framework 4.0

1.2 Create a new class TargetTestClass and edit it as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TargetClient
{
    public class TargetTestClass
    {
        public string Test()
        {
            return "hello world";
        }
    }
}

The Test method is the method we want to tamper with

1.3 Drag a button into the default Form1 form and change the button name to “Test”, as shown below:

1.4 The method of clicking the button is as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TargetClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string ret=new TargetTestClass().Test();
            MessageBox.Show(ret);
        }
    }
}

1.5 Run and click the “Test” button to output the English hello world, as shown below:

2. Inject client program code

2.1 Create a new winfrom form program named InjectClient, select .net framework 4.0

2.2 Add Jlion.DotNetDetour package reference, as shown below:

2.3 Add a class named InjectClass and inherit the IMethodHook interface to edit the logic that covers the tampered method, as follows:

using DotNetDetour;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InjectClient
{
    public class InjectClass:IMethodHook
    {
        //TargetClient.TargetTestClass The full path of the TargetTestClass class to be tampered with (that is, the full path of the class TargetTestClass in the TargetClient.exe client, that is, namespace + class name)
        //Test is the tampered method name, which must be consistent
        [HookMethod("TargetClient.TargetTestClass")]
        public string Test()
        {
            return "Hello world";
        }
        //Implement a placeholder method, the original method to be overwritten, the naming format is: tampered method name + _Original
        [OriginalMethod]
        public string Test_Original()
        {
            return null; //It doesn't matter what you write here, as long as it can be compiled
        }

    }
}

Notice:

TargetClient.TargetTestClass The full path of the TargetTestClass class to be tampered with (that is, the full path of the class TargetTestClass in the TargetClient.exe client, that is, namespace + class name)

Test is the tampered method name, which must be consistent.

Test_Original is the original method to be overwritten. The naming format is: tampered method name + _Original

2.3 Create a new method to install the registration class HookService to prepare for injection, and edit it as follows:

using DotNetDetour;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InjectClient
{
    public class HookService
    {
        /// <summary>
        /// Must be a static method
        /// </summary>
        /// <param name="paramValue">Not used yet</param>
        /// <returns></returns>
        public static int Start(string paramValue)
        {
            try
            {
                MethodHook.Install();
            }
            catch
            {
                return -1;
            }
            return 1;
        }
    }
}

The name of the Start method depends on your preference, but the method must be a static method.

2.4 Now that the methods are ready, it’s time to write the injection logic and install the injection package FastWin32, as shown below:

2.5 Add a new injection service class InjectService and edit it as follows:

using FastWin32.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace InjectClient
{
    public class InjectService
    {
        //Injected core dll path
        public static string path = AppDomain.CurrentDomain.BaseDirectory + "InjectClient.exe";

        /// <summary>
        /// process id
        /// </summary>
        public static uint pid = 0;

        /// <summary>
        /// start up
        /// </summary>
        public static void Start()
        {
            Inject();
        }


        #region private method
        private static void Inject()
        {
            try
            {
                Injector.InjectManaged(pid, path, "InjectClient.HookService", "Start", "Test parameters, not used yet", out int returnValue);
                MessageBox.Show("The injection was successful");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion
    }
}

The name InjectClient.HookService is the registered class HookService installed earlier (namespace + class name)

Start is the name of the Start method of the previously installed registration class HookService.

2.3 Drag a text label, text box and a button into the Form1 interface. The layout and name are as follows:

And edit the code as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace InjectClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// Inject the logic of the button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnInject_Click(object sender, EventArgs e)
        {
            //Get the process ID entered by the interface
            InjectService.pid = Convert.ToUInt32(this.txtPid.Text.Trim());
            InjectService.Start();
        }
    }
}

2.4 Generate project for backup

Three comprehensive tests

3.1 Run the client program TargetClient.exe to be tampered with, as shown below:

You can see that the output before being tampered was still English hello world.

3.2 Run the injection program InjectClient.exe

3.3 Open the window’s task manager and find the process Pid corresponding to TargetClient.exe, as shown below:

You can see that the process Pid corresponding to TargetClient.exe is 27580. There is a high probability that this is not the case for you.

3.4 Enter the process Pid 27580 corresponding to TargetClient.exe into the injection program InjectClient.exe and click the injection button, as shown below, you can see that the injection is successful

3.5 Click the test button of TargetClient.exe again

You can see that the output Chinese world is Hello, which proves that the method was successfully injected.

This can do a lot of bad things, such as tampering with other people’s system login methods (no matter whether it is obfuscated or unobfuscated code, there are ways to get it, so I won’t go into it here), you know