先回答摘要的答案:Shell 的安全防护最终是不写 Shell,而是转为写
C++
、Go
等语言并且使用带有混淆加密功能的编译器
前言
Shell 作为有举足轻重地位的解释型语言,安全防护必然是少不了的一个内容,可以怎么防护是一个需要深入的问题
常见混淆加密方案
过于简单或过于复杂的不在此提起
明文混淆加密
gzexe
gzexe
的原理较为简单,本质就是通过 gzip
将源码压缩,放置于脚本文件的尾部,然后解压执行
如果要变种也很简单,比如说多层压缩、多层编码嵌套,但是并没有什么实质作用
gzexe 的优点
- 由于是把处理后的二进制数据直接放在脚本文件内,通过文本编辑器无法直接编辑
gzexe 的缺点
- 由于是把处理后的二进制数据直接放在脚本文件内,执行时需要获取
$0
(也就是自身),从而导致兼容性较差,无法通过.
/source
执行 - 只是单纯把源码处理,可读性极强,解密非常简单
gzexe 的解密
看执行逻辑,然后直接执行对应的解压/解码就可以了
变量混淆
这种混淆的出处暂未找到,本质是将源码中出现的每一个字符都替换成可读性差的变量
变量混淆的优点
- 源码被替换成变量,可读性较差
- 不需要获取
$0
,兼容性优秀
变量混淆的缺点
- 出发点是较好的,但是将源码替换变量后直接使用
eval
执行,极易解密 - 对于较为复杂的源码,可能无法加密
变量混淆的解密
直接把 eval
改成 echo
然后执行,源码就会直接输出出来了
可执行混淆加密
shc
shc
的实现也不复杂,将字符串加密后调用 sh -c
执行
特征也很明显,反编译后看伪代码可以很明显地看出调用 sh -c
执行的这一过程
shc 的优点
- 有字符串加密,如果要直接在二进制层面解密,并非易事
- 通过
sh -c
执行,兼容性尚可
shc 的缺点
- 通过
sh -c
执行,极易解密 - 获取到的
$0
不是其真实名称
shc 的解密
执行后读取 cmdline
即可
shellc/xbash
shellc
是一个强度较高的项目,xbash
的强度更是更上一层楼
shellc/xbash 的优点
shellc
的兼容性较高,支持shell
、perl
、python
、node
、Rscript
、php
等语言shellc
的功能多,可用性强xbash
实现了内置解释器,交给其他解释器和直接内置解释器是完全不一样的强度
shellc/xbash 的缺点
- 反调试不够多,但是由于
xbash
闭源,不知道其具体手段
shellc/xbash 的解密
作者已写,只不过 xbash
的话,没有一些技术手段是弄不出来的
玉龙加密
有这么个东西,但是我没有看到有谁在用,但也说说吧,它还叫什么 XXC 加密?
本质也较为简单,实现的代码极为低劣,处理过程极其抽象
流程是通过 upx
压缩传入,成功则视为二进制,失败则视为脚本
然后处理 upx
特征,并将其加密存放于事先编译好的可执行的尾部
执行的时候是将其解密至 /data/data
内的随机目录,然后如果是可执行就直接执行,如果是脚本则调用 sh
执行
执行后会立即删除解密后的文件
玉龙加密的优点
没有任何优点,可能就是看起来唬人吧?
玉龙加密的缺点
- 本身的实现就很抽象
- 获取到的工作目录不是其真实目录
玉龙加密的解密
要直接在二进制层面解密较为简单,找到尾部标志的位置读取出其尾部数据,然后进行异或解密即可
如果是通过执行来解密,只需要给 /data/data
设置 chattr +a
,然后把 chattr
指令直接干掉即可(因为执行的时候会调用 chattr -a
来防止破解)
进阶混淆加密方案
只提大概方向,不提具体实现
进阶混淆加密大纲
- 不留任何中间文件
- 做好反调试
- 做好真实性校验
- 开头固然重要,执行时更重要
明文进阶混淆加密
明文实际上非常不安全,因为执行完全受到执行者的掌控,所以只能做到尽可能地降低可读性,这里以 AW 加密举例
外层壳
`:|echo 4L0B|tr 0-9A-Z a-z` <<- zako\ desu\ ne \
{ \
for __zako_... in false true \;\
do \$__zako_... \&\& `:|echo 4L0B|tr 0-9A-Z a-z` \
\"\` \
tr -d @%^\\\\\\n \
\| `:|echo 10I4|tr 0-9A-Z a-z`64 -d \
\| bzcat \
\| zcat \
\| cat \
\`\" \;\
done\
\;}
...
zako desu ne
中层壳
__urusai_...=0 <<-sukui\ you\ no\ nai\ hentai `:|echo|sed -E s\ .\*\ MDSvqy==\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g` while\ :\;do\ __urusai_...=\$\(\(__urusai_...+1\)\)\;case\ \$__urusai_...\ in\ 3\)echo\ "\"\``:|echo|sed -E s\ .\*\ wy0n\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`|tr a-zA-Z A-Za-z|sed -E s\ \(.\)\(.\)\(.\)\(.\)\ \\\\\4\\\\\2\\\\\1\\\\\3\ g|`:|echo|sed -E s\ .\*\ wyLjZC2qslKb\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`|`:|echo|sed -E s\ .\*\ MEHj3y=q\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`\`\""\;__urusai_...=\$?\;break\;\;\$__urusai_...\)`:|echo|sed -E s\ .\*\ MDSvqy==\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`\ $(:|echo|sed -E s\ .\*\ S4ihaaaaaacawZoaRqdmrbdmi6HRD4aw0fmkMywp8/FhbNSA1jGQRVAC2DKlrYKHuFgH2S9TH77mdGtAKuHaNHsfkQGEHNAgrmB7hOIFv9obvBYzs/jF0RWrPa/+hxmv8Ut+lTDFDrfDVSpaZ1MGL+8PNIghFBKK9nhApqb7gQs3aqaM=a=a\ \;s\ \(.\)\(.\)\(.\)\(.\)\ \\\4\\\2\\\1\\\3\ g\;q|tr a-zA-Z A-Za-z|`:|echo|sed -E s\ .\*\ wyLjZC2qslKb\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`|`:|echo|sed -E s\ .\*\ 3y0Pqy==\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|tr a-zA-Z A-Za-z|base64 -d|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g`|sed -E s\ \(.\)\(.\)\ \\\2\\\1\ g)\;\;esac\;done\;\(exit\ \$__urusai_...\)
...
sukui you no nai hentai
内层壳(由于换行非常影响可读性,故已去除)
<<-zako-no-kuse-ni `:|echo|sed -E s\ .\*\ 566716c6\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|xxd -r -p` `:|echo|sed -E s\ .\*\ 566716c6\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|xxd -r -p` "\"\``:|echo|sed -E s\ .\*\ 361647\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|xxd -r -p`|sed -E s\ \(.\)\(.\)\ \\\\\2\\\\\1\ g\;s\ \\\\\^\ =\ g|tr a-zA-Z A-Za-z|tr -d @%^|`:|echo|sed -E s\ .\*\ 26163756634302d246\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|xxd -r -p`|`:|echo|sed -E s\ .\*\ a7361647\ \;s\ \(.\)\(.\)\ \\\2\\\1\ g\;q|xxd -r -p`\`\""
...
zako-no-kuse-ni
变量名称中的 ...
是随机名称,其他的则是具体的处理后内容
AW 加密是一个较为简单的多层壳混淆加密,其主要目的是提供艺术性较强的混淆加密,主要防的是低技术人群
AW 加密主要实现了多层壳、低可读性、反调试,由于项目性质,其中并没有添加例如更强的混淆、源码分割、真实性校验、更强的反调试等
并且基于纯 POSIX Shell 实现,在 set -e
情况下也可正常运行,兼容性极佳
AW 加密实现原理
简单来说,就是把 eval
等关键代码去特征化,并且尽可能写不规范但是可正常运行的语句,引号几乎不用,绝大部分都是基于转义连接字符串
这种方案并不保险,不过要增加强度,增强反调试策略、验证解释器/指令真实性、混淆封装指令、分隔处理后的源码、添加伪源码即可,就目前的强度而言,拿来做案例绰绰有余
更强的内容自然是机密
可执行进阶混淆加密
由于强度偏高,不提供实际案例
外置解释器方案
为了不重蹈覆辙 shc
直接 sh -c
带来的后果,可以采用管道执行,还可以通过多线程来确保解释器真实性(如果执行者做了管道转发那就很难说了),但是切忌一次性执行,逐行执行更稳妥
缺点是必须手动执行 exit
,不过这只是个小问题,需要注意的是 $0
需要通过 exec -a
加上一点小手段才能解决,命令行传入则是使用 set --
解决
内置解释器方案
都做到这个地步了,要做的就是反调试和防内存了,要去掉解释器内一切可能暴露源码的内容
当然,有混淆加密的编译器、静态编译、符号剥离同样也相当重要
总结
能别写解释型语言就别写解释型语言啊!