Skip to content
Permalink
Browse files

first commit for mips

  • Loading branch information
fffonion committed Aug 25, 2017
1 parent 6b7a834 commit 741db65963808fc84872ddfa35eced012bfb43d4
Showing with 42 additions and 20 deletions.
  1. +6 −0 README.md
  2. +18 −10 latest/unshc.sh
  3. +18 −10 release/0.8/unshc-v0.8.sh
@@ -1,6 +1,8 @@
# UnSHc
UnSHc - How to decrypt SHc *.sh.x encrypted file ?

**This version of script only works for MIPS binaries.** For x86/x64, please use the original version https://github.com/yanncam/UnSHc .

# Please note

I will not decrypt any file for people.
@@ -96,3 +98,7 @@ Updated and modernized by Yann CAM
* https://www.asafety.fr/prog-and-dev/bashshunix-shc-le-compilateur-et-protecteur-de-script-shell/
* UnSHc (in french) :
* https://www.asafety.fr/unshc-the-shc-decrypter/
# Note for UnSHc-MIPS
- This script has been modified to not automatically run `objdump`. You will need to run `objdump -D` and `objdump -s` at first. If your mips platform is not able to run `objdump`, run `mipsel-linux-gnu-objdump` on other platform (for example your x86/x64 desktop or server)
@@ -43,6 +43,8 @@
###################
VERSION="0.8"

DATASEGBASE=0x410000

