diff --git a/README.md b/README.md index 767070f..8eb8189 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,4 @@ PoC's showing how rust can do stuff people often critiquize it about. # Members - `rust-teeny`: A rust std binary only **8.0 KiB** big, achieves so by `abort()`ing instead of having graceful error logging, panics shouldn't have any source information nor should there be `Debug` implementations, no debug symbols and any potential path reference to `$PWD` is renamed. It carries a shellcode payload loaded into memory and executed from memory. -- `rust-teeny-nostd`: Same as avobe but `no_std`, **4.1 KiB**. +- `rust-teeny-nostd`: Same as avobe but `no_std`, **4.1 KiB**. Can't even get raw assembly as small, rust wins by 16 Bytes, `.text` is the same size but rust beats with dynamic table sections and such. diff --git a/rust-teeny-nostd/justfile b/rust-teeny-nostd/justfile index c26c900..57f494b 100644 --- a/rust-teeny-nostd/justfile +++ b/rust-teeny-nostd/justfile @@ -2,6 +2,10 @@ alias b := build alias s := stat alias z := stat-size +alias basm := build-asm +alias sasm := stat-asm +alias zasm := stat-size-asm + target := "x86_64-unknown-linux-gnu" build: @@ -16,7 +20,7 @@ build: -Cpanic=immediate-abort --remap-path-prefix=$PWD=[src] \ " cargo \ \ - -Zbuild-std=core,alloc,std,panic_abort \ + -Zbuild-std=core,panic_abort \ -Zbuild-std-features="optimize_for_size" \ \ b -r --target {{ target }} @@ -32,8 +36,18 @@ build: # Not sure why .gnu.version and .gnu.hash don't break if I remove them in my machine, but that's very relative and its related to dynamic loading, but they could reduce size by `0.2 KiB` +build-asm: + clang -Wl,--gc-sections -Wl,--as-needed -Wl,--strip-all -Wl,--build-id=none -s -fuse-ld=lld -Oz same.S -o target/asm + strip --strip-all --strip-unneeded -R .comment -R .note.\* -R .eh_frame\* target/asm + stat: stat target/{{ target }}/release/rust-teeny +stat-asm: + stat target/asm + stat-size: stat target/{{ target }}/release/rust-teeny -c "%s" | numfmt --to=iec-i + +stat-size-asm: + stat target/asm -c "%s" | numfmt --to=iec-i diff --git a/rust-teeny-nostd/same.S b/rust-teeny-nostd/same.S new file mode 100644 index 0000000..af5778c --- /dev/null +++ b/rust-teeny-nostd/same.S @@ -0,0 +1,60 @@ +.intel_syntax noprefix +.globl main + +.section .rodata +SHELLCODE: .ascii "\x31\xC0\xFF\xC0\x89\xC7\x48\x8D\x35\x08\x00\x00\x00\xBA\x0E\x00\x00\x00\x0F\x05\xC3Hello, World!\n" +SHELLCODE_end: + +SHELLCODE_len = SHELLCODE_end - SHELLCODE + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 + +#define MAP_PRIVATE 0x2 +#define MAP_ANONYMOUS 0x20 + +#define MAP_FAILED -1 + +.section .text +main: + #define VAR1 [rsp] + sub rsp, 8 + + // rax = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + xor edi, edi + mov rsi, OFFSET SHELLCODE_len + mov edx, PROT_READ | PROT_WRITE + mov ecx, MAP_PRIVATE | MAP_ANONYMOUS + mov r8, -1 + xor r9d, r9d + call QWORD PTR [mmap@GOTPCREL + rip] + mov VAR1, rax + + cmp rax, MAP_FAILED + je .abort + + // rax = mmove(VAR1, SHELLCODE, SHELLCODE_len) + mov rdi, rax + lea rsi, [rip+SHELLCODE] + mov rdx, OFFSET SHELLCODE_len + call QWORD PTR [memmove@GOTPCREL + rip] + + // rax = mprotect(exec_mem, content.len(), PROT_READ | PROT_EXEC) + mov rdi, rax + mov rsi, OFFSET SHELLCODE_len + mov edx, PROT_READ | PROT_EXEC + call QWORD PTR [mprotect@GOTPCREL + rip] + + test rax, rax + jnz .abort + + mov rax, VAR1 + call qword ptr VAR1 + + // exit(0) + xor edi, edi + call QWORD PTR [exit@GOTPCREL + rip] + +.abort: + call QWORD PTR [abort@GOTPCREL + rip]