由於項目需要,最近研究了一下跨進程通訊改寫第三方程式中的方法(運行中),把自己程式中的目標方法直接覆蓋第三方程式中的方法函數;一直沒有頭緒,通過搜索引擎找了一大堆解決方案,資料甚是稀少,最後功夫不負有心人,經過兩天的研究,終於在github 上找到兩個開源的代碼,通過兩個開源代碼結合起來即可實現我的... ...
一、前言
由於項目需要,最近研究了一下跨進程通訊改寫第三方程式中的方法(運行中),把自己程式中的目標方法直接覆蓋第三方程式中的方法函數;一直沒有頭緒,通過搜索引擎找了一大堆解決方案,資料甚是稀少,最後功夫不負有心人,經過兩天的研究,終於在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