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ẻ.
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
Có vẻ xấu trên x64, chỉ cần nhảy tới một thanh ghi –