#include #include #include #include void caller(void (*trampoline)()) { puts("Attempting to call a trampoline..."); trampoline(); } void do_trampoline() { void nested() { puts("Succeeded."); } caller(nested); } void do_exploit() { puts("Attempting to simulate a buffer overflow exploit..."); #ifdef __i386__ __asm__ __volatile__( "movl $1f,%%eax\n\t" ".byte 0x68; popl %%ecx; jmp *%%eax; nop\n\t" "pushl %%esp\n\t" "ret\n\t" "1:" : : : "ax", "cx"); #elif defined(__x86_64__) __asm__ __volatile__( "mov $1f,%%rax\n\t" ".byte 0x68; pop %%rcx; jmp *%%rax; nop\n\t" "push %%rsp\n\t" "ret\n\t" "1:" : : : "ax", "cx"); #else #error Wrong architecture #endif puts("Succeeded."); } #define USAGE \ "Usage: %s OPTION\n" \ "Non-executable user stack area tests\n\n" \ " -t\tcall a GCC trampoline\n" \ " -e\tsimulate a buffer overflow exploit\n" \ " -b\tsimulate an exploit after a trampoline call\n" void usage(char *name) { printf(USAGE, name ? name : "stacktest"); exit(1); } int main(int argc, char **argv) { if (argc != 2) usage(argv[0]); if (argv[1][0] != '-' || strlen(argv[1]) != 2) usage(argv[0]); switch (argv[1][1]) { case 't': do_trampoline(); break; case 'b': do_trampoline(); case 'e': do_exploit(); break; default: usage(argv[0]); } return 0; }