Compilando Shell Scripts com o SHC

De ISPUP!
Ir para navegação Ir para pesquisar

Introdução

Em algumas situações você pode querer que seu código escrito em shell script seja compilado por diversos motivos como por exemplo: esconder alguma informação sigilosa que está dentro do script, uma credencial de acesso à base de dados, ou porque você não quer que alguém altere o código sem a sua permissão, ou porque você não quer entregar o "ouro" da sua consultoria. Enfim, é uma maneira de esconder o seu código dos olhos alheios. Mas existem algumas coisas que temos que ter em mente quando formos usá-lo:

  • Ele não é a prova de NSA (National Security Agency). Não possui uma criptografia de alto nível mas ajuda bastante na tarefa.
  • Não gera binários independentes. Você continuará dependendo do shell e de todos os programas que ele chama.
  • O SHC (Shell Script Compiler) precisa ter no topo do arquivo o shebang, a informação que aponta o shell que será usado, por exemplo: #!/usr/bin/bash ou #!/usr/bin/sh
  • O SHC gera um código em fonte C do shell script, que na sequência é compilado. Sim você precisa ter um compilador C para isso. No processo de execução, o programa é desencriptado e executado como um bash normal; por isso não é um binário independente.
  • Você pode colocar um prazo de validade do binário e uma mensagem para quem executar o programa após vencer a validade. Ex: "Programa expirado contacte fulano".
  • O binário fica bem maior que o seu arquivo shell script.
  • Não pense que a execução do seu novo binário será muito mais rápido que o seu shell, porque como eu disse, o processo é rodado como shell após ser desencriptado.


Instalação

Como é de hábito aqui, faremos isso no Debian, nesse caso a versão 11 (Bullseye). Você pode instalar o SHC em qualquer distribuição GNU/Linux de sua preferência, só precisará checar se já existe um pacote para ele ou se vai precisar compilar o fonte e logicamente ter um compilador C também instalado para isso.

apt install shc build-essential

Utilizando o SHC

Vou pegar como exemplo um script de backup que tenho aqui e que além de fazer backup dos arquivos e diretórios que tenho no servidor, ele gera um backup da base de dados e as tabelas separadamente.

#!/usr/bin/bash
SERVIDOR="azn"
PROVEDOR="Area Zero Network"
TEMP="/usr/local/backup/azn"
USER="root"
PASS="tua_senha_aqui"

dpkg -l > $TEMP/`date +%d`/lista_pacotes.txt
tar -czpf $TEMP/`date +%d`/$SERVIDOR.tar.gz /etc /root /var/www
tar -tzpf $TEMP/`date +%d`/$SERVIDOR.tar.gz
if [ $? -ne 0 ]; then
        echo "Erro gerando backup AZN tar.gz!" | /usr/local/sbin/telegram-notify --error --text -
   exit
fi

