博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 病毒virus解毒
阅读量:5756 次
发布时间:2019-06-18

本文共 7256 字,大约阅读时间需要 24 分钟。

disinfect.c

/* * = 编译: * gcc -O2 disinfect.c -o disinfect * ./disinfect 
*/#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//elf 相关信息typedef struct elfdesc { Elf64_Ehdr *ehdr; Elf64_Phdr *phdr; Elf64_Shdr *shdr; Elf64_Addr textVaddr; Elf64_Addr dataVaddr; //程序头偏移 Elf64_Addr dataOff; size_t textSize; size_t dataSize; uint8_t *mem; struct stat st; char *path;} elfdesc_t;//缓冲区#define TMP ".disinfect_file.xyz"//如果找到了push/ret 同时地址在正常x86_64范围内//说明正常//判断是否在正常范围内//770CD526 68 00000000 PUSH 0x0//770CD52B C3 RETNuint32_t locate_orig_entry(elfdesc_t *elf){ uint32_t i, entry; uint8_t *mem = elf->mem; for (i = 0; i < elf->st.st_size; i++) { if (mem[0] == 0x68 && mem[5] == 0xc3) { entry = *(uint32_t *)&mem[1]; if (entry >= 0x400000 && entry < 0x4fffff) return entry; } } //没有找到 return 0;}//770CD53A |. 31ED XOR EBP,EBP//770CD53C |. 49 DEC ECX//770CD53D |. 89D1 MOV ECX,EDX//770CD53F |. 5E POP ESI//770CD540 |. 48 DEC EAX//770CD541 |. 89E2 MOV EDX,ESPuint32_t locate_glibc_init_offset(elfdesc_t *elf){ uint32_t i; uint8_t *mem = elf->mem; for (i = 0; i < elf->st.st_size; i++) { if ( mem[i + 0] == 0x31 && mem[i + 1] == 0xed && mem[i + 2] == 0x49 && mem[i + 3] == 0x89 && mem[i + 4] == 0xd1 && mem[i + 5] == 0x5e && mem[i + 6] == 0x48 && mem[i + 7] == 0x89 && mem[i + 8] == 0xe2) return i; } return 0;}//移除 PLT/GOT hooksint disinfect_pltgot(elfdesc_t *elf){ //文件头 Elf64_Ehdr *ehdr = elf->ehdr; //程序头 Elf64_Phdr *phdr = elf->phdr; //节表头 Elf64_Shdr *shdr = elf->shdr; //映射基址 uint8_t *mem = elf->mem; //动态库符号表基地 Elf64_Sym *symtab = NULL; //重定位表 Elf64_Rela *rela = NULL; Elf64_Addr addr = 0, plt_addr = 0; Elf64_Off plt_off = 0, gotoff = 0; size_t plt_size = 0, symtab_size = 0, rela_size = 0; //字符串表基址 char *shstrtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset]; char *strtab = NULL; uint8_t *gotptr, *plt; int i, j, symindex = 0, c = 0; //遍历所有的节表 for (i = 0; i < ehdr->e_shnum; i++) { //类型 switch(shdr[i].sh_type) { //动态库中符号 case SHT_DYNSYM: //符号表 symtab = (Elf64_Sym *)&mem[shdr[i].sh_offset]; symtab_size = shdr[i].sh_size; //对于符号表段sh_link记录的是符号表使用的串表所在段(一般是.strtab)对应段表项在段表内的索引 //.strtab偏移 strtab = (char *)&mem[shdr[shdr[i].sh_link].sh_offset]; break; //重定位所使用的节的节表索引 case SHT_RELA: if (!strcmp(&shstrtab[shdr[i].sh_name], ".rela.plt")) { //重定位表 rela = (Elf64_Rela *)&mem[shdr[i].sh_offset]; //大小 rela_size = shdr[i].sh_size; } break; //程序数据 case SHT_PROGBITS: if (!strcmp(&shstrtab[shdr[i].sh_name], ".plt")) { //plt相关 plt_off = shdr[i].sh_offset; plt_addr = shdr[i].sh_addr; plt_size = shdr[i].sh_size; } break; } } if (plt_off == 0 || symtab == NULL || rela == NULL) { printf("没有找到relocation/symbol/plt info!!!\n"); return -1; } //第一个PLT地址 plt = &mem[plt_off]; //遍历所有重定位表条目 for (i = 0; i < rela_size/sizeof(Elf64_Rela); i++) { //高24 位表示重定位符号对应符号表项在符号表内有索引 symindex = ELF64_R_SYM(rela->r_info); //在symtab中找到puts函数符号 if (!strcmp(&strtab[symtab[ELF64_R_SYM(rela->r_info)].st_name], "puts")) { printf("尝试消毒PLT/GOT!!!\n"); gotoff = elf->dataOff + (rela->r_offset - elf->dataVaddr); gotptr = &mem[gotoff]; addr = gotptr[0] + (gotptr[1] << 8) + (gotptr[2] << 16) + (gotptr[3] << 24); if (!(addr >= plt_addr && addr < plt_addr + plt_size)) { for (c = 0, j = 0; j < plt_size; j += 16, c++) { //判断索引号 if (c == symindex) { printf("成功消毒PLT/GOT表!!!\n"); *(uint32_t *)gotptr = plt_addr + j + 6; return 0; } } } printf(" PLT/GOT表解毒失败!!!\n"); return -1; } } return 0;}//尝试消毒 一般64位的代码加载基址为0x400000int disinfect(elfdesc_t *elf){ size_t paddingSize; Elf64_Phdr *phdr = elf->phdr; Elf64_Shdr *shdr = elf->shdr; uint32_t text_offset = 0; char *strtab = NULL; uint8_t *mem = elf->mem; int i, textfound, fd; ssize_t c, last_chunk; //如果大于0x400000 if (elf->textVaddr >= 0x400000) { printf("不是所要消除的特征!!!\n"); return -1; } //0x400000-代码段的基址(病毒用的逆向text技术) //计算差值 paddingSize = 0x400000 - elf->textVaddr; //如果存在 hook移除 int ret = disinfect_pltgot(elf); //移除magic 标记 *(uint32_t *)&elf->ehdr->e_ident[EI_PAD] = 0x00000000; // PT_PHDR, PT_INTERP 前移 phdr[0].p_offset -= paddingSize; phdr[1].p_offset -= paddingSize; //phdr设置回正常 for (textfound = 0, i = 0; i < elf->ehdr->e_phnum; i++) { if (textfound) { phdr[i].p_offset -= paddingSize; continue; } if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0 && phdr[i].p_flags & PF_X) { if (phdr[i].p_paddr == phdr[i].p_vaddr) { phdr[i].p_vaddr += paddingSize; phdr[i].p_paddr += paddingSize; } else phdr[i].p_vaddr += paddingSize; //重置文本段大小 phdr[i].p_filesz -= paddingSize; phdr[i].p_memsz -= paddingSize; phdr[i].p_align = 0x200000; phdr[i + 1].p_align = 0x200000; textfound = 1; } } //偏移 text_offset = locate_glibc_init_offset(elf); //校正节表 strtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset]; for (i = 0; i < elf->ehdr->e_shnum; i++) { //只要处理感染部分代码 if (!strcmp(&strtab[shdr[i].sh_name], ".text")) { //保持不变 if (text_offset == 0) continue; shdr[i].sh_offset = text_offset - paddingSize; shdr[i].sh_addr = (text_offset - paddingSize) + 0x400000; continue; } shdr[i].sh_offset -= paddingSize; } //设置phdr和shdr表 elf->ehdr->e_shoff -= paddingSize; elf->ehdr->e_phoff -= paddingSize; //设回正常OEP elf->ehdr->e_entry = 0x400000 + text_offset; elf->ehdr->e_entry -= paddingSize; //重建elf if ((fd = open(TMP, O_CREAT | O_TRUNC | O_WRONLY, elf->st.st_mode)) < 0) return -1; if ((c = write(fd, mem, sizeof(Elf64_Ehdr))) != sizeof(Elf64_Ehdr)) return -1; mem += paddingSize + sizeof(Elf64_Ehdr); last_chunk = elf->st.st_size - (paddingSize + sizeof(Elf64_Ehdr)); if ((c = write(fd, mem, last_chunk)) != last_chunk) return -1; if (fchown(fd, elf->st.st_uid, elf->st.st_gid) < 0) return -1; //重命名 rename(TMP, elf->path); return 0;}//加载文件int load_executable(const char *path, elfdesc_t *elf){ uint8_t *mem; Elf64_Ehdr *ehdr; Elf64_Phdr *phdr; Elf64_Shdr *shdr; int fd; struct stat st; int i; if ((fd = open(path, O_RDONLY)) < 0) { perror("open"); return -1; } fstat(fd, &st); mem = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (mem == MAP_FAILED) { perror("mmap"); return -1; } ehdr = (Elf64_Ehdr *)mem; phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff]; shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff]; elf->st = st; //为了找到以0 为偏移的代码段 for (i = 0; i < ehdr->e_phnum; i++) { //非0 为1 0 还是0 switch(!!phdr[i].p_offset) { case 0: elf->textVaddr = phdr[i].p_vaddr; elf->textSize = phdr[i].p_filesz; break; case 1: elf->dataOff = phdr[i].p_offset; elf->dataVaddr = phdr[i].p_vaddr; elf->dataSize = phdr[i].p_filesz; break; } } elf->mem = mem; elf->ehdr = ehdr; elf->phdr = phdr; elf->shdr = shdr; elf->path = (char *)path; return 0;}//检查是否为病毒int test_for_skeksi(elfdesc_t *elf){ uint32_t magic = *(uint32_t *)&elf->ehdr->e_ident[EI_PAD]; return (magic == 0x15D25); }int main(int argc, char **argv){ elfdesc_t elf; if (argc < 2) { printf("Usage: %s
\n", argv[0]); exit(0); } //加载 elf 同时保存相关信息 if (load_executable(argv[1], &elf) < 0) { printf("加载失败: %s\n", argv[1]); exit(-1); } //检查病毒 if (test_for_skeksi(&elf) == 0) { printf("File: %s, 没有感染virus\n", argv[1]); exit(-1); } printf("File: %s, 已经感染virus! 尝试消毒!\n", argv[1]); if (disinfect(&elf) < 0) { printf("消毒失败 file: %s\n", argv[1]); exit(-1); } printf("消毒成功: %s\n", argv[1]);}

