Linux下Shell脚本的加密与解密

2,175次阅读
没有评论

上一篇文章讲到《最近比较火的OpenVPN免流一键安装包》,看了原作者的博客,继续搜索终于找到一键包,拖到本地用NotePad++看源文件,第一次发现这种奇怪的Shell脚本,脚本前部分内容跟OpenVPN毫无关系,脚本文件第44行开始都是乱码,看样子应该是被加密了,吓得博主赶紧百度了下,结合已有的样本分析应该是使用gzexe加密的,看样子应该不难,博主简单尝试后就把文件还原了,以下是还原过程。

用gzexe加密后的脚本,其实可以通过爆破来获得原来的代码,但是其实也是可以通过解压缩来获得原文件,源代码有个skip变量,等于44。从第44行开始就是乱码了,说明要从第44行开始导入到另外一个文件中,换句话讲,从44行开始就是真实的压缩文件了。

加密脚本如下:

#!/bin/sh
skip=44

tab='	'
nl='
'
IFS=" $tab$nl"

umask=`umask`
umask 77

gztmpdir=
trap 'res=$?
  test -n "$gztmpdir" && rm -fr "$gztmpdir"
  (exit $res); exit $res
' 0 1 2 3 5 10 13 15

if type mktemp >/dev/null 2>&1; then
  gztmpdir=`mktemp -dt`
else
  gztmpdir=/tmp/gztmp$$; mkdir $gztmpdir
fi || { (exit 127); exit 127; }

gztmp=$gztmpdir/$0
case $0 in
-* | */*'
') mkdir -p "$gztmp" && rm -r "$gztmp";;
*/*) gztmp=$gztmpdir/`basename "$0"`;;
esac || { (exit 127); exit 127; }

case `echo X | tail -n +1 2>/dev/null` in
X) tail_n=-n;;
*) tail_n=;;
esac
if tail $tail_n +$skip <"$0" | gzip -cd > "$gztmp"; then
  umask $umask
  chmod 700 "$gztmp"
  (sleep 5; rm -fr "$gztmpdir") 2>/dev/null &
  "$gztmp" ${1+"$@"}; res=$?
else
  echo >&2 "Cannot decompress $0"
  (exit 127); res=127
fi; exit $res
??Wopenvpn ?ks又稛彪?m蓶_q蜭?s(蒊B蹤迬慹9雠枌$'?仏?z?iK)垂??サd?岈龕,?%恟f顄K$斫众{烕瑶J0漌僫扇q韍笪低?;?zU鏵??辩f靺?kg?~Y浸/(汹邡zm鶃鍦uj藕?7─搧渋杤儊灶%?
Zk椽Vt]訐伨矙郁黁商k*蔎鵅YW?h枇ё靺徽K?Z飨鬯笳硍猭棴袭r脈c?癜v
蚍l鐰鳐^T衐?l??僈9錒I覯勆54.Io鞈淎A柚>m\k{銋?e*怐)+bB?]挊?薭"*墶t4&J?庄暒酎x文?;逛廄?鶦旷+?4妴J婜摒~>,D1?+焄'珥厃媵7终E
??]蔂?2覔艂 ?c<鼔SH蜛@ǒP@#x QE烶2次閲?迉?髽n?E鵓渢x绺匈?rNC??=0誳
?Eh&{廤?垾>?U.N?h[嶦律x擶JJ佔?C醕|TP5I梥俕*b爔4		P(5霹DPz:DW(鋰(H榺?虡2d硱?A衷l7QR?橸?I??LI茝笢?H".蔂b蔄
冃??R愒a?怰ア捲5蛣oJ2)e妝祰!庞揹鴑K#??Ob鼰S訋揠?蛚W?卍囏媒E#?禝臠2搔晿,嗕tDLK?峵壻?e淤t?X?
?9*.F?x?佻?'??N?蓪?B醲V導3J?嵚k?ue"i1-+=芑ylQ哐3?99)8Jb58軛设奱$N?&b&花訆n慔8,h鷛03T# ?鈬忴猫a?孛a髽L勅虙鱄$演脩0捀?赧kゃx€閹c鮺M;廀E:X?婐靚?Fhδ蓭'芥U詠q13逝儨\?F以%杖*篳錁`f€z肓O鄕6痩l?60X;洞o堏筛p倏灘-?sq*啷M纐?_碞薅蟖/[絨?鄑E蕗?}/?醖g褔滦q徇_鑽i擫?<J粞G6峟NQ??}P怫?媵譕謳=?V嚒?W(睷0娕p俸鮟項踿鄦嗊遯億1u$蟌Ks祇O謓]澋镙?熝鄪(臖u凡}O磿#j餋厠僣Q庝MZ曂搑.[Ve
查污k痵歉6,€闁癤tvz?匈齑u摸?Kb踮眯p[?緞:?I搘?镱D.q吆5l6郷┟;市?L孢:朝,C?H嚄P?
s觍\rz駔gZ]诀癏%儔1+<軝制'調s帚摖MJJ?蟺贮7??癄@0U?歟5 <麒!Q*L?錁??;?8?L郯頧k3謪e稚銞`0,您?Z?9p枳垸顒Be?p(赪.?NXnb摔(.tQ轮靰W鳜?綦壅?^?楣}鶓祐瀠泬h5蝀Q€(??G?Vn~瞂]﹝n俸?a%滿懨j枟募52L瓌z)w藸忈轜E頟綪愢僁
M?2!])j
猝孋??o€駟[氂奐?7竨8Y聨虶?諾腈警}s助|讲z讫dm朓鎱s柱?H?劝罌歺?.癰9射FaG吰ドC鶫<x唶a*墜"洔?劽杆-泆YMZ3谘,皈GBs)?^B?`?~寋量??*閥躷Mw?偡F剼?砂??9_[_痋?G勱[?68??X騢齥噌CN?8?S廱c阖BM煙?c裶G钟M?	??7??唛逼??遆愤 ??:-絉o擞I?讇韅t阋5?b?﹎??雠?Q讬燔鶥sC??鷩??杻後?纍迊i=?*€u?7津?惒鳶?5?冕X徢綪MdAL丘p牕g糟凭緈=峻媫?u>o?f箶慙€?.CtJ渉^邅?褈侒/A鑄]]h妎绤昄)]P?頁銗]C?鍻?縪6譀2?檲顲肅#C?骺峹?!!剟P0E紗3B?鸉q``锢Sh觥笼?苝??寈>C諬q鈴i趱??~(?鴫P"鬊{黱?vG_?J?"?缷?岶^=~&熘]?B蘈?O?}o?}g`锂憗}}c{熞洊示{Bx稪S躎袁?F?X8j郾??l愤湷?┅?鐇?鏝暇罢I?^#&F"迒<?&糫Wq&% =n6
山?MD酧
X>)?埖E?切BF蒍鍌)??槉?I枙挋2?L`J资 DI樔C姰*:??葰蕟b鶈禡箶2Y?錋4満礊蠈+炝玒^编螗8!L黫p?&閊8肿?^T覲徟"qo﹖け匀Yi?蘝W妓W??妴唬蓠畃w?燸倈:I?`耿朅‘X坭6['3?I^Y}YA剋躬騪岛x芞9?躼V戢哘p瀕爌T?豔I*?霮*沍Q:摇qj_)3潂	Cw伋谜諔$xT雲$?r??:庒嫣瘺餑廳?蛻丫-IN`?Z-=QP?dV=| ?<磲 甆鵙櫆栅尻R][縦??:akG??踽筟蘲釳(b-?f>樁r攦炶 \i扇?岂軵惜鉗6U6????Zr._辱妸b惉4贞奣(Ⅶ晜?dj?%C啍7;
D和kja
罷"*G@C.犙複)3 <h睌U煎塒蒜柏瞲+*][Qi].喡1浫Xk?:M$Z柷篬鞫嫈?磉??唺?€!e煠奛轥ゼ?72饛?{箟糄?u錺昑N?姙聨
滝黐設*鼏2?吚rl嶽幞qE5?碩榸v和纔?^餖9矺>,Tj摓1?]tY抯J*撟Q9k犩劋崚??娩厫G醁媐咹?*EB锞蒩O?K凧#??h愦^槥?
€鮂渘*z?垦豝~哓@瓠戒鶜w燋uq軶敂┽!QOS^镑轔清苙笛邟B=?)ly蚿
J葸zV巛5~?Mfr敫?n熧;}肸澅盿4寘挡鷐趼g?柇筮H岫a?q[?sdy-?p!L?Z1?黯?搙單6K?G)餑浻Za嘟硓罾聞€7o蝾?幤?$軥大BO?剸邵制鳇餿珠E簾傳蛠r菅m蹕循r篈ujh覷<悵?賠i剞煮盂j+y_
g晅纓k锪O敊町3?馘鲁鏢z肤瘧n廱o
殪U/}m蟐栾冶???鷰X伓6?	+<閂({l誌妉蚟稸W矦?s停?
謒鬅穧翜?蟽嬅I-?
?&2%竟v嗜鰂傊襇{鰜藳遟?壙蟶I??忟?呹?z  M≮契?g,諙n崦爂绗隷罩揩畘_]?嘹庇阙卄?Q徎D珊=i6艽?慟N麅q站瞈y8Syx荿鸻髬嶊礝闁hm?dE经cL頴錳岮7h弅1闟訸鮖焐?仕7蟽jVc\??|f崻k﹠f鲸$臘禴?'{3l?-?`[8ri?"g€?2xt繅葨窽i禗薼Y闶t蔂馔fT袪A篒`_>屐Yx悳?运屯儌釦嫫駔騉騲Ni佑窋*>軪hW/鼿?kь€p規蠻?4鴁觏儵?FP ?i睠︵?$??€?剮yU岜^鉫^+洢2p!V?> ?SUE6淘紴髼练?Za倉艭\;撁?Вt蔋焱?瓺N=
|0&?^硊??a\ 釴腎惡%役矍鶂Rx?5迧?锕:鳵踗厦紪Mt,?嬬▓{鬱m秪萲wN覟b絀蟻0D`Qoq*_俵荄?効iGm?tN#ua鷪袏(S?瀬?机^檤`牴帴	
5?翓怨F驍佁按?;悑橦P皍5?2?O暁1!VgB?b?畛Q晣鳉l斆l熎缌荸yS酺
"?W耏?羮铅6r?噵bT瘘髚丘?庅#K轿整.Z戰醴繌蹙篽	D?E雈冐蓼洛!]W?L戂c/嚫韹?&€!V%嗥r-??tc榓緾竝nKf?篯"薲u厌T儣?UR?X鏱?震楫4xw玷d撨枅慯/紀O?[晨U?p近鮷uj灷煃檮軐bm?碲/遈?4澬D?Y絴烞恈滀Hk咿w饔?怮u怬?祖?	俌y8_鹍津p?4哾?
红?ボ种諰~寏k⑥峭KWk锁P'跬t悰玏 麕?(6?魫杢老w駚T忏ず?沷?怋z鉁?仂9fN嗕垫ヰ?噱洴戠錆;颸篬驈]i虯_魟M钵辖蜵霄?邑??悶筯o`U5?zC!Ю陿犖?fN踳o?蜺?獥涧枠ρp驈?譈骼N€%??[@ì還继ㄓ嫋P?絔k€熹璐R婎?eL?觓 え暻g(1A裍糬忀?硊~檼Fno1ㄛ)懒?诳眣鮒C?y鱄/藛髝鶊??W6栰K忦I/B爖}删q姂筽帵薶缾焰虒ujズv滚鴖(娆G?毣'阄V6敬頬鲕{a&€?諙僆灘C??)曕es?蘨e鍦7LC鴶勼a|<?\t?OUL灮d28靺臐?G祶:楺j躨! FpiZ漿3?d鑵攝b胿蚫瞜?nM#!x屉TvQ綃z蒥N#[畎z?睥?卖(}蔫#N]魬爮n?bOFGd凞FIdFK岋:@VC|#?$??郎烐鎿懙2;晣gj腚?冊充7v鹭 k简餿e?嵨╖慺声v??殧岢鶄B?\鵳.{甹5溭G紷伦坽?抙5r\tG垪X锋)?{唼鮸睇Y腙"E?b_9?:眆泄t蚟<顛?7開?韎儔n崖<{┍{!?碣.1?遌Zご缞贄W竹??葓诛眏l股Ev齠?驹蝠燳K_m^=	v赆|躅w謪??斋腱农;甀n^|罠禑d;跤蟍???v?頮{u?*秀?,何j洺??M{膝骞刅wu?蹭?4,z伩覎?9輲诋??稝

把上面的文件存为openvpn.sh,放到当前用户目录,执行以下命令:

/usr/bin/tail -n +14 openvpn.sh >/tmp/openvpn.gz
cd /tmp/openvpn.gz
gunzip openvpn.gz

解压后的文件在/tmp,对比解压后的未加密文件和原来已加密的文件可以发现内容都是一样的。

diff /root/openvpn.sh~ /tmp/openvpn.sh

续篇:后来博主继续深挖,发现新的脚本已经用另一种方式加密了,整个脚本文件大部分都是乱码,经过博主一番研究后发现此文件应该是用linux上提供shc加密的,shc是比gzexe安全的多的加密软件,它可以将shell编译成二进制的形式,gzexe生成的二进制文件 可以通过 /bin/bash xxx.sh 来执行,而shc生成的二进制文件只能通过 ./xxx 命令来执行。

关于shc,博主懂的也不是很多。直接发一个shc解密脚本给大家。

 

#!/bin/bash

#
# Author: Luiz Otavio Duarte a.k.a. (LOD)
#  11/03/08 - v.0.1
#
VERSION="0.1"

OBJDUMP=/usr/bin/objdump
GREP=/bin/grep
CUT=/bin/cut
SHRED=/bin/shred

BINARY=$1
TMPBINARY=$(mktemp /tmp/XXXXXX)

OBJFILE=$(mktemp /tmp/XXXXXX)
STRINGFILE=$(mktemp /tmp/XXXXXX)
CALLFILE=$(mktemp /tmp/XXXXXX)

# Variable to know the index of variables.
j=0 

function usage(){
 echo "!- usage : $0 <file.sh.x>" 
 echo "!- e.g : $0 script.sh.x"
}

function check_binaries() {
 if [ ! -x ${OBJDUMP} ]
 then
  echo "!- Error, cannot execute or find objdump binary" 
  exit 1
 fi
 if [ ! -x ${GREP} ]
 then
  echo "!- Error, cannot execute or find grep binary" 
  exit 1
 fi
 if [ ! -x ${CUT} ]
 then
  echo "!- Error, cannot execute or find cut binary" 
  exit 1
 fi
 if [ ! -x ${SHRED} ]
 then
  echo "!- Error, cannot execute or find shred binary" 
  exit 1
 fi
}

function generate_dump() {
 # Generate objdump to OBJFILE
 $OBJDUMP -D $BINARY > $OBJFILE

 # Generate another dump para STRINGFILE
 $OBJDUMP -s $BINARY > $STRINGFILE
}

function extract_variables_from_binary(){
 ##
 # For ever full address in $CALLFILE
 ##
 for i in $($GREP -Eo "0x[0-9a-f]{7}" $CALLFILE)
 do
 
  echo -n ":- Working with address: $i " 
  # Some diferences in assembly.
  # We can have:
  #  mov <adr>,%eax
  #  push 0x<hex>
  #  push %eax
  #  call $CALLADDR
  #
  #  or
  #
  #  push 0x<hex>
  #  push 0x<adr>
  #  call $CALLADDR
  if [ "x$($GREP "mov.*$i" $CALLFILE)" != "x" ]
  then
   let NBYTES=$($GREP -A 1 -E "$i" $CALLFILE | $GREP push | $GREP -Eo "0x[0-9a-f]+" )
  else
   let NBYTES=$($GREP -B 1 -E "$i" $CALLFILE | $GREP push | $GREP -Eo "0x[0-9a-f]+" )
  fi

  echo -n "." 

  ##
  # Key is the address with the variable content.
  ##
  KEY=$(echo $i | $CUT -d 'x' -f 2)

  ##
  # A 2 bytes variable (NBYTES > 0) can be found like this: (in STRINGFILE)
  # ---------------X
  # X---------------
  #
  # So we need 2 lines from STRINGFILE to make it all correct. So:
  NLINES=$(( ($NBYTES / 16) +2 ))

  # All line in STRINGFILE starts from 0 to f. So LASTBIT tells me the
  #  index in the line to start recording.
  let LASTBYTE="0x${KEY:$((${#KEY}-1))}"

  # echo :-
  # echo :- $KEY: $NBYTES - $LASTBYTE

  # Grep all lines needed from STRINGFILE, merge lines.
  STRING=$( $GREP -A $(($NLINES-1)) -E "^ ${KEY:0:$((${#KEY}-1))}0 " $STRINGFILE | awk '{ print $2$3$4$5}' | tr '\n' 'T' | sed -e "s:T::g")

  echo -n "." 
  # Change string to begin in the line index.
  STRING=${STRING:$((2*$LASTBYTE))}
  # Cut the string to the number off bytes of the variable.
  STRING=${STRING:0:$(($NBYTES * 2))}


  ###
  # We need to mount a \x??\x?? structure so:
  FINALSTRING=""
  for ((i=0;i<$((${#STRING} /2 ));i++))
  do
   FINALSTRING="${FINALSTRING}\x${STRING:$(($i * 2)):2}"
  done

  echo "." 

  define_variable

done
}

function define_variable() {

 ##
 # The variable name depends on the arc4 call sequence.
 ##
 # The first time is called arc4 with MSG1 variable.. and so one.
 ##
 
 if [ $j -eq 0 ]
 then
  VAR_MSG1=$FINALSTRING
  VAR_MSG1_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 1 ]
 then
  VAR_DATE=$FINALSTRING
  VAR_DATE_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 2 ]
 then
  VAR_SHLL=$FINALSTRING
  VAR_SHLL_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 3 ]
 then
  VAR_INLO=$FINALSTRING
  VAR_INLO_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 4 ]
 then
  VAR_XECC=$FINALSTRING
  VAR_XECC_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 5 ]
 then
  VAR_LSTO=$FINALSTRING
  VAR_LSTO_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 6 ]
 then
  VAR_TST1=$FINALSTRING
  VAR_TST1_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 7 ]
 then
  VAR_CHK1=$FINALSTRING
  VAR_CHK1_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 8 ]
 then
  VAR_MSG2=$FINALSTRING
  VAR_MSG2_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 9 ]
 then
  VAR_RLAX=$FINALSTRING
  VAR_RLAX_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 10 ]
 then
  VAR_OPTS=$FINALSTRING
  VAR_OPTS_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 11 ]
 then
  VAR_TEXT=$FINALSTRING
  VAR_TEXT_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 12 ]
 then
  VAR_TST2=$FINALSTRING
  VAR_TST2_Z=$NBYTES
  j=$(($j + 1))
 elif [ $j -eq 13 ]
 then
  VAR_CHK2=$FINALSTRING
  VAR_CHK2_Z=$NBYTES
  j=$(($j + 1))
 fi

}

function extract_password_from_binary(){

 echo :- Extracting password 

 ###
 # The password is used in the key function right before first call to arc4.
 ##
 # So the previous call from the first "call CALLADDR" is the function I need.
 ##

 $GREP -B 8 -m 1 "call   $CALLADDR" $OBJFILE | $GREP -v $CALLADDR > $CALLFILE

 # Discovering the address containing the key.
 KEY_ADDR=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP mov | $GREP -oE "0x[0-9a-z]+")

 # Discovering the key size.
 let KEY_SIZE=$($GREP -B 3 -m 1 "call" $CALLFILE | $GREP push | $GREP -oE "0x[0-9a-z]+")

 # Defining the address without 0x.
 KEY=$(echo $KEY_ADDR | $CUT -d 'x' -f 2)

 # Like the other NLINES
 NLINES=$(( ($KEY_SIZE / 16) +2 ))
 # Like the other LASTBYTE
 let LASTBYTE="0x${KEY:$((${#KEY}-1))}"

 STRING=$( $GREP -A $(($NLINES-1)) -E "^ ${KEY:0:$((${#KEY}-1))}0 " $STRINGFILE | awk '{ print $2$3$4$5}' | tr '\n' 'T' | sed -e "s:T::g")

 STRING=${STRING:$((2*$LASTBYTE))}
 STRING=${STRING:0:$(($KEY_SIZE * 2))}

 FINALSTRING=""
 for ((i=0;i<$((${#STRING} /2 ));i++))
 do
  FINALSTRING="${FINALSTRING}\x${STRING:$(($i * 2)):2}"
 done

 VAR_PSWD=$FINALSTRING
}

function generic_file(){
##
# This function append a generic engine for decrypt
#  from shc project. With my own new variables =P
##
cat > ${TMPBINARY}.c << EOF
#define msg1_z $VAR_MSG1_Z
#define date_z $VAR_DATE_Z
#define shll_z $VAR_SHLL_Z
#define inlo_z $VAR_INLO_Z
#define xecc_z $VAR_XECC_Z
#define lsto_z $VAR_LSTO_Z
#define tst1_z $VAR_TST1_Z
#define chk1_z $VAR_CHK1_Z
#define msg2_z $VAR_MSG2_Z
#define rlax_z $VAR_RLAX_Z
#define opts_z $VAR_OPTS_Z
#define text_z $VAR_TEXT_Z
#define tst2_z $VAR_TST2_Z
#define chk2_z $VAR_CHK2_Z
#define pswd_z $KEY_SIZE

static char msg1 [] = "$VAR_MSG1";
static char date [] = "$VAR_DATE";
static char shll [] = "$VAR_SHLL";
static char inlo [] = "$VAR_INLO";
static char xecc [] = "$VAR_XECC";
static char lsto [] = "$VAR_LSTO";
static char tst1 [] = "$VAR_TST1";
static char chk1 [] = "$VAR_CHK1";
static char msg2 [] = "$VAR_MSG2";
static char rlax [] = "$VAR_RLAX";
static char opts [] = "$VAR_OPTS";
static char text [] = "$VAR_TEXT";
static char tst2 [] = "$VAR_TST2";
static char chk2 [] = "$VAR_CHK2";
static char pswd [] = "$VAR_PSWD";

#define      hide_z     4096

/* rtc.c */

#include <sys/stat.h>
#include <sys/types.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

/* 'Alleged RC4' */

static unsigned char stte[256], indx, jndx, kndx;

/*
 * Reset arc4 stte. 
 */
void stte_0(void)
{
        indx = jndx = kndx = 0;
        do {
                stte[indx] = indx;
        } while (++indx);
}

/*
 * Set key. Can be used more than once. 
 */
void key(void * str, int len)
{
        unsigned char tmp, * ptr = (unsigned char *)str;
        while (len > 0) {
                do {
                        tmp = stte[indx];
                        kndx += tmp;
                        kndx += ptr[(int)indx % len];
                        stte[indx] = stte[kndx];
                        stte[kndx] = tmp;
                } while (++indx);
                ptr += 256;
                len -= 256;
        }
}

/*
 * Crypt data. 
 */
void arc4(void * str, int len)
{
        unsigned char tmp, * ptr = (unsigned char *)str;
        while (len > 0) {
                indx++;
                tmp = stte[indx];
                jndx += tmp;
                stte[indx] = stte[jndx];
                stte[jndx] = tmp;
                tmp += stte[indx];
                *ptr ^= stte[tmp];
                ptr++;
                len--;
        }
}

/* End of ARC4 */

/*
 * Key with file invariants. 
 */
int key_with_file(char * file)
{
        struct stat statf[1];
        struct stat control[1];

        if (stat(file, statf) < 0)
                return -1;

        /* Turn on stable fields */
        memset(control, 0, sizeof(control));
        control->st_ino = statf->st_ino;
        control->st_dev = statf->st_dev;
        control->st_rdev = statf->st_rdev;
        control->st_uid = statf->st_uid;
        control->st_gid = statf->st_gid;
        control->st_size = statf->st_size;
        control->st_mtime = statf->st_mtime;
        control->st_ctime = statf->st_ctime;
        key(control, sizeof(control));
        return 0;
}

void rmarg(char ** argv, char * arg)
{
        for (; argv && *argv && *argv != arg; argv++);
        for (; argv && *argv; argv++)
                *argv = argv[1];
}

int chkenv(int argc)
{
        char buff[512];
        unsigned mask, m;
        int l, a, c;
        char * string;
        extern char ** environ;

        mask  = (unsigned)chkenv;
        mask ^= (unsigned)getpid() * ~mask;
        sprintf(buff, "x%x", mask);
        string = getenv(buff);
        l = strlen(buff);
        if (!string) {
                /* 1st */
                sprintf(&buff[l], "=%u %d", mask, argc);
                putenv(strdup(buff));
                return 0;
        }
        c = sscanf(string, "%u %d%c", &m, &a, buff);
        if (c == 2 && m == mask) {
                /* 3rd */
                rmarg(environ, &string[-l - 1]);
                return 1 + (argc - a);
        }
        return -1;
}

char * xsh(int argc, char ** argv)
{
        char * scrpt;
        int ret, i, j;
        char ** varg;

        stte_0();
         key(pswd, pswd_z);
        arc4(msg1, msg1_z);
        arc4(date, date_z);
        if (date[0] && date[0]<time(NULL))
                return msg1;
        arc4(shll, shll_z);
        arc4(inlo, inlo_z);
        arc4(xecc, xecc_z);
        arc4(lsto, lsto_z);
        arc4(tst1, tst1_z);
         key(tst1, tst1_z);
        arc4(chk1, chk1_z);
        if ((chk1_z != tst1_z) || memcmp(tst1, chk1, tst1_z))
                return tst1;
        ret = chkenv(argc);
        arc4(msg2, msg2_z);
        if (ret < 0)
                return msg2;
        varg = (char **)calloc(argc + 10, sizeof(char *));
        if (!varg)
                return 0;
        if (ret) {
                arc4(rlax, rlax_z);
                if (!rlax[0] && key_with_file(shll))
                        return shll;
                arc4(opts, opts_z);
                arc4(text, text_z);
                printf("%s",text);
                return 0;
                arc4(tst2, tst2_z);
                 key(tst2, tst2_z);
                arc4(chk2, chk2_z);
                if ((chk2_z != tst2_z) || memcmp(tst2, chk2, tst2_z))
                        return tst2;
                if (text_z < hide_z) {
                        /* Prepend spaces til a hide_z script size. */
                        scrpt = malloc(hide_z);
                        if (!scrpt)
                                return 0;
                        memset(scrpt, (int) ' ', hide_z);
                        memcpy(&scrpt[hide_z - text_z], text, text_z);
                } else {
                        scrpt = text;   /* Script text */
                }
        } else {                        /* Reexecute */
                if (*xecc) {
                        scrpt = malloc(512);
                        if (!scrpt)
                                return 0;
                        sprintf(scrpt, xecc, argv[0]);
                } else {
                        scrpt = argv[0];
                }
        }
        j = 0;
        varg[j++] = argv[0];            /* My own name at execution */
        if (ret && *opts)
                varg[j++] = opts;       /* Options on 1st line of code */
        if (*inlo)
                varg[j++] = inlo;       /* Option introducing inline code */
        varg[j++] = scrpt;              /* The script itself */
        if (*lsto)
                varg[j++] = lsto;       /* Option meaning last option */
        i = (ret > 1) ? ret : 0;        /* Args numbering correction */
        while (i < argc)
                varg[j++] = argv[i++];  /* Main run-time arguments */
        varg[j] = 0;                    /* NULL terminated array */
        execvp(shll, varg);
        return shll;
}

int main(int argc, char ** argv)
{
        argv[1] = xsh(argc, argv);
        return 1;
}
EOF
}

##########################################
## Starting
echo ":- unshc - The shc decrypter."
echo ":- Version: $VERSION"

if [ $# -lt 1 ]
then
 usage
 exit 0
fi

if [ ! -e $1 ]
then
 echo "!- Error, File $1 not found."
 exit 1
fi

check_binaries

generate_dump

# find out the most called function. (ARC4 =P)
CALLADDR=$($GREP -Eo "call   [0-9a-f]{7}" $OBJFILE | $GREP -Eo [0-9a-f]{7} | sort | uniq -c | sort | tail -n 1 | $GREP -Eo [0-9a-f]{7})

echo ":- Selected Call: $CALLADDR (arc4)"

##
# find out the parameters used to call CALLADDR. 
# The CALLFILE stores pre-calls, moves and pushes. Before call CALLADDR
##
$GREP -B 3 "call   $CALLADDR" $OBJFILE | $GREP -Ev "(push.*eax)|(--)|(call)|(je)" > $CALLFILE

### echo ":- CALLFILE content "
#cat $CALLFILE


# Retrieve the data used in each parameter.
extract_variables_from_binary


# Now is time to recover the password... funny... password.
extract_password_from_binary

generic_file

gcc -o $TMPBINARY ${TMPBINARY}.c 

echo ":- Executing $TMPBINARY"
echo ":- Generating ${BINARY%x}"

$TMPBINARY > ${BINARY%.x}

$SHRED -zu -n 1 $OBJFILE $CALLFILE $STRINGFILE $TMPBINARY ${TMPBINARY}.c
echo ":- All done!"

exit 0