/** MEESIL: Multipurpose Exploration Engine Software Integration Library An open-source library designed for the remote control of semi-autonomous mobile devices, such as remote control toys, smart thermostats, flying bombs, etc. */ #include <stdio.h> #include <stdlib.h> /** These should be enough for anyone. If you want more, I find you wanting. */ #define MEESIL_MAX_ACTUATORS 4 #define MEESIL_MAX_SENSORS 4 #define MEESIL_MAX_OPCODES 8 /* Forward declare the MEESIL struct */ struct MEESIL; /** This user-defined function drives the actual machine: it writes m->actuators to physical world, and reads world into m->sensors. */ typedef void (*MEESIL_RUN_FUNCTION)(struct MEESIL *m); /** This struct represents the control state of a MEESIL vehicle. */ struct MEESIL { /** Control actuator values get loaded here: */ int actuators[MEESIL_MAX_ACTUATORS]; /** Input sensor values get loaded here: */ int sensors[MEESIL_MAX_SENSORS]; /** Control firmware gets loaded here: */ unsigned char opcodes[MEESIL_MAX_OPCODES]; /** This function actually runs the machine. */ MEESIL_RUN_FUNCTION run; }; /** Load MEESCRIPT byte opcodes from the input file, until you reach a -1 opcode (or EOF). */ void meesil_load(struct MEESIL *m,FILE *input) { int index=0; int opcode=0; while (1==fscanf(input,"%x",&opcode)) { if (opcode==-1) return; m->opcodes[index++]=opcode; } } /** Debug function: print what's in the struct */ void meesil_print(struct MEESIL *m,const char *status) { int i; printf("MEESIL state: %s\n",status); for (i=0;i<MEESIL_MAX_ACTUATORS;i++) printf(" actuators[%d]=%d sensors[%d]=%d\n", i,m->actuators[i], i,m->sensors[i]); printf(" run=%p\n",m->run); } /** Run the meesil control loop forever. */ void meesil_run(struct MEESIL *m) { int i=0; unsigned int index=0; while (1) { /* Read next step from the firmware */ int opcode=m->opcodes[index++]; if (opcode==1) for (i=0;i<MEESIL_MAX_ACTUATORS;i++) m->actuators[i]=0; /* STOP! */ /* meesil_execute_opcode(m,opcode); <-- omitted for now */ if (index>=MEESIL_MAX_OPCODES) index=0; /* wraparound */ /* Write firmware values to real world */ m->run(m); } } /** Gosh, here's a function you hope you never need to call. Really, nobody should ever call this. Not even sure why we put it in here. */ void meesil_self_destruct(void) { puts(" SELF DESTRUCT ACTIVATED. Evac to MINIMUM SAFE DISTANCE of 150 meters in the next 10 seconds!"); exit(1313); } void meesil_demo_run(struct MEESIL *m) { meesil_print(m,"demo_run"); static long nruns=0; nruns++; if (nruns>=2) { printf("That's all, you get the picture?\n"); exit(0); } } void foo(void) { printf("MEESIL v0.1 active.\n"); printf(" Self-destruct routine at %p\n", meesil_self_destruct); struct MEESIL *m=(struct MEESIL *)calloc(1,sizeof(struct MEESIL)); m->run=meesil_demo_run; meesil_print(m,"before load"); meesil_load(m,stdin); meesil_print(m,"after load"); meesil_run(m); }This works fine ... as long as we provide no more than 8 opcodes as input (MEESIL_MAX_OPCODES).
1 2 3 4 5 6 7 8Reminder from CS 301: two hex digits make one byte. Bytes get loaded into an int or pointer starting from the little end because x86 is little-endian. So the first byte in 0x400f4a is 0x4a, then 0x0f, then 0x04, then 5 zero bytes, which is why we load them in that order.
4a 0f 40 00 00 00 00 00 -1
1 2 3 4 5 6 7 8In a real program, we usually don't get a nice clear printout with the address of vulnerable functions, but an attacker can still extract this data with a debugger (if an identical system is available), or by just exhaustively trying addresses until they find something useful.
4a 0f -1
Many big programs like web browsers and word processors are written in C++. Unlike plain C, it's rare to have structs with pointers to functions, instead C++ uses classes with virtual methods. But the same sort of direct memory manipulation attacks can target the virtual function table (vtable). Here we're overwriting the vtable itself, a more common attack targets the vtable pointer stored in each class.
class parent { public: virtual void print(void) { puts("parent print method: Yes, walter."); } virtual void exit(void) { puts("parent exit method: I'm done."); } }; class child : public parent { public: virtual void print(void) { puts("child print method: Sup?"); } virtual void exit(void) { puts("child exit method: out"); } }; // There's one vtable (virtual function table) // for each class--all parents point to the same parent vtable; // all children point to the same child vtable. struct vtable { void *fun[10]; }; // Any class that has virtual methods has a vtable pointer, // often a hidden first field in the class. struct class_with_vtable { vtable *vt; }; #include <sys/mman.h> long foo(void) { parent *p=new child; // Manually extract the child vtable pointer: vtable *v=((class_with_vtable *)p)->vt; printf("child instance contents: "); dump_hex(p,sizeof(child)*8); printf("vtable contents: "); dump_hex(v,sizeof(void *)*8*4); // Get read/write access to everything (otherwise writing to vtable segfaults) mprotect((void *)0x400000,1000*1000,PROT_READ|PROT_WRITE|PROT_EXEC); printf("Modifying the vtable\n"); // Modify the child's vtable to exit when it calls print: v->fun[0]=(void *)0x4010d8; printf("Modified the vtable, running virtual method:\n"); p->print(); return sizeof(child); }