本篇文章中提到的所有方法均是在本人实际工作中接触使用并提炼出来的,例如:当遇到的rootkit会从自身解密ELF模块,并将其加载进内存中时,才发现详细了解ELF文件结构是多么的重要;当使用IDA远程调试,代码执行逻辑有些混乱时,才发现使用GDB进行调试才是最靠谱的;当需要对嵌入在内核中的内核代码进行调试时,才发现原来使用IDA进行内核调试是多么的方便。
因此,在各种Linux内核的设备中,都能被植入Linux恶意程序。
1.ELF文件的编译链接
Linux下ELF文件的编译链接过程主要分为:预处理、编译、汇编、链接;在链接过程中,我们可以根据需求采用静态链接或动态链接。
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
2.ELF文件类型
a.可重定位目标文件
包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。一般有扩展名为:“.o”
包含二进制代码和数据,其形式可以被直接复制到内存并执行。
一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接。
3.ELF结构解析
在010editor中使用ELF模板,即可对ELF文件进行结构解析。
数据结构如下:
程序头数据结构如下:
节头表数据结构如下:
符号表数据结构如下:
1.静态分析
在Linux系统中,提供了多种命令辅助我们对Linux恶意程序进行静态分析,例如:“file”、“readelf”、“ldd”、“strings”、“nm”、“objdump”、“hexdump”命令等。
备注:在Linux恶意程序分析过程中,恶意程序可能会没有节头表,因为节头对于程序的执行来说不是必需的,没有节头表,恶意程序仍可以运行。
备注:恶意程序可通过静态编译的方式解决对共享库的依赖,例如:路由器或防火墙中运行的恶意代码。
(4)strings命令
/lib/ld-linux.so.2
libc.so.6
IOstdinused
puts
libc_start_main
gmon_start
GLIBC_2.0
PTRh
UWVS
t$,U
[^]
hello world!
;*2$”(
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
crtstuff.c
JCR_LIST
deregistertmclones
do_global_dtors_aux
completed.7209
doglobaldtorsaux_fini_array_entry
frame_dummy
frame_dummy_init_array_entry
helloworld.c
FRAME_END
__JCR_END
init_array_end
_DYNAMIC
init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE
libc_csu_fini
_ITM_deregisterTMCloneTable
x86.getpcthunk.bx
edata
data_start
puts@ .0
gmonstart
dso_handle
_IO_stdin_used
libc_start_main@ .0
libc_csu_init
_fp_hw
bss_start
main
_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
2.动态分析
3.动态调试
a.调试有调试信息的程序;(使用gcc编译加-g选项)
b.调试没有调试信息的程序;(针对Linux恶意程序的分析,基本都是采用没有调试信息的调试方式。)
有调试信息的程序,如下:
语法如下:
set disassembly-flavor intel:将汇编指令格式设置为intel格式
set follow-fork-mode parent:程序执行fork系统调用后调试父进程
set follow-fork-mode child:程序执行fork系统调用后调试子进程
b main:在main函数处下断点;
r:运行被调试的程序;
display /i $pc:每次程序中断后可以看到即将被执行的下一条汇编指令;
si:相当于其它调试器中的“Step Into (单步跟踪进入)”;
ni:相当于其它调试器中的“Step Over (单步跟踪)”
在进入函数前,可以通过“x /10xw $esp”命令查看寄存器信息:
对具有fork调用的Linux样本,无法设置后续调试模式;
若调试指令运行过快,有时会导致数据通信出错,随即会导致调试流程出错;
IDA远程调试很简单,网上也有很多教程资料,因此这里就简单描述一下步骤即可:
1.用IDA打开Linux样本;
2.在IDA的安装路径(IDA 7.0dbgsrv)里找到linux_server或linux_server64,并在Linux环境中运行;
3.在IDA中,选择菜单栏>Debugger>Select a debugger(或者是switch debugger)>选择Remote linux debugger>ok;
4.设置各种参数(调试文件路径,远程Linux虚拟机的ip地址及端口)
5.在IDA中下断点;
6.在IDA中开始调试;
使用IDA+Vmware进行内核调试是目前我觉得最方便的分析方法;因此在这里以redhat5.5_i386_2.6.18主机作为案例进行简单演示操作。
1.修改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”
2.开启虚拟机
3.IDA连接
如果是64位系统,则使用ida64.exe,连接localhost主机的8864端口。
32位系统:
4.用户态与内核态的切换
5.查看内核代码
(1)查看Linux系统调用表
(2)查看系统调用函数代码
(3)HOOK
在这片文章中,笔者只是对Linux恶意样本的分析方法进行了简单的梳理,后续笔者还会对Linux恶意样本的病毒技术进行梳理,还望大家多多指教。
- End -
精彩推荐
红队新思路:利用Windows调试框架在.NET进程内直接调用.NET方法
BlackHat2020议题之Web缓存投毒
php源码分析 require_once 绕过不能重复包含文件的限制
一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论