日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

.NET高级调试 | 通过JIT拦截无侵入调试 C# Emit 生成的动态代码

發(fā)布時間:2023/12/4 C# 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET高级调试 | 通过JIT拦截无侵入调试 C# Emit 生成的动态代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大家還記得上一篇的測試代碼嗎?我們用了:

Console.WriteLine("Function?Pointer:?0x{0:x16}",?Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());

來獲得 委托 的 函數(shù)指針 地址,通過這個突破口最終實現(xiàn)了 動態(tài)代碼 的調(diào)試,這種方式可以是可以,但很顯然這是侵入式的,那有沒有辦法實現(xiàn) 非侵入 調(diào)試動態(tài)代碼呢?在 .NET高級調(diào)試 這本書上還真給找到了,方法就是在 ?JIT 編譯動態(tài)方法時進行攔截,獲取其中的 方法描述符。

為了方便講解,先上測試代碼:

class?Program{private?delegate?int?AddDelegate(int?a,?int?b);static?void?Main(string[]?args){var?dynamicAdd?=?new?DynamicMethod("Add",?typeof(int),?new[]?{?typeof(int),?typeof(int)?},?true);var?il?=?dynamicAdd.GetILGenerator();il.Emit(OpCodes.Ldarg_0);il.Emit(OpCodes.Ldarg_1);il.Emit(OpCodes.Add);il.Emit(OpCodes.Ret);var?addDelegate?=?(AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));//Debugger.Break();//Console.WriteLine("Function?Pointer:?0x{0:x16}",?Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());Console.WriteLine(addDelegate(10,?20));}}

可以看到,我把上面兩行侵入式的代碼給屏蔽掉了,接下來在 il.Emit(OpCodes.Ret); 處下斷點,目的是為了在 clr 加載后尋找 JIT的 compileMethod 方法。

0:000>?!mbp?Program.cs?28 The?CLR?has?not?yet?been?initialized?in?the?process. Breakpoint?resolution?will?be?attempted?when?the?CLR?is?initialized. 0:000>?g ModLoad:?76910000?7698a000???C:\Windows\SysWOW64\ADVAPI32.dll ... ModLoad:?77190000?77226000???C:\Windows\SysWOW64\OLEAUT32.dll Breakpoint:?JIT?notification?received?for?method?ConsoleApp1.Program.Main(System.String[])?in?AppDomain?00783758. Breakpoint?set?at?ConsoleApp1.Program.Main(System.String[])?in?AppDomain?00783758. Breakpoint?1?hit eax=00000001?ebx=0019f5ac?ecx=023c3684?edx=ffffffff?esi=023c230c?edi=0019f4fc eip=048a0a02?esp=0019f4ac?ebp=0019f508?iopl=0?????????nv?up?ei?pl?zr?na?pe?nc cs=0023??ss=002b??ds=002b??es=002b??fs=0053??gs=002b?????????????efl=00000246 048a0a02?b901000000??????mov?????ecx,1

接下來可以用 x 命令模糊搜索 compileMethod 簽名,找出簽名是為了更好的下斷點。

0:000>?x?*!*compileMethod* ... 61413700??????????clrjit!CILJit::compileMethod?(class?ICorJitInfo?*,?struct?CORINFO_METHOD_INFO?*,?unsigned?int,?unsigned?char?**,?unsigned?long?*)

可以看到 compileMethod 的完整簽名是 clrjit!CILJit::compileMethod, 并且它的方法入口點地址是 61413700,有了它就可以對其下斷點啦!

0:000>?bp?61413700 0:000>?g Breakpoint?0?hit eax=61494698?ebx=80000004?ecx=61413700?edx=00005c10?esi=6148b3fc?edi=0019efa4 eip=61413700?esp=0019ede0?ebp=0019ee38?iopl=0?????????nv?up?ei?ng?nz?na?po?nc cs=0023??ss=002b??ds=002b??es=002b??fs=0053??gs=002b?????????????efl=00000282 clrjit!CILJit::compileMethod: 61413700?55??????????????push????ebp 0:000>?kb#?ChildEBP?RetAddr??????Args?to?Child?????????????? 00?0019ee38?62a4ccc3?????61494698?0019efa4?0019ef1c?clrjit!CILJit::compileMethod?[f:\dd\ndp\clr\src\jit32\ee_il_dll.cpp?@?151]? 01?0019ee38?62a4cd9b?????0019ef1c?0019f06c?0019f024?clr!invokeCompileMethodHelper+0x10b

很開心,成功命中,接下來提取 compileMethod 方法的第三個參數(shù),它就是需要編譯方法所指向的 方法描述符 地址,可以用 dp 給提取出來。

0:000>?dp?0019ef1c?L1 0019ef1c??0071537c 0:000>?!dumpmd?0071537c Method?Name:??DynamicClass.Add(Int32,?Int32) Class:????????007152e8 MethodTable:??0071533c mdToken:??????06000000 Module:???????00714ea8 IsJitted:?????no CodeAddr:?????ffffffff Transparency:?Transparent

方法描述符果然給調(diào)出來了,但這里的方法字節(jié)碼是 CodeAddr: ffffffff ,說明此時動態(tài)方法還沒有開始編譯,為了能夠使其編譯,我們在 Console.WriteLine(addDelegate(10, 20)); 處再下一個斷點,因為代碼到此處時, JIT 肯定編譯了該辦法,自然就能看到編譯后的 CodeAddr 地址。

0:000>?!mbp?Program.cs?35 Breakpoint?set?at?ConsoleApp1.Program.Main(System.String[])?in?AppDomain?00783758. 0:000>?g Breakpoint?3?hit eax=023c5f88?ebx=0019f5ac?ecx=023c5f3c?edx=00008f17?esi=023c230c?edi=0019f4fc eip=048a0a9b?esp=0019f4ac?ebp=0019f508?iopl=0?????????nv?up?ei?pl?zr?na?pe?nc cs=0023??ss=002b??ds=002b??es=002b??fs=0053??gs=002b?????????????efl=00000246 048a0a9b?6a14????????????push????14h 0:000>?!dumpmd?0071537c Method?Name:??DynamicClass.Add(Int32,?Int32) Class:????????007152e8 MethodTable:??0071533c mdToken:??????06000000 Module:???????00714ea8 IsJitted:?????yes CodeAddr:?????04a00050 Transparency:?Transparent

可以看到,此時的 CodeAddr: 04a00050 ,也就表明已經(jīng)編譯完成了,接下來繼續(xù) bp 。

0:000>?bp?04a00050 0:000>?g Breakpoint?4?hit eax=023c5f98?ebx=0019f5ac?ecx=0000000a?edx=00000014?esi=023c230c?edi=0019f4fc eip=04a00050?esp=0019f4a8?ebp=0019f508?iopl=0?????????nv?up?ei?pl?nz?na?po?nc cs=0023??ss=002b??ds=002b??es=002b??fs=0053??gs=002b?????????????efl=00000202 04a00050?8bc1????????????mov?????eax,ecx

可以看到,全部搞定,非侵入式,🐂

總結(jié)

以上是生活随笔為你收集整理的.NET高级调试 | 通过JIT拦截无侵入调试 C# Emit 生成的动态代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。