热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux恶意软件分析:自定义加密算法的不足

一、前言Linux是我最喜欢的操作系统之一,人们很少能看到针对该系统的恶意软件,因此我很好奇,当我的蜜罐捕捉到Linux恶意软件时是怎样的一种场景。本文介绍了我对Linux恶意软件样本的一次分析过程,

一、前言

Linux是我最喜欢的操作系统之一,人们很少能看到针对该系统的恶意软件,因此我很好奇,当我的蜜罐捕捉到Linux恶意软件时是怎样的一种场景。本文介绍了我对Linux恶意软件样本的一次分析过程,重点分析了该软件所用的解密函数。通过这个案例,我们就能知道为何使用自己的加密算法并不是特别安全。

 

二、样本分析

与常见的分析过程一样,首先我把该样本提交到VirusTotal,观察检测结果,如下所示:

从结果中可知,59家厂商中只有34家成功识别出这一款恶意软件,考虑到这是一个Linux程序,这个结果也比较正常。该程序没有经过封装,VirusTotal的分析结果中也没有给出特别有趣的信息。接下来,我通过rabin2工具获取了该样本的一些基本信息,如下所示:

arch x86
binsz 646674
bintype elf
bits 32
canary false
class ELF32
crypto false
endian little
havecode true
lang c
linenum true
lsyms true
machine Intel 80386
maxopsz 16
minopsz 1
nx true
os linux
pcalign 0
pic false
relocs true
rpath NONE
static true
stripped false
subsys linux
va true

同样没有得到比较有趣的信息。这款Linux程序使用C语言编写而成。然而,如果我们在rabin2中使用-E标志,我们可以分析其中的导出信息,事情开始变得有趣起来:

[Exports]
956 0x00020070 0x08068070 GLOBAL FUNC 1365 __vsyslog_chk
957 0x00073c00 0x080bbc00 GLOBAL OBJECT 36 _nl_C_LC_CTYPE
959 0x00021790 0x08069790 GLOBAL FUNC 8 __stack_chk_fail_local
965 0x0008b9e8 0x080d49e8 GLOBAL OBJECT 4 __morecore
966 0x0001fc80 0x08067c80 GLOBAL FUNC 41 __getdtablesize
967 0x00014f80 0x0805cf80 GLOBAL FUNC 40 _IO_remove_marker
969 0x00009090 0x08051090 GLOBAL FUNC 291 __libc_sigaction
970 0x00051ef0 0x08099ef0 GLOBAL FUNC 69 __isnanl
971 0x00042ae0 0x0808aae0 GLOBAL FUNC 170 __libc_pread
974 0x0001db60 0x08065b60 GLOBAL FUNC 34 strcpy
975 0x0003c460 0x08084460 GLOBAL FUNC 200 _IO_wdefault_xsgetn
976 0x00012080 0x0805a080 GLOBAL FUNC 9 __fcloseall
977 0x00020630 0x08068630 GLOBAL FUNC 44 __syslog
978 0x00000ba3 0x08048ba3 GLOBAL FUNC 74 V8ULRand
979 0x0000e600 0x08056600 GLOBAL FUNC 234 __setstate_r
980 0x0006ce50 0x080b4e50 GLOBAL FUNC 213 _dl_vsym

从输出结果中我们可以清楚地看到所有的对象信息及函数名称。作者可能会在调试该恶意软件的时候用到这些信息。现在我们不需要使用radare2来为这些函数设置名称,因为一切已近在眼前。接下来,我们可以将程序传给radare2,查找主函数。

我首先注意到的就是如下一段代码:

从代码注释中,我们可以看到名为strHost的一个字符串,同时我们也知道strHost作为参数被传递给DecryptData函数。据此我们可以猜测,strHost中可能会保存恶意软件需要连接的某些主机名或者地址信息,DecryptData会解密这个字符串,解析出正确结果,还原“yy123-e4213-mfs”对应的真实值。现在,我们可以跳转到DecryptData,分析代码内容。

首先,我们可以看到某个计数器变量被赋值为0(请注意:我使用afvn命令重命名了该函数中的所有变量,以便后续分析)。接下来,代码开始循环检查计数器变量值是否小于字符串的长度(即以参数传入的字符串)。如果小于字符串长度,则会跳转到该循环对应的主逻辑代码中。

如果你在逆向分析方面不是特别熟练,这段代码看起来可能比较复杂,这里我会详细介绍这段代码的功能。程序会将字符串的当前索引传递给另一个计数器变量(不要去纠结作者为什么这么做,有许多方法可以完成这个任务),然后使用0x55555556这个十六进制数来声明一个新的变量,这个值充当了“魔术数”(magic number)角色,可以提高除法运算的性能。这个数字对应的十进制数值为1431655766。如果我们将某个数乘以这个数,然后将结果逻辑右移32位,所得的结果与原数除以3的结果相同。虽然这是我第一次看到这个魔术数,我会尽力去解释这个过程,因为该过程的确非常有趣。

以数字6为例,该数字除以3得到的结果为2。在这种情况下,6 * 1431655766的结果为8589934596,二进制表示如下:

1000000000000000000000000000000100

