2010-09-08 38 views
21

Tôi có bãi sau của đối tượng delegate:Nhận tên phương pháp từ đại biểu với WinDbg

Name: MyEventHandler 
MethodTable: 132648fc 
EEClass: 1319e2b4 
Size: 32(0x20) bytes 
Fields: 
    MT Field Offset     Type VT  Attr Value Name 
790fd0f0 40000ff  4  System.Object 0 instance 014037a4 _target 
7910ebc8 4000100  8 ...ection.MethodBase 0 instance 00000000 _methodBase 
791016bc 4000101  c  System.IntPtr 1 instance 2ef38748 _methodPtr 
791016bc 4000102  10  System.IntPtr 1 instance  0 _methodPtrAux 
790fd0f0 400010c  14  System.Object 0 instance 00000000 _invocationList 
791016bc 400010d  18  System.IntPtr 1 instance  0 _invocationCount 

Làm thế nào tôi có thể lấy tên của phương pháp này, chỉ bởi các đại biểu?

Trả lời

32

Theo kinh nghiệm của tôi, đề xuất được cung cấp bởi hakan không hoạt động. Đây là những gì tôi làm.

Kết quả cho thấy trình xử lý đính kèm là thành viên của đối tượng được trỏ đến bởi _target. Bằng cách bán phá giá, bạn sẽ nhận được bảng phương thức của nó.

tôi đã xây dựng một ví dụ tương tự, để minh họa:

0:000> !do 02844de4 
Name: System.EventHandler 
MethodTable: 0067afa4 
EEClass: 0052ef88 
Size: 32(0x20) bytes 
(C:\windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll) 
Fields: 
     MT Field Offset     Type VT  Attr Value Name 
002e6d58 40000ff  4  System.Object 0 instance 02842d20 _target 
0058df70 4000100  8 ...ection.MethodBase 0 instance 00000000 _methodBase 
0058743c 4000101  c  System.IntPtr 1 instance 2cc060 _methodPtr 
0058743c 4000102  10  System.IntPtr 1 instance  0 _methodPtrAux 
002e6d58 400010c  14  System.Object 0 instance 00000000 _invocationList 
0058743c 400010d  18  System.IntPtr 1 instance  0 _invocationCount 

Trong trường hợp này, tôi sẽ xem xét các đối tượng ở 02842d20.

0:000> !do 02842d20 
Name: app.Foo 
MethodTable: 002c30bc 
EEClass: 002c13d4 
Size: 12(0xc) bytes 
(C:\workspaces\TestBench\app\bin\x86\Debug\app.exe) 
Fields: 
None 

Vì vậy, loại mục tiêu là app.Foo. Hãy đổ các phương thức cho kiểu này.

0:000> !dumpmt -md 002c30bc 
EEClass: 002c13d4 
Module: 002c2c5c 
Name: app.Foo 
mdToken: 02000002 (C:\workspaces\TestBench\app\bin\x86\Debug\app.exe) 
BaseSize: 0xc 
ComponentSize: 0x0 
Number of IFaces in IFaceMap: 0 
Slots in VTable: 6 
-------------------------------------- 
MethodDesc Table 
    Entry MethodDesc  JIT Name 
002ec015 002e6cbc  NONE System.Object.ToString() 
002ec019 002e6cc4  NONE System.Object.Equals(System.Object) 
002ec029 002e6cf4  NONE System.Object.GetHashCode() 
005f4930 002e6d1c  JIT System.Object.Finalize() 
005f8238 002c30b4  JIT app.Foo..ctor() 
005f8270 002c30a8  JIT app.Foo.Bar(System.Object, System.EventArgs) 

So sánh giá trị của MethodDesc bảng với giá trị ban đầu là _methodPtr. Không có kết quả rõ ràng.

_methodPtr trỏ tới một đoạn mã thực hiện jmp đến địa chỉ của hàm đang được đề cập hoặc gọi là thường trình sửa, vì vậy bước tiếp theo là sử dụng lệnh !u với giá trị _methodPtr. Nếu chúng tôi thấy hướng dẫn jmp, chúng tôi có địa chỉ và bằng cách sử dụng !u về điều đó, chúng tôi nhận được phương pháp.

Nếu, mặt khác, chúng ta thấy một call-clr!PrecodeFixupThunk chúng tôi có thể nhận được MethodDesc bằng cách đổ bộ nhớ được trỏ đến bởi _methodPtr như thế này

0:000> dd 2cc060 
002cc060 7e5d65e8 00005e6e 002c30a8 00000000 
002cc070 00000000 00000000 00000000 00000000 
002cc080 00000000 00000000 00000000 00000000 

chúng ta thấy cái gì đó trông giống như một mục bảng phương pháp trong là DWORD thứ ba. Bằng cách so sánh giá trị 002c30a8 với bảng phương pháp ở trên, chúng ta thấy rằng tên của phương thức là app.Foo.Bar.

Vì đây là một ví dụ được xây dựng, tôi biết rằng tôi đã tìm thấy phương pháp, tôi đang tìm kiếm trong trường hợp này.

