亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

純C#實現Hook功能詳解

2019-10-29 21:15:59
字體:
來源:轉載
供稿:網友

發布一個自己寫的用于Hook .Net方法的類庫,代碼量不大,完全的C#代碼實現,是一個比較有趣的功能,分享出來希望能和大家共同探討

安裝:Install-Package DotNetDetour

1.為何想做這個

說到hook大家都應該不陌生,就是改變函數的執行流程,讓本應該執行的函數跑到另一個函數中執行,這是個很有用也很有趣的功能(例如獲取函數參數信息,改變函數執行流程,計算函數執行時間等等),殺軟中主防的原理就是hook,通過hook攔截函數獲取參數信息來判斷是否是危險行為,但這類程序大多是C++的,一直以來我都想實現可以hook .net函數的庫,網上搜索了很多,但都不理想,所以想自己實現一個

2.實現原理

我采用的是inline hook的方式,因為我對.net虛擬機以及一些內部的結構并不是很熟悉,并且有些東西的確找不到任何文檔,所以就采用原生代碼的inline hook的方式來實現。

首先說一下inline hook的基本原理,它是通過修改函數的前5字節指令為jmp xxxxxxxx來實現的,例如一個C#方法:

hook,實現,C#實現Hook

用windbg調試查看方法信息:

hook,實現,C#實現Hook

查看已經jit了的原生代碼:

hook,實現,C#實現Hook

這里的地址(0x008c0640)可以通過MethodInfo.MethodHandle.GetFunctionPointer().ToPointer()方法獲取

到了這里,我們就知道了修改從push ebp開始的5個字節為jmp跳轉指令,跳入我們自己的函數就可以達到hook的目的,但執行到我們的函數后,如果我們并不是要攔截執行流程,那么我們最終是需要再調用原函數的,但原函數已經被修改了,這會想到的辦法就是恢復那修改的5字節指令,但這又會引發另一個問題,就是當我們恢復時,正好另一個線程調用到這個函數,那么程序將會崩潰,或者說漏掉一次函數調用,修改時暫停其他線程并等待正跑在其中的CPU執行完這5字節再去恢復指令也許是個不錯的辦法,但感覺并不容易實現,而且影響性能,所以我放棄了這種辦法

那么如何才能調用修改前的函數呢,我首先想到是C中寫裸函數的方式,即自己用匯編拼出來一個原函數再執行:

原函數前5字節指令+jmp跳轉指令

但其實這也是不可行的,聰明的人已經發現,圖中所示的函數的前5字節并不是一個完整的匯編指令,不同的函數,長度都不一樣,.net的函數并不像某些原生函數那樣,會預留mov edi,edi這樣的正好5字節的指令,我先想到的是復制函數的所有匯編指令生成新的函數,但這樣也會出問題,因為像E8,E9這樣的相對跳轉指令,如果指令地址變了,那么跳轉的位置也就變了,程序就會崩潰,所以這也不可行。

到了這里,我有些不耐煩了,畢竟我是要hook所有函數的,而不是某個固定的函數,而函數入口的指令又不相同,這可怎么辦,難道我需要計算出大于等于5字節的最小完整匯編指令長度?

按照這個思路,最終找到了一個用C寫的反匯編庫(BlackBone),其中提供了類似的方法,我稍作了修改后試用了下,的確不錯,可以準確求出匯編指令長度,例如

push ebp

mov ebp,esp

mov eax,dword ptr ds:[33F22ACh]

求出值是9,這樣我根據求出的值動態拼接一個函數出來即可,哈哈,到了這里,感覺實現的差不多了,但沒想到64位下又給了我當頭一棒,之前的原函數指令可以寫成:

大于等于5字節的最小完整匯編指令+jmp跳轉指令即可構成我們的原函數

但我們知道,C#中要想執行匯編,是需要用Marshal.AllocHGlobal來分配非托管空間的,而這樣分配的地址與我們要跳轉到的原函數的地址在64位下是超過2GB地址范圍的,一般的跳轉指令是無法實現的,所以想到了用ret指令實現,而64位地址又不能直接push,所以最后寫出如下匯編:

push rax

mov rax,target_addr

push rax

mov rax,qword ptr ss:[rsp+8]

ret 8

由于某些C#函數竟然第一行就是修改rax寄存器的值,所以只能是先保存rax,推入堆棧后再恢復,這里匯編操作就方便多了,之前實現另一個東西,用到IL指令,但發現只有dup這種復制棧頂元素的指令,卻沒有獲取堆棧中某個非棧頂元素值的指令,所以說還是匯編靈活啊,想怎么寫就怎么寫,啥都能實現。

