Introduction
The panther language is a language made for exploitations.
It's main focus is minimal code size through code size optimizations and compiling directly to a shellcode (position independent code).
Flow
- Lexer: Parse text file into tokens
- Parser: Parse tokens into AST
- Analyzer: Validate that the AST is correct panther syntax
- Bytecode: Parse AST into bytecode
- LLVM: Parse bytecode into LLVM IR
- Optimizations + Backend: llvm
What can it do currently?
Currently, the panther binary can compile a single file using the llvm backend, with minimal type inference and type checking.
When running the panther compiler on main.pan
# Compile the panther compiler nimble build -d:release # Panther compiles an object file, in this example I compile to a windows COFF ./panther c -i main.pan -o output.o -t x86_64-pe-windows-coff # Link the object file to an executable, needed to get rid of relocations ld -nostartfiles output.o -o output.exe # Extract the .shell section created by the compiler objcopy -j .shell -O binary output.exe shellcode.bin
When main.pan looks like:
proc _start(); // First function in the shellcode proc fib(a: s32) -> s32 { if a < 2 { return a; } else { return fib(a - 1) + fib(a - 2); } } // The printf symbol predetermined by an address. // In the future I would like to add a feature of searching for a symbol at runtime. let printf = 0x402ba0 as proc(fmt: string, num1: s32, num2: s32); proc _start() { let i = 1; while i <= 15 { printf("%d: %d\n", i, fib(i)); i = i + 1; } }
Results in a shellcode (shellcode.bin) that prints the the first 15 fibonnaci numbers.