libcurl linux 静态链接库_如何分析Linux恶意程序

f2b49daf4507372182b8dcd047f72d5c.png

6576557a5ae9bd74de7db176a16d49ad.png一、前言 近期接手了不少Linux恶意程序的分析任务,在处理任务的过程中,当然会参考网络中的一些技术文档,于是就发现了一个问题:在各大平台上,关于Linux恶意程序的分析介绍相对较少;所以,自己就想对这方面的知识进行一些弥补,把自己对Linux恶意程序的分析方法和思路提炼分享出来,供大家参考交流。
本篇文章中提到的所有方法均是在本人实际工作中接触使用并提炼出来的,例如:当遇到的rootkit会从自身解密ELF模块,并将其加载进内存中时,才发现详细了解ELF文件结构是多么的重要;当使用IDA远程调试,代码执行逻辑有些混乱时,才发现使用GDB进行调试才是最靠谱的;当需要对嵌入在内核中的内核代码进行调试时,才发现原来使用IDA进行内核调试是多么的方便。 6576557a5ae9bd74de7db176a16d49ad.png二、Linux恶意程序的适用范围 Linux存在着许多不同的Linux版本,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如:路由器、防火墙、台式计算机及服务器等。
因此,在各种Linux内核的设备中,都能被植入Linux恶意程序。 6576557a5ae9bd74de7db176a16d49ad.png三、ELF文件解析 要反编译Linux恶意程序,首先需要理解Linux恶意程序的二进制结构本身;ELF目前已经成为UNIX和类UNIX操作系统的标准二进制格式。在RedHat、Ubuntu、Kail以及其他操作系统中,ELF格式可用于可执行文件、共享库、目标文件、coredump文件,甚至内核引导镜像文件等。因此,要想更好的分析Linux恶意程序,了解ELF文件结构至关重要。

1.ELF文件的编译链接

通过对编译链接过程中生成的不同文件进行分析对比,可以辅助我们更好的理解ELF文件结构。
Linux下ELF文件的编译链接过程主要分为:预处理、编译、汇编、链接;在链接过程中,我们可以根据需求采用静态链接或动态链接。

55c6c1b82bfe04ef311ffec761ac181e.png

4e6b6a36e327c767d47ff91b19721844.png

a.预处理:将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输出到一个“.i”文件中等待进一步处理。
gcc -E -o sum.i sum.c
gcc -E -o main.i main.c
b.编译:把C/C++代码(比如上面的”.i”文件)“翻译”成汇编代码。
gcc -S -o sum.s sum.i
gcc -S -o main.s main.i
c.汇编:将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现位ELF目标文件(OBJ文件)。
gcc -c -o sum.o sum.s
gcc -c -o main.o main.s
d.链接:将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行程序。
gcc -o prog main.o sum.o
e.动态链接:使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。
gcc -o prog_dynamic main.o sum.o
f.静态链接:使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序体积较大。
gcc -static -o prog_static main.o sum.o f425e9b09a10daf19adc6516fe9af4bf.png

2.ELF文件类型

ELF文件类型主要有:可重定位目标文件、可执行目标文件、共享目标文件。
a.可重定位目标文件
包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。一般有扩展名为:“.o” 7a0d95b44047a8f05daaa3720c7d2e87.png b.可执行目标文件
包含二进制代码和数据,其形式可以被直接复制到内存并执行。 413d909e4e641327acc5fd4a0e2d2d52.png c.共享目标文件
一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接。 ce8086799cb10e7218751f1883ad62ed.png

3.ELF结构解析

