Ping for https://gcc.gnu.org/ml/gcc-patches/2014-08/msg02559.html
Also added Caroline Tice, as libvtv maintainer, to cc and attached virtual_func_test_min_UAF.cpp, which I forgot in the original mail. Patrick On 28.08.2014 13:03, Patrick Wollgast wrote: > This patch contains a port of VTV -fvtable-verify=std for Cygwin and MinGW. > > Since weak symbols on Windows and Linux are implemented differently, and > VTV should have the possibility to be switched on and off, the structure > of the feature had to be modified. > On Linux libstdc++ contains the weak stub functions of VTV. For Cygwin > and MinGW they have been removed, due to the difference of weak symbols. > On Linux and on Windows libstdc++ itself gets build with > -fvtable-verify=std. Since libvtv gets build after libstdc++, and > libstdc++ doesn't contain the stub functions any more, 'undefined > reference' errors are thrown during linking of libstdc++. To prevent > these errors during the linking process a libvtv-0.dll gets build from > the stub functions before libstdc++-6.dll is linked. > At the end of the build process two VTV dlls have been build. One is > called libvtv-0.dll, containing the real functions, the other is called > libvtv_stubs-0.dll, containing the stub functions. Depending on whether > libvtv-0.dll is first found in the dll search path or > libvtv_stubs-0.dll, renamed to libvtv-0.dll, the real functions or the > stub functions are used. > > Testing: > The test builds were configured the following way: > Linux 64bit (from patched and unpatched trunk): > /path/to/configure --prefix=/prefix/gcc-vtv-bin-64 > --enable-libstdcxx-threads --enable-vtable-verify=yes > MinGW 32bit cross compiled: > /path/to/configure --target=i686-w64-mingw32 > --prefix=/prefix/mingw-vtv-bin-32 --with-gnu-ld --with-gnu-as > --enable-fully-dynamic-string --disable-multilib > --enable-libstdcxx-threads --enable-vtable-verify=yes > MinGW 64bit cross compiled: > /path/to/configure --target=x86_64-w64-mingw32 > --prefix=/prefix/mingw-vtv-bin-64 --with-gnu-ld --with-gnu-as > --enable-fully-dynamic-string --disable-multilib > --enable-libstdcxx-threads --enable-vtable-verify=yes > Cygwin 64bit: > /path/to/configure --enable-languages=c,c++ --enable-libstdcxx-threads > --enable-vtable-verify=yes > > At Linux the patched and unpatched version resulted in the same number > of passed tests with 'make check-target-libvtv'. > > Since MinGW was cross compiled the test cases couldn't be built and run > with 'make check-target-libvtv'. Therefore they were built with the > attached makefiles and tested afterwards on Windows 7 64bit. Some test > cases contain Linux specific parts and weren't tested. See the makefiles > for further information. Additionally virtual_func_test_min_UAF.cpp was > also built and tested. All built tests passed. > > Cygwin was just tested on gcc 4.9.0, because the current trunk isn't > building for me. Even the clean trunk without the patch attached to this > mail. On Cygwin with gcc 4.9.0 VTV worked. > > Besides the test cases Botan was also built and tested (gcc 4.9.0) with > MinGW 32bit and VTV. > > regards > -- Beste Grüße, Patrick
#include<iostream> #include<stdio.h> /* * Demonstrates an use after free c++ internally by deleting an object * and resetting its vtable pointing to legitimate functions */ // set pointer size and integer size dependent on architechture #if __x86_64__ /* 64-bit */ const char* arch = "x86_64"; int ptrSize = 8; typedef long long myInt; // 8 byte #else /* 32-bit */ const char* arch = "x86"; int ptrSize = 4; typedef int myInt; // 4 byte #endif // using namespace std; // BASE CLASS class Addition{ protected: // member variables int s1,s2; public: // virtual member function will be implemented in derived class virtual int add(int a,int b){ }; int i; }; // // inherit new class class Add: public Addition{ public: // constructor: /* Add(int a, int b){ s1 = a; s2 = b; }; */ void setvals(int a, int b){ s1 = a; s2 = b; } // implement virtual function virtual int TRIGGER(){ cout<<s1 + s2<<"\n"; }; int j; }; // // use this function in vtable which will be injected void inject(){ printf("%s\n","I've been executed"); } int main(){ printf("We're on a %s architecture\n\n",arch); // create object of inherited class //Add* A = new Add(4,5); Add* A = new Add; //heap allocation happens here A->setvals(4,5); // add attributes A->i = 6; A->j = 7; // get vtable address myInt vtablePTR = NULL; vtablePTR = *((myInt*)A); printf("vtable: %.16x\n", vtablePTR); //function 1 printf("%.16x : %.16x\n", vtablePTR, *((myInt*)vtablePTR)); //function 2 printf("%.16x : %.16x\n", vtablePTR + ptrSize, *((myInt*)(vtablePTR + ptrSize))); // call instantiated virtual function (legitimate) A->TRIGGER(); // FREE OBJECT ! delete A; //A = NULL; // this prevents use after free // get objects address as it is still valid myInt* ObjPTR = (myInt*)A; // let object point to old vtable (inject old vtable) *ObjPTR = vtablePTR; // NOT legitimate A->TRIGGER(); myInt vtable_func = (myInt)inject; // create new vtable myInt vtable_new[2] = {vtable_func, vtable_func}; // let object point to new vtable (inject new vtable) *ObjPTR = (myInt)vtable_new; // USE AFTER FREE (execute injected function in vtable) A->TRIGGER(); __asm__( "nop;" "nop;" "nop;" ); // USE AFTER FREE with data members printf("%i %i\n", A->i, A->j); }