Thực tế nó có thể phức tạp hơn một chút so với ví dụ trên, vì các trường được sử dụng khác nhau tùy thuộc vào cách sử dụng thực tế của sự kiện. Tuy nhiên, theo kinh nghiệm của tôi, cách tiếp cận ở trên sẽ hoạt động trong kịch bản nhà xuất bản/người đăng ký chung.

Để biết thêm chi tiết về chi tiết triển khai, hãy xem tệp comdelegate.cpp của CLI nguồn được chia sẻ.

+0

Thay vì so sánh thủ công với bảng phương thức, bạn cũng có thể sử dụng lệnh DumpMD với bộ mô tả phương thức. – kicsit

+0

Có vẻ xấu trên x64, chỉ cần nhảy tới một thanh ghi –

3

Tôi tin rằng bạn có thể sử dụng! Ip2md trên giá trị của methodPtr. Điều đó sẽ cho mô tả phương thức.

+0

Điều đó sẽ không luôn hoạt động. Nhưng theo kinh nghiệm của tôi, không có phương pháp nào hoạt động mọi lúc, vì vậy bạn phải biết và thử các kỹ thuật khác nhau để có được tên phương thức – sloth

+0

Các bạn có lẽ đúng, nhanh chóng googling cho thấy rằng điều này có thể không hoạt động nếu phương pháp này chưa được JITted. Nhưng tôi vẫn sẽ thử cái này và nếu nó không hoạt động theo cách khác. Giải pháp của Brian, bán phá giá các phương thức của đối tượng đích, trông rất tiện lợi. – hakan

2

Cách khác là để tháo rời dữ liệu tại _methodPtr.

phép nói rằng EventHandler của chúng tôi trông như thế này:

 MT Field Offset     Type VT  Attr Value Name 
6da484dc 40000ff  4  System.Object 0 instance 02d8ff64 _target 
6da4d0ac 4000100  8 ...ection.MethodBase 0 instance 00000000 _methodBase 
6da4b188 4000101  c  System.IntPtr 1 instance d955840 _methodPtr 

Hãy xem xét tháo gỡ của d955840

!U d955840 
Unmanaged code 
08577a50 b884f8a007  mov  eax,7A0F884h 
08577a55 90    nop 
08577a56 e855b4d665  call mscorwks+0x2eb0 (6e2e2eb0) 
08577a5b e9ac8de4f7  jmp  003c080c 
08577a60 b8d4f9a007  mov  eax,7A0F9D4h 
08577a65 90    nop 
08577a66 e845b4d665  call mscorwks+0x2eb0 (6e2e2eb0) 
08577a6b e99c8de4f7  jmp  003c080c 
08577a70 00b000eb0cb0 add  byte ptr [eax-4FF31500h],dh 
08577a76 03eb   add  ebp,ebx 

Chúng tôi thấy một mov để 7A0F884 đây, vì vậy đây có thể là phương pháp chúng tôi đang tìm kiếm cho:

!dumpmd 7A0F884 
Method Name: DemoClass.OnDemoEvent(System.Object, System.EventArgs) 
Class: 07c079e8 
MethodTable: 07c10034 
mdToken: 060010ee 
Module: 07a0b7ac 
IsJitted: no 
CodeAddr: ffffffff 

bingo!

Có nhiều cách khác nhau để có được tên của phương pháp này, và không phải tất cả sẽ làm việc trong mọi tình huống

3

Tôi đã creatd một Littel Windbg kịch bản để giải quyết các phương pháp lưu trữ trực tiếp từ một giá trị methodPtr. Bạn có thể đọc thêm về here.

The Script là:

r $t0 = ${$arg1}+5 
r $t1 = $t0 + 8*by($t0+2) + 3 
r $t2 = 8*by($t0+1) 
r $t3 = poi($t1) + $t2 
!DumpMD $t3 

Lưu trữ nó trong một tập tin và thực hiện nó với giá trị _methodPtr của đại biểu của bạn như

$$>a< "c:\source\DelegateTest\Resolve.txt" 2ef38748 

Điều đó sẽ làm các trick trên tất cả các nền tảng và cho .NET 2.0 lên tới .NET 4.5.

+0

Nó hoạt động! Cảm ơn rất nhiều cho câu trả lời và cho liên kết – 6opuc

+0

Làm thế nào bạn tìm thấy thủ thuật đó với con trỏ kỳ diệu? – 6opuc

+0

Bằng cách xem mã bộ mã hóa được tạo. Nó là dễ dàng như vậy. Tôi có thể lưu ý rằng thực tế có hai loại cuộc gọi đại biểu. Hành động, Func, ... rất nhanh. Nhưng "cũ" stlye delgates mà bạn tuyên bố rõ ràng đi vào con đường mã rất khác nhau (ví dụ như MethodInvoker cho WndProc đại biểu) là một khá phổ biến. –

0

Với sự trợ giúp của ClrMd, tôi đang làm việc theo số tool để khám phá tệp kết xuất .Net với giao diện người dùng thân thiện. Có một số feature để tìm đại biểu và hiển thị danh sách yêu cầu và tên phương thức của nó.

+1

Vui lòng không đăng liên kết tại đây nhưng sao chép mã có liên quan. –

Các vấn đề liên quan