(1)工具_010editor 为了辅助我们对ELF文件的二进制数据进行查看,我们可以借助010editor工具进行ELF文件分析。
在010editor中使用ELF模板,即可对ELF文件进行结构解析。 80d08c3b00dac0ae00bb590579a02ba1.png 7d6c100c409b9789e2c650516368dd44.png (2)ELF文件数据结构 通过查看ELF.h文件可以找到ELF文件的数据结构信息,在ELF.h文件中,数据类型主要有以下几种: 44601d04d58976efe8029335b9b34164.png ELF目标文件格式的最前部是ELF文件头,它定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表的位置和长度、段的数量。
数据结构如下: 2c37ae7238859baffd878562380c1360.png bc3868d570fe409d950ace066eda13da.png aa14a84061786b04b6e2a809f968911e.png ELF程序头是对二进制文件中段的描述,是程序装载必需的一部分。段是在内核装载时被解析的,描述了磁盘上可执行文件的内存布局以及如何映射到内存中。
程序头数据结构如下: 9d26b74b7abf1213718762033129c679.png b5bf7e74f5ceb98ab3656f0a42d323fb.png 433a11d88b0c73db1950e69dff2025b4.png 段是程序执行的必要组成部分,在每个段中,会有代码或者数据被划分为不同的节。节头表是对这些节的位置和大小的描述,主要用于链接和调试。
节头表数据结构如下: f1f20d8f3b2d0cdabc2aaa0dd35fb237.png 642c90d8687ab95e7ac8d58c3b6a1c96.png 53b1c11d15988708ec4f14e6e1a63698.png 符号表保存了程序实现或使用的所有(全局)变量和函数(包含了程序的导入导出符号)。
符号表数据结构如下: 875fb29d1d31b59550a5940859e3cc45.png 4aa932ff32a17d0656ee43dae7ae114b.png dceae7d9d7b02ebeaf16662c0f3e5af8.png e300da4dbd8e7cba7cbab9745279f449.png 4714094f7634b8f052244e03411df26f.png d43e9fe9535b5120c22741767375e3cd.png ELF文件中还有很多节类型,例如:.text、.got、.plt等,这里暂不一一介绍,网络中有很多分析说明,大家可以自行研究。   6576557a5ae9bd74de7db176a16d49ad.png四、Linux恶意程序分析 由于笔者只是对Linux恶意程序的分析方法进行梳理,因此,暂不使用真实样本进行分析对比;故在这里,我们生成一个正常的ELF文件,用于分析比较。 9a2581831751585590d10ee6b7e894e2.png 73a2e683bc556cd705917a1675a823ab.png

1.静态分析

在分析Linux恶意程序前,我们需要尽可能多的掌握恶意代码的基本情况,才能便于我们选择合适的分析环境,采用适当的分析方法进行分析。
在Linux系统中,提供了多种命令辅助我们对Linux恶意程序进行静态分析,例如:“file”、“readelf”、“ldd”、“strings”、“nm”、“objdump”、“hexdump”命令等。 (1)file命令 在分析Linux样本前,首先需要辨识文件类型,可以通过“file”命令查看文件的类型(可执行文件?位数?链接方式?)。 a9e462284a765a3891c8b23af0049ae3.png 通过file命令,我们可以确定此文件是一个32位的ELF文件,由动态链接库链接而成。 (2)readelf命令 除了使用“file”命令辨识文件类型,我们也可以使用“readelf”命令查看文件的详细格式信息(程序头表、节头表、符号表等)。
备注:在Linux恶意程序分析过程中,恶意程序可能会没有节头表,因为节头对于程序的执行来说不是必需的,没有节头表,恶意程序仍可以运行。 (3)ldd命令 “ldd”命令可以用来查看程序运行所需的共享库,常用来解决程序因缺少某个库文件而不能运行的一些问题。
备注:恶意程序可通过静态编译的方式解决对共享库的依赖,例如:路由器或防火墙中运行的恶意代码。 117b7cab43d4c571bad47ad79340c3de.png

(4)strings命令

