Skip to main content

πŸ”Ž Creating a VM for fun - Part 2: C

<time datetime="2022-05-09 10:39:42 &#43;0200 &#43;0200">9 May 2022</time><span class="px-2 text-primary-500">&middot;</span><span>1225 words</span><span class="px-2 text-primary-500">&middot;</span><span title="Reading time">6 mins</span><span class="px-2 text-primary-500">&middot;</span><span> <span id="views_posts/c vm/index.md" title="views">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"> <path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg> </span> </span> </span><span class="px-2 text-primary-500">&middot;</span><span> <span id="likes_posts/c vm/index.md" title="likes">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg> </span> </span> </span><span class="px-2 text-primary-500">&middot;</span><span> <button id="likes_button" class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400" onclick="process_article()"> <span id="likes_button_heart" style="display:none" class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg> </span> </span> <span id="likes_button_emtpty_heart" class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M244 84L255.1 96L267.1 84.02C300.6 51.37 347 36.51 392.6 44.1C461.5 55.58 512 115.2 512 185.1V190.9C512 232.4 494.8 272.1 464.4 300.4L283.7 469.1C276.2 476.1 266.3 480 256 480C245.7 480 235.8 476.1 228.3 469.1L47.59 300.4C17.23 272.1 0 232.4 0 190.9V185.1C0 115.2 50.52 55.58 119.4 44.1C164.1 36.51 211.4 51.37 244 84C243.1 84 244 84.01 244 84L244 84zM255.1 163.9L210.1 117.1C188.4 96.28 157.6 86.4 127.3 91.44C81.55 99.07 48 138.7 48 185.1V190.9C48 219.1 59.71 246.1 80.34 265.3L256 429.3L431.7 265.3C452.3 246.1 464 219.1 464 190.9V185.1C464 138.7 430.4 99.07 384.7 91.44C354.4 86.4 323.6 96.28 301.9 117.1L255.1 163.9z"/></svg> </span> </span> <span id="likes_button_text">&nbsp;Like</span> </button> </span><span class="px-2 text-primary-500">&middot;</span> <span class="mb-[2px]"> <a href="https://github.com/OxNinja/blog" class="text-lg hover:text-primary-500" rel="noopener noreferrer" target="_blank" title="Edit content" ><span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M490.3 40.4C512.2 62.27 512.2 97.73 490.3 119.6L460.3 149.7L362.3 51.72L392.4 21.66C414.3-.2135 449.7-.2135 471.6 21.66L490.3 40.4zM172.4 241.7L339.7 74.34L437.7 172.3L270.3 339.6C264.2 345.8 256.7 350.4 248.4 353.2L159.6 382.8C150.1 385.6 141.5 383.4 135 376.1C128.6 370.5 126.4 361 129.2 352.4L158.8 263.6C161.6 255.3 166.2 247.8 172.4 241.7V241.7zM192 63.1C209.7 63.1 224 78.33 224 95.1C224 113.7 209.7 127.1 192 127.1H96C78.33 127.1 64 142.3 64 159.1V416C64 433.7 78.33 448 96 448H352C369.7 448 384 433.7 384 416V319.1C384 302.3 398.3 287.1 416 287.1C433.7 287.1 448 302.3 448 319.1V416C448 469 405 512 352 512H96C42.98 512 0 469 0 416V159.1C0 106.1 42.98 63.1 96 63.1H192z"/></svg> </span> </span></a > </span> 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 2: This Article

This is the second part of my series about creating a custom virtual machine: part 1 - assembly VM.

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

Introduction #

Doing the PoC in assembly (see part 1) gave me enough information about how to create my own virtual machine, I got the basic concepts for such a subject, such as:

  • Parsing opcode
  • Emulating instruction
  • Use of virtual registers

It also showed me the limitations of this language, I needed a more sofisticated yet low level one, C was the perfect match πŸ₯΅.

Architecture #

I came with the following flow for the VM:

graph LR; A[Registers init] --> B[Emulate opcode] B --> C{Parsing} C -->|Good opcode| D[Exec instruction] C -->|Unknown opcode| E[Nothing happens] D --> F[Loop] E --> F[Loop] F --> B

PoC||GTFO #

Let’s break down how I created this VM.

Registers #

