PE感染型病毒专杀的编写

2013-03-20 18:06:55 17 4726


PE感染型病毒专杀的编写

    平常我们虚拟机经常下一些乱七八糟的软件,免不了中招,关键是虚拟机中招不要紧,主机中招就比较郁闷了,这不朋友的电脑在和虚拟机进行交互软件的时候中招了,我帮她分析了下,这个病毒只是感染全盘的 .exe的程序,通过添加新节,写入病毒代码至新节,然后跳转至入口点,病毒的具体功能就懒得分析了,我们直奔今天的主题 “病毒专杀的编写”。

  首先我们拿0llydbg载入一个感染过的程序,如下图,我们可以看到入口点已经被改到新节表中了,以下就是病毒的入口点。


  通过查看上面的代码,我们发现下面有一个异或的解密过程,那么我们直接断点在$0054701D。


  断下来后,F9执行,OK病毒体已经解密完成,我们继续跟入CALL 005471A0偏移中,


  我们发现执行CALL 005471A0, 会将其00547023压入堆栈,然后我们进入到这个过程005471A0,我们发现mov eax, ebp  add eax, 4 将eax指向栈顶,因为栈顶存储005471A0, 然后我们继续向下分析mov edi, [eax] ,此时取出005471A0至edi寄存器,我们继续向下看Sub edi, 5  mov eax, dword [edi+c]   add eax, [edi+8]  执行以上3句指令时eax就是原来程序的入口点。


  通过以上分析我们大概了解了入口点是存储在CALL 005471A0 指令其后的内存偏移处,并且是加密的。那么我们写专杀关键是找出原来程序的入口点,然后清除病毒体。但是由于这个病毒的入口点是加密存储的,所以我们必须进行解密操作。又由于这个病毒的入口点不是固定的,并且解密头也不是固定的,那么我们的专杀必须要做到以下几点。
  
  1、找出固定特征

  2、根据固定特征获取到病毒体偏移  病毒体的解密HASH 、病毒体的大小。

  3、然后进行对病毒体解密,然后找出我们需要的入口点。


  我分析了几个感染后程序的病毒入口点,这个病毒的入口点做了随机化处理,但是有几个特征是固定的,那就是它需要将病毒体偏移、解密HASH、病毒体大小传入寄存器,通常传入寄存器无非两种,一个是push xxxx ,pop 寄存器,然后一种是直接mov 寄存器、xxxx。这样它的指令长度都是5字节,但是由于它每个感染程序传入的寄存器都不太一样,所以我们必须将范围设置大点。
  
  我们可以通过以下思路,通过长度反汇编引擎搜索指令长度,如果指令长度是5,那么就判断是不是push 或者是(mov eax — mov edi) 然后获取其后的值,由于它的顺序是固定的就是先传入HASH、解密偏移、解密大小。所以我们做个循环然后通过长度反汇编引擎搜索指令,直到找到这3个数据,然后退出循环,进行解密。



  我们解密完的内存病毒体如上图,我们看到e8 7D 01 00 00 就是我们的call 解密体的过程,通过刚刚上面的分析,me8 7D 01 00 00 后面的相对偏移$0c 和$08 处分别是源程序的基地址和相对偏移。
  
  到了这里,我们基本上对整个专杀的过程十分熟悉了吧,那么还等什么呢,直接上专杀代码吧。
  function ClearVirusFile(VirusFile, NewFile: string): Boolean;
  var
    Pe: TPeFile;
    EntryAddr: DWORD;
    SectionNum: DWORD;
    VirusBytes: PChar;
    I: DWORD;
    HashKey: DWORD;
    Data: DWORD; // 解密数据偏移
    DataLen: DWORD;
    NewEntryAddr: DWORD;
    Len: ULONG;
  begin
    Result:= False;
    Pe:= TPeFile.Create;
    Pe.LoadFromFile(PChar(VirusFile));
  
    try
      if Pe.ValidHeaders then
      begin
  
        HashKey:= 0;
        Data:= 0;
        EntryAddr:= Pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
        SectionNum:= Pe.ImageNtHeaders.FileHeader.NumberOfSections;
  
        //  如果入口点设置为最后一个节
        if (EntryAddr >= Pe.ImageSections[SectionNum-1].VirtualAddress) then
        begin
          VirusBytes:= PChar(DWORD(Pe.lpBuffer) +
            Pe.ImageSections[SectionNum-1].PointerToRawData);
  
  
          i:= 0;
          while i < Pe.ImageSections[SectionNum-1].SizeOfRawData do
          begin
            GetInstLenght(@VirusBytes[i],  @Len);
            if Len = 5 then
            begin
              if HashKey = 0 then
              begin
                if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
                    and (Byte(VirusBytes[i]) <= $BF)) then
                  HashKey:= PDWORD(@VirusBytes[i+1])^;
              end else
              begin
                if (Data = 0) then
                begin
                  if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
                    and (Byte(VirusBytes[i]) <= $BF)) then
                  begin
                    Data:= PDWORD(@VirusBytes[i+1])^;
                  end;
                end else
                begin
                  if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
                    and (Byte(VirusBytes[i]) <= $BF)) then
                  begin
                      DataLen:= PDWORD(@VirusBytes[i+1])^;
                      Break;
                  end;
                end;
              end;
            end;
            i:= i + Len;
          end;
  
  
          if HashKey <> 0 then
          begin
  
            //  查找入口点
            if Data <> 0 then
            begin
              Data:= Pe.RVaToFileOffset(Data - Pe.ImageNtHeaders.OptionalHeader.ImageBase );
              Data:= Data + DWORD(Pe.lpBuffer);
  
              i:= DataLen;
              while i > 0 do
              begin
                PDWORD(Data+i)^ := PDWORD(Data+i)^ xor HashKey;
                Dec(i, 4);
              end;
  
  
              //  设置入口点和基地址
              Pe.SetAddressOfEntryPoint(PDWORD(Data+$c+4)^);
  
              Pe.SetImageBase(PDWORD(Data+$8+4)^);
  
              //  删除病毒体
              Pe.DeleteBytes(Pe.GetHighestSectionSize,
                Pe.FileSize - Pe.GetHighestSectionSize);
  
  
              //Pe.DeleteSection(SectionNum-1);
  
  
              Pe.SaveToFile(NewFile);
  
              Result:= True;
            end;
          end;
        end;
      end;
    finally
      Pe.Free;
    end;
  end;
 
反病毒、逆向板块 没权限,只能发这里了。

关于作者

xfish6篇文章60篇回复

评论17次

要评论?请先  登录  或  注册