核心逻辑:拓展elf文件空间,写入shellcode。
silvio elf文件感染方法
直接从linux二进制分析里面抄算法
.text感染算法
- 增加ELF文件头中的ehdr->e_shoff(节表偏移)的PAGE_SIZE(页长度)
- 定位text段的phdr 修改入口点
ehdr->e_entry = phdr[TEXT].p_vaddr + phdr[TEXT].p_filesz
增加phdr[TEXT].p_filesz(文件长度)的长度为寄生代码的长度 增加phdr[TEXT].p_memsz(内存长度)的长度为寄生代码的长度 - 对每个phdr(程序头),对应段若在寄生代码之后,则根据页长度增加对应的偏移
- 找到text段的最后一个shdr(节头),把shdr[x].sh_size增加为寄生代码的长度
- 对每个位于寄生代码插入位置之后shdr,根据页长度增加对应的偏移
- 将真正的寄生代码插入到text段的file_base + phdr[TEXT].p_filesz(text段的尾部)
实现拆解
书中,感染算法是走C语言代码实现的(而且网上抄的代码跑不起来,也不好读。。。。所以还是得自己写一遍),由于当时没有好的elf文件patch工具,但是现在我们有了lief,为理解silvio的文件感染思路,打算使用lief来实现一遍。我们把silvio 感染分为两步,拓展 ,植入
如下代码实现了拓展,那植入就看各自所需了。
import lief
obj = lief.parse("./elf1")
segments = obj.segments
sections = obj.sections
header = obj.header
text_sec = obj.get_section(".text")
# print segment which .text belong to .
text_segment = ""
load_flag = False
# extend segments
for segment in segments:
if segment.type == lief.ELF.SEGMENT_TYPES.LOAD:
if segment.has(".text") :
text_segment = segment
segment.physical_size = segment.physical_size + 0x800
segment.virtual_size += 0x800
load_flag = True
continue
# if load_flag == True :
# segment.physical_size += 0x800
# extent sections
sec_flag = False
for sec in sections:
if sec.name == ".fini" :
sec.size += 0x800
#sec.virtual_address += 0x1000
sec_flag = True
continue
# if sec_flag == True :
# sec.size += 0x800
# modify entryp_point
#header.entrypoint = obj.entrypoint + 0x1000
print(type(obj.entrypoint))
obj.write("update_segment_section")
其他各种文件感染方法
data段感染
按照之前的逻辑,先拓展segment,section,再写入shellcode
假设shellcode长度为SIZEdai。
- 增加data section的offset
- 增加data所在segment的memsize 和filesize。
- 延后bss section的位置 —-》 拓展结束
- 调整data权限, 赋予执行权限。
- data 空余部分写入shellcode 。
- 修改ep。
将PT_NOTE 转化PT_LOAD
这个很简单,PT_NOTE 是临近PT_LOAD的最后一个segment,且不会被加载到内存。
0 条评论