rm $TEMP/`date +%d`/*.bz2
for banco in $(mysql -u$USER -p$PASS --execute="show databases" | grep -v Database) ; do
 for tabela in $(mysql -u$USER -p$PASS --execute="show tables" $banco | grep -v Tables_in_) ; do
   if [ "$banco" == "mysql" -a "$tabela" == "general_log" ]; then
      mysqldump -c -u$USER -p$PASS --lock-tables=0 $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2
   else
      if [ "$banco" == "mysql" -a "$tabela" == "slow_log" ]; then
         mysqldump -c -u$USER -p$PASS --lock-tables=0 $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2
      else
         mysqldump -c -u$USER -p$PASS --single-transaction=TRUE $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2
      fi
   fi
   if [ $? -ne 0 ]; then
        echo "Erro gerando backup AZN MariaDB!" | /usr/local/sbin/telegram-notify --error --text -
      exit
   fi
 done
done

echo "Backup do servidor AZN feito corretamente!" | /usr/local/sbin/telegram-notify --success --text -

Esse script além de fazer o backup, me avisa pelo Telegram se foi tudo bem ou se deu algum erro. Percebam que ali na variável PASS teria a senha da base de dados para o backup e não é bom que fique assim disponível para qualquer um ver. Então vamos compilar nosso shell script assim, supondo que o nome dele seja backup.sh.

# shc -o backup -f backup.sh

Esse comando lerá o backup.sh, gerará nosso binário chamado backup e o fonte em C chamado backup.sh.x.c.

# ls -lah backup_*
-rwxrwxr-x 1 root root  17K fev  5 14:19 backup
-rwx------ 1 root root 1,5K fev  5 13:59 backup.sh
-rw-r--r-- 1 root root  25K fev  5 14:19 backup.sh.x.c

Primeira coisa que reparamos é o tamanho de cada arquivo; nosso backup.sh possui um apenas 1,5k de tamanho enquanto o binário ficou com 17k. Mas não vamos ser mesquinhos quanto a isso, porque na maioria das vezes temos bastante recurso de memória nos servidores que mexemos não é mesmo?

Após a execução do binário

Para testar rodei o binário, este fez todo o backup e por fim ainda avisou no meu Telegram. Obs.: em outro artigo mostrarei como configurar esse programa que uso para o Telegram.

Código fonte em C

Vamos olhar como ficou nosso fonte em C?

#if 0
        shc Version 4.0.3, Generic Shell Script Compiler
        GNU GPL Version 3 Md Jahidul Hamid <[email protected]>

        shc -o backup -f backup.sh
#endif

static  char data [] =
#define      chk2_z     19
#define      chk2       ((&data[3]))
        "\132\367\223\065\273\354\372\026\336\302\175\261\134\337\354\357"
        "\375\203\257\174\303\036"
#define      msg2_z     19
#define      msg2       ((&data[26]))
        "\155\236\003\175\207\220\316\347\020\101\333\207\160\021\241\204"
        "\017\071\370\357\256\164\171\203\210"
#define      tst1_z     22
#define      tst1       ((&data[47]))
        "\230\215\223\271\263\242\067\162\123\145\022\201\376\321\007\232"
        "\336\205\051\005\242\301\356\243\232\046\200"
#define      rlax_z     1
#define      rlax       ((&data[74]))
        "\166"
#define      opts_z     1
#define      opts       ((&data[75]))
        "\315"
#define      xecc_z     15
#define      xecc       ((&data[76]))
        "\355\244\240\352\251\255\145\034\004\045\341\147\267\353\330\001"
        "\113"
#define      text_z     1447
#define      text       ((&data[445]))
        "\200\361\155\356\220\160\153\024\371\350\061\363\327\324\216\376"
        "\125\100\311\217\007\243\030\145\307\233\147\023\170\140\363\371"
        "\122\140\347\342\321\123\366\313\073\050\277\023\375\115\021\123"
        "\216\332\343\226\176\373\373\106\227\143\131\020\303\115\011\025"
        "\256\360\370\177\103\357\113\177\027\012\222\025\130\244\151\346"
        "\176\114\175\374\110\171\102\337\334\234\357\237\351\371\265\227"
        "\351\255\027\055\234\143\255\264\156\100\312\306\344\063\255\143"
        "\200\052\140\310\243\243\250\200\100\230\037\052\221\324\301\173"
        "\202\331\250\037\075\126\323\253\226\236\162\173\321\037\336\121"
        "\112\077\032\356\342\302\156\042\133\216\114\354\143\016\147\345"
        "\350\020\004\045\146\330\321\375\166\103\171\110\143\127\231\255"
        "\227\264\233\171\167\012\233\322\230\347\276\373\366\045\340\336"
        "\066\345\004\234\276\325\232\064\030\023\174\173\153\026\051\002"
        "\313\304\174\102\317\027\024\147\377\323\142\366\371\103\324\057"
        "\051\330\314\347\255\146\034\306\172\231\101\346\257\152\351\172"
        "\057\145\275\376\175\321\146\174\245\311\163\236\015\107\315\066"
        "\040\231\036\315\000\072\224\172\323\325\140\203\100\111\376\157"
        "\257\274\156\054\216\325\251\063\236\034\321\253\143\236\342\204"
        "\070\001\122\070\073\346\262\017\273\023\223\373\135\221\153\014"
        "\116\332\071\334\257\342\017\115\376\340\371\142\177\334\347\267"
        "\335\071\357\030\037\242\050\332\266\273\326\024\115\102\040\233"
        "\034\132\167\313\074\207\030\073\147\022\236\347\356\205\236\313"
        "\233\371\176\335\105\332\023\173\031\136\021\047\075\346\271\136"
        "\355\074\167\335\232\056\205\052\300\064\000\012\377\036\170\333"
        "\057\321\206\064\306\260\160\276\226\217\301\254\246\003\034\075"
        "\257\100\264\272\042\105\117\252\060\211\073\163\331\064\317\164"
        "\320\321\000\067\012\234\257\331\110\110\324\153\257\206\234\041"
        "\147\271\357\244\113\105\017\227\127\300\255\111\014\120\272\366"
        "\156\313\217\171\257\066\331\320\066\150\073\234\275\012\364\237"
        "\054\001\154\276\113\361\373\317\053\211\251\217\103\015\043\302"
        "\054\207\100\301\337\232\137\013\056\301\145\105\116\226\222\077"
        "\316\346\311\273\066\256\334\022\176\152\031\351\327\270\315\177"
        "\335\333\154\367\367\166\355\106\355\275\336\335\221\052\350\323"
        "\320\337\211\040\255\271\012\073\311\170\010\055\335\351\360\207"
        "\302\240\366\061\057\042\116\177\165\160\102\357\307\137\053\163"
        "\036\045\043\123\231\007\217\000\212\012\310\121\345\104\343\370"
        "\360\153\324\133\045\353\127\072\167\153\011\151\161\076\067\300"
        "\337\371\270\330\232\207\030\213\046\316\006\302\246\274\005\160"
        "\100\037\351\126\142\242\051\117\046\220\175\351\041\156\155\220"
        "\333\334\125\112\135\336\246\374\252\132\355\054\046\132\326\175"
        "\363\134\114\056\113\163\326\163\160\237\364\026\371\301\226\111"
        "\373\126\264\325\310\061\066\274\115\230\137\055\203\255\047\213"
        "\016\140\143\000\222\073\247\120\056\002\263\170\367\313\050\376"
        "\314\215\225\061\254\140\241\057\151\147\047\342\040\314\174\132"
        "\236\136\154\160\032\233\256\101\310\117\367\264\053\216\326\231"
        "\323\172\362\243\136\201\150\136\035\067\055\325\311\171\307\042"
        "\336\305\276\370\071\123\371\063\006\214\225\125\141\036\076\151"
        "\330\247\141\231\030\370\271\216\140\030\163\365\252\157\224\041"
        "\261\125\147\245\060\030\307\240\300\260\263\021\324\174\203\010"
        "\275\313\254\145\266\340\162\052\020\245\060\232\307\002\102\354"
        "\270\110\011\230\332\035\234\135\020\342\122\260\372\251\302\250"
        "\034\114\171\362\307\166\142\137\270\153\371\117\073\251\352\267"
        "\016\157\220\362\226\117\075\275\041\261\210\074\227\274\045\073"
        "\154\250\217\233\322\023\211\163\044\316\326\372\347\334\310\036"
        "\277\062\335\045\163\221\136\162\147\321\170\016\037\043\073\115"
        "\115\352\250\143\314\210\017\337\211\071\222\026\064\022\115\336"
        "\341\214\240\217\320\057\167\232\043\020\155\272\144\316\222\305"
        "\311\112\213\346\377\036\142\270\241\272\163\363\024\264\157\131"
        "\215\371\345\323\264\074\135\126\222\062\352\220\154\101\363\256"
        "\071\161\210\254\372\312\106\076\273\272\062\221\007\306\164\351"
        "\112\343\360\006\011\362\304\071\307\112\274\125\172\024\174\375"
        "\365\150\307\106\042\357\220\337\253\174\225\247\110\374\066\005"
        "\311\376\230\335\232\304\206\340\374\302\112\346\353\063\340\061"
        "\261\075\302\367\344\374\125\256\245\002\142\105\162\212\060\350"
        "\033\351\206\150\162\020\033\064\375\035\035\016\360\001\373\304"
        "\317\157\266\202\333\316\127\203\041\124\162\347\167\064\322\033"
        "\072\343\231\126\224\371\234\171\372\263\051\075\262\363\203\024"
        "\151\304\264\210\021\353\204\124\245\271\072\250\042\226\044\174"
        "\330\246\271\012\246\334\325\261\331\147\334\335\257\010\362\076"
        "\306\364\231\134\167\242\025\050\273\207\125\166\007\132\101\226"
        "\130\331\174\070\236\063\356\140\371\375\265\270\066\244\010\004"
        "\013\321\352\126\200\372\211\275\204\327\361\346\121\273\121\277"
        "\326\116\013\114\200\245\060\225\047\223\051\172\310\113\065\364"
        "\165\064\225\330\032\240\013\252\074\301\222\162\005\252\223\055"
        "\271\361\313\161\147\236\176\145\315\354\140\111\341\331\207\164"
        "\103\353\061\217\155\135\226\260\263\223\150\124\271\151\146\261"
        "\041\362\050\276\377\350\021\045\336\103\134\235\042\200\217\142"
        "\271\273\154\035\056\354\351\014\077\214\141\057\111\220\255\137"
        "\064\171\377\324\146\251\362\020\325\124\260\101\246\117\167\102"
        "\152\274\034\161\330\240\317\360\155\002\232\256\111\031\336\152"
        "\036\235\015\137\006\314\211\130\310\237\045\034\177\375\143\322"
        "\116\164\006\005\203\260\012\361\012\073\054\014\125\263\301\327"
        "\040\002\072\235\274\002\342\355\042\025\131\250\204\231\300\374"
        "\125\015\006\327\105\311\126\142\257\371\156\034\333\051\316\072"
        "\014\116\327\250\164\037\337\370\254\345\323\067\055\225\257\247"
        "\104\045\176\142\215\246\367\323\356\303\131\101\172\034\356\101"
        "\001\115\054\102\300\062\367\053\056\011\254\375\147\244\265\131"
        "\305\054\230\031\144\171\224\223\246\072\002\244\020\212\303\053"
        "\033\377\017\314\210\064\064\152\303\323\230\152\373\060\070\360"
        "\006\063\272\334\232\257\273\004\002\162\041\177\032\143\334\303"
        "\207\021\153\210\257\075\336\344\151\250\255\111\022\167\104\342"
        "\265\150\000\057\271\331\265\210\357\315\141\374\252\120\035\273"
        "\023\170\117\234\324\071\372\345\272\155\334\311\102\173\026\030"
        "\156\355\362\244\025\367\361\100\212\117\220\342\311\111\240\052"
        "\133\117\365\363\324\364\357\121\171\320\352\103\110\017\055\352"
        "\050\034\222\060\374\335\253\120\211\310\175\374\243\376\135\003"
        "\367\015\374\311\250\146\137\001\377\132\211\136\125\163\124\246"
        "\034\373\002\201\347\376\023\211\010\122\073\356\066\333\234\151"
        "\010\075\141\220\377\163\045\253\001\043\005\170\014\232\005\226"
        "\017\113\177\153\123\350\047\151\174\300\340\060\226\163\072\205"
        "\257\124\101\113\132\112\165\150\040\231\016\245\301\165\020\055"
        "\205\214\260\014\245\213\013\075\062\267\244\162\247\154\301\332"
        "\031\200\231\146\364\111\123\237\273\376\145\000\347\117\017\215"
        "\077\105\240\013\024\024\301\233\046\331\016\242\340\211\212\374"
        "\270\310\037\126\321\133\344\136\336\352\023\075\277\107\011\065"
        "\053\061\041\130\367\217\004\074\300\224\177\361\313\375\215\356"
        "\203\354\272\353\174\144\374\261\210\277\365\073\246\064\061\041"
        "\176\311\260\345\340\164\310\322\133\125\161\330\044\214\346\221"
        "\132\260\311\232\240\364\126\026\242\077\155\122\012\202\163\041"
        "\367\266\130\106\306\360\301\335\175\035\301\253\066\163\163\027"
        "\243\112\112\015\141\013\130\354\204\030\172\043\043\126\003\040"
        "\357\032\200\104\074\042\146\243\003\001\271\132\352\030\310\062"
        "\151\107\040\340\311\050\064\276\216\344\335\061\014\270\350\310"
        "\217\374\026\321\035\261\355\167\051\270\263\260\321\357\030\343"
        "\215\377\322\023\236\235\321\055\202\257\137\217\150\107\130\367"
        "\103\156\310\140\040\265\327\112\156\213\373\077\173\023\043\010"
        "\023\365\034\262\223\355\337\026\235\076\245\005\206\375\374\311"
        "\154\305\052\214\172\001\327\351\215\322\051\010\345\115\021\371"
        "\102\055\253\326\033\213\354\270\311\222\276\117\220\272\031\374"
        "\177\103\211\372\105\140\344\323\062\015\333\030\132\355\021\235"
        "\033\275\164\066\110\141\357\022\363\256\142\204\150\173\201\350"
        "\277\013\343\004\153\307\327\236\325\263\267\057\240\311\315\274"
        "\206\101\363\316\242\342\340\226\220\102\033\371\276\234\342\175"
        "\247\305\202\023\215\132\262\142\015\152\222\256\063\140\152\271"
        "\242\135\210\105\100\150\333\321\253\367\313\151\223\255\347\073"
        "\163\151\117\001\303\001\144\321\153\366\177\237\127\352\131\371"
        "\110\341\076\211\112\032\132\365\021\045\137\245\323\107\340\107"
        "\260\060\110\164\062\254\105\236\243\305\075\372\260\226\363\371"
        "\167\062\202\302\114\334\270\136\002\027\003\326\137\344\035\017"
        "\024\145\204\106\022\312\345\265\220\042\257\100\271\243\072\060"
        "\325\274\363\042\230\253\200\233\303\203\161\042\150\216\062\174"
        "\364\266\303\006\201\250\273\021\313\153\122\204\016\214\265\343"
        "\110\250"
#define      pswd_z     256
#define      pswd       ((&data[2264]))
        "\206\174\026\011\356\071\161\175\153\356\161\041\262\167\243\133"
        "\063\264\047\236\007\253\254\223\141\220\334\012\226\276\135\034"
        "\073\164\046\051\255\230\246\031\207\027\073\072\217\336\225\302"
        "\223\274\141\232\150\015\056\311\236\101\076\361\044\220\317\170"
        "\261\011\034\377\147\300\222\275\137\211\064\206\360\045\346\355"
        "\231\152\334\061\323\337\213\050\041\312\031\106\133\351\276\014"
        "\362\332\014\131\233\237\027\372\050\113\201\030\161\147\006\012"
        "\322\342\073\245\302\307\315\343\222\347\051\355\320\347\372\302"
        "\302\006\034\135\245\063\130\315\177\332\346\360\102\354\373\024"
        "\317\067\271\221\377\207\165\221\157\236\176\077\206\170\002\111"
        "\176\036\247\044\122\000\361\321\332\330\302\034\304\275\060\224"
        "\364\352\046\363\162\233\205\341\071\003\041\300\174\043\011\373"
        "\102\260\037\225\260\021\146\213\351\050\247\256\346\330\102\332"
        "\302\150\316\065\004\123\026\076\127\067\376\323\133\007\317\236"
        "\270\356\063\151\000\232\364\351\303\234\227\251\164\332\204\067"
        "\103\122\154\107\246\202\205\375\272\204\321\026\214\240\264\105"
        "\217\350\256\217\202\243\171\105\077\021\356\264\353\163\353\057"
        "\305\130\167\154\333\375\152\225\201\073\253\015\334\140\123\153"
        "\110\001\373\312\245\164\020\345\205\377\231\161\162\205\240\067"
        "\335\027\244\270\024\016\116\226\112\012\324\064\311\061\121\004"
        "\246\170\055\124\020\324\155\230\354\250\322\174\207\147"
#define      shll_z     14
#define      shll       ((&data[2541]))
        "\201\333\141\250\373\350\322\221\324\376\333\204\172\165"
#define      tst2_z     19
#define      tst2       ((&data[2558]))
        "\255\342\127\230\174\067\202\133\305\341\056\052\041\216\246\161"
        "\266\045\220\035\116\151\114\355"
#define      date_z     1
#define      date       ((&data[2579]))
        "\173"
#define      lsto_z     1
#define      lsto       ((&data[2580]))
        "\061"
#define      msg1_z     65
#define      msg1       ((&data[2585]))
        "\130\134\275\306\206\170\220\063\325\271\325\374\376\070\240\216"
        "\263\032\004\000\156\271\123\225\240\070\024\223\202\157\071\257"
        "\103\314\022\152\374\277\174\330\076\251\125\113\033\155\230\356"
        "\032\306\005\320\306\227\244\323\257\032\172\026\305\153\101\147"
        "\346\271\102\230\037\364\251\157\306\045\366\056\144\020\123\004"
        "\304\340\262\247"
#define      inlo_z     3
#define      inlo       ((&data[2665]))
        "\054\131\301"
#define      chk1_z     22
#define      chk1       ((&data[2670]))
        "\300\122\272\277\177\234\273\371\140\206\142\100\226\064\304\245"
        "\163\143\142\034\026\135\015\306\006"/* End of data[] */;
