Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1584475
  • 博文数量: 239
  • 博客积分: 1760
  • 博客等级: 上尉
  • 技术积分: 1595
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-08 23:53
文章分类

全部博文(239)

文章存档

2016年(1)

2015年(28)

2014年(53)

2013年(42)

2012年(50)

2011年(65)

分类:

2011-02-11 21:56:35

原文地址:程序的自我改写 作者:shell_way

曾经,程序的自动改写是每个黑客必备的知识,因为这样可以有效的节约内存,下面是在现代的GNU/Linux 操作系统上实现的程序自我改写(本文的演示基于32 位系统和编译器)。
列一下环境:

speller@SHELL-LAB:~/code/c$ egrep "model name" /proc/cpuinfo | uniq -c
      2 model name      : Pentium(R) Dual-Core  CPU      E6300  @ 2.80GHz
speller@SHELL-LAB:~/code/c$ uname -sr
Linux 2.6.35.10-smp
speller@SHELL-LAB:~/code/c$ gcc --version | grep GCC
gcc (GCC) 4.4.4
speller@SHELL-LAB:~/code/c$


上代码:
  1. /*
  2.  * 文件名: self-modification.c
  3.  * 备注: 一个可以修改自身代码的小程序 ;p
  4.  */
  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <sys/mman.h>

  8. void func (void);

  9. int main
  10. (int argc, char *argv[]) {
  11.     
  12.     int count = 0;

  13.     for (count = 0; count < 3; ++count) {
  14.         printf ("第<%d>次执行函数func:\n", count+1);
  15.         func ();
  16.     }

  17.     return 0;
  18. }

  19. void func
  20. (void) {

  21.     __asm__ __volatile__ (
  22.         "slot:\n"
  23.         "nop\nnop\n" /* 这两个nop 指令用来为下面的自动改写留出位置 */
  24.         "after_slot:\n"
  25.     );

  26.     puts ("\t你只能在第<1>次执行函数func 的时候看到这条消息\n"
  27.           "\t\t——因为程序对自身的代码进行了修改。\n");
  28.     
  29.     /* 将函数func 的堆栈属性设置为可读写、可执行 */
  30.     int pagesize = (int)sysconf (_SC_PAGESIZE);
  31.     char *p = (char *)((int)func & ~(pagesize - 1));
  32.     mprotect (p, pagesize * 10, PROT_READ | PROT_WRITE | PROT_EXEC);
  33.     
  34.     /* 进行自我改写 */
  35.     __asm__ __volatile__ (
  36.         ".byte 0xe8, 0, 0, 0, 0\n"     /* 0xe8 是call 指令,把popl 指令当作函数调用 */
  37.         "popl %%eax\n"                /* popl 出栈的是popl 指令自身的地址 */
  38.         "addl $20, %%eax\n"         /* 定位到第二个puts 函数 */
  39.         "subl $after_slot, %%eax\n"/* 得到第二个puts 函数相对于after_slot 标签的偏移 */
  40.         "shl $8, %%eax\n"             /* 这里是little endian 系统 */
  41.         "movb $0xeb, %%al\n"      /* 0xeb 是jmp 指令,%ax 里现在是 */
  42.         "movw %%ax, slot"           /* 填充先前两个nop 指令预留出的空间 */
  43.         :
  44.         :
  45.         : "eax"
  46.     );

  47.     puts ("\t这条消息应该在每次调用函数func 的时候都被输出到stdout。\n");
  48.     
  49.     return;
  50. }
效果如下:
speller@SHELL-LAB:~/code/c$ gcc -o self-modification self-modification.c
speller@SHELL-LAB:~/code/c$ ./self-modification
第<1>次执行函数func:
        你只能在第<1>次执行函数func 的时候看到这条消息
                ——因为程序对自身的代码进行了修改。

        这条消息应该在每次调用函数func 的时候都被输出到stdout。

第<2>次执行函数func:
        这条消息应该在每次调用函数func 的时候都被输出到stdout。

第<3>次执行函数func:
        这条消息应该在每次调用函数func 的时候都被输出到stdout。

speller@SHELL-LAB:~/code/c$


程序自身对自身的指令进行修改,有点黑客帝国的味道,不是么 ;p
阅读(797) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~