Skip to content

Commit

Permalink
first commit for mips
Browse files Browse the repository at this point in the history
  • Loading branch information
fffonion committed Aug 25, 2017
1 parent 6b7a834 commit 741db65
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 20 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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)
28 changes: 18 additions & 10 deletions latest/unshc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
###################
VERSION="0.8"

DATASEGBASE=0x410000

OBJDUMP=`which objdump`
GREP=`which grep`
CUT=`which cut`
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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]"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]"
Expand Down
28 changes: 18 additions & 10 deletions release/0.8/unshc-v0.8.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
###################
VERSION="0.8"

DATASEGBASE=0x410000

OBJDUMP=`which objdump`
GREP=`which grep`
CUT=`which cut`
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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]"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]"
Expand Down

7 comments on commit 741db65

@yanncam
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Owner Author

@fffonion fffonion commented on 741db65 Sep 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@yanncam
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@m0sia
Copy link

@m0sia m0sia commented on 741db65 Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Owner Author

@fffonion fffonion commented on 741db65 Dec 29, 2017 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fffonion
Copy link
Owner Author

@fffonion fffonion commented on 741db65 Jan 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.