#define      hide_z     4096
#define SETUID 0        /* Define as 1 to call setuid(0) at start of script */
#define DEBUGEXEC       0       /* Define as 1 to debug execvp calls */
#define TRACEABLE       1       /* Define as 1 to enable ptrace the executable */
#define HARDENING       0       /* Define as 1 to disable ptrace/dump the executable */
#define BUSYBOXON       0       /* Define as 1 to enable work with busybox */

#if HARDENING
static const char * shc_x[] = {
"/*",
" * Copyright 2019 - Intika <[email protected]>",
" * Replace ******** with secret read from fd 21",
" * Also change arguments location of sub commands (sh script commands)",
" * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl",
" */",
"",
"#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */",
"#define PLACEHOLDER \"********\"",
"#include <dlfcn.h>",
"#include <stdlib.h>",
"#include <string.h>",
"#include <unistd.h>",
"#include <stdio.h>",
"#include <signal.h>",
"",
"static char secret[128000]; //max size",
"typedef int (*pfi)(int, char **, char **);",
"static pfi real_main;",
"",
"// copy argv to new location",
"char **copyargs(int argc, char** argv){",
"    char **newargv = malloc((argc+1)*sizeof(*argv));",
"    char *from,*to;",
"    int i,len;",
"",
"    for(i = 0; i<argc; i++){",
"        from = argv[i];",
"        len = strlen(from)+1;",
"        to = malloc(len);",
"        memcpy(to,from,len);",
"        // zap old argv space",
"        memset(from,'\\0',len);",
"        newargv[i] = to;",
"        argv[i] = 0;",
"    }",
"    newargv[argc] = 0;",
"    return newargv;",
"}",
"",
"static int mymain(int argc, char** argv, char** env) {",
"    //fprintf(stderr, \"Inject main argc = %d\\n\", argc);",
"    return real_main(argc, copyargs(argc,argv), env);",
"}",
"",
"int __libc_start_main(int (*main) (int, char**, char**),",
"                      int argc,",
"                      char **argv,",
"                      void (*init) (void),",
"                      void (*fini)(void),",
"                      void (*rtld_fini)(void),",
"                      void (*stack_end)){",
"    static int (*real___libc_start_main)() = NULL;",
"    int n;",
"",
"    if (!real___libc_start_main) {",
"        real___libc_start_main = dlsym(RTLD_NEXT, \"__libc_start_main\");",
"        if (!real___libc_start_main) abort();",
"    }",
"",
"    n = read(21, secret, sizeof(secret));",
"    if (n > 0) {",
"      int i;",
"",
"    if (secret[n - 1] == '\\n') secret[--n] = '\\0';",
"    for (i = 1; i < argc; i++)",
"        if (strcmp(argv[i], PLACEHOLDER) == 0)",
"          argv[i] = secret;",
"    }",
"",
"    real_main = main;",
"",
"    return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end);",
"}",
"",
0};
#endif /* HARDENING */

