radare2/binr/ragg2/ragg2-cc

321 lines
5.5 KiB
Bash
Executable File

#!/bin/sh
# ragg2-cc : a shellcode compiler -- pancake - 2011-2016
#
# Supported operating systems:
# - GNU/Linux
# - OSX
# - BSD
# Supported compilers
# - gcc
# - clang
# TODO
# 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" >&2
exit 1
fi
fi
# Get path for sflib
if [ -z "${SFLIBPATH}" ]; then
SFLIBPATH="$(r2 -hh | grep INCDIR | awk '{print $2}')"/sflib
fi
if [ ! -d "${SFLIBPATH}" ]; then
echo "Cannot find ${SFLIBPATH}"
echo "Define SFLIBPATH env var or fix the r2 installation"
exit 1
fi
# Get local architecture
case "$(uname -m)" in
arm64|aarch64|x86_64)
B=64
;;
*)
B=32
;;
esac
dohelp() {
cat<<EOF
Usage: ragg2-cc [-cdsvx] [-a arch] [-b bits] [-k kernel] [-o output] [file.c]
-a x86 set arch (x86, arm)
-b 32 bits (32, 64)
-c generate compiled shellcode
-d enable debug mode
-k linux set kernel (darwin, linux)
-o file set output file
-s generate assembly
-v show version
-x show hexpair bytes
EOF
}
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
JMP=jmp
case "$A" in
arm|aarch64|arm64|thumb|arm32)
JMP=b
;;
mips|mips32|mips64)
JMP=b
;;
esac
FMT=elf
if [ "$K" = darwin ]; then
OBJCOPY=gobjcopy
FMT=mach0
ARCH="$A"
if [ "$ARCH" = x86 ]; then
if [ "${B}" = 32 ]; then
ARCH=i386
TRIPLET=darwin-x86-32
else
ARCH=x86_64
TRIPLET=darwin-x86-64
fi
case "$B" in
32)
CFLAGS="-arch $ARCH "
LDFLAGS="-arch $ARCH -shared -c"
;;
64)
CFLAGS="-arch $ARCH"
LDFLAGS="-arch $ARCH -shared -c"
;;
esac
else
LDFLAGS="-shared -c"
fi
SHDR="
.text
${JMP} _main"
else
OBJCOPY=objcopy
SHDR="
.section .text
.globl main
// .type main, @function
${JMP} main
"
if [ "$A" = x86 ]; then
case "$B" in
64)
CFLAGS="-fPIC -fPIE -pie -fpic -m64"
LDFLAGS="-fPIC -fPIE -pie -fpic -m64"
TRIPLET=linux-x86-64
;;
*)
CFLAGS="-fPIC -fPIE -pie -fpic -m32"
LDFLAGS="-fPIC -fPIE -pie -fpic -m32"
TRIPLET=linux-x86-32
;;
esac
else
CFLAGS="-fPIC -fPIE -pie -fpic -nostartfiles"
LDFLAGS="-fPIC -fPIE -pie -fpic -nostartfiles"
fi
fi
[ "$A$K" ] && TRIPLET="$K-$A-$B"
case "$K" in
windows)
#TEXT="__TEXT.__text"
TEXT=".text"
FMT=pe
;;
darwin)
#TEXT="__TEXT.__text"
#TEXT="0.__text"
TEXT=0.__TEXT.__text
FMT=mach0
;;
*|linux)
TEXT=".text"
FMT=elf
;;
esac
USE_CLANG=0
case "$K-$A-$B" in
darwin-arm-64)
CC="xcrun --sdk iphoneos gcc -arch arm64"
USE_CLANG=1
TEXT=0.__TEXT.__text
;;
darwin-arm-32)
USE_CLANG=1
CC="xcrun --sdk iphoneos gcc -arch armv7"
TEXT=0.__TEXT.__text
;;
esac
OPT=-Os
CFLAGS="${CFLAGS} -nostdinc -include ${SFLIBPATH}/${TRIPLET}/sflib.h"
if [ 1 = "${USE_CLANG}" ]; then
CFLAGS="${CFLAGS} -fomit-frame-pointer -fno-zero-initialized-in-bss"
else
CFLAGS="${CFLAGS} -z execstack -fomit-frame-pointer -finline-functions -fno-zero-initialized-in-bss"
fi
LDFLAGS="${LDFLAGS} -nostdlib"
rmtemps() {
[ -z "$D" ] && rm -f $F.tmp $F.text $F.s $F.o
}
fail() {
echo "ERROR: $@"
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"
${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
echo ==============================
if [ "$D" ]; then
echo "==> Assemble"
echo "${CC} ${LDFLAGS} ${OPT} -o $F.o $F.s"
fi
echo "${CC} ${LDFLAGS} ${OPT} -o $F.o $F.s"
${CC} ${LDFLAGS} ${OPT} -o "$F.o" "$F.s" || fail 'compile object'
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 [ ! -f "$F.o" ]; then
echo "Cannot find $F.o"
exit 1
fi
if [ "`du $F.text|awk '{print $1}'`" = 0 ]; then
# use objcopy as falback for rabin2
echo "FALLBACK: Using objcopy instead of 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 ${FMT} -a $A -o "$O" || fail "ragg2 cannot generate executable. Use -x"
echo "$O"
rmtemps
exit 0