最后就是這個原函數的調用過程了,因為是動態拼接的函數,所以想到的就是用Marshal.GetDelegateForFunctionPointer轉成委托來執行,后來發現不對,因為我雖然拼接的是匯編,而這個匯編是C#方法jit后的匯編,這個并不是C方法編譯后的匯編,通過把非托管指針轉換為委托的方式運行函數是會添加很多不需要的操作的,例如托管類型與非托管類型的轉換,但我拼接出的函數是不需要這些過程的,這個怎么辦,看來只能用調用C#普通函數的方式調用,這個怎么實現呢,其實很好辦,只需寫一個空殼函數,然后修改這個函數的方法表中的原生指令指針即可,具體方法如下:

*((ulong*)((uint*)method.MethodHandle.Value.ToPointer() + 2)) = (ulong)ptr;

method是空殼函數的MethodInfo,ptr是動態拼接的原函數的地址

好,到了這里就基本完成核心功能了,最不好處理的就是這個原函數調用,我的完整的64位原函數指令拼接就實現了,代碼很少,如下所示:

byte[] jmp_inst ={ 0x50,            //push rax 0x48,0xB8,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, //mov rax,target_addr 0x50,            //push rax 0x48,0x8B,0x44,0x24,0x08,       //mov rax,qword ptr ss:[rsp+8] 0xC2,0x08,0x00          //ret 8}; protected override void CreateOriginalMethod(MethodInfo method){ uint oldProtect; var needSize = NativeAPI.SizeofMin5Byte(srcPtr); byte[] src_instr = new byte[needSize]; for (int i = 0; i < needSize; i++) {  src_instr[i] = srcPtr[i]; } fixed (byte* p = &jmp_inst[3]) {  *((ulong*)p) = (ulong)(srcPtr + needSize); } var totalLength = src_instr.Length + jmp_inst.Length; IntPtr ptr = Marshal.AllocHGlobal(totalLength); Marshal.Copy(src_instr, 0, ptr, src_instr.Length); Marshal.Copy(jmp_inst, 0, ptr + src_instr.Length, jmp_inst.Length); NativeAPI.VirtualProtect(ptr, (uint)totalLength, Protection.PAGE_EXECUTE_READWRITE, out oldProtect); RuntimeHelpers.PrepareMethod(method.MethodHandle); *((ulong*)((uint*)method.MethodHandle.Value.ToPointer() + 2)) = (ulong)ptr;}

3.類庫開發所用到的語言

之前我說,我的這個庫是完全用C#實現的,但其中的確用到了一個C寫的反匯編庫,于是我用C#把那個庫重寫了一遍,說來也簡單,C的代碼粘過來,C#啟用unsafe代碼,改了10分鐘就好了,真心是非常方便,畢竟C#是支持指針和結構體的,而且基礎類型非常豐富,這里得給C#點個贊!

4.具體使用

使用非常簡單,首先新建控制臺程序并添加一個類,繼承接口IMethodMonitor,Get是你自己的函數,Ori是原函數會在運行時動態生成,在Get中你可以干你想干的任何事情

public class CustomMonitor : IMethodMonitor //自定義一個類并繼承IMethodMonitor接口{ [Monitor("TargetNamespace", "TargetClass")] //你要hook的目標方法的名稱空間,類名 public string Get() //方法簽名要與目標方法一致 {  return "B" + Ori(); }  [MethodImpl(MethodImplOptions.NoInlining)] [Original] //原函數標記 public string Ori() //方法簽名要與目標方法一致 {  return null; //這里寫什么無所謂,能編譯過即可 }}

然后定義目標函數,例如

public string Get() { return "A"; }

最后調用Monitor.Install()安裝監視器,例如:

Console.WrtieLine(Get());Monitor.Install()Console.WrtieLine(Get());

你會發現第一次調用Get輸出的值是"A",第二次是"BA"

當然這個庫只是hook,但hook一般都需要dll注入來配合,因為hook自身進程沒什么意義,hook別人的進程才有意義,我之后會發布一個用于.net程序遠程注入的類庫,注入的是.net的dll哦,不是C++的

好了,講了這么多,其實這個庫代碼量并不大,但主要是自己研究的一個成果,很多東西都是自己琢磨出來的,所以覺得這個過程很有意思,也希望高手能指出改進方案,畢竟感覺目前這種方法雖然實現了功能,但是并不是很好,總覺得以hook .net虛擬機的方式來實現會更簡單一些,或者網絡上已經有了現成的解決方案我沒有找到,總之,拋磚引玉,希望大家能共同探討

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧洲日本亚洲国产区| 久久中国妇女中文字幕| 亚洲欧美激情精品一区二区| 久久久精品2019中文字幕神马| 精品国产乱码久久久久酒店| 日韩精品中文字幕有码专区| 成人激情春色网| 国产精品电影在线观看| 精品调教chinesegay| 91在线|亚洲| 成人黄色在线播放| 久久免费视频这里只有精品| 欧美激情网站在线观看| 久久伊人精品一区二区三区| 精品人伦一区二区三区蜜桃网站| 91欧美精品午夜性色福利在线| 国产a∨精品一区二区三区不卡| 日韩av综合中文字幕| 久久网福利资源网站| 中文字幕久久亚洲| 亚洲片在线观看| 国产精品福利片| 亚洲欧美激情视频| 精品视频在线播放免| 欧美最猛性xxxxx(亚洲精品)| 欧美日韩国产成人在线| 亚洲国产精品悠悠久久琪琪| 久久激情五月丁香伊人| 国产欧美精品xxxx另类| 久久综合久中文字幕青草| 69久久夜色精品国产69| 国产成人精品久久二区二区| 日本免费久久高清视频| 欧美成人高清视频| 久久九九有精品国产23| 日韩av资源在线播放| 久久精品国产精品| 亚洲欧美精品在线| 日韩欧美视频一区二区三区| 精品成人国产在线观看男人呻吟| 精品中文字幕在线观看| 国产不卡在线观看| 亚洲无限av看| 国产精品稀缺呦系列在线| 中文字幕日韩视频| 九九热精品视频国产| 日韩高清电影免费观看完整| 成人夜晚看av| 成人久久久久久久| 亚洲成人精品久久| 精品国产自在精品国产浪潮| 色噜噜狠狠狠综合曰曰曰88av| 精品视频在线播放| 国产91亚洲精品| 成人av番号网| 久久久久中文字幕2018| 国产精品91在线观看| 日韩暖暖在线视频| 国产一区二区日韩| 欧美性生活大片免费观看网址| 这里只有精品视频| 中文字幕日韩欧美精品在线观看| 久久久精品美女| 午夜精品视频在线| 久久网福利资源网站| 国产精品国产自产拍高清av水多| 国产一区二区三区在线免费观看| 国产精品jizz在线观看麻豆| 亚洲精品欧美一区二区三区| 日韩在线精品一区| 亚洲色图综合久久| 精品久久久久久久久久久久| 亚洲女人天堂网| 岛国av一区二区在线在线观看| 精品久久久久久国产| 欧美大片大片在线播放| 国产精品第三页| 美女久久久久久久久久久| 欧美成人在线影院| 国内精品久久久久久影视8| 日韩在线观看你懂的| 日韩有码视频在线| 国产狼人综合免费视频| 久久国产精品影视| 国产精品美女午夜av| 国产不卡精品视男人的天堂| 在线成人激情视频| 亚洲精品自在久久| 日韩精品在线免费观看视频| 亚洲精品小视频| 国产精品91久久久久久| 亚洲综合中文字幕在线观看| 久久韩国免费视频| 亚洲电影在线看| 亚洲天堂免费在线| 久久久国产精彩视频美女艺术照福利| 欧美精品久久久久久久| 亚洲人成电影网站色| 亚洲美女喷白浆| 亚洲人成电影在线播放| 欧美尺度大的性做爰视频| 一夜七次郎国产精品亚洲| 欧美在线一区二区三区四| 欧美高清在线视频观看不卡| 中文字幕日韩欧美| 亚洲欧美国产精品久久久久久久| 在线成人免费网站| 91九色国产社区在线观看| 91理论片午午论夜理片久久| 国产+成+人+亚洲欧洲| 国产精品麻豆va在线播放| 一道本无吗dⅴd在线播放一区| 欧美孕妇与黑人孕交| 午夜精品蜜臀一区二区三区免费| 亚洲在线观看视频| 亚洲免费人成在线视频观看| 国产精品美女呻吟| 国产日韩欧美一二三区| 91免费高清视频| 久久99精品国产99久久6尤物| 国产精品久久久久久久7电影| 欧美性猛交xxxx免费看| 国产精品老女人精品视频| 色无极亚洲影院| 秋霞成人午夜鲁丝一区二区三区| 色综合久久88| zzijzzij亚洲日本成熟少妇| 奇门遁甲1982国语版免费观看高清| 精品亚洲一区二区三区在线播放| 日韩精品在线免费观看视频| 国产日韩在线视频| 国产日韩欧美一二三区| 久久99精品久久久久久噜噜| 欧美专区中文字幕| 久久精品国产一区| 欧美野外wwwxxx| 亚洲一区二区三区毛片| 欧美大胆在线视频| 欧美在线视频在线播放完整版免费观看| 日韩av中文字幕在线免费观看| 亚洲aaaaaa| 成人深夜直播免费观看| 亚洲成人黄色在线观看| 国产福利精品视频| 久久九九国产精品怡红院| 国产在线观看91精品一区| 欧美成人激情视频| 国产精品99久久久久久www| 91最新国产视频| 成人网欧美在线视频| 精品中文视频在线| 亚洲区在线播放| 亚洲男人天堂九九视频| 日韩久久免费电影| 国产91成人在在线播放| 亚洲精品国产精品国自产观看浪潮| 欧美成人手机在线| 亚洲欧美日韩在线高清直播| 97精品欧美一区二区三区| 精品动漫一区二区| 亚洲激情在线观看视频免费| 成人a免费视频| 国产亚洲视频中文字幕视频| 亚洲男人的天堂在线播放|