In order to store information such as inputs or outputs, I needed some registers. These must be readable and writeable from anywhere in my program, I needed to make either a forbidden global variable, or create a local one which will be passed to the used functions. I went with the second solution, as it is less dirty, and I wanted to try my best by using pointers and C stuff.

I created a struct for my registers:

 1typedef struct Registers {
 2  // common operations registers
 3  int a, b, c, d;
 4
 5  // array to work with when manipulating registers' indexes
 6  // each element will point to the address of the correspponding register
 7  // see `setup_registers()` for more details
 8  int *registers[4];
 9
10  // flags are stored in one integer, using masks to extract them
11  // remainder, zero (cmp)
12  int flags;
13} Registers;

I started to work with only 4 registers a, b, c, d and one for the flags after instruction’s execution.

I also needed a way to (re)set the said registers to whatever I wanted, so I created this reset function:

 1/* Set all registers in the array in order to easyliy manupulate them
 2 * like: regs->registers[2] = 0x2a;
 3 * is the same as: regs->c = 0x2a;
 4 */
 5void setup_registers(Registers *regs) {
 6  // each element of the array points to the corresponding register's address
 7  regs->registers[0] = &regs->a;
 8  regs->registers[1] = &regs->b;
 9  regs->registers[2] = &regs->c;
10  regs->registers[3] = &regs->d;
11}
12
13/* Just print the values
14 */
15void print_registers(Registers *regs) {
16  printf("=== Registers: ===\n");
17  printf("a: 0x%x\n", regs->a);
18  printf("b: 0x%x\n", regs->b);
19  printf("c: 0x%x\n", regs->c);
20  printf("d: 0x%x\n", regs->d);
21  printf("flags: 0x%x\n", regs->flags);
22}
23
24/* Force the values of the registers to 0
25 */
26void reset_registers(Registers *regs) {
27  regs->a = 0;
28  regs->b = 0;
29  regs->c = 0;
30  regs->d = 0;
31  regs->flags = 0;
32}

Emulation #

Emulating an instruction is very basic:

  1. Parse the input
  2. Detect the corresponding instruction
  3. Execute the instruction

But I wanted to do something a bit fancy here: instead of just make a big 0xswitch statement, I created a map, or more precisely an array of pointers of functions. Meaning that each entry of the array is a pointer, pointing to the corresponding function to call:

 1void emulate(Registers *regs, int shellcode) {
 2  // parsing the input to extract only the opcode
 3  int opcode = (shellcode & 0xff000000) >> 0x18;
 4
 5  // instructions is an array of pointers of function
 6  // each index points to the according function corresponding to the opcode
 7  // it is very easy to change the opcode for a certain function
 8  void (*instructions[10])(Registers *, int);
 9  // no opcode 0 defined for the moment
10  instructions[1] = my_mov;
11  instructions[2] = my_push;
12  instructions[3] = my_add;
13  instructions[4] = my_sub;
14  instructions[5] = my_jmp;
15  instructions[6] = my_cmp;
16  instructions[7] = my_call;
17  instructions[8] = my_exit;
18  instructions[9] = my_pop;
19
20  // code ommited for future spoilers
21  redacted();
22}

Why this “crazy” stuff instead of the good old switch? You may ask. Well, for the sake of simplicity, yes, s i m p l i c i t y, I used this strategy for a good reason:

1// calling the corresponding function only takes 1 line of code,
2// and no processing at all: no if, nor loop
3(*instructions[opcode])(regs, shellcode);

Then each function, such as my_mov and so, do the wanted behaviour of the corresponding instruction, for example:

 1/* Moves the value into the register
 2 * value is either a register or a plain hex integer
 3 */
 4void my_mov(Registers *regs, int shellcode) {
 5  int is_reg1 = (shellcode & 0x00f00000) >> 0x14;
 6  if (is_reg1 == 0x1) {
 7    // get index of target reg
 8    int target_reg = (shellcode & 0x000f0000) >> 0x10;
 9    // get value to mov
10    int is_reg2 = (shellcode & 0x0000f000) >> 0xc;
11    // get moved value
12    int value = (shellcode & 0x00000fff);
13    // if source is a register and not a value
14    if (is_reg2 == 0x1) {
15      int source_reg = value >> 0x8;
16      value = *regs->registers[source_reg];
17    }
18
19    // finally, move the value into the register
20    *regs->registers[target_reg] = value;
21
22  } else {
23    except("Invalid value for mov (arg a is not a register)");
24  }
25}

