
/**
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);
}