- A+
所属分类:笔记
Silvio. text感染算法
- ELF文件头的
ehdr->e_shoff
增加page_size
的大小。 - 定位
text
段的phdr
- 入口点修改为寄生代码的位置。
- 将
phdr[TEXT].p_filesz
增加寄生代码的长度值。 - 将
phdr[TEXT].p_memsz
增加寄生代码的长度值。
- 对应的段位于寄生代码之后的
phdr
,将phdr[x].p_offset
增加PAGE_SIZE
大小的字节。 - 找到 text 段的最后一个
shdr
,将shdr[x].sh_size
增加寄生代码的长度值(因为在这个节中将会存放寄生代码)。 - 对每个位于寄生代码插入位置之后的
shdr
,将shdr[x].sh_offset
增加PAGE_SIZE
的大小值。 - 将真正的寄生代码插入到
text
段的file_base + phdr[TEXT].p_filesz
。
逆向text感染
允许注入比较大的病毒代码,还允许将入口点指向.text
节。
- 将
ehdr-e_shoff
增加PAGE_ROUND(parasite_len)
。 - 找到
text
段和phdr
,保存p_vaddr
的初始值。
- 将
p_vaddr
减小PAGE_ROUND(parasite_len)
- 将
p_paddr
减小PAGE_ROUND(parasite_len)
- 将
p_filesz
增加PAGE_ROUND(parasite_len)
- 将
p_memsz
增加PAGE_ROUND(parasite_len)
- 找出所有的
p_offset
比text
的p_offset
大的phdr
,并将对应的p_offset
增加PAGE_ROUND(parasite_len)
- 将
ehdr-e_entry
设置为:
orig_text_vaddr -PAGE_ROUND(parasite_len)+sizeof(ElfN_Ehdr)
- 将
ehdr-e_phoff
增加PAGE_ROUND(parasite_len)
- 创建一个新的二进制文件映射出所有的修改,插入真正的寄生代码,然后覆盖掉旧的二进制文件。
PT_NOTE -> PT_LOAD转换感染
将
PT_NOTE
段的类型改为PT_LOAD
,然后将段的位置移到其他所有段之后。
感染控制流
寄生函数代替二进制文件中的某个已有函数执行,这就是所谓的函数劫持
- 直接PLT感染
- 修改PLT代码,使其存放不同的指令来改变控制流。
.plt
节位于text
段,只读,不能用于检测程序漏洞。
- 函数蹦床
含义:使用某种能够改变控制流的分支指令重写函数代码的前 5~7 个字节,重写完后调用寄生函数。有些常见的用例场景下,寄生函数需要调用最初的函数,那么寄生函数需要将原有函数的这前 5~7 个字节修改成原先的指令,然后进行调用。
- 重写
.ctors/.dtors
函数指针
.ctors/.init_array
函数指针会在 main()
函数调用之前触发,可以通过重写某个指向正确地址的指针来将控制流指向病毒或者寄生代码。
远程代码注入技术
1.共享库注入
- .so感染/
ET_DYN
感染 来将一个共享库(无论恶意与否)注入到已存在的进程地址空间中,要通过 PLT/GOT 重定向、函数蹦 床等将感染点之一重定向到共享库。 - .so感染——使用
LD_PRELOAD
设置LD_PRELOAD
环境变量,将想要的共享库放在其他共享库之前加载,该技术可以用来快速测试 PLT/GOT 重定向等技术,不过并不隐蔽。 - 利用open()/mmap() shellcode 通过往已存在的进程的 text 段中注入 shellcode(使用 ptrace)并执行 shellcode,利用共享库上的 open/mmap 操作,将任何文件(包括共享库)注入到进程的地址空间中。
- 使用dlopen() shellcode 一个可执行文件在没有第一时间被链接的情况下,会使用 dlopen()函数来动态加载共享库。
2.text段代码注入
- 创建函数蹦床或者需要直接修改.plt代码时。
- 最好将代码加载到进程中,或者创建可以存储代码的新的内存映射。
3.可执行文件注入
PoC-elfdemon
,将可执行文件映射到新的映射区域,然后劫持控制流,注入程序执行完之后将控制流重新传个宿主进程。
4.重定位代码注入-ET_REL
注入
- 不兼容dlopen()
- ET_REL不能作为单独的文件执行,可链接到可执行文件或者共享库中。
ELF反调试和封装技术
PTRACE——TRACEME
技术
- 利用进程追踪的特性---一个程序在同一时间只能被一个进程追踪。该技术让程序追踪自身, 这样 调试器就无法附加到该进程上。
SIGTRAP
处理技术
- 设置一个信号处理器来捕获SIGTRAP信号,然后故意发出一个断点指令,信号处理器捕获到SIGTRAP信号之后,会将一个全局变量从0加到1。
- 然后程序对该全局变量检查,若为1,说明没有被调试器调试,反则,该程序正在被调试。
/proc/self/status
技术
- 每个进程的动态文件中就存放了进程是否正在被追踪的相关信息。
- 打开/proc/self/status,检查该项值是否为0,若否,则说明程序正在被追踪。
- 代码混淆技术(代码转换技术)
- 通过修改汇编层的代码来引入不明确的分支指令或者未对齐指令,使得反汇编程序无法正确读取字节码文件。
- 字符串表转换技术
- 打乱每个符号名和节相关信息的顺序,以致可能出现的结果就是所有的节头、函数名和符号名看上去都是乱序混在一起的。
- ELF病毒检测和杀毒
Linux二进制保护
ELF二进制加壳器
加壳器: 对可执行文件进行压缩或加密,来对代码和数据进行混淆。例如加壳工具 UPX。
存根机制和用户层执行
- 软件保护器
- 保护阶段的代码:应用到目标二进制文件上的保护程序。
- 运行时引擎或存根:与目标二进制文件合并在一起,负责运行时反混淆和反调试的程序。
- 存根
- 一个相对简单的运行时引擎与被保护的二进制合并在一起,该运行时引擎称之为存根(封装器)。
- 用户层执行
- 在内存中对可执行文件进行解密,然后再内存中加载并执行,由于该过程使用用户层代码来完成,所以称为用户层执行。