通过“strings”命令可以查看Linux样本中的所有字符串: 6ec8bb92b5dfe3701183c3be6f841854.png
/lib/ld-linux.so.2libc.so.6IOstdinusedputslibc_start_maingmon_startGLIBC_2.0PTRhUWVSt$,U[^]hello world!;*2$”(GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609crtstuff.cJCR_LISTderegistertmclonesdo_global_dtors_auxcompleted.7209doglobaldtorsaux_fini_array_entryframe_dummyframe_dummy_init_array_entryhelloworld.cFRAME_END__JCR_ENDinit_array_end_DYNAMICinit_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLElibc_csu_fini_ITM_deregisterTMCloneTablex86.getpcthunk.bxedatadata_startputs@@GLIBC_2.0gmonstartdso_handle_IO_stdin_usedlibc_start_main@@GLIBC_2.0libc_csu_init_fp_hwbss_startmain_Jv_RegisterClasses__TMC_END_ITM_registerTMCloneTable.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.plt.got.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.plt.data.bss.comment
前两行显示了Linux样本使用的库,中间部分可以看到编译器信息为GCC,后面部分为程序各部分的名称。 (5)nm命令 “nm”命令可以用来列出目标文件的符号清单(.dynsym节、.symtab节)。 e550a1f925fc972858120b66aea9c1a1.png (6)objdump工具 分析Linux样本的反汇编代码,最常见的分析工具是IDA,如果Linux样本代码比较简单,也可以使用“objdump”工具: 26b92601124dee741a48a8d38f527e85.png 5c1f7aec7e68f6d4ea1eb4193f8be695.png (7)hexdump工具 查看Linux样本的16进制数据,可以使用“hexdump”工具: 3240c52c47ceae6c53d52ceddadb38c3.png 9c8ab511dae051dbd7fcd13085b61111.png

2.动态分析

Linux平台提供了多种工具支持对Linux样本进行动态分析,我们可以通过调用ltrace和strace对程序调用进行监控;ltrace能够跟踪进程的库函数调用,它会显现出哪个库函数被调用,而strace则是跟踪程序的每个系统调用。 (1)ltrace 用ltrace跟踪Linux样本,如下: b2af7a2338c6270e81091007184abee0.png 我们看到程序调用了puts库函数做了输出,同时0x804840b即是反汇编代码中对应函数地址; 566fa093f75e6d8284c20c8083969722.png (2)strace 用strace跟踪Linux样本,如下: 896055a2ef06dce0a77207f23cb4bd69.png 我们看到程序调用write()系统调用做了输出,同时strace还把程序运行时所做的系统调用都打印出来了。 (3)ftrace 除了ltrace和strace,我们还可以使用基于ptrace编写的相关分析工具,例如:ftrace工具;( https://github.com/elfmaster/ftrace) 78838b7ec33488283dac7197fac6c4a2.png

3.动态调试

(1)GDB 在Linux中调试样本,最常见的调试方法就是使用GDB进行调试,GDB调试可以分为两种情况:
a.调试有调试信息的程序;(使用gcc编译加-g选项)
b.调试没有调试信息的程序;(针对Linux恶意程序的分析,基本都是采用没有调试信息的调试方式。)
有调试信息的程序,如下: 0ba1c325a6bb989876dbf455a666b0b1.png 672b808d674856c8d648f419118497f9.png 无调试信息的程序,如下: c566c7f7337753d3360b09556a1b1422.png 0f180279a8545e8f1eec86e109e05adf.png 在对无调试信息的Linux样本进行分析时,我们首先需要将反汇编语法设置为intel,因为GDB的默认汇编语法是AT&T格式,使用起来可能会有点不习惯;
语法如下:
set disassembly-flavor intel:将汇编指令格式设置为intel格式 b6af6813baf6977350afa8099f7576f1.png 针对部分Linux样本在运行过程中,会执行fork系统调用,我们还可以通过设置follow-fork-mode允许我们选择程序在执行fork系统调用后是继续调试父进程还是调试子进程。其语法如下:
set follow-fork-mode parent:程序执行fork系统调用后调试父进程
set follow-fork-mode child:程序执行fork系统调用后调试子进程 ce3fe56b3f7e33f6a0cba81bd9be95b4.png 在进入正式调试前,我们可以使用“disass”命令查看指定功能的反汇编: 0711ab691d6c27f218630706bd77a65b.png 983ac66b5630dba3d57c795355d71cc2.png 然后通过“b main”、“r”、“display /i $pc”命令运行被调试的程序:
b main:在main函数处下断点;
r:运行被调试的程序;
display /i $pc:每次程序中断后可以看到即将被执行的下一条汇编指令; 5c3542ca08a59913a52f91b317d8db06.png 在调试过程中,通过执行“i r”命令获取寄存器信息: 4ce20742344cca2c8c086bf243e50cf7.png 在调试过程中,通过执行“si”、“ni”命令进行调试:
si:相当于其它调试器中的“Step Into (单步跟踪进入)”;
ni:相当于其它调试器中的“Step Over (单步跟踪)”
在进入函数前,可以通过“x /10xw $esp”命令查看寄存器信息: dc84e248b69f6e579d05db61386ce85b.png GDB调试Linux木马常见命令如下: 777638465482d9c87dd46f8c4a0c5a81.png (2)IDA远程调试 除了使用GDB进行Linux样本调试外,我们还可以使用IDA远程调试对Linux样本进行分析。使用IDA远程调试比使用GDB调试更方便,分析效率更高,但还是有一些局限性,例如:
对具有fork调用的Linux样本,无法设置后续调试模式;
若调试指令运行过快,有时会导致数据通信出错,随即会导致调试流程出错;
IDA远程调试很简单,网上也有很多教程资料,因此这里就简单描述一下步骤即可:
1.用IDA打开Linux样本;
2.在IDA的安装路径(IDA 7.0\dbgsrv\)里找到linux_server或linux_server64,并在Linux环境中运行;
3.在IDA中,选择菜单栏>Debugger>Select a debugger(或者是switch debugger)>选择Remote linux debugger>ok;
4.设置各种参数(调试文件路径,远程Linux虚拟机的ip地址及端口)
5.在IDA中下断点;
6.在IDA中开始调试;  6576557a5ae9bd74de7db176a16d49ad.png五、Linux内核分析 GDB调试和IDA远程调试方法只适用于用户态调试,如果需要调试内核数据,则需要寻求专门的内核调试方法。
使用IDA+Vmware进行内核调试是目前我觉得最方便的分析方法;因此在这里以redhat5.5_i386_2.6.18主机作为案例进行简单演示操作。 07e676192c64ffcfa1f05fd713f34ebe.png

1.修改vmx文件

首先,将虚拟机关机,然后根据虚拟机的不同系统位数,在vmx文件末尾添加以下代码:
32位:
debugStub.listen.guest32 = “TRUE”
debugStub.hideBreakpoints = “TRUE”
debugStub.listen.guest32.remote = “TRUE”
monitor.debugOnStartGuest64 = “TRUE”
64位:
debugStub.listen.guest64 = “TRUE”
debugStub.hideBreakpoints = “TRUE”
debugStub.listen.guest64.remote = “TRUE”
monitor.debugOnStartGuest64 = “TRUE” 5fe6d5b9cf6afe3eb49c944b3c6c12d4.png

2.开启虚拟机

直接将虚拟机系统开机即可;

3.IDA连接

如果是32位系统,则使用ida.exe,在IDA界面中点击:【Debugger】->【Attach】->【Remote GDB debugger】,连接localhost主机的8832端口。
如果是64位系统,则使用ida64.exe,连接localhost主机的8864端口。
32位系统: 5e64d92679af0af2da62092dac3614ad.png d03cc5e9dfd68023ddfe4d67c71f133c.png 9bcbcb386415f4fe40063d83b9047a30.png 64位系统: b357102cc7710ba1d0e925f9f0938b58.png

4.用户态与内核态的切换

IDA连接成功后,虚拟机系统将中断在内核地址中,此时即可对内核中的恶意程序进行断点调试。 dacdbcf9c592818e035007e5855292a0.png 29ec46d31baadce37b1d77f9d472b4fb.png 若需要对恶意程序的用户态代码进行调试,只需在IDA中的以下两个按钮间进行切换即可: 896567bdf2907086f38b597c19f8720d.png 884edbd5c915e0c4f332227211c8756b.png 通过这种方法,我们即可实现对Linux恶意程序的用户态代码、内核态注入代码的全面分析。

5.查看内核代码

在Linux系统中,/boot/System.map包含了整个内核的所有符号;内核地址是从0xC0000000开始的。

(1)查看Linux系统调用表

在Linux主机中,通过查看System.map文件,可以获取系统调用表地址: 54068a9b75ee9af5c38f62df4ce13a50.png 在IDA的Hex View界面中,可以查看Linux主机中系统调用表中的所有系统调用地址: 7ebe7a009a1fc0a7a099ff36e1edeb23.png

(2)查看系统调用函数代码

通过查看System.map文件,可以获取系统调用函数的地址,例如,sys_read函数的内核地址为0xc04765aa; 7e248f017e5b60d3ceb28fa97538f5b4.png 在IDA中,直接跳转至对应地址处即可查看sys_read函数的内核代码。 2ee29bed04864b790b993766b832dbff.png

(3)HOOK

病毒木马程序在执行过程中,可通过修改系统调用表中对应系统调用函数的函数地址,即可实现对系统调用函数的HOOK,例如:修改0xC06224F4处的数据。 4d734c6f7fcbca377900f09d26e2df75.png 6576557a5ae9bd74de7db176a16d49ad.png六、总结 在对Windows恶意样本进行分析的时候,有大量的成熟的界面化工具可以供我们使用;然而在对Linux恶意样本进行分析的时候,此类工具相对较少,并且大部分工具均是命令行操作,因此需要我们熟悉各种命令,才能提升我们的分析效率,达到事半功倍的效果。
在这片文章中,笔者只是对Linux恶意样本的分析方法进行了简单的梳理,后续笔者还会对Linux恶意样本的病毒技术进行梳理,还望大家多多指教。 465b21b505e3ed1b100703a51f1fb023.png

- End -

精彩推荐

红队新思路:利用Windows调试框架在.NET进程内直接调用.NET方法

BlackHat2020议题之Web缓存投毒

php源码分析 require_once 绕过不能重复包含文件的限制

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

465b21b505e3ed1b100703a51f1fb023.png

2d138090e21214c2b1ee9f8cd816f552.gif 戳“阅读原文”查看更多内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值