/* 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 */

#if HARDENING

#include <sys/ptrace.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/prctl.h>
#define PR_SET_PTRACER 0x59616d61

/* Seccomp Sandboxing Init */
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/socket.h>

#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/audit.h>

#define ArchField offsetof(struct seccomp_data, arch)

#define Allow(syscall) \
    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##syscall, 0, 1), \
    BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)

struct sock_filter filter[] = {
    /* validate arch */
    BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ArchField),
    BPF_JUMP( BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0),
    BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),

    /* load syscall */
    BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)),

    /* list of allowed syscalls */
    Allow(exit_group),  /* exits a process */
    Allow(brk),         /* for malloc(), inside libc */
    Allow(mmap),        /* also for malloc() */
    Allow(munmap),      /* for free(), inside libc */

    /* and if we don't match above, die */
    BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
};
struct sock_fprog filterprog = {
    .len = sizeof(filter)/sizeof(filter[0]),
    .filter = filter
};

/* Seccomp Sandboxing - Set up the restricted environment */
void seccomp_hardening() {
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
        perror("Could not start seccomp:");
        exit(1);
    }
    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &filterprog) == -1) {
        perror("Could not start seccomp:");
        exit(1);
    }
}
/* End Seccomp Sandboxing Init */

void shc_x_file() {
    FILE *fp;
    int line = 0;

    if ((fp = fopen("/tmp/shc_x.c", "w")) == NULL ) {exit(1); exit(1);}
    for (line = 0; shc_x[line]; line++) fprintf(fp, "%s\n", shc_x[line]);
    fflush(fp);fclose(fp);
}

