How I wrote a "hypervisor" for defcon ctf

(Full writeup coming out soon)

Here's a story of how I wrote a very simple "hypervisor" for defcon ctf, or at least emulate a kernel mode code so that I can debug.

Problem

I wanted to be able to do some dynamic analysis on kernel-mode program for RTOoOS challenge. I wished I could've stuck it in like a GDB instance and it just worked.

Except the problem was:

  • The kernel had very weird hyper-calling mechanisms which were totally incompatible to linux syscalls.
  • The kernel was loaded at address 0, and some of the unique bugs of this was entirely dependent on being at address 0.

So I first started with tackling the first issue. I simply just monkey patched the essential hypercalls (fortunately they are all in the same location):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
seg000:0000000000000055 ; __int64 __fastcall sys_putchar(char)
seg000:0000000000000055 sys_putchar proc near ; CODE XREF: sys_write:sys_ls↓j
seg000:0000000000000055 ; put_str+37↓p
seg000:0000000000000055 push rdi
seg000:0000000000000056 mov rsi, rsp
seg000:0000000000000059 mov edi, 1
seg000:000000000000005E mov edx, edi
seg000:0000000000000060 mov eax, edi
seg000:0000000000000062 syscall ; Low latency system call
seg000:0000000000000064 pop rdi
seg000:0000000000000065 retn
seg000:0000000000000065 sys_putchar endp
seg000:0000000000000065
seg000:0000000000000065 ; ---------------------------------------------------------------------------
seg000:0000000000000066 db 0
seg000:0000000000000067 db 0
seg000:0000000000000068 ; ---------------------------------------------------------------------------
seg000:0000000000000068 retn
seg000:0000000000000069
seg000:0000000000000069 ; =============== S U B R O U T I N E =======================================
seg000:0000000000000069
seg000:0000000000000069
seg000:0000000000000069 ; __int64 __fastcall sys_read_input(__int64 a1, __int64 a2)
seg000:0000000000000069 sys_read_input proc near ; CODE XREF: _start+8E↓p
seg000:0000000000000069
seg000:0000000000000069 ; FUNCTION CHUNK AT seg000:0000000000000083 SIZE 00000006 BYTES
seg000:0000000000000069
seg000:0000000000000069 mov edx, esi
seg000:000000000000006B mov rsi, rdi
seg000:000000000000006E xor edi, edi
seg000:0000000000000070 xor eax, eax
seg000:0000000000000072 syscall ; Low latency system call
seg000:0000000000000074 jmp short loc_83
seg000:0000000000000074 sys_read_input endp
seg000:0000000000000074
seg000:0000000000000076
seg000:0000000000000076 ; =============== S U B R O U T I N E =======================================
seg000:0000000000000076
seg000:0000000000000076
seg000:0000000000000076 ; __int64 __fastcall sys_write(char *a1)
seg000:0000000000000076 sys_write proc near ; CODE XREF: do_command+82↓p
seg000:0000000000000076 ; do_command+D7↓p ...
seg000:0000000000000076 call put_str
seg000:000000000000007B mov edi, 0Ah
seg000:0000000000000080
seg000:0000000000000080 sys_ls: ; CODE XREF: do_command+AA↓p
seg000:0000000000000080 jmp short sys_putchar
seg000:0000000000000082 ; ---------------------------------------------------------------------------
seg000:0000000000000082 retn
seg000:0000000000000082 sys_write endp
seg000:0000000000000082
seg000:0000000000000083 ; ---------------------------------------------------------------------------
seg000:0000000000000083 ; START OF FUNCTION CHUNK FOR sys_read_input
seg000:0000000000000083
seg000:0000000000000083 loc_83: ; CODE XREF: sys_read_input+B↑j
seg000:0000000000000083 ; do_command+18D↓p
seg000:0000000000000083 mov byte ptr [rsi+rax-1], 0
seg000:0000000000000088 retn
seg000:0000000000000088 ; END OF FUNCTION CHUNK FOR sys_read_input

Essentially the code up there is just rewritting the sys_putchar, sys_write_line, and sys_read hypercalls.

Now time to do the second part of this scheme: loading the code into address 0 \. I remembered a technique that you can actually mmap address 0, but it will require root to do so.

Without ado, here's my hypervisor code for that. It isn't a full-blown hypervisor, but it was good enough to locally debug it in gdb, hehehehe....

Full writeup for this coming soon...

Share