频道直达 - 专题 - 新闻 - 技巧 - 组网 - 开发 - 安全 - web编程 - 图像 - 操作系统 - 数据库 - 教育 - 旅游 - 健康 - 时尚 - 驱动 - 软件 - 游戏 - 多媒体 - ERP - 讨论组

从core映像文件中重新构造ELF可执行文件

来源:ChinaITLab 作者: 出处:巧巧读书 2006-08-08 进入讨论组
关 键 词:.net  ie  linux  unix  病毒  

  /////////////////////////////////////////////////////////////////////////////////////
  最近会贴一些当初学习unix病毒和elf结构时的文章,帮助大家理解elf格式,以及
  利用这些知识做一些比较有趣的事情
  /////////////////////////////////////////////////////////////////////////////////////
  
  从core映像文件中重新构造ELF可执行文件
  ------------------------------------------------
  
  - Silvio Cesare
  - December 1999
  - http://www.big.net.au/~silvio
  - http://virus.beergrave.net/
  整理:e4gle from www.whitecell.org
  
  目录
  -----------------
  
  2.0到2.2内核的改变
  绪论
  进程映像
  core映像
  重建可执行文件
  重建失败的一些例子
  实现
  
  
  2.0到2.2内核的改变
  ------------------------------
  
  本文主要是针对linux的2.0.x内核,但是这些代码应该也可以在2.2.x执行.2.0.x内核和2.2.x内
  核的内存映像是有区别的,包括ELF的core dump的映像我想也有所改变.译者注:我尽力调试此文档
  使它可以适合2.2.x内核.
  
  
  绪论
  ------------
  
  这篇文档实践并讲述了在给定一个core dump或者进程映像的快照文件下重新构造ELF可格式的二进制
  可执行文件的技术.对于本文的读者,ELF格式的相关知识是必要的.
  
  
  进程映像
  -----------------
  
  简单来说,一个core映像就是进程映像发生dump的那个时候的快照.进程映像包括了许多可加载的程序段
  或虚拟内存区.这在一个ELF格式的二进制文件里涉及程序头,在linux内核里涉及到vm_area_struct
  结构.一个core dump就是vm_area_struct的dump,而相应的可执行程序头和共享库用来创建进程
  映像.在linux里,一组vm_area_struct为proc伪文件系统提供了内存映像.我们看一下下面这个例子,
  这是一个拥了libc的典型的映像:
  
  [e4gle@linux]# cat /proc/31189/maps
  08048000-0804d000 r-xp 00000000 03:08 243714 /bin/login
  0804d000-0804e000 rw-p 00004000 03:08 243714 /bin/login
  0804e000-0805a000 rwxp 00000000 00:00 0
  40000000-40013000 r-xp 00000000 03:08 304059 /lib/ld-2.1.3.so
  40013000-40014000 rw-p 00012000 03:08 304059 /lib/ld-2.1.3.so
  40014000-40016000 rw-p 00000000 00:00 0
  40016000-40018000 r-xp 00000000 03:08 96347 /lib/security/pam_securetty.so
  40018000-40019000 rw-p 00001000 03:08 96347 /lib/security/pam_securetty.so
  40019000-4001a000 r-xp 00000000 03:08 96341 /lib/security/pam_nologin.so
  4001a000-4001b000 rw-p 00000000 03:08 96341 /lib/security/pam_nologin.so
  4001c000-40021000 r-xp 00000000 03:08 304068 /lib/libcrypt-2.1.3.so
  40021000-40022000 rw-p 00004000 03:08 304068 /lib/libcrypt-2.1.3.so
  40022000-40049000 rw-p 00000000 00:00 0
  40049000-40050000 r-xp 00000000 03:08 304304 /lib/libpam.so.0.72
  40050000-40051000 rw-p 00006000 03:08 304304 /lib/libpam.so.0.72
  40051000-40053000 r-xp 00000000 03:08 304075 /lib/libdl-2.1.3.so
  40053000-40055000 rw-p 00001000 03:08 304075 /lib/libdl-2.1.3.so
  40055000-40057000 r-xp 00000000 03:08 304307 /lib/libpam_misc.so.0.72
  40057000-40058000 rw-p 00001000 03:08 304307 /lib/libpam_misc.so.0.72
  40058000-40059000 rw-p 00000000 00:00 0
  40059000-40146000 r-xp 00000000 03:08 304066 /lib/libc-2.1.3.so
  40146000-4014a000 rw-p 000ec000 03:08 304066 /lib/libc-2.1.3.so
  bfff9000-c0000000 rwxp ffffa000 00:00 0
  
  
  从上面可以看到,我举了一个login程序的例子,首先的两块内存区域用虚拟地址08048000-0804d000
  和0804d000-0804e000分别对应了文本段和数据段.注意一下也是有权限设置的.同时内存区域仅仅
  由页边界来决定.所有的core dump或映像内存区域都取决于页边界.意思是最小的内存区域就是一个
  页的长度.需要注意的是由ELF格式的程序头表现的程序段是和页边界无关的,所以程序段不会在虚拟
  内存区域产生映像.后面几个区域是动态链接相关的库的加载,最后一行是栈.
  
  
  CORE映像
  --------------
  
  core映像就是进程dump出来的映像,具有一些额外寄存器的节和一些有用的信息.在一个ELF的core
  映像里,进程映像的的内存区域相对应程序段,所以一个core文件拥有一个针对每个虚拟内存空间的
  程序头列表.关于寄存器的信息存储在ELF二进制格式的notes节里.从一个core dump或者进程映像
  里来重建可执行文件,我们可以忽略寄存器且把精力仅仅集中在内存区域上.
  
  
  重建可执行文件
  --------------------------
  
  从一个core dump的文件里重建可执行文件我们必须从core映像中提取ELF可执行所需的文本段和
  数据段对应的内存区域.当在加载代码段的时候,ELF头和程序头也同时加载进内存了(这样可以提高
  效率)所以我们可以利用这些来创建可执行映像.可执行的ELF头包括一些象真实的代码段和数据段的
  起始地址和大小这样的信息(记住,内存区域取决于页边界).
  
  现在,假如我们只在我们重建的文件中用到代码段和数据段,导致的结果就使我们的可执行程序只可
  以工作在被创建这个程序的系统上.因为PLT可能拥有一个共享库函数指向它的加载值.移动二进制
  程序会使库函数不同的位置,或者使函数改变位置.所以,只能在重建的系统上运行,要使可以运行在
  系统就必须使整个映像(栈除外)包括在重建的可执行程序里,这在下面的程序可以反应出来.
  
  
  重建失败的一些例子
  --------------------------
  
  重建的一些问题,进程映像的快照是实时运行的,并不是起始时间,所以数据段的值可能会被改掉,数据
  段是可写的.看看下面的代码
  
  static int i = 0;
  
  int main()
  {
  if (i++) exit(0);
  printf("Hi\n");
  }
  
  在这个例子中,重建映像会导致程序立即退出,因为它依靠全局变量i的初始值来判定程序的流程.
  
  实现
  ----------------------
  
  其实重建可执行映像没用到很高深的理论,它只是把一个只有执行权限的可执行程序复制出来而已.
  创建一个core dump不难,只需要给进程发送一个SIGSEGV信号,core映像就从进程映像中被拷贝
  到了proc文件系统里了.
  
  --
  
  [e4gle@linux]$ cat test_harness.c
  int main()
  {
  for (;;) printf("Hi\n");
  }
  [e4gle@linux]$ gcc test_harness.c -o test_harness
  [e4gle@linux]$ ./test_harness <-验证该程序的输出(e4gle:好像杀不掉了,所以为了便于测试我采用后台运行它,再给它发送一个SIGSEGV信号)
  Hi
  Hi
  Hi
  .
  .
  .
  [e4gle@linux]$ ./test_harness >/dev/null &
  [1] 15254
  [e4gle@linux]# ps -eaf|grep test_harness
  root 15254 15229 99 17:16 pts/3 00:00:19 ./test_harness
  root 15256 15229 0 17:17 pts/3 00:00:00 grep test_harness
  [e4gle@linux]# kill -SIGSEGV 15254 <-使它core dump
  
  [e4gle@linux]$ gcc -o core_reconstruct core_reconstruct.c
  [e4gle@linux]$ ./core_reconstruct <-我们写的提取例程来从core中提出可执行映像
  [e4gle@linux]$ ./a.out <-测试我们提取出来的可执行文件
  Hi
  Hi
  Hi
  .
  .
  .
  
  以下是提取core文件到可执行程序的例程.(e4gle:这个程序还是很容易理解的:)
  代码:
  
  --------------------------------- CUT ---------------------------------------
  
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  
  void die(const char *fmt, ...)
  {
   va_list ap;
  
   va_start(ap, fmt);
   vfprintf(stderr, fmt, ap);
   va_end(ap);
   fputc('\n', stderr);
   exit(1);
  }
  
  #define PAGE_SIZE 4096
  
  static char shstr[] =
   "\0"
   ".symtab\0"
   ".strtab\0"
   ".shstrtab\0"
   ".interp\0"
   ".hash\0"
   ".dynsym\0"
   ".dynstr\0"
   ".rel.got\0"
   ".rel.bss\0"
   ".rel.plt\0"
   ".init\0"
   ".plt\0"
   ".text\0"
   ".fini\0"
   ".rodata\0"
   ".data\0"
   ".ct进入讨论组讨论。
收藏此文】【 】【打印】【关闭
相关图文阅读
频道图文推荐
健 康 咨 询
时 尚 咨 询
巧巧读书宗旨
相关专题
热点标签: .net  ie  linux  unix  病毒  
最新论坛文章
站内各频道最新更新文档
站内最新制作专题
热门关键字导读
Photoshop教 程照片处理 照片制作 PS快捷键 抠图
计 算 机 故 障XP系统修复
艺 术 与 设 计设计 流媒体 设计欣赏 边框
计 算 机 安 全ARP
站内频道文章精选
百度推荐,商机无限
搜索您感兴趣的内容
 
Web 本站
巧巧电脑频道编辑信箱  告诉我们您想看的专题或文章