-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
3,269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM kalilinux/kali-rolling | ||
COPY ./labs /labs | ||
RUN apt update | ||
RUN apt install -y build-essential nasm bsdmainutils | ||
RUN apt install -y grub-pc-bin grub-efi-amd64-bin xorriso mtools | ||
RUN apt install -y python3 pip | ||
RUN pip install construct fixedint crc32c portion pypsrp capstone uuid | ||
RUN /bin/bash -c "cd /labs && make" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
CFLAGS = -march=native -std=gnu99 -Wall -nostdlib -nostartfiles -nodefaultlibs -fno-stack-protector -mno-red-zone | ||
MKRESCUE = /usr/bin/grub-mkrescue | ||
GRUB_EFI_FLAGS = -d /usr/lib/grub/x86_64-efi/ | ||
GRUB_BIOS_FLAGS = -d /usr/lib/grub/i386-pc/ | ||
OBJECTS = main.o bootstrap.o common.o protocol.o | ||
|
||
all: kernel_efi.iso kernel_bios.iso | ||
|
||
%.o : %.c | ||
$(CC) $(CFLAGS) -c $< -o $@ | ||
|
||
bootstrap.o : bootstrap.asm | ||
nasm -felf64 $< -o $@ | ||
|
||
kernel_efi.iso: iso/boot/kernel | ||
$(MKRESCUE) $(GRUB_EFI_FLAGS) -o $@ iso | ||
|
||
kernel_bios.iso: iso/boot/kernel | ||
$(MKRESCUE) $(GRUB_BIOS_FLAGS) -o $@ iso | ||
|
||
iso/boot/kernel: $(OBJECTS) | ||
$(LD) -melf_x86_64 $^ -o $@ | ||
|
||
clean: | ||
rm -f *.o iso/boot/kernel *.iso | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
extern kmain | ||
global _start | ||
[bits 32] | ||
|
||
[section .bss] | ||
align 0x1000 | ||
resb 0x2000 | ||
stack_top: | ||
pd: resb 0x1000 * 4 ; 4 PDs = maps 4GB | ||
pdpt: resb 0x1000 ; 1 PDPT | ||
pml4: resb 0x1000 ; 1 PML | ||
|
||
[section .data] | ||
gdt: ; minimal 64-bit GDT | ||
dq 0x0000000000000000 | ||
dq 0x00A09b000000ffff ; kernel CS | ||
dq 0x00C093000000ffff ; kernel DS | ||
gdt_end: ; TODO: TSS | ||
gdtr: | ||
dw gdt_end - gdt - 1 ; GDT limit | ||
dq gdt ; GDT base | ||
|
||
[section .text] | ||
align 8, db 0 | ||
;; multiboot2 header | ||
mb_header_size equ (mb_header_end - mb_header) | ||
mb_header: | ||
dd 0xE85250D6 ; magic field | ||
dd 0 ; architecture field: i386 32-bit protected-mode | ||
dd mb_header_size ; header length field | ||
dd 0xffffffff & -(0xE85250D6 + mb_header_size) ; checksum field | ||
;; termination tag | ||
dw 0 ; tag type | ||
dw 0 ; tag flags | ||
dd 8 ; tag size | ||
mb_header_end: | ||
;; kernel code starts here | ||
_start: | ||
mov esp, stack_top | ||
mov edi, pd | ||
mov ecx, 512*4 | ||
mov eax, 0x87 | ||
init_pde: | ||
mov dword [edi], eax | ||
add eax, 0x200000 | ||
add edi, 8 | ||
dec ecx | ||
jnz init_pde | ||
mov dword [pdpt], pd + 7 | ||
mov dword [pdpt+0x08], pd + 0x1007 | ||
mov dword [pdpt+0x10], pd + 0x2007 | ||
mov dword [pdpt+0x18], pd + 0x3007 | ||
mov eax, pml4 | ||
mov dword [eax], pdpt + 7 | ||
mov cr3, eax ; load page-tables | ||
mov ecx, 0xC0000080 | ||
rdmsr | ||
or eax, 0x101 ; LME | SCE | ||
wrmsr ; set EFER | ||
lgdt [gdtr] ; load 64-bit GDT | ||
mov eax, 0x1ba ; PVI | DE | PSE | PAE | PGE | PCE | ||
mov cr4, eax | ||
mov eax, 0x8000003b ; PG | PE | MP | TS | ET | NE | ||
mov cr0, eax | ||
jmp 0x08:code64 | ||
[bits 64] | ||
code64: | ||
mov ax, 0x10 | ||
mov ds, ax | ||
mov es, ax | ||
mov ss, ax | ||
mov rdi, rbx ; MULTIBOOT_MBI_REGISTER | ||
call kmain |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import os | ||
from subprocess import run | ||
from tempfile import NamedTemporaryFile | ||
|
||
class Code: | ||
def __init__(self, code, sym): | ||
self.code = '[bits 64]\n' | ||
self.code += '\n'.join(f'{k} equ {v:#x}' for (k, v) in sym.items()) | ||
self.code += '\n%include "macros.asm"\n' + code | ||
|
||
def build(self, base_address): | ||
with NamedTemporaryFile('w') as f: | ||
f.write(f'[org {base_address:#x}]\n' + self.code) | ||
f.flush() | ||
run(f'nasm -fbin -o {f.name}.bin {f.name}', shell=True) | ||
|
||
with open(f'{f.name}.bin', 'rb') as fout: | ||
ret = fout.read() | ||
|
||
os.remove(f'{f.name}.bin') | ||
|
||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <x86intrin.h> | ||
#include "protocol.h" | ||
|
||
static uint16_t SerialPort = 0x3f8; /* TODO: set it dynamically */ | ||
|
||
static void outb(uint16_t port, uint8_t val) { | ||
__asm__ __volatile__("outb %0, %1" :: "a"(val), "Nd"(port)); | ||
} | ||
|
||
static uint8_t inb(uint16_t port) { | ||
uint8_t ret; | ||
__asm__ __volatile__("inb %1, %0" : "=a"(ret) : "Nd"(port)); | ||
return ret; | ||
} | ||
|
||
void setup_serial() { | ||
outb(SerialPort + 1, 0x00); /* disable interrupts */ | ||
outb(SerialPort + 3, 0x80); /* enable DLAB */ | ||
outb(SerialPort + 0, 0x01); /* divisor low = 1 (115200 baud) */ | ||
outb(SerialPort + 1, 0x00); /* divisor high = 0 */ | ||
outb(SerialPort + 3, 0x03); /* 8-bit, no parity, 1 stop bit */ | ||
outb(SerialPort + 2, 0xC7); /* FIFO, clear, 14-byte threshold */ | ||
outb(SerialPort + 4, 0x03); /* DTR/RTS */ | ||
} | ||
|
||
void write_serial(const void *data, unsigned long len) { | ||
const uint8_t *ptr = data; | ||
while (len) { | ||
if (!(inb(SerialPort + 5) & 0x20)) | ||
continue; | ||
len -= 1; | ||
outb(SerialPort, *ptr++); | ||
} | ||
} | ||
|
||
void read_serial(void *data, unsigned long len) { | ||
uint8_t *ptr = data; | ||
while (len) { | ||
if (!(inb(SerialPort + 5) & 1)) | ||
continue; /* TODO: yield CPU */ | ||
len -= 1; | ||
*ptr++ = inb(SerialPort); | ||
} | ||
} | ||
|
||
/* TODO: portable implementation supporting older CPUs */ | ||
uint32_t crc32(const void *data, unsigned long len) { | ||
const uint8_t *ptr = data; | ||
uint32_t ret = 0xffffffff; | ||
|
||
while (len--) | ||
ret = _mm_crc32_u8(ret, *ptr++); | ||
|
||
return ret ^ 0xffffffff; | ||
} | ||
|
||
void reset() { | ||
struct { | ||
uint16_t limit; | ||
unsigned long base; | ||
} __attribute__((packed)) idtr = {0}; | ||
|
||
/* Hard-reset by triple-fault */ | ||
__asm__ __volatile__( | ||
"lidt %0\n" | ||
"int $1" :: "m" (idtr)); | ||
} | ||
|
||
void _reset_oob_buffer(); | ||
|
||
void __assert(const char *msg, const char *file, int line) { | ||
_reset_oob_buffer(); | ||
PUT_LIST(true, UInt32, OOBAssert, CString, | ||
msg, CString, file, Int32, line | ||
); | ||
send_msg(MTOOB); | ||
reset(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef COMMON_H | ||
#define COMMON_H | ||
#include <stdint.h> | ||
|
||
#define va_start(v,l) __builtin_va_start(v,l) | ||
#define va_arg(v,l) __builtin_va_arg(v,l) | ||
#define va_end(v) __builtin_va_end(v) | ||
typedef __builtin_va_list va_list; | ||
|
||
void setup_serial(); | ||
void write_serial(const void *data, unsigned long len); | ||
void read_serial(void *data, unsigned long len); | ||
uint32_t crc32(const void *data, unsigned long len); | ||
void reset(); | ||
void __assert(const char *msg, const char *file, int line); | ||
#define assert(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__),0)) | ||
|
||
#define PTR_ADD(a, s) ((typeof(a))((unsigned long)a + s)) | ||
#define ALIGN_UP(a, s) ((a + (typeof(a))s - 1) & ~((typeof(a))s - 1)) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import protocol | ||
from enum import Enum | ||
from subprocess import Popen, PIPE | ||
from remotemem import RemoteMemory | ||
|
||
class OpType(Enum): | ||
Write = 0 | ||
Exec = 1 | ||
|
||
class Guest: | ||
guest_id = None | ||
|
||
def __init__(self): | ||
self.proc = None | ||
self.memory = None | ||
self.symbols = None | ||
self._request = [] | ||
|
||
def __enter__(self): | ||
self.proc = Popen( | ||
('exec qemu-system-x86_64 ' | ||
'-display none ' | ||
'-boot d ' | ||
'-cdrom kernel_bios.iso ' | ||
'-m 300M ' | ||
'-serial stdio ' | ||
'-enable-kvm ' | ||
), | ||
stdout=PIPE, stdin=PIPE, shell=True | ||
) | ||
return self | ||
|
||
def __exit__(self, type, value, traceback): | ||
self.proc.kill() | ||
|
||
def _init_boot_info(self, symbols, mmap): | ||
self.symbols = dict(symbols) | ||
self.memory = RemoteMemory() | ||
|
||
for entry in map(dict, mmap): | ||
if entry['type'] == 1: # MULTIBOOT_MEMORY_AVAILABLE | ||
self.memory.add_region(entry['address'], entry['length']) | ||
|
||
kernel_end = (self.symbols['_end'] + 0x1000) & ~0xfff | ||
self.memory.del_region(0, kernel_end) | ||
|
||
def messages(self): | ||
while self.proc.returncode is None: | ||
msg = protocol.recv(self.proc.stdout) | ||
msg_type, body = msg | ||
|
||
if msg_type == protocol.MT.Boot: | ||
self._init_boot_info(**dict(body)) | ||
|
||
yield msg | ||
|
||
def op_write_data(self, data, address=None): | ||
if address is None: | ||
address = self.memory.alloc(len(data)) | ||
|
||
self._request += [ | ||
protocol.f.UInt32(OpType.Write.value), | ||
protocol.f.UInt64(address), | ||
tuple(protocol.f.UInt8(x) for x in data) | ||
] | ||
return address | ||
|
||
def op_write(self, code, address=None): | ||
if address is None: | ||
address = self.memory.alloc(len(code.build(0))) | ||
|
||
return self.op_write_data(code.build(address), address) | ||
|
||
def op_exec(self, address): | ||
self._request += [ | ||
protocol.f.UInt32(OpType.Exec.value), | ||
protocol.f.UInt64(address) | ||
] | ||
|
||
def op_commit(self): | ||
protocol.send(self.proc.stdin, self._request) | ||
self._request.clear() | ||
|
||
def execute(self, code): | ||
address = self.op_write(code) | ||
self.op_exec(address) | ||
self.op_commit() | ||
self.memory.free(address) |
Oops, something went wrong.