#!/bin/sh # ragg2-cc : a shellcode compiler -- pancake - 2011-2013 # # Supported operating systems: # - GNU/Linux # - OSX # - BSD # Supported compilers # - gcc # - clang # TODO # remove temporary files # add support for arm # add support for nested shellcodes # Find which compiler is installed if [ -z "${CC}" ]; then for a in llvm-gcc clang gcc ; do $a --version >/dev/null 2>&1 if [ $? = 0 ]; then CC="$a" break fi done if [ -z "${CC}" ]; then echo "Cannot find CC" > /dev/stderr exit 1 fi fi # Get path for sflib SFLIBPATH=`ragg2 -v | cut -d ' ' -f 3-` if [ ! -d "${SFLIBPATH}" ]; then echo "Cannot find ${SFLIBPATH}" exit 1 fi # Get local architecture case "`uname -m`" in "x86_64") B=64 ;; *) B=32 ;; esac dohelp() { echo "Usage: ragg2-cc [-dabkoscxv] [file.c]" echo " -d enable debug mode" echo " -a x86 set arch (x86, arm)" echo " -b 32 bits (32, 64)" echo " -k linux set kernel (darwin, linux)" echo " -o file set output file" echo " -s generate assembly" echo " -c generate compiled shellcode" echo " -x show hexpair bytes" echo " -v show version" } case "`uname`" in Darwin) K=darwin ;; *) K=linux ;; esac X=0 C="" D="" O="" F="" ASM=0 A=x86 while : ; do [ -z "$1" ] && break F=$1 case "$F" in -a) # architecture (x86, mips, arm) shift A=$1 [ -z "$A" ] && { echo "Missing argument for -a" ; exit 1; } ;; -b) # register size (32, 64, ...) shift B=$1 [ -z "$B" ] && { echo "Missing argument for -b" ; exit 1; } ;; -k) # kernel shift K=$1 [ -z "$K" ] && { echo "Missing argument for -k" ; exit 1; } ;; -x) # execute X=1 ;; -c) # set configuration option C=1 ;; -d) # patch dword (4 bytes) at given offset D=1 ;; -s) # show assembler ASM=1 ;; -o) # output file shift O=$1 if [ -z "$O" ]; then echo "Missing argument for -o" exit 1 fi ;; -h) # help dohelp exit 0 ;; -v) # version ragg2 -v | sed -e 's,2,2-cc,' exit 0 ;; esac shift done if [ -z "$F" ]; then dohelp exit 1 fi if [ "`uname`" = Darwin ]; then OBJCOPY=gobjcopy case "$B" in 32) CFLAGS="-arch i386 " LDFLAGS="-arch i386 -shared -c" ARCH=darwin-x86-32 ;; 64) CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64 -shared -c" ARCH=darwin-x86-64 ;; esac SHDR=" .text jmp _main" else OBJCOPY=objcopy CFLAGS="-fPIC -fPIE -pie -fpic" LDFLAGS="-fPIC -fPIE -pie -fpic" SHDR=" .section .text .globl main .type main, @function jmp main " case "$B" in 64) ARCH=linux-x86-64 ;; *) ARCH=linux-x86-32 ;; esac fi [ "$A$K" ] && ARCH="$K-$A-$B" OPT=-Os CFLAGS="${CFLAGS} -nostdinc -include ${SFLIBPATH}/${ARCH}/sflib.h" CFLAGS="${CFLAGS} -z execstack" CFLAGS="${CFLAGS} -fomit-frame-pointer -finline-functions -fno-zero-initialized-in-bss" LDFLAGS="${LDFLAGS} -nostdlib" case "$K" in darwin) #TEXT="__TEXT.__text" TEXT="0.__text" ;; *|linux) TEXT=".text" ;; esac rmtemps() { [ -z "$D" ] && rm -f $F.tmp $F.text $F.s $F.o } fail() { rmtemps exit 1 } if [ "$D" ]; then echo "==> Compile" echo "${CC} ${CFLAGS} -o $F.tmp -S ${OPT} $F" fi rm -f $F.bin # echo ${CC} ${CFLAGS} -o $F.tmp -S ${OPT} $F > /dev/stderr ${CC} ${CFLAGS} -o $F.tmp -S ${OPT} $F || fail echo "${SHDR}" > $F.s cat $F.tmp \ | sed -e s,rdata,text, -e s,rodata,text, -e 's,get_pc_thunk.bx,__getesp__,g' \ | grep -v .cstring | grep -v size | grep -v ___main | grep -v section \ | grep -v __alloca | grep -v zero | grep -v cfi >> $F.s rm -f $F.tmp if [ $ASM = 1 ]; then echo $F.s exit 0 fi if [ "$D" ]; then echo "==> Assemble" echo "${CC} -c ${LDFLAGS} -Os -o $F.o $F.s" fi ${CC} ${LDFLAGS} ${OPT} -o $F.o $F.s || fail if [ "$D" ]; then echo "==> Link" #echo "${OBJCOPY} -j .text -O binary $F.o $.text" echo "rabin2 -o '$F.text' -O d/S/${TEXT} $F.o" fi rabin2 -o "$F.text" -O d/S/${TEXT} $F.o if [ "`du $F.text|awk '{print $1}'`" = 0 ]; then # use objcopy as falback for rabin2 ${OBJCOPY} -j .text -O binary $F.o $F.text || fail fi if [ "$C" = 1 ]; then if [ "$O" ]; then mv $F.text $O else O="$F.text" fi echo "$O" exit 0 fi [ "$X" = 1 ] && exec rax2 -S < $F.text if [ "$D" ]; then # hexdump -C $F.text rax2 -S - < $F.text ls -l $F.text fi [ -z "$O" ] && O=$F.bin ragg2 -b $B -C $F.text -F -o $O || fail echo $O rmtemps exit 0