Explore the call mechanism of the CLR world [4] method with WINDBG

zhaozj2021-02-12  146

http://www.blogcn.com/User8/flier_lu/index.html?id=1745355http://www.blogcn.com/User8/flier_lu/index.html?id=1745373http://www.blogcn.com/ User8 / flier_lu / index.html? id = 1745407

Don Box in ".NET Normal Theory Volume 1: Public Language Runture", Detailed explanation of the principle of the Miography of the Chinese Miography in the middle of the CLR; QQChen also has a good introduction to the method in its blog Call classification article "CLR Drilling Down: The overhead of Method Calls". But because the purpose of their articles is different, so it is not enough to deepen the internal details that I satisfied, huh, I have to analyze myself. : D

I introduced how to use the JIT procedure described using Windbg Tracking Don Box in "JIT Procedure for Explore CLR World [3] Tracking Method" in WINDBG. This article will further analyze the call mechanisms of the method in the CLR in the WINDBG function described above.

First let's take a simple example, there are two classes and an interface definition, and use several different call types to modify:

The following is quoted:

Using system;

Namespace flier {public interface ifoo {void callfromintfbase (); void callfromintfderived ();

Public class base: ifoo {public void callfromobjbase () {system.console.writeline ("Base.callFromObjBase);}

Public Virtual Void CallFromObjderived () {System.console.writeline ("Base.callFromObjderive);}

public void CallFromIntfBase () {System.Console.WriteLine ( "Base.IFoo.CallFromIntfBase");} public virtual void CallFromIntfDerived () {System.Console.WriteLine ( "Base.IFoo.CallFromIntfDerived");}}

Public class deive: base, ifoo {public new void callfromobjbase () {system.console.writeline ("Derived.callFromObjbase);}

Public override void callfromObjderived () {system.console.writeline ("derived.callfromobjderive);}

Public override void callfromintfderived () {system.console.writeline ("derived.ifoo.callfromintfderive);}}

Class entrypoint {[stathread] static void main (String [] args) {base b = new base (), d = new derived (); b.callfromobjbase ();

D.callfromobjbase (); d.callfromobjderived ();

IFOO I = (IFOO) B;

i.callfromintfbase ();

i = (ifoo) d;

i.callfromintfderived ();}}}

After compiling it into callit.exe, start debugging with Windbg. After entering debugging, you can use the SOS! Name2ee command to view the current state of the specified type, such as:

The following is quoted:

0: 000>! Name2ee callit.exe flier.derived

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodTable: 00975288

EECLASS: 06C63414

Name: flier.derived

Use! Dumpclass command to further view Type Details:

The following is quoted:

0: 000>! Dumpclass 06c63414

Class name: flier.derived

MDToken: 02000004 ()

Parent Class: 06c6334c

ClassLoader: 0015EE08

Method Table: 00975288

VTable Slots: 9

Total Method Slots: B

Class Attributes: 100001:

Flags: 1000003

NumInstanceFields: 0

NumStaticfields: 0

ThreadStaticOffset: 0

ThreadStaticsSize: 0

ContextStaticOffset: 0

ContextStaticsSize: 0

You can find that the derived type has 11 Method Slot, but only 9 VTable Slot. Use! Dumpmt further review:

The following is quoted:

0: 000>! Dumpmt -md 00975288

EECLASS: 06C63414

Module: 00167D98

Name: flier.derived

MDToken: 02000004 (D: TempcallitcallIndebugCallit.exe)

MethodTable Flags: 80000

Number of ifaces in iFacemap: 1

Interface map: 009752E0

Slots in vTable: 11

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodDesc TABLE

Entry MethodDesc Jit Name

79b7c4eb 79b7c4f0 none [default] [hasthis] string system.Object.toString ()

79b7c473 79b7c478 none [default] [hasthis] boolean system.Object.equals (Object)

79b7c48b 79b7c490 none [default] [hasthis] i4 system.Object.gethashcode ()

79b7c52b 79b7c530 none [default] [hasthis] void system.Object.Finalize () 0097525B 00975260 None [default] [hasthis] void flier.derived.callfromObjderived ()

009751AB 009751B0 NONE [Default] [Hasthis] void flier.base.callfromintfbase ()

0097526B 00975270 None [default] [hasthis] void flier.derived.callfromintfderived ()

// The following starts for the IFOO interface method table

009751AB 009751B0 NONE [Default] [Hasthis] void flier.base.callfromintfbase ()

0097526B 00975270 None [default] [hasthis] void flier.derived.callfromintfderived ()

// The following start is a non-virtual method table

0097524B 00975250 None [default] [hasthis] void flier.derived.callfromobjbase ()

0097527B 00975280 None [default] [hasthis] void flier.derived..ctor ()

It can be seen that Don Box said in the book, the type of method table is divided into dummy method and non-virtual method tables. The front 9 Method Slot forms Derived vTable, and the latter SLOT saves non-virtual methods. Similarly to the situation of checking the Base class:

The following is quoted:

0: 000>! Name2ee callit.exe flier.base

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodTable: 009751D8

EECLASS: 06C6334C

Name: Flier.Base

0: 000> dumpclass 06c6334c Class Name:! Flier.Base mdToken: 02000003 () Parent Class: 79b7c3c8 ClassLoader: 0015ee08 Method Table: 009751d8 Vtable Slots: 7 Total Method Slots: 9 Class Attributes: 100001: Flags: 1000003 NumInstanceFields: 0 NumStaticFields : 0 ThreadStaticOffset: 0 ThreadStaticssize: 0 ContextStaticOffset: 0 ContextStaticsSize: 0

0: 000> dumpmt -md 009751d8 EEClass:! 06c6334c Module: 00167d98 Name: flier.Base mdToken: 02000003 (D: TempCallItCallItinDebugCallIt.exe) MethodTable Flags: 80000 Number of IFaces in IFaceMap: 1 Interface Map: 00975228 Slots in VTable: 9 -------------------------------------- MethodDesc Table Entry MethodDesc Jit Name 79b7c4eb 79b7c4f0 none [default] [hasThis] String System.Object.ToString () 79b7c473 79b7c478 None [DEFAULT] [hasThis] Boolean System.Object.Equals (Object) 79b7c48b 79b7c490 None [DEFAULT] [hasThis] I4 System.Object.GetHashCode () 79b7c52b 79b7c530 None [ DEFAULT] [hasThis] Void System.Object.Finalize () 0097519b 009751a0 None [DEFAULT] [hasThis] Void flier.Base.CallFromObjDerived () // start the interface method table IFoo 009751ab 009751b0 None [DEFAULT] [hasThis] Void flier .Base.callfromintfbase () 009751BB 009751C0 NONE [Default] [Hasthis] void flier.base.callfromintfderived () // The following start is non-virtual method table 0097518B 00975190 None [default] [Hasthis] void Flier .BASE.CALLFROMOBJBASE () 009751CB 009751D0 NONE [DEFAULT] [Hasthis] Void Flier.Base..ctor () For each interface, the CLR is actually maintained separately. For example, the Base class is pointed out that there is an interface method mapping table at address 0x009752E0 to see the contents:

The following is quoted:

0: 000> DD 0x009752E0

009752E0 00975138 00070001 000000 000,0000000

Each interface mapping table entry consists of 2 DWORD, and one DWORD is the address of the interface method table.

The following is quoted:

0: 000>! Dumpmt -md 00975138

EECLASS: 06C633B0

Module: 00167D98

Name: Flier.ifoo

MDToken: 02000002 (D: tempcallitcallitindebugcallit.exe)

MethodTable Flags: 80000

Number of iFaces in iFacemap: 0

Interface map: 0097516C

Slots in vTable: 2

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodDesc TABLE

Entry MethodDesc Jit Name

00975EB 009750F0 none [default] [Hasthis] void flier.ifoo.callfromintfbase () 00975113 00975118 None [default] [hasthis] void flier.ifoo.callfromintfderived ()

Comparison will find that the interface mapping table points to the BASE and Derived classes is the same.

The following is quoted:

0: 000> dd 009752e0

009752E0 00975138 00070001 000000 000,0000000

0: 000> dd 00975228 0097528 00975138 000,000 00000000 000,00000

Just the interface mapping table entry 2nd DWORD high Word Name This interface is different in the starting index in the original method table (BASE 5, Derived 7). This is consistent with the interface mapping table structure shown in That picture 167 in "Nature".

After understanding the physical structure of the method, we will then analyze the dynamic call mechanism of the method.

From the method of call type, CLR supports direct calls, indirect calls, and rare TAIL CALL mode.

Direct calls are the most common, and can be divided into CallVirt instructions using the false method and the Call and JMP instructions that do not use the false method. Indirect calls are slightly rare, and two sets of instructions in LDFTN / Calli and LDVIRTFTN / Calli are acquired from the stack, and the semantically equivalent to the Call / CallVirt command. Tail Call calls more sees, similar to JMP, but as a prefix instruction is attached to the Call / Calli / CallVirt command.

Below we make a simple analysis of the most common direct calls, first take a look at an example program virt_not.il:

The following is quoted:

.assembly extern mscorlib {}

.assembly virt_not {}

.Module Virt_not.exe

.ctor () {return () {ldstr "a :: foo" call void [mscorlib] system.console :: writeline (String) Ret} .method Public Virtual Void Bar () {ldstr "A :: Bar" Call void [mscorlib] system.console :: writeline (string) Ret}. {ldster "a :: baz" call void [mscorlib ] System.Console :: WriteLine (String) Ret}}}

.class public b extends a {.method public specialname void .ctor () {RET} .method public void foo () {ldstr "b :: foo" call void [mscorlib] system.console :: writeline (string) Ret} .method public virtual void bar () {ldstr "b :: bar" call void [mscorlib] system.console :: writeline (String) Ret} .Method public virtual newslot void baz () {ldstr "b :: baz" Call void [mscorlib] System.Console :: WriteLine (string) ret}} .method public static void Exec () {.entrypoint newobj instance void B ::. ctor () // create instance of derived class castclass class A // cast IT to base class

Dup // We need 3 instance pointers dup // on Stack for 3 Calls

Call Instance Void A :: Foo () Callvirt Instance Void A :: Bar () Callvirt Instance Void A :: Baz ()

Ret}

The above code is to write directly using IL assembly, and its EXEC function will be compiled into IL code as follows:

The following is quoted:

.method public static void exec () CIL Managed

// Sig: 00 00 01

{

.entrypoint

//Method Begins AT RVA 0x209c

// Code Size 28 (0x1c)

.MAXSTACK 8

IL_0000: / * 73 | (06) 000006 * / Newobj Instance Void B ::. Ctor ()

IL_0005: / * 74 | (1B) 000001 * / CastClass Class A

IL_000A: / * 25 | * / DUP

IL_000b: / * 25 | * / DUP

IL_000c: / * 28 | (06) 000003 * / Call Instance Void A :: foo ()

IL_0011: / * 6F | (06) 000004 * / Callvirt instance void A :: bar ()

IL_0016: / * 6F | (06) 000005 * / Callvirt instance void A :: baz ()

IL_001B: / * 2A | * / RET

} // end of method 'Global Functions' :: EXEC

You can see that the call and the callvirt command when calling directly, is a method's token as a parameter. But differences are implementation, the Call command uses the type of method table, and the CallVirt uses the object of the object. After WindBG loads Virt_not.exe, you can use the! IP2md command to use the! Ip2md command to use the! Ip2md command, as follows:

0: 000> g;! CLRSTACK

Breakpoint 0 Hit

THREAD 0

ESP EIP

0012F694 791D6A4A [Frame: PrestubMethodFrame] [Default] [Hasthis] void a.foo ()

0012F6A4 06D90088 [Default] void exec ()

0012F9B0 791DA717 [Frame: gcframe]

0012fa94 791da717 [frame: gcframe]

0: 000> ip2md 06d90088 MethodDesc:! 0x00975070 Jitted by normal JIT Method Name: [DEFAULT] Void Exec () MethodTable 975078 Module: 15cd20 mdToken: 06000001 (C: DevelopMS.NetBooksInside Microsoft .NET IL Assembler CodeVirt_not.EXE) Flags: 10 Method Va: 06d90058

The code of the opposing EXEC method is as follows:

The following is quoted:

0: 000> u 06d90058

06D90058 55 PUSH EBP

06D90059 8BEC MOV EBP, ESP

// newobj instance void b ::. Ctor () 06d9005b 56 Push ESI 06D9005C B9A8519700 MOV ECX, 0x9751A8 // class B method Table address 06d90061 E8B21FBDF9 CALL 00962018 06D90066 8BF0 MOV ESI, ESI

06D90068 8BCE MOV ECX, ESI 06D9006A FF15EC519700 CALL DWORD PTR [009751EC]

// CastClass Class A 06D90070 8BD6 MOV EDX, ESI 06D90072 B900519700 MOV ECX, 0x975100 // class A method Table address 06d90077 E8a00b4672 Call Mscorwks! JIT_CHKCASTCLASS (791F0C1C)

06D9007C 8BF0 MOV ESI, EAX // Object Address 06D9007E 90 NOP 06D9007F 90 NOP

// call instance void a :: foo () 06d90080 8bce MOV ECX, ESI 06D90082 FF1544519700 Call Dword Ptr [00975144]

// callvirt instance void A :: Bar () 06d90088 8bce mov ecx, esi 06d9008a 8b01 mov eax, [ecx] 06d9008c ff5038 call dword ptr [eax 0x38] // callvirt instance void A :: Baz () 06d9008f 8bce mov ecx , ESI 06D90091 8B01 MOV EAX, [ECX] 06D90093 FF503C Call Dword PTR [EAX 0x3c]

06D90096 90 NOP 06D90097 5E POP ESI 06D90098 5D POP EBP 06D90099 C3 RET

It can be seen that the CALL instruction is called through an indirect addressing call function of an absolute address. This call pointing to the code as follows:

The following is quoted:

0: 000> dd 00975144

00975144 009750D3 0000000000000000002

0: 000> u 009750d3 009750d3 e808857dff call 0014D5E0

0: 000> u 0014d5e0 0014d5e0 52 push edx 0014d5e1 68f0301b79 push 0x791b30f0 0014d5e6 55 push ebp 0014d5e7 53 push ebx 0014d5e8 56 push esi 0014d5e9 57 push edi 0014d5ea 8d742410 lea esi, [esp 0x10] 0014d5ee 51 push ecx 0014d5ef 52 push edx 0014d5f0 648b1d2c0e0000 mov ebx, fs: [00000e2c] 0014d5f7 8b7b08 mov edi, [ebx 0x8] 0014d5fa 897e04 mov [esi 0x4], edi 0014d5fd 897308 mov [ebx 0x8], esi 0014d600 56 push esi 0014d601 e844940879 call mscorwks PreStubWorker (791d6a4a! ) 0014D606 897B08 MOV [EBX 0x8], EDI

Oh, is this not the last analysis of the JIT pack code?

After JIT, the above EXEC code calls A :: Foo method is modified by JIT to:

The following is quoted:

0: 000> DD 975144

00975144 009750D3 0000000000000000002

0: 000> U 009750D3 009750D3 E9F8AF4106 JMP 06D900D0

0: 000> ip2md 06d900d0 MethodDesc:! 0x009750d8 Jitted by normal JIT Method Name: [DEFAULT] [hasThis] Void A.Foo () MethodTable 975100 Module: 15cd20 mdToken: 06000003 (C: DevelopMS.NetBooksInside Microsoft .NET IL Assembler CodeVirt_not. EXE) FLAGS: 0 Method VA: 06D900D0 That is to say, the CALL instruction actually calls the code of the A :: FOO method body after JIT.

The CallVirt command uses two segments of indirect addressing to call methods.

The following is quoted:

// Callvirt instance void a :: bar ()

06D90088 8BCE MOV ECX, ESI

06D9008A 8B01 MOV EAX, [ECX]

06D9008C FF5038 Call DWORD PTR [EAX 0x38]

The ESI here is a pointer to the object, and the first DWORD of the object structure is pointed to the pointer to the actual type method table, which is the RuntimeTypeHandle, which is "in the nature", please refer to my previous article "TYPE , RuntimeType and runtimetypeHandle "). The 0x38 offset of the method table is as follows:

The following is quoted:

0: 000>! Dumpmt -md 00975100

EECLASS: 06C63344

Module: 0015CD20

Name: a

MDToken: 02000002 (C: developms.netbooksInde Microsoft .NET IL Assembler CodeVirt_not.exe)

MethodTable Flags: 80000

Number of iFaces in iFacemap: 0

Interface map: 0097514C

Slots in vTable: 8

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodDesc TABLE

Entry MethodDesc Jit Name

79b7c4eb 79b7c4f0 none [default] [hasthis] string system.Object.toString ()

79b7c473 79b7c478 none [default] [hasthis] boolean system.Object.equals (Object)

79b7c48b 79b7c490 none [default] [hasthis] i4 system.Object.gethashcode ()

79b7c52b 79b7c530 none [default] [hasthis] void system.Object.Finalize ()

009750E3 009750E8 None [default] [hasthis] void a.bar ()

009750f3 009750f8 none [default] [hasthis] void a.baz ()

009750c3 009750c8 none [default] [hasthis] void A..ctor ()

009750d3 009750d8 none [default] [hasthis] void a.foo ()

Entry address 000> dd 00975100 00975100 00080000 0000000c 06c63344 00000000 00975110 00120000 0015cd20 0006ffff 0097514c 00975120 00000000 00000008 79b7c4eb 79b7c473 00975130 79b7c48b 79b7c52b 009750e3 009750f3 00975140 009750c3 009750d3 00000000 00000000 00975100 0x38 can see exactly A.Bar () method: 0

The following is quoted:

0: 000> u 009750E3

00975E3 E8F8847DFF CALL 0014D5E0

0: 000> U 14D5E0 0014D5E0 52 Push Edx ... 0014D600 56 Push ESI 0014D601 E844940879 CALL MSCORWKS! PRESTUBWORKER (791D6A4A) 0014D606 897B08 MOV [EBX 0x8], EDI

0: 000> dumpmd 009750e8 Method Name:! [DEFAULT] [hasThis] Void A.Bar () MethodTable 975100 Module: 15cd20 mdToken: 06000004 (C: DevelopMS.NetBooksInside Microsoft .NET IL Assembler CodeVirt_not.EXE) Flags: 0 IL RVA 0000205

Therefore, the CallVirt directive is actually a method of calling the type of variable actually saved object, which is the virtual function semantics we said.

Go back back to the example of the C # code in front, after the JIT is complete:

The following is quoted:

.method private hidebysig static void main (String [] args) CIL Managed

// Sig: 00 01 01 1D 0E

{

.entrypoint

.custom instance void [mscorlib] system.stathreadattribute ::. CTOR () = (01 00 00 00)

// Method Begins AT RVA 0x2120

// Code Size 47 (0x2f)

.MAXSTACK 1

.locals init ([0] Class Flier.base B,

[1] Class Flier.base D,

[2] Class Flier.ifoo I)

IL_0000: / * 73 | (06) 000007 * / Newobj Instance Void Flier.base ::. Ctor ()

IL_0005: / * 0A | * / STLOC.0

IL_0006: / * 73 | (06) 00000B * / Newobj Instance Void Flier.derived ::. Ctor ()

IL_000b: / * 0b | * / STLOC.1

IL_000c: / * 06 | * / LDLOC.0

IL_000D: / * 6F | (06) 000003 * / Callvirt Instance Void Flier.Base :: CallFromObjBase ()

IL_0012: / * 07 | * / LDLOC.1IL_0013: / * 6F | (06) 000003 * / Callvirt Instance Void Flier.base :: CallFromObJBase ()

IL_0018: / * 07 | * / LDLOC.1

IL_0019: / * 6F | (06) 000004 * / Callvirt Instance Void Flier.base :: CallFromObjderived ()

IL_001E: / * 06 | * / LDLOC.0

IL_001F: / * 0C | * / STLOC.2

IL_0020: / * 08 | * / LDLOC.2

IL_0021: / * 6F | (06) 000001 * / Callvirt Instance Void Flier.ifoo :: CallFromintfbase ()

IL_0026: / * 07 | * / LDLOC.1

IL_0027: / * 0C | * / STLOC.2

IL_0028: / * 08 | * / LDLOC.2

IL_0029: / * 6F | (06) 000002 * / CallVirt Instance Void Flier.ifoo :: CallFromintfderived ()

IL_002E: / * 2A | * / RET

} // end of method Entrypoint :: main

0: 000> ip2md 06d900a7 MethodDesc:! 0x00975070 Jitted by normal JIT Method Name: [DEFAULT] Void flier.EntryPoint.Main (SZArray String) MethodTable 975088 Module: 167d98 mdToken: 0600000c (D: TempCallItCallItinDebugCallIt.exe) Flags: 10 Method VA : 06d90058

0: 000> u 06d90058 06d90058 55 push ebp 06d90059 8bec mov ebp, esp 06d9005b 83ec10 sub esp, 0x10 06d9005e 57 push edi 06d9005f 56 push esi 06d90060 53 push ebx 06d90061 894dfc mov [ebp-0x4], ecx 06d90064 c745f800000000 mov dword ptr [ EBP-0x8], 0x0 06d9006b 33f6 xor ESI, ESI 06D9006D 33FF XOR EDI, EDI

// newobj instance void flier.Base ::. Ctor () 06d9006f b9d8519700 mov ecx, 0x9751d8 // class method table flier.Base 06d90074 e89f1fbdf9 call 00962018 06d90079 8bd8 mov ebx, eax 06d9007b 8bcb mov ecx, ebx 06d9007d ff1520529700 call dword ptr [00975220] // Call Flier.Base ::. Ctor () 06d90083 895df8 MOV [EBP-0X8], EBX // stloc.0 // newobj instance void flier.derived ::. Ctor () 06d90086 b988529700 MOV ECX, 0x975288 // class method table flier.Derived 06d9008b e8881fbdf9 call 00962018 06d90090 8bd8 mov ebx, eax 06d90092 8bcb mov ecx, ebx 06d90094 ff15d8529700 call dword ptr [009752d8] // call flier.Derived ::. ctor () 06d9009a 8bf3 mov esi, EBX // STLOC.1

06D9009C 8B4DF8 MOV ECX, [EBP-0x8] // LDLOC.0 06D9009F 3909 CMP [ECX], ECX 06D900A1 FF151C529700 Call Dword PTR [0097521C] // CallVirt Instance Void Flier.base :: CallFromObjBase ()

06D900A7 8BCE MOV ECX, ESI // LDLOC.1 06D900A9 3909 CMP [ECX], ECX 06D900AB FF151C529700 CALL DWORD PTR [0097521C] // CallVirt Instance Void Flier.base :: CallFromObJBase ()

06D900B1 8BCE MOV ECX, ESI // LDLOC.1 06D900B3 8B01 MOV EAX, [ECX] 06D900B5 FF5038 CALL DWORD PTR [EAX 0x38] // Callvirt Instance Void Flier.base :: CallFromObjderived ()

06D900B8 8B7DF8 MOV EDI, [EBP-0X8] // LDLOC.0 06D900BB 8BCF MOV ECX, EDI // STLOC.2 06D900BD 8B01 MOV EAX, [ECX] 06d900BF 8B400C MOV EAX, [EAX 0xC] 06d900C2 8B402C MOV EAX, [ eax 0x2c] 06d900c5 ff10 call dword ptr [eax] // callvirt instance void flier.IFoo :: CallFromIntfBase () 06d900c7 8bfe mov edi, esi // ldloc.1 06d900c9 8bcf mov ecx, edi // stloc.2 06d900cb 8b01 mov Eax, [ECX] 06D900CD 8B400C MOV EAX, [EAX 0xC] 06d900d0 8b402c MOV Eax, [EAX 0x2c] 06d900d3 ff5004 Call Dword PTR [EAX 0x4] // Callvirt Instance Void Flier.ifoo :: CallFromintfderived ()

06D900D6 90 NOP 06D900D7 5B POP EBX 06D900D9 5E POP ESI 06D900D9 5F POP EDI 06D900DA 8BE5 MOV ESP, EBP 06D900DC 5D POP EBP 06D900DD C3 RET

In addition to the CALL that has just been analyzed and the CallVirt instruction for virtual functions, there is a more operation of the interface virtual function.

The following is quoted:

06D900BB 8BCF MOV ECX, EDI // STLOC.2

06D900BD 8B01 MOV EAX, [ECX] // Load Object Address Point Type Information Added by Object Structure Headquarters (04AA1B4C) field

06D900BF 8B400C MOV EAX, [EAX 0xC] // Load Global Interface Offset Table Base

06D900C2 8B402C MOV EAX, [EAX 0x2C] // Gets the IFOO interface mapping table offset

06D900C5 FF10 Call DWORD PTR [EAX] // Callvirt Instance Void Flier.ifoo :: CallFromintfbase ()

Use WindBG to dynamically track the above instructions

The following is quoted:

0: 000>! DumpstackObjects

ESP / REG OBJECT NAME

EBX 04AA1B74 FLIER.DERIVED

ECX 04AA2804 System.io.TextWriter / SyncTextWriteresi 04AA1B74 FLIER.DERIVED

EDI 04AA1B68 Flier.base

0012F6A0 04AA1B68 Flier.base

0012F6A4 04AA1B4C System.Object []

0012F6D8 04AA1B4C System.Object []

0012F928 04AA1B4C System.Object []

0012F92C 04AA1B4C System.Object []

EDI points to the object instance of the Flier.Base type (0x04aa1b68)

The following is quoted:

0: 000>! Dumpobj 04aa1b68

Name: Flier.Base

MethodTable 0x009751D8

EECLASS 0x06C6334C

Size 12 (0xc) bytes

MDToken: 02000003 (D: tempcallitcallitindebugcallit.exe)

0: 000> DD 04AA1B68 04AA1B68 009751D8 00000000 00000000 00975288 04AA1B78 00000000 80000000 79B7DAF8 00000015

And this object's offset 0 saves the type information address of this object (0x009751D8)

The following is quoted:

0: 000>! Dumpmt 009751d8

EECLASS: 06C6334C

Module: 00167D98

Name: Flier.Base

MDToken: 02000003 (D: tempcallitcallitindebugcallit.exe)

MethodTable Flags: 80000

Number of ifaces in iFacemap: 1

Interface map: 00975228

Slots in vTable: 9

0: 000> dd 009751d8 009751d8 00080000 000,000c 06c6334c 0097BFF0 009751E8 00120001 00167D98 000FFFF 00975228

The 0xc offset of type information is the entry base address of the global interface offset table (0x0097BFF0)

The following is quoted:

0: 000> DD 0097BFF0

0097BFF0 ???????? ???????? ????????

0097C000 00000000 0097C000 00004000 000,0000000

0097C010 00000000 000003E8 00000001 00975214

0097c020 009752CC 000000000000002

The physical address of the IFOO interface is at the 0x2c offset of this offset table (0x00975214). This address is directly point to the virtual method of the Flier.Base class.

The following is quoted:

0: 000>! Dumpmt -md 009751d8

EECLASS: 06C6334C

Module: 00167D98

Name: Flier.Base

MDToken: 02000003 (D: tempcallitcallitindebugcallit.exe)

MethodTable Flags: 80000

Number of ifaces in iFacemap: 1

Interface map: 00975228

Slots in vTable: 9

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

MethodDesc TABLE

Entry MethodDesc Jit Name

79b7c4eb 79b7c4f0 none [default] [hasthis] string system.Object.toString () 79b7c473 79b7c478 none [default] [hasthis] boolean system.object.equals (Object)

79b7c48b 79b7c490 none [default] [hasthis] i4 system.Object.gethashcode ()

79b7c52b 79b7c530 none [default] [hasthis] void system.Object.Finalize ()

0097519B 009751A0 none [default] [hasthis] void flier.base.callfromobjderived ()

009751AB 009751B0 NONE [Default] [Hasthis] void flier.base.callfromintfbase ()

009751BB 009751C0 NONE [Default] [Hasthis] void flier.base.callfromintfderived ()

0097518B 00975190 None [default] [hasthis] void flier.base.callFromObjbase ()

009751cb 009751d0 none [default] [hasthis] void flier.base..ctor ()

0: 000> dd 009751d8 009751d8 00080000 0000000c 06c6334c 0097bff0 009751e8 00120001 00167d98 0008ffff 00975228 009751f8 00000000 00000009 79b7c4eb 79b7c473 00975208 79b7c48b 79b7c52b 0097519b 009751ab 00975218 009751bb 0097518b 009751cb 00000000 00975228 00975138 00050001 00000000 00000000 00975238 00975288 00000000 00000003 00000000 00975248 e8000008 ff7d9110 00000009 c00020c4

0x0097519B is the entry address of the last flier.base.callfromobjderived () function. Therefore, the CallVirt command called by the interface is actually followed by the following Dispatch route:

Objectptr -> Object -> Class -> Global Interface Map Table -> Class Method Table

For details, please refer to the "Nature" 167 (6.5 - 0.1), -_- b

At this point, the most common modulation mode in the CLR is approximately the process, and there will be an opportunity to continue to analyze other functions such as JMP, indirect calls, and Tail Call.

转载请注明原文地址:https://www.9cbs.com/read-6589.html

New Post(0)