转载于:https://blog.51cto.com/haidragon/2135912

你可能感兴趣的文章
基于 Laravel Route 的 ThinkSNS+ Component
查看>>
ClassFlow推出全新课堂活动轨迹功能
查看>>
IDC:超大规模数据中心服务器出货量增长推动市场收入上扬6.3%
查看>>
第七届北大政府CIO班开学聚焦顶层设计与新IT应用
查看>>
OpenSSL 1.1.0b又出漏洞了 OpenSSL内存分配漏洞将会导致本地DoS攻击
查看>>
互联网金融迎来正规军,凤凰构建大版图
查看>>
我的第一篇博客
查看>>
BT亚太总监Neal Gerber:动态网络服务让企业达成服务成本与用户体验的平衡
查看>>
曙光绿色数据中心全国巡展启动 展示全新业务布局
查看>>
如何向云要效益?2017 F5 Agility“构筑智慧云”高峰论坛即将召开
查看>>
金牌体验师探班360浏览器 图多乐趣更多
查看>>
MySQL SSL/TLS连接存在安全漏洞 可遭中间人攻击
查看>>
Cray将集成分析套件带入高端超级计算机
查看>>
阿里云人工智能ET夺肺结节诊断世界冠军
查看>>
光纤激光器原理与特性详解
查看>>
你的服务器真的安全吗?
查看>>
DTCC:Oracle高级总监谈职场进阶法则
查看>>
HTML5的你应该记住的一些知识点
查看>>
IDF 2016:Intel CEO Brian Krzanich携“合并现实”套件亮相
查看>>
你以为只有WannaCry滥用了NSA漏洞?早有隐秘后门走在前面
查看>>