112 lines
2.4 KiB
C++
112 lines
2.4 KiB
C++
#include <assert.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <stdio.h>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
using std::ofstream;
|
|
using std::ifstream;
|
|
using std::ios;
|
|
|
|
struct A {
|
|
A():value(123) {}
|
|
int value;
|
|
virtual int access() { return this->value; }
|
|
};
|
|
struct B {
|
|
B():value(456) {}
|
|
int value;
|
|
virtual int access() { return this->value; }
|
|
};
|
|
struct C : public A, public B {
|
|
C():better_value(789) {}
|
|
int better_value;
|
|
virtual int access() { return this->better_value; }
|
|
};
|
|
struct D: public C {
|
|
D():other_value(987) {}
|
|
int other_value;
|
|
virtual int access() { return this->other_value; }
|
|
};
|
|
|
|
volatile static int signal_count = 0;
|
|
|
|
sigjmp_buf before_segv;
|
|
|
|
static void
|
|
handler(int sig, siginfo_t *si, void *unused)
|
|
{
|
|
/*
|
|
printf("Got SIGSEGV at address: 0x%lx\n",
|
|
(long) si->si_addr);
|
|
*/
|
|
|
|
signal_count++;
|
|
/* You are not supposed to longjmp out of a signal handler but it seems
|
|
to work for this test case and it simplifies it */
|
|
siglongjmp(before_segv, 1);
|
|
/* exit(1); */
|
|
}
|
|
|
|
/* Access one of the vtable_map variables generated by this .o */
|
|
extern void * _ZN4_VTVI1BE12__vtable_mapE;
|
|
|
|
/* Access one of the vtable_map variables generated by libstdc++ */
|
|
extern void * _ZN4_VTVISt8ios_baseE12__vtable_mapE;
|
|
|
|
int use(B *b)
|
|
{
|
|
int ret;
|
|
|
|
ret = sigsetjmp(before_segv, 1);
|
|
if (ret == 0)
|
|
{
|
|
/* This should generate a segmentation violation. ie: at this point it should
|
|
be protected */
|
|
_ZN4_VTVI1BE12__vtable_mapE = 0;
|
|
}
|
|
assert(ret == 1 && signal_count == 1);
|
|
|
|
ret = sigsetjmp(before_segv, 1);
|
|
if (ret == 0)
|
|
{
|
|
/* Try to modify one of the vtable_map variables in the stdc++ library.
|
|
This should generate a segmentation violation. ie: at this point it
|
|
should be protected */
|
|
_ZN4_VTVISt8ios_baseE12__vtable_mapE = 0;
|
|
}
|
|
assert(ret == 1 && signal_count == 2);
|
|
|
|
return b->access();
|
|
}
|
|
|
|
void myread(std::istream * in)
|
|
{
|
|
char input_str[50] = "\0";
|
|
if (in->good())
|
|
(*in) >> input_str;
|
|
std::cout << input_str << std::endl;
|
|
delete in;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
ifstream * infile = new ifstream("./thunk_vtable_map_attack.cpp");
|
|
myread(infile);
|
|
|
|
/* Set up handler for SIGSEGV. */
|
|
struct sigaction sa;
|
|
sa.sa_flags = SA_SIGINFO;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_sigaction = handler;
|
|
if (sigaction(SIGSEGV, &sa, NULL) == -1)
|
|
assert(0);
|
|
|
|
C c;
|
|
assert(use(&c) == 789);
|
|
|
|
return 0;
|
|
}
|