现在如果我们将结果右移32位,得到如下结果:

0000000000000000000000000000000010

该结果对应的正是十进制的2!这是非常有趣的一个小技巧,我们可以借此了解计算机架构的工作过程。这的确是除法运算,但并没有用到我们常见的除法操作!大家可以阅读这篇文章了解这方面的更多信息。

回到这个程序上面来,程序会通过这个魔术数来处理计数器,将某个变量的值赋值为0、1或者2。如果变量值为1,则跳转到某个代码片段,否则就跳转到另一个代码片段。接下来我们来看一下这两个代码分支。

这两个分支功能基本相同,只有些许差别。刚开始时这两个分支都会检查当前索引处的字符的十六进制值是否小于或等于0x20(空格符)。如果满足该条件,就不处理这个字符,增加计数器值,继续下一次迭代过程。如果不满足该条件,那么代码会检查该值是否等于0x7f(ASCII表中的DELETE字符)。如果等于该值,则不处理这个字符,继续下一次迭代过程。如果不等于,那么继续解密过程。这样做会将待处理的字符限制在可写的ASCII字符范围内,即0x20–0x7f。

因此,如果计算出来的魔术变量等于1,则我们会进入左边分支,在字符范围检查过程后,将该字母减1。也就是说,B会变成A,D会变成C,以此类推。如果魔术变量不等于1,那么则将字母加1,A变成B,C变成D,以此类推。整个过程就是这么简单,并不可怕,根据该过程我们很容易就能解密出原始字符串。现在来看看strHost字符串(即“yy123-e4213-mfs”)的处理结果。

首先,将该字符串中的每个字符都对应成0、1或者2,具体值与魔术数的处理结果相同。

y y 1 2 3 - e 4 2 1 3 - m f s
0 1 2 0 1 2 0 1 2 0 1 2 0 1 2

接下来,对于每个字符,如果对应的值不为1,那么我会将其ASCII值1,对于值为1的那些字符,我会将其ASCII值1。

zx232.f3322.net

从结果可知,这款恶意软件很有可能会连接到zx232.f3322.net这个主机,该主机很有可能是命令与控制中心。

我写了个python脚本,可以解压使用这种加密方式的所有字符串:

def decrypt_string(string, length):
counter = 0 #local_4h
local_18 = 0
local_1c = 0
new_string = ''
while counter if not local_18 == 1:
letter = string[counter]
if not letter == ' ':
new_string += chr(ord(letter)+1)
else:
letter = string[counter]
if not letter == ' ':
new_string += chr(ord(letter)-1)
counter += 1
local_18 += 1
if local_18 > 2:
local_18 = 0

该样本中找到的其他变量以及解密后的结果如下所示:

该样本的剩余部分非常简单。样本会将自身拷贝至/etc/.zl/tmp/.lz以及/etc/init.d/.zl文件。接下来,恶意软件会在rc2.drc3.drc4.d以及rc5.d中创建副本,并以符号链接方式将这些副本链接到/etc/init.d中的.zl文件。由于系统在启动时会调用这些文件,因此这样做就能达到本地持久化目标。如果你在系统中看到这些文件,就可以将其作为基于主机的标识符来识别这款恶意软件。接下来,恶意软件会ping地址为zx232.f3322.net服务器的54188端口,希望收到某些响应数据,我们可以将其作为基于网络的标识符来识别这款恶意软件。我还没有看到这款恶意软件收到过服务器返回的响应数据,这可能由几个原因所造成。比如,服务器可能已经下线、控制者当时不想发送命令等等。我猜测程序会从服务器那收到命令,然后再执行这些命令。

 

三、总结

这款恶意软件最有趣的部分就是解密函数了,因此从这篇文章中,我们可以吸取一些教训,那就是使用自定义的加密算法并不是个好主意。对于这个样本,我们可利用这种算法解密许多字符串,了解恶意软件的具体功能。分析这个样本的过程非常有趣,希望大家阅读本文时也能兴趣盎然。在恶意软件分析方面我还是一名新手,因此如果大家有什么意见或者建议欢迎随时向我反馈。大家可以通过我的Twitter以及Linkedin页面来联系我。

感谢阅读本文,希望大家享受逆向分析过程。


推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 配置IPv4静态路由实现企业网内不同网段用户互访
    本文介绍了通过配置IPv4静态路由实现企业网内不同网段用户互访的方法。首先需要配置接口的链路层协议参数和IP地址,使相邻节点网络层可达。然后按照静态路由组网图的操作步骤,配置静态路由。这样任意两台主机之间都能够互通。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 本文介绍了使用Rust语言编写、保存和编译程序的简单步骤。首先,打开记事本文件并编写程序代码,然后将代码保存到一个以.rs为扩展名的文件中。接下来,使用rustc命令来编译运行程序。最后,通过命令行运行编译后的程序,得到输出结果。如果遇到编译错误,可以下载Build Tools for Visual Studio 2017来解决。 ... [详细]
  • c语言基础编写,c语言 基础
    本文目录一览:1、C语言如何编写?2、如何编写 ... [详细]
author-avatar
金豪情圣
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有