OBJDUMP=`which objdump`
GREP=`which grep`
CUT=`which cut`
@@ -148,7 +150,7 @@ function generate_dump() {
# Update 28/07/2016 : Adding multiple ARC4 offsets support (loop on each candidate)
function extract_arc4_call_addr(){
TAILNUMBER=$1
CALLADDRS=$($GREP -Eo "call.*[0-9a-f]{6,}" $DUMPFILE | $GREP -Eo "[0-9a-f]{6,}" | $SORT | $UNIQ -c | $SORT | $GREP -Eo "(14).*[0-9a-f]{6,}" | $GREP -Eo "[0-9a-f]{6,}")
CALLADDRS=$($GREP -Eo "jal.*[0-9a-f]{6,}" $DUMPFILE | $GREP -Eo "[0-9a-f]{6,}" | $SORT | $UNIQ -c | $SORT | $GREP -Eo "(14).*[0-9a-f]{6,}" | $GREP -Eo "[0-9a-f]{6,}")
TAILMAX=`wc -l <<< "$CALLADDRS"`
CALLADDR=$(echo $CALLADDRS | $SED "s/ /\n/g" | $TAIL -n $TAILNUMBER | $HEAD -n 1)
if [[ -z "$CALLADDR" || $TAILNUMBER -gt $TAILMAX ]]; then
@@ -165,21 +167,21 @@ function extract_variables_from_binary(){
i=2
# Retrieve ordered list of address var and put it to $CALLADDRFILE
while [[ $($WC -l < $CALLADDRFILE) -ne 14 ]]; do
$GREP -B $i "call.*$CALLADDR" $DUMPFILE | $GREP -v "$CALLADDR" | $GREP -Eo "(0x[0-9a-f]{6,})" > $CALLADDRFILE
$GREP -B $i "jal.*$CALLADDR" $DUMPFILE | $GREP addiu | $GREP -Po ",\-*(\d+)"|$GREP -Po "\-*\d+" > $CALLADDRFILE
i=$(($i + 1))
if [ $i -eq 10 ]; then
if [ $i -eq 5 ]; then
echo "[-] Unable to extract addresses of 14 arc4 args with ARC4 address call [0x$CALLADDR]..."
return;
fi
done

# Initialize the number of line before CALLADDR to looking for sizes of args
i=3
i=2
# Retrieve ordered list of size var and append it to $CALLSIZEFILE
while [[ $($WC -l < $CALLSIZEFILE) -ne 14 ]]; do
$GREP -B $i "call.*$CALLADDR" $DUMPFILE | $GREP -v "$CALLADDR" | $GREP -Eo "(0x[0-9a-f]+,)" | $GREP -Eo "(0x[0-9a-f]+)" | $GREP -Ev "0x[0-9a-f]{6,}" > $CALLSIZEFILE
$GREP -B $i "jal.*$CALLADDR" $DUMPFILE | $GREP "li.*a1" |$GREP -Po ",\-*(\d+)"|$GREP -Po "\-*\d+" > $CALLSIZEFILE
i=$(($i + 1))
if [ $i -eq 10 ]; then
if [ $i -eq 5 ]; then
echo "[-] Unable to extract sizes of 14 arc4 args with ARC4 address call [0x$CALLADDR]..."
return;
fi
@@ -191,6 +193,8 @@ function extract_variables_from_binary(){
for (( x = 0; x < ${#LISTOFADDR[*]}; x = x+1 ))
do
i=${LISTOFADDR[$x]}
let i=i+DATASEGBASE
i=$(printf "0x%x" $i)
NBYTES=${LISTOFSIZE[$x]}
echo -e "\t[$x] Working with var address at offset [$i] ($NBYTES bytes)"
# Some diferences in assembly.
@@ -306,17 +310,20 @@ function extract_password_from_binary(){
# Initialize the number of line before CALLADDR to watch
i=5
while [[ ( -z "$KEY_ADDR" ) || ( -z "$KEY_SIZE" ) ]]; do
$GREP -B $i -m 1 "call.*$CALLADDR" $DUMPFILE | $GREP -v $CALLADDR > $CALLFILE
$GREP -B $i -m 1 "jal.*$CALLADDR" $DUMPFILE | $GREP -v $CALLADDR > $CALLFILE
#cat $CALLFILE
# Adjust these two next line to grep right addr & size value (depending on your architecture)
KEY_ADDR=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP mov | $GREP -oE "0x[0-9a-z]{6,}+" | $HEAD -n 1)
KEY_SIZE=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP mov | $GREP -v $KEY_ADDR | $GREP -v movb | $GREP -oE "0x[0-9a-z]+" | $HEAD -n 1)
KEY_ADDR=$($GREP -B 3 -m 1 "jal" $CALLFILE | $GREP addiu | $GREP -oP ",\d+"|$GREP -oP "\d+" | $HEAD -n 1)
KEY_SIZE=$($GREP -B 3 -m 1 "jal" $CALLFILE | $GREP li | $GREP -oP ",\d+"|$GREP -oP "\d+" | $HEAD -n 1)
i=$(($i + 1))
if [ $i -eq 10 ]; then
echo "[-] Error, function call previous first call of arc4() hasn't been identified..."
exit_error
fi
done
let KEY_ADDR=KEY_ADDR+DATASEGBASE
KEY_ADDR=$(printf "0x%x" $KEY_ADDR)
KEY_SIZE=$(printf "0x%x" $KEY_SIZE)
echo -e "\t[+] PWD address found : [$KEY_ADDR]"
echo -e "\t[+] PWD size found : [$KEY_SIZE]"

@@ -680,7 +687,7 @@ else
fi

# Fill DUMPFILE and STRINGFILE from objdump of the *.sh.x encrypted script
generate_dump
#generate_dump

# Find out the most called function. This function is arc4() and there are 14 calls.
# Then retrieve the data used in each CALLADDR call
@@ -710,6 +717,7 @@ echo "[*] Executing [$TMPBINARY] to decrypt [${BINARY}]"

if [ -z "$OUTPUTFILE" ]; then
echo "[*] Retrieving initial source code in [${BINARY%.sh.x}.sh]"
chmod +x $TMPBINARY
$TMPBINARY > ${BINARY%.sh.x}.sh
else
echo "[*] Retrieving initial source code in [$OUTPUTFILE]"
@@ -43,6 +43,8 @@
###################
VERSION="0.8"

DATASEGBASE=0x410000

OBJDUMP=`which objdump`
GREP=`which grep`
CUT=`which cut`
@@ -148,7 +150,7 @@ function generate_dump() {
# Update 28/07/2016 : Adding multiple ARC4 offsets support (loop on each candidate)
function extract_arc4_call_addr(){
TAILNUMBER=$1
CALLADDRS=$($GREP -Eo "call.*[0-9a-f]{6,}" $DUMPFILE | $GREP -Eo "[0-9a-f]{6,}" | $SORT | $UNIQ -c | $SORT | $GREP -Eo "(14).*[0-9a-f]{6,}" | $GREP -Eo "[0-9a-f]{6,}")
CALLADDRS=$($GREP -Eo "jal.*[0-9a-f]{6,}" $DUMPFILE | $GREP -Eo "[0-9a-f]{6,}" | $SORT | $UNIQ -c | $SORT | $GREP -Eo "(14).*[0-9a-f]{6,}" | $GREP -Eo "[0-9a-f]{6,}")
TAILMAX=`wc -l <<< "$CALLADDRS"`
CALLADDR=$(echo $CALLADDRS | $SED "s/ /\n/g" | $TAIL -n $TAILNUMBER | $HEAD -n 1)
if [[ -z "$CALLADDR" || $TAILNUMBER -gt $TAILMAX ]]; then
@@ -165,21 +167,21 @@ function extract_variables_from_binary(){
i=2
# Retrieve ordered list of address var and put it to $CALLADDRFILE
while [[ $($WC -l < $CALLADDRFILE) -ne 14 ]]; do
$GREP -B $i "call.*$CALLADDR" $DUMPFILE | $GREP -v "$CALLADDR" | $GREP -Eo "(0x[0-9a-f]{6,})" > $CALLADDRFILE
$GREP -B $i "jal.*$CALLADDR" $DUMPFILE | $GREP addiu | $GREP -Po ",\-*(\d+)"|$GREP -Po "\-*\d+" > $CALLADDRFILE
i=$(($i + 1))
if [ $i -eq 10 ]; then
if [ $i -eq 5 ]; then
echo "[-] Unable to extract addresses of 14 arc4 args with ARC4 address call [0x$CALLADDR]..."
return;
fi
done

# Initialize the number of line before CALLADDR to looking for sizes of args
i=3
i=2
# Retrieve ordered list of size var and append it to $CALLSIZEFILE
while [[ $($WC -l < $CALLSIZEFILE) -ne 14 ]]; do
$GREP -B $i "call.*$CALLADDR" $DUMPFILE | $GREP -v "$CALLADDR" | $GREP -Eo "(0x[0-9a-f]+,)" | $GREP -Eo "(0x[0-9a-f]+)" | $GREP -Ev "0x[0-9a-f]{6,}" > $CALLSIZEFILE
$GREP -B $i "jal.*$CALLADDR" $DUMPFILE | $GREP "li.*a1" |$GREP -Po ",\-*(\d+)"|$GREP -Po "\-*\d+" > $CALLSIZEFILE
i=$(($i + 1))
if [ $i -eq 10 ]; then
if [ $i -eq 5 ]; then
echo "[-] Unable to extract sizes of 14 arc4 args with ARC4 address call [0x$CALLADDR]..."
return;
fi
@@ -191,6 +193,8 @@ function extract_variables_from_binary(){
for (( x = 0; x < ${#LISTOFADDR[*]}; x = x+1 ))
do
i=${LISTOFADDR[$x]}
let i=i+DATASEGBASE
i=$(printf "0x%x" $i)
NBYTES=${LISTOFSIZE[$x]}
echo -e "\t[$x] Working with var address at offset [$i] ($NBYTES bytes)"
# Some diferences in assembly.
@@ -306,17 +310,20 @@ function extract_password_from_binary(){
# Initialize the number of line before CALLADDR to watch
i=5
while [[ ( -z "$KEY_ADDR" ) || ( -z "$KEY_SIZE" ) ]]; do
$GREP -B $i -m 1 "call.*$CALLADDR" $DUMPFILE | $GREP -v $CALLADDR > $CALLFILE
$GREP -B $i -m 1 "jal.*$CALLADDR" $DUMPFILE | $GREP -v $CALLADDR > $CALLFILE
#cat $CALLFILE
# Adjust these two next line to grep right addr & size value (depending on your architecture)
KEY_ADDR=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP mov | $GREP -oE "0x[0-9a-z]{6,}+" | $HEAD -n 1)
KEY_SIZE=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP mov | $GREP -v $KEY_ADDR | $GREP -v movb | $GREP -oE "0x[0-9a-z]+" | $HEAD -n 1)
KEY_ADDR=$($GREP -B 3 -m 1 "jal" $CALLFILE | $GREP addiu | $GREP -oP ",\d+"|$GREP -oP "\d+" | $HEAD -n 1)
KEY_SIZE=$($GREP -B 3 -m 1 "jal" $CALLFILE | $GREP li | $GREP -oP ",\d+"|$GREP -oP "\d+" | $HEAD -n 1)
i=$(($i + 1))
if [ $i -eq 10 ]; then
echo "[-] Error, function call previous first call of arc4() hasn't been identified..."
exit_error
fi
done
let KEY_ADDR=KEY_ADDR+DATASEGBASE
KEY_ADDR=$(printf "0x%x" $KEY_ADDR)
KEY_SIZE=$(printf "0x%x" $KEY_SIZE)
echo -e "\t[+] PWD address found : [$KEY_ADDR]"
echo -e "\t[+] PWD size found : [$KEY_SIZE]"

@@ -680,7 +687,7 @@ else
fi

# Fill DUMPFILE and STRINGFILE from objdump of the *.sh.x encrypted script
generate_dump
#generate_dump

# Find out the most called function. This function is arc4() and there are 14 calls.
# Then retrieve the data used in each CALLADDR call
@@ -710,6 +717,7 @@ echo "[*] Executing [$TMPBINARY] to decrypt [${BINARY}]"

if [ -z "$OUTPUTFILE" ]; then
echo "[*] Retrieving initial source code in [${BINARY%.sh.x}.sh]"
chmod +x $TMPBINARY
$TMPBINARY > ${BINARY%.sh.x}.sh
else
echo "[*] Retrieving initial source code in [$OUTPUTFILE]"

7 comments on commit 741db65

@yanncam

This comment has been minimized.

Copy link

@yanncam yanncam replied Sep 16, 2017

Hello,

Excellent work ! Thank you for your evolution on the original UnSHc script to be compliant with MIPS architecture :) !

Can I mention your contribution with a link to this repository on the UnSHc base project ?

Sincerely,

Ycam

@fffonion

This comment has been minimized.

Copy link
Owner Author

@fffonion fffonion replied Sep 16, 2017

@yanncam Sure! Thanks for your excellent work on the original version. This version will not be possible without your previous work! 😄

@yanncam

This comment has been minimized.

Copy link

@yanncam yanncam replied Sep 16, 2017

I have added a note on the README.md of UnSHc original repos to point to your MIPS version:

Thank you again !

Next step : ARM arch ^^ !

@fffonion

This comment has been minimized.

Copy link
Owner Author

@fffonion fffonion replied Sep 17, 2017

@yanncam Great I appreciate that!
And that's good plan ;- )

@m0sia

This comment has been minimized.

Copy link

@m0sia m0sia replied Dec 28, 2017

Hey, @fffonion and @yanncam !

What kind of MIPS ABI you created your patch for? As far as I know traditional MIPS ABI(aka GOT/PLT) assumes you are using $t9 register to store the subroutine addresses and then jal.* $t9. Its fare for both PIC and non-PIC code.

Here is the example of arc4 call:

  4015fc:       24422526        addiu   v0,v0,9510
  401600:       00402021        move    a0,v0
  401604:       24050041        li      a1,65
  401608:       8f998088        lw      t9,-32632(gp)
  40160c:       00000000        nop
  401610:       0320f809        jalr    t9

And what you call DATASEGBASE , I believe, is actually not a .data segment address(that can be found from objdump/readelf), but a $gp value that you can theoretically calculate. At least it is true in my case.

@fffonion

This comment has been minimized.

Copy link
Owner Author

@fffonion fffonion replied Dec 29, 2017

@fffonion

This comment has been minimized.

Copy link
Owner Author

@fffonion fffonion replied Jan 2, 2018

Hi @m0sia,

I've attached the binary below and it matches your description about $t9 and $gp register. Per my understanding, $gp is used to store the address of global variables. So that should also lay in the .data seg?

sample.zip

Please sign in to comment.
You can’t perform that action at this time.