simple vm

first it plays process russian dolls

Hidden Process

The program loads in ld before jumping to the start of 0x8048000 which contains the vm. I used gcore to get a dump of the unpacked image and used Ghidra to find references to the ‘Input :’ string.

char shellcode[0x200];
char curr_opcode;

void exec()
    int ret;
    curr_opcode = get_next_opcode();
    switch(curr_opcode) {
        case 2:
            movmem(); /* mov byte ptr[rd], rs */
        case 6:
            xormem(); /* xor byte ptr[rd], byte ptr[rs] */
        case 7:
            cmpmem(); /* cmp byte ptr[rd], byte ptr[rs] */
        case 9:
            jnz(); /* jnz loc */
        case 10:
            jmp(); /* jmp loc */
        case 11:
            ret = 1;
        default: break;
    return ret;

void trigger()
    int fds[2];
    int guid = getuid();
    if(guid == 0) {
        write(1, "Input :", 8);
        int chk = pipe(fds);
        if(chk == -1) { /*...*/ } 
        chk = fork();
        if(chk == -1) { /*...*/ } 
        if(chk == 0) {
            /* child sets up shellcode */
        } else {
            /* unpacks shellcode */

The vm is simple, buffer[0-6] is the user input, buffer[7] is a generic register, buffer[8] is the zero flag and buffer[9] is the instruction pointer. Everything past that is code.

Here’s the disassembly of the bytecode. The flag is id3*ndh .

0x0 jmp 0x6
0x2 xor byte ptr[0x0], byte ptr [0x0]
0x6 mov byte ptr[0x7], 0x60
0x9 xor byte ptr[0x0], byte ptr [0x7]
0xc mov byte ptr[0x7], 0x9
0xf cmp byte ptr[0x0], byte ptr [0x7]
0x12 jnz 0x2
0x14 mov byte ptr[0x7], 0x66
0x17 xor byte ptr[0x1], byte ptr [0x7]
0x1a mov byte ptr[0x7], 0x2
0x1d cmp byte ptr[0x1], byte ptr [0x7]
0x20 jnz 0x2
0x22 mov byte ptr[0x7], 0x15
0x25 xor byte ptr[0x2], byte ptr [0x7]
0x28 mov byte ptr[0x7], 0x26
0x2b cmp byte ptr[0x2], byte ptr [0x7]
0x2e jnz 0x2
0x30 mov byte ptr[0x7], 0x7
0x33 xor byte ptr[0x3], byte ptr [0x7]
0x36 mov byte ptr[0x7], 0x2d
0x39 cmp byte ptr[0x3], byte ptr [0x7]
0x3c jnz 0x2
0x3e mov byte ptr[0x7], 0x4c
0x41 xor byte ptr[0x4], byte ptr [0x7]
0x44 mov byte ptr[0x7], 0x22
0x47 cmp byte ptr[0x4], byte ptr [0x7]
0x4a jnz 0x2
0x4c mov byte ptr[0x7], 0x63
0x4f xor byte ptr[0x5], byte ptr [0x7]
0x52 mov byte ptr[0x7], 0x7
0x55 cmp byte ptr[0x5], byte ptr [0x7]
0x58 jnz 0x2
0x5a mov byte ptr[0x7], 0x78
0x5d xor byte ptr[0x6], byte ptr [0x7]
0x60 mov byte ptr[0x7], 0x10
0x63 cmp byte ptr[0x6], byte ptr [0x7]
0x66 jnz 0x2
0x68 mov byte ptr[0x0], 0x1