int make() {
        char * cc, * cflags, * ldflags;
    char cmd[4096];

        cc = getenv("CC");
        if (!cc) cc = "cc";

        sprintf(cmd, "%s %s -o %s %s", cc, "-Wall -fpic -shared", "/tmp/shc_x.so", "/tmp/shc_x.c -ldl");
        if (system(cmd)) {remove("/tmp/shc_x.c"); return -1;}
        remove("/tmp/shc_x.c"); return 0;
}

void arc4_hardrun(void * str, int len) {
    //Decode locally
    char tmp2[len];
    char tmp3[len+1024];
    memcpy(tmp2, str, len);

        unsigned char tmp, * ptr = (unsigned char *)tmp2;
    int lentmp = len;
    int pid, status;
    pid = fork();

    shc_x_file();
    if (make()) {exit(1);}

    setenv("LD_PRELOAD","/tmp/shc_x.so",1);

    if(pid==0) {

        //Start tracing to protect from dump & trace
        if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
            kill(getpid(), SIGKILL);
            _exit(1);
        }

        //Decode Bash
        while (len > 0) {
            indx++;
            tmp = stte[indx];
            jndx += tmp;
            stte[indx] = stte[jndx];
            stte[jndx] = tmp;
            tmp += stte[indx];
            *ptr ^= stte[tmp];
            ptr++;
            len--;
        }

        //Do the magic
        sprintf(tmp3, "%s %s", "'********' 21<<<", tmp2);

        //Exec bash script //fork execl with 'sh -c'
        system(tmp2);

        //Empty script variable
        memcpy(tmp2, str, lentmp);

        //Clean temp
        remove("/tmp/shc_x.so");

        //Sinal to detach ptrace
        ptrace(PTRACE_DETACH, 0, 0, 0);
        exit(0);
    }
    else {wait(&status);}

    /* Seccomp Sandboxing - Start */
    seccomp_hardening();

    exit(0);
}
#endif /* HARDENING */