Which leads to my next subject: parsing.

Parsing #

Yes, I did not mentionned how my instructions are encoded and how to parse them. See the following scheme to understand my way of crafting one instruction:

opcodeisReg1value1isReg2value2
01100045

This instruction (0x1100045) is a mov a, 0x45. Yes this is a bit silly but here is an another scheme in order to better explain my way of encoding my instructions:

graph LR; A[opcode] --> B[isReg1] B -->|==1| C[value1, index of register] B -->|==0| D[value1, plain hex] C --> E[isReg2] D --> E E -->|==1| F[value2, index of register] E -->|==0| G[value2, plain hex, left 0-padded]

And here is the size of each portion of the instruction:

  • opcode: word
  • isReg1: byte
  • value1: byte if isReg1 == 1, any size else (depends on the instruction)
  • isReg2: byte
  • value2: byte if isReg2 == 1, any size else (depends on the instruction)

I made the choice to use a constant-sized instruction set, to help me parsing each one, instead of having to hardcode every variant that a variable-length instruction set would require.

Once this logic has been declared, there was one thing left to do: actually parsing the instructions. In fact, as you may have noticed in my instruction functions (my_mov() my_add()...), I used binary masking and shifting like so: (a && 0xff) >> 0x10.

Demo time #

I used the following code:

 1int main(void) {
 2  // init the struct
 3  Registers regs;
 4  // setup the registers' array
 5  setup_registers(&regs);
 6
 7  // set everything to 0
 8  reset_registers(&regs);
 9  print_registers(&regs);
10
11  // mov a, 0x45
12  emulate(&regs, 0x1100045);
13  print_registers(&regs);
14
15  // mov c, 0x2
16  emulate(&regs, 0x1120002);
17  print_registers(&regs);
18
19  // exit(a)
20  emulate(&regs, 0x8000000);
21
22  // yes, pointless return but it is for the personnal ethics
23  return 0;
24}

demo


Special thanks to:

  • Masterfox: for helping me debugging my issues with pointers and structs
  • Nofix: for helping me debugging my array of pointers of functions stuff
Custom VM - This article is part of a series.
Part 2: This Article

Related

Draft
πŸ”Ž Creating a VM for fun - Part 1: ASM
<time datetime="2022-03-17 10:39:42 &#43;0200 &#43;0200">17 March 2022</time><span class="px-2 text-primary-500">&middot;</span><span>451 words</span><span class="px-2 text-primary-500">&middot;</span><span title="Reading time">3 mins</span><span class="px-2 text-primary-500">&middot;</span><span> <span id="views_posts/assembly vm/index.md" title="views">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"> <path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg> </span> </span> </span><span class="px-2 text-primary-500">&middot;</span><span> <span id="likes_posts/assembly vm/index.md" title="likes">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg> </span> </span> </span>
Custom VM assembly low-level reverse
🏌️ Binary golfing - Introduction
<time datetime="2022-04-15 16:00:00 &#43;0000 UTC">15 April 2022</time><span class="px-2 text-primary-500">&middot;</span><span>711 words</span><span class="px-2 text-primary-500">&middot;</span><span title="Reading time">4 mins</span><span class="px-2 text-primary-500">&middot;</span><span> <span id="views_posts/binary golf/index.md" title="views">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"> <path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg> </span> </span> </span><span class="px-2 text-primary-500">&middot;</span><span> <span id="likes_posts/binary golf/index.md" title="likes">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg> </span> </span> </span>
Binary golfing binary elf golf low-level
Les pyjails pour les dΓ©butants
<time datetime="2019-03-09 18:30:00 &#43;0000 UTC">9 March 2019</time><span class="px-2 text-primary-500">&middot;</span><span>513 words</span><span class="px-2 text-primary-500">&middot;</span><span title="Reading time">3 mins</span><span class="px-2 text-primary-500">&middot;</span><span> <span id="views_posts/les pyjails pour les dΓ©butants/index.md" title="views">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"> <path fill="currentColor" d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg> </span> </span> </span><span class="px-2 text-primary-500">&middot;</span><span> <span id="likes_posts/les pyjails pour les dΓ©butants/index.md" title="likes">0</span> <span class="inline-block align-text-bottom"> <span class="relative block icon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="currentColor" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg> </span> </span> </span>
ctf jail python