Skip to main content

🔎 Creating a VM for fun - Part 4: Implementation and refacto

·461 words·3 mins· loading · loading · · Draft
Custom VM c low-level reverse
0xNinja
Author
0xNinja
mov al, 11
Table of Contents
Custom VM - This article is part of a series.
Part 4: This Article

The code is here: https://github.com/OxNinja/C-VM

Step 1: stack first
#

The first thing I did was implementing the stack, according to the previous posts of this series. I changed the code a little bit, but the idea stays the same.

The patched code for the stack:

 1typedef struct stack_node {
 2  // Chained list
 3  struct stack_node *prev;
 4  struct stack_node *next;
 5  // Void pointer for values
 6  // each stack node will have a pointer towards the target value
 7  int *val;
 8} stack_node;
 9
10typedef struct stack {
11  // Pointers to first and last elements
12  stack_node *first;
13  stack_node *last;
14} stack;

My new take on this project was to code everything in the same .h file, to ease using this on other projects. The first version was composed of many .h and .c files, which helped while developping, but needed more work to implement on external projects.

Now, one shall only #include "vm.h" to get started!

Step 2: add instructions
#

I then re-implemented my old code for the instructions and the parser. This was very easy, and needed 0 fix surprisingly, but who am I to spit like that.

So as the last version, here is the code:

 1void vm_emulate(registers *regs, stack *s, int shellcode) {
 2  int opcode = (shellcode & 0xff000000) >> 0x18;
 3  
 4  // instructions is an array of pointers of function
 5  // each index points to the according function corresponding to the opcode
 6  // it is very easy to change the opcode for a certain function
 7  void (*instructions[10])(registers *, stack *, int);
 8  // no opcode 0 defined for the moment
 9  instructions[1] = vm_mov;
10  instructions[2] = vm_push;
11  instructions[3] = vm_add;
12  instructions[4] = vm_sub;
13  instructions[5] = vm_jmp;
14  instructions[6] = vm_cmp;
15  instructions[7] = vm_call;
16  instructions[8] = vm_exit;
17  instructions[9] = vm_pop;                                                 
18  // this is not optimal, as this occurs every time we want to emulate code
19  // one should declare this array once for all for better performance
20  
21  (*instructions[opcode])(regs, s, shellcode);
22}

Step 3: quick test
#

I could test my code with the following simple testcase:

 1#include <stdio.h>
 2#include <stdlib.h>
 3
 4#include "vm.h"
 5
 6int main(void) {
 7  // init VM
 8  //   init stack
 9  stack *stack = stack_init();
10  //   init heap?
11  //   init registers
12  registers *regs = registers_init(stack);
13
14  registers_print(regs);
15
16  // emulate some instructions
17  // mov a, 0x45
18  vm_emulate(regs, stack, 0x1100045);
19  // mov c, 0x2
20  vm_emulate(regs, stack, 0x1120002);
21  registers_print(regs);
22  // exit(a)
23  vm_emulate(regs, stack, 0x8000000);
24
25  return 0;
26}

Step 4: add push/pop
#

Work in progress

Wrote code for stack-related stuff (push, pop).

Step 5: test the whole
#

Custom VM - This article is part of a series.
Part 4: This Article

Related

Draft
🔎 Creating a VM for fun - Part 3: C virtual stack
·919 words·5 mins· loading · loading
Custom VM c low-level reverse
Draft
🔎 Creating a VM for fun - Part 2: C
·1225 words·6 mins· loading · loading
Custom VM c low-level reverse
Draft
🔎 Creating a VM for fun - Part 1: ASM
·451 words·3 mins· loading · loading
Custom VM assembly low-level reverse
🔎 Linux Kernel Module - Introduction
·332 words·2 mins· loading · loading
LKM c lkm low-level
🏌️ BGGP3 - How to crash a famous JS engine for fun
·1571 words·8 mins· loading · loading
Binary golfing bggp low-level reverse golf js fuzz
Draft
🔎 xchg rax, rax
·1526 words·8 mins· loading · loading
assembly low-level