/*
 * 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;
}

#if DEBUGEXEC
void debugexec(char * sh11, int argc, char ** argv)
{
        int i;
        fprintf(stderr, "shll=%s\n", sh11 ? sh11 : "<null>");
        fprintf(stderr, "argc=%d\n", argc);
        if (!argv) {
                fprintf(stderr, "argv=<null>\n");
        } else {
                for (i = 0; i <= argc ; i++)
                        fprintf(stderr, "argv[%d]=%.60s\n", i, argv[i] ? argv[i] : "<null>");
        }
}
#endif /* DEBUGEXEC */

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

void chkenv_end(void);

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

        mask = (unsigned long)getpid();
        stte_0();
         key(&chkenv, (void*)&chkenv_end - (void*)&chkenv);
         key(&data, sizeof(data));
         key(&mask, sizeof(mask));
        arc4(&mask, sizeof(mask));
        sprintf(buff, "x%lx", mask);
        string = getenv(buff);
#if DEBUGEXEC
        fprintf(stderr, "getenv(%s)=%s\n", buff, string ? string : "<null>");
#endif
        l = strlen(buff);
        if (!string) {
                /* 1st */
                sprintf(&buff[l], "=%lu %d", mask, argc);
                putenv(strdup(buff));
                return 0;
        }
        c = sscanf(string, "%lu %d%c", &m, &a, buff);
        if (c == 2 && m == mask) {
                /* 3rd */
                rmarg(environ, &string[-l - 1]);
                return 1 + (argc - a);
        }
        return -1;
}

void chkenv_end(void){}

#if HARDENING

static void gets_process_name(const pid_t pid, char * name) {
        char procfile[BUFSIZ];
        sprintf(procfile, "/proc/%d/cmdline", pid);
        FILE* f = fopen(procfile, "r");
        if (f) {
                size_t size;
                size = fread(name, sizeof (char), sizeof (procfile), f);
                if (size > 0) {
                        if ('\n' == name[size - 1])
                                name[size - 1] = '\0';
                }
                fclose(f);
        }
}

void hardening() {
    prctl(PR_SET_DUMPABLE, 0);
    prctl(PR_SET_PTRACER, -1);

    int pid = getppid();
    char name[256] = {0};
    gets_process_name(pid, name);

    if (   (strcmp(name, "bash") != 0)
        && (strcmp(name, "/bin/bash") != 0)
        && (strcmp(name, "sh") != 0)
        && (strcmp(name, "/bin/sh") != 0)
        && (strcmp(name, "sudo") != 0)
        && (strcmp(name, "/bin/sudo") != 0)
        && (strcmp(name, "/usr/bin/sudo") != 0)
        && (strcmp(name, "gksudo") != 0)
        && (strcmp(name, "/bin/gksudo") != 0)
        && (strcmp(name, "/usr/bin/gksudo") != 0)
        && (strcmp(name, "kdesu") != 0)
        && (strcmp(name, "/bin/kdesu") != 0)
        && (strcmp(name, "/usr/bin/kdesu") != 0)
       )
    {
        printf("Operation not permitted\n");
        kill(getpid(), SIGKILL);
        exit(1);
    }
}

#endif /* HARDENING */

#if !TRACEABLE

#define _LINUX_SOURCE_COMPAT
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

#if !defined(PT_ATTACHEXC) /* New replacement for PT_ATTACH */
   #if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
       #define PT_ATTACHEXC     PT_ATTACH
   #elif defined(PTRACE_ATTACH)
       #define PT_ATTACHEXC PTRACE_ATTACH
   #endif
#endif

void untraceable(char * argv0)
{
        char proc[80];
        int pid, mine;

        switch(pid = fork()) {
        case  0:
                pid = getppid();
                /* For problematic SunOS ptrace */
#if defined(__FreeBSD__)
                sprintf(proc, "/proc/%d/mem", (int)pid);
#else
                sprintf(proc, "/proc/%d/as",  (int)pid);
#endif
                close(0);
                mine = !open(proc, O_RDWR|O_EXCL);
                if (!mine && errno != EBUSY)
                        mine = !ptrace(PT_ATTACHEXC, pid, 0, 0);
                if (mine) {
                        kill(pid, SIGCONT);
                } else {
                        perror(argv0);
                        kill(pid, SIGKILL);
                }
                _exit(mine);
        case -1:
                break;
        default:
                if (pid == waitpid(pid, 0, 0))
                        return;
        }
        perror(argv0);
        _exit(1);
}
#endif /* !TRACEABLE */

char * xsh(int argc, char ** argv)
{
        char * scrpt;
        int ret, i, j;
        char ** varg;
        char * me = argv[0];
        if (me == NULL) { me = getenv("_"); }
        if (me == 0) { fprintf(stderr, "E: neither argv[0] nor $_ works."); exit(1); }

        ret = chkenv(argc);
        stte_0();
         key(pswd, pswd_z);
        arc4(msg1, msg1_z);
        arc4(date, date_z);
        if (date[0] && (atoll(date)<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;
        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);
#if HARDENING
            arc4_hardrun(text, text_z);
            exit(0);
       /* Seccomp Sandboxing - Start */
       seccomp_hardening();
#endif
                arc4(text, text_z);
                arc4(tst2, tst2_z);
                 key(tst2, tst2_z);
                arc4(chk2, chk2_z);
                if ((chk2_z != tst2_z) || memcmp(tst2, chk2, tst2_z))
                        return tst2;
                /* Prepend hide_z spaces to script text to hide it. */
                scrpt = malloc(hide_z + text_z);
                if (!scrpt)
                        return 0;
                memset(scrpt, (int) ' ', hide_z);
                memcpy(&scrpt[hide_z], text, text_z);
        } else {                        /* Reexecute */
                if (*xecc) {
                        scrpt = malloc(512);
                        if (!scrpt)
                                return 0;
                        sprintf(scrpt, xecc, me);
                } else {
                        scrpt = me;
                }
        }
        j = 0;
#if BUSYBOXON
        varg[j++] = "busybox";
        varg[j++] = "sh";
#else
        varg[j++] = argv[0];            /* My own name at execution */
#endif
        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 */
#if DEBUGEXEC
        debugexec(shll, j, varg);
#endif
        execvp(shll, varg);
        return shll;
}

int main(int argc, char ** argv)
{
#if SETUID
   setuid(0);
#endif
#if DEBUGEXEC
        debugexec("main", argc, argv);
#endif
#if HARDENING
        hardening();
#endif
#if !TRACEABLE
        untraceable(argv[0]);
#endif
        argv[1] = xsh(argc, argv);
        fprintf(stderr, "%s%s%s: %s\n", argv[0],
                errno ? ": " : "",
                errno ? strerror(errno) : "",
                argv[1] ? argv[1] : "<null>"
        );
        return 1;
}

Conferindo o sigilo

Agora lembra que coloquei na variável de senha da base de dados isso aqui PASS="tua_senha_aqui" ? Vamos checar se ela aparece em algum lugar no binário usando o programa strings, que existe na maioria das distribuições GNU/Linux, e permite extrair strings visíveis de dentro de binários.

# strings backup | grep "tua_senha_aqui"
#

Como pudemos ver, não foi encontrada a senha no binário mas ela encontra-se codificada no fonte em C; então não esqueça de apagar o fonte.

Colocando um prazo de validade no binário

Para colocarmos um prazo de validade no binário façamos assim como exemplo. A data é no formato dd/mm/yyyy (dia/mês/ano).

shc -e 04/03/2023 -m "Seu programa expirou falar com fulano" -o backup -f backup.sh

Dessa data em diante ao executar o binário irá aparecer a mensagem que colocamos.

# ./backup
./backup: has expired!
Seu programa expirou falar com fulano

Finalizando

Basicamente é isso que o SHC faz, acho bem útil para determinadas situações e acredito que possa ajudá-lo em algo nesse sentido. Lembre-se que compartilhar conhecimento é uma via de duas mãos e procure contribuir com seus códigos também. Procure usar esse artifício para necessidades que envolvam um pouco mais de segurança na sua administração de sistemas.

Já ia esquecendo! Depois você pode remover o shc e o build-essential caso não precise mais compilar os scripts.

# apt remove shc build-essential
# apt autoremove

Essa documentação foi útil? Compartilhe, divulgue e ajude outras pessoas. Meus contatos podem ser vistos aqui.