• PE头的应用---插入代码到EXE或DLL文件中


    三、代码实现(DELPHI版本),采用第三种方式实现代码插入。

     1. 定义两个类,一个用来实现在内存中建立输入表;一个用来实现对PE头的代码插入。

    DelphiCode:

    const MAX_SECTION_NUM = 20;
    const DYN_LOADER_START_MAGIC  = $C0DE51A9;
    const DYN_LOADER_END_MAGIC      = $C0DEE2DE;
    const DYN_LOADER_START_DATA1  = $DA1EDA1E;
    
    const IMPORT_TABLE_EXE = 0;
    const IMPORT_TABLE_DLL = 1;
    
    Type
      TIIDUnion = record
        case Integer of
          0: (Characteristics: DWORD);            // 0 for terminating null import descriptor
          1: (OriginalFirstThunk: DWORD);      // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
      end;
    
      PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
      {$EXTERNALSYM PIMAGE_IMPORT_DESCRIPTOR}
      _IMAGE_IMPORT_DESCRIPTOR = record
        Union: TIIDUnion;
        TimeDateStamp: DWORD;                  
        ForwarderChain: DWORD;                 
        Name: DWORD;
        FirstThunk: DWORD;                     
      end;
      {$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}
      IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
      {$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}
      TImageImportDecriptor = IMAGE_IMPORT_DESCRIPTOR;
      PImageImportDecriptor = PIMAGE_IMPORT_DESCRIPTOR;
    
      PIMAGE_TLS_DIRECTORY32 = ^IMAGE_TLS_DIRECTORY32;
      {$EXTERNALSYM PIMAGE_TLS_DIRECTORY32}
      _IMAGE_TLS_DIRECTORY32 = record
        StartAddressOfRawData: DWORD;
        EndAddressOfRawData: DWORD;
        AddressOfIndex: DWORD;            
        AddressOfCallBacks: DWORD;         
        SizeOfZeroFill: DWORD;
        Characteristics: DWORD;
      end;
      {$EXTERNALSYM _IMAGE_TLS_DIRECTORY32}
      IMAGE_TLS_DIRECTORY32 = _IMAGE_TLS_DIRECTORY32;
      {$EXTERNALSYM IMAGE_TLS_DIRECTORY32}
      TImageTlsDirectory32 = IMAGE_TLS_DIRECTORY32;
      PImageTlsDirectory32 = PIMAGE_TLS_DIRECTORY32;
    
      PImageImport = ^TImageImport;
      TImageImport = packed record
       szLibrary     : array[0..31] of char;
       ThunksList : TList;
      end;
    
      {在内存中建立一个输入表的内存块,地址放在pMem中,大小是dwSize}
      TImportTableMaker = class
       private
        function GetIATSize : DWORD;
        procedure Init(iType : integer);
       protected
        ImportTable : TList;
       public
        dwSize : DWORD;
        pMem   : Pointer;
        constructor Create(iType : integer);
        destructor Destroy; override;
        procedure Build(baseRVA : DWORD);
      end;
    
    {用来传递数据的一个结构}
    
    PData = ^TData;
     TData = record
      dwReserved1           : DWORD;      
      dwFileType                : DWORD;
      dwImageBase          : DWORD;      
      dwOrgEntryPoint      : DWORD;  
      dwImportVAddr         : DWORD;
      dwRelocationVAddr : DWORD;
      dwRelocationSize    : DWORD;
      imgTLSDirectory      : IMAGE_TLS_DIRECTORY32;
     end;
    
    
      TPE = class
       private
        dwFileSize           : DWORD;
        pMem                   : Pointer;
        SectionNum        : integer;
        pNewSection       : Pointer;
        function ReturnToBytePtr(FuncCode : pointer; findstr : DWORD): pointer;
        procedure SetSectionsWritePermission;
        procedure CopyData(dwVirtualAddress : DWORD);
       protected
        ITMaker                    : TImportTableMaker;
    
        imgDosHeader          : TImageDosHeader;
        pDosStub                    : Pointer;
        dwDosStubSize         : DWORD;
        dwDosStubOffset      : DWORD;
        imgNtHeaders           : TImageNtHeaders;
        imgSectionHeaders : array[0..MAX_SECTION_NUM -1] of TImageSectionHeader;
        imgSections               : array[0..MAX_SECTION_NUM -1] of Pointer;
        imgTLSDirectory        : IMAGE_TLS_DIRECTORY32;
        function PEAlign(dwTarNum : DWORD; dwAlignTo : DWORD) : DWORD;
        procedure AlignmentSections;
        function Offset2RVA(dwOffset : DWORD) : DWORD;
        function RVA2Offset(dwRVA : DWORD) : DWORD;
        function ImgRVA2Section(dwRVA : DWORD) : PImageSectionHeader;
        function ImgOffset2Section(dwOffset: DWORD): PImageSectionHeader;
        function ImgOffset2SectionNum(dwOffset: DWORD): integer;
        function AddNewSection(szName: string; dwSize: DWORD): PImageSectionHeader;
       public
        constructor Create;
        destructor Destroy; override;
        procedure OpenFile(filename : string);
        procedure SaveFile(filename : string);
        procedure CyrptFile;
      end;

    二、类代码

    DelphiCode:

    implementation
    
    uses PEInit;   //被用来插入的代码单元
    
    const szWindowsAPIs : array[0..10] of string = ('Kernel32.dll',
                                                   'GetModuleHandleA',
                                                   'VirtualProtect',
                                                   'GetModuleFileNameA',
                                                   'CreateFileA',
                                                   'GlobalAlloc',
                                                   '',
                                                   'User32.dll',
                                                   'MessageBoxA',
                                                   '',
                                                   '');
    const szIATEXEStrings : array[0..4] of string = ('Kernel32.dll',
                                                     'LoadLibraryA',
                                                     'GetProcAddress',
                                                     '',
                                                     '');
    
    const szIATDLLStrings : array[0..29] of string = (
     'Kernel32.dll',
     'LoadLibraryA',
     'GetProcAddress',
     'GetModuleHandleA',
     '',
     'User32.dll',
     'GetKeyboardType',
     'WindowFromPoint',
     '',
     'AdvApi32.dll',
     'RegQueryValueExA',
     'RegSetValueExA',
     'StartServiceA',
     '',
     'Oleaut32.dll',
     'SysFreeString',
     'CreateErrorInfo',
     'SafeArrayPtrOfIndex',
     '',
     'Gdi32.dll',
     'UnrealizeObject',
     '',
     'Ole32.dll',
     'CreateStreamOnHGlobal',
     'IsEqualGUID',
     '',
     'ComCtl32.dll',
     'ImageList_SetIconSize',
     '',
     '');
    
    constructor TPE.Create;
    begin
     dwDosStubSize := 0;
    end;
    
    destructor TPE.Destroy;
    begin
    
    end;
    
    {实现File或Section对齐}
    function TPE.PEAlign(dwTarNum: DWORD; dwAlignTo: DWORD): DWORD;
    begin
     result := ((dwTarNum + dwAlignTo - 1) div dwAlignTo) * dwAlignTo;
    end;
    
    {把所有的节进行Section对齐}
    procedure TPE.AlignmentSections;
    var
     i   : integer;
    begin
     for i:= 0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
      imgSectionHeaders[i].VirtualAddress := PEAlign(imgSectionHeaders[i].VirtualAddress, imgNtHeaders.OptionalHeader.SectionAlignment);
      imgSectionHeaders[i].Misc.VirtualSize := PEAlign(imgSectionHeaders[i].Misc.VirtualSize, imgNtHeaders.OptionalHeader.SectionAlignment);
      imgSectionHeaders[i].PointerToRawData := PEAlign(imgSectionHeaders[i].PointerToRawData, imgNtHeaders.OptionalHeader.FileAlignment);
      imgSectionHeaders[i].SizeOfRawData := PEAlign(imgSectionHeaders[i].SizeOfRawData, imgNtHeaders.OptionalHeader.FileAlignment);
     end;
     imgNtHeaders.OptionalHeader.SizeOfImage := imgSectionHeaders[i-1].VirtualAddress + imgSectionHeaders[i-1].Misc.VirtualSize;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size := 0;
    end;
    
    {找到内存中某一个RVA所映射的磁盘文件上的offset}
    function TPE.RVA2Offset(dwRVA : DWORD): DWORD;
    var
     offset : DWORD;
     section : PImageSectionHeader;
    begin
     section := ImgRVA2Section(dwRVA);
     if section = nil then
      result := 0
     else
     begin
      offset := dwRVA + section.PointerToRawData - section.VirtualAddress;
      result := offset;
     end;
    end;
    
    {找到磁盘上某一个offset所映射的内存中的RVA}
    function TPE.Offset2RVA(dwOffset : DWORD): DWORD;
    var
     section : PImageSectionHeader;
    begin
     section := ImgOffset2Section(dwOffset);
     if section = nil then
      result := 0
     else
      result := dwOffset + section.VirtualAddress - section.PointerToRawData;
    end;
    
    {返回PE文件加载到内存后,RVA地址所处的Section}
    function TPE.imgRVA2Section(dwRVA : DWORD) : PImageSectionHeader;
    var
     i : integer;
    begin
     for i:= 0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
      if ((dwRVA >= imgSectionHeaders[i].VirtualAddress) and (dwRVA <= (imgSectionHeaders[i].VirtualAddress + imgSectionHeaders[i].SizeOfRawData))) then
      begin
       result := @imgSectionHeaders[i];
       exit;
      end;
     end;
     result := nil;
    end;
    
    {返回OFFSET地址在PE文件位于磁盘上的所落的Section}
    function TPE.ImgOffset2Section(dwOffset : DWORD): PImageSectionHeader;
    var
     i: integer;
    begin
     for i:=0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
      if ((dwOffset >= imgSectionHeaders[i].PointerToRawData) and (dwOffset < (imgSectionHeaders[i].PointerToRawData + imgSectionHeaders[i].SizeOfRawData))) then
      begin
       result := @ImgSectionHeaders[i];
       exit;
      end;
     end;
     result := nil;
    end;
    
    {返回Offset地址在PE文件位于磁盘上所落Section的编号}
    function TPE.ImgOffset2SectionNum(dwOffset : DWORD): integer;
    var
     i: integer;
    begin
     for i:=0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
      if ((dwOffset >= imgSectionHeaders[i].PointerToRawData) and (dwOffset < (imgSectionHeaders[i].PointerToRawData + imgSectionHeaders[i].SizeOfRawData))) then
      begin
       result := i;
       exit;
      end;
     end;
     result := -1;
    end;
    
    {增加一个新的Section,可读/写, 包含已初始化数据.}
    function TPE.AddNewSection(szName: string; dwSize: DWORD): PImageSectionHeader;
    var
     i       : integer;
     roffset : DWORD;
     rsize   : DWORD;
     voffset : DWORD;
     vsize   : DWORD;
    begin
     i := imgNtHeaders.FileHeader.NumberOfSections;
     rsize := PEAlign(dwSize, imgNtHeaders.OptionalHeader.FileAlignment);
     vsize := PEAlign(rsize, imgNtHeaders.OptionalHeader.SectionAlignment);
     roffset := PEAlign(imgSectionHeaders[i-1].PointerToRawData + imgSectionHeaders[i-1].SizeOfRawData,
                        imgNtHeaders.OptionalHeader.FileAlignment);
     voffset := PEAlign(imgSectionHeaders[i-1].VirtualAddress + imgSectionHeaders[i-1].Misc.VirtualSize,
                        imgNtHeaders.OptionalHeader.SectionAlignment);
     FillChar(imgSectionHeaders[i],sizeof(TImageSectionHeader),#0);
     imgSectionHeaders[i].PointerToRawData := roffset;
     imgSectionHeaders[i].VirtualAddress := voffset;
     imgSectionHeaders[i].SizeOfRawData := rsize;
     imgSectionHeaders[i].Misc.VirtualSize := vsize;
     imgSectionHeaders[i].Characteristics := $C0000040; 
    
     CopyMemory(@imgSectionHeaders[i].Name[0],@szName[1],length(szName));
     imgSections[i] := Pointer(GLobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,rsize)); 
     imgNtHeaders.FileHeader.NumberOfSections := imgNtHeaders.FileHeader.NumberOfSections + 1;
     result := @imgSectionHeaders[i];
    end;
    
    {打开一个PE文件,按其格式分部分读入}
    
    procedure TPE.OpenFile(filename : string);
    var
     dwBytesRead        : DWORD;
     hFile              : THANDLE;
     sectionNum         : DWORD;
     i                  : integer;
     firstSectionOffset : DWORD;
     dwOffset           : DWORD;
    begin
     pMem := nil;
     hFile := CreateFile(PChar(filename),GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
     if hFile = INVALID_HANDLE_VALUE then
     begin
      exit;
     end;
     dwFileSize := GetFileSize(hFile,0);
     if dwFileSize = 0 then
     begin
      CloseHandle(hFile);
      exit;
     end;
     pMem := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT, dwFileSize));
     if dwFileSize = 0 then
     begin
      CloseHandle(hFile);
      exit;
     end;
     ReadFile(hFile,pMem^,dwFileSize,dwBytesRead,nil);
     CloseHandle(hFile);
     CopyMemory(@imgDosHeader,pMem,sizeof(IMAGE_DOS_HEADER));
     dwDosStubSize := imgDosHeader._lfanew - sizeof(IMAGE_DOS_HEADER);
     dwDosStubOffset := sizeof(IMAGE_DOS_HEADER);
     getMem(pDosStub,dwDosStubSize);
     if (dwDosStubSize and $80000000) = $00000000 then
     begin
      copyMemory(pDosStub,pointer(DWORD(pMem) + dwDosStubOffset), dwDosStubSize);
     end;
     copyMemory(@imgNtHeaders,pointer(DWORD(pMem)+imgDosHeader._lfanew),sizeof(IMAGE_NT_HEADERS));
     firstSectionOffset := imgDosHeader._lfanew + sizeof(IMAGE_NT_HEADERS);
     if imgDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then
     begin
      GlobalFree(DWORD(pMem));
      exit;
     end;
     SectionNum := imgNtHeaders.FileHeader.NumberOfSections;
     for i:=0 to SectionNum -1 do
     begin
      CopyMemory(@imgSectionHeaders[i],pointer(DWORD(pMem)+ firstSectionOffset + i * sizeof(IMAGE_SECTION_HEADER)),sizeof(IMAGE_SECTION_HEADER));
     end;
     for i:=0 to SectionNum -1 do
     begin
      imgSections[i] := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,PEAlign(imgSectionHeaders[i].SizeOfRawData,imgNtHeaders.OptionalHeader.FileAlignment)));
      copyMemory(imgSections[i],pointer(DWORD(pMem)+imgSectionHeaders[i].PointerToRawData), imgSectionHeaders[i].SizeOfRawData);
     end;
    
     if imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress <> 0 then
     begin
      dwOffset := RVA2Offset(imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
      copymemory(@imgTLSDirectory,pointer(DWORD(pMem) + dwOffset), sizeof(IMAGE_TLS_DIRECTORY32));
     end;
     GlobalFree(DWORD(pMem));
    end;
    
    procedure TPE.SaveFile(filename : string);
    var
     dwBytesWritten : DWORD;
     i              : integer;
     dwRO_first_section : DWORD;
     sectionNum : DWORD;
     hFile : THANDLE;
    begin
     hFile := CreateFile(PChar(filename),GENERIC_WRITE, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
     if hFile = INVALID_HANDLE_VALUE then
     begin
      hFile := CreateFile(PChar(filename), GENERIC_WRITE, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,0);
      if hFile = INVALID_HANDLE_VALUE then
       exit;
     end;
     AlignmentSections;
     i := imgNtHeaders.FileHeader.NumberOfSections;
     dwFileSize := imgSectionHeaders[i-1].PointerToRawData + imgSectionHeaders[i-1].SizeOfRawData;
     pMem := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,dwFileSize));
     if pMem = nil then
     begin
      CloseHandle(hFile);
      exit;
     end;
     copyMemory(pMem,@imgDosHeader,sizeof(IMAGE_DOS_HEADER));
     if (dwDOSStubSize and $80000000) = $00000000 then
      copyMemory(pointer(DWORD(pMem) + dwDosStubOffset), pDosStub, dwDosStubSize);
     copyMemory(pointer(DWORD(pMem)+imgDosHeader._lfanew), @imgNtHeaders, sizeof(IMAGE_NT_HEADERS));
     dwRO_first_section := imgDosHeader._lfanew + sizeof(IMAGE_NT_HEADERS);
     sectionNum := imgNtHeaders.FileHeader.NumberOfSections;
     for i:=0 to SectionNum - 1 do
     begin
      CopyMemory(pointer(DWORD(pMem) + dwRO_first_Section + i * sizeof(IMAGE_SECTION_HEADER)), @imgSectionHeaders[i],sizeof(IMAGE_SECTION_HEADER));
     end;
     for i:=0 to SectionNum - 1 do
     begin
      CopyMemory(pointer(DWORD(pMem) + imgSectionHeaders[i].PointerToRawData), imgSections[i], ImgSectionHeaders[i].SizeOfRawData);
     end;
     SetFilePointer(hFile ,0, nil,FILE_BEGIN);
     writeFile(hFile,pMem^,dwFileSize, dwBytesWritten,nil);
     setFilePointer(hFile,dwFileSize, nil,FILE_BEGIN);
     setEndOfFile(hFile);
     CloseHandle(hFile);
     GlobalFree(DWORD(pMem));
    end;
    
    {用来查找一段代码的标志位,在FuncCode指针开始的字符串中,查找一个DWORD的标志}
    function TPE.ReturnToBytePtr(FuncCode : pointer; findstr : DWORD): pointer;
    var
     tmpd : Pointer;
    begin
     asm
           pushad
           mov eax, FuncCode
           jmp @label1
      @label0:
           inc eax
      @label1:
           mov ebx, [eax]
           cmp ebx, findstr
           jnz @label0
           mov tmpd, eax
           popad
     end;
     result := tmpd;
    end;
    
    {把一段跳转指令加入到PE文件中,先建立一个新SECTION,然后把新输入表放入新区的     }
    { 起始地址,把一点代码放到输入表后.然后把跳转指令加入到新Section,跳回原来的程序,}
    {同时使用新的输入表来取代旧的输入表 }
    procedure TPE.CyrptFile;
    var
     ch_temp          : Pointer;
     i                : DWORD;
     imgSectionHeader : PImageSectionHeader;
     dwNewSectionSize : DWORD;
     dwCodeSize       : DWORD;
     dwCodeOffset     : DWORD;
    begin
     if (imgNTHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then
      ITMaker := TImportTableMaker.Create(IMPORT_TABLE_DLL)
     else
      ITMaker := TImportTableMaker.Create(IMPORT_TABLE_EXE);
    
     ch_temp := Pointer(DWORD(ReturnToBytePtr(@InitPE,DYN_LOADER_START_MAGIC)) +4);
     dwCodeSize := DWORD(ReturnToBytePtr(@InitPE,DYN_LOADER_END_MAGIC)) - DWORD(ch_temp);
    
     dwCodeOffset := ITMaker.dwSize;
     dwNewSectionSize := dwCodeSize + ITMaker.dwSize;
     getmem(pNewSection,dwNewSectionSize);
     copymemory(Pointer(DWORD(pNewSection) + dwCodeOffset), ch_temp, dwCodeSize);
    
     imgSectionHeader := AddNewSection('.xxx',dwNewSectionSize);
     CopyData(imgSectionHeader.VirtualAddress);
    
    
     ITMaker.Build(imgSectionHeader.VirtualAddress);
     copyMemory(pNewSection,ITMaker.pMem, ITMaker.dwSize);
     copymemory(imgSections[imgNtHeaders.FileHeader.NumberOfSections-1], pNewSection, dwNewSectionSize);
     imgNtHeaders.OptionalHeader.AddressOfEntryPoint := imgSectionHeader.VirtualAddress + dwCodeOffset;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress := imgSectionHeader.VirtualAddress;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size := ITMaker.dwSize;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress := 0;
     imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size := 0;
     SetSectionsWritePermission;
     freemem(pNewSection,dwNewSectionSize);
     ITMaker.Free;
    end;
    
    procedure TPE.CopyData(dwVirtualAddress : DWORD);
    var
     i         : integer;
     APINum    : integer;
     pData     : Pointer;
     dwOffset  : DWORD;
     len       : longint;
     DataTable : TData;
     temp      : byte;
    begin
     DataTable.dwReserved1 := $CCCCCCCC;
     if ((imgNtHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL) then
      DataTable.dwFileType := IMPORT_TABLE_DLL
     else
      DataTable.dwFileType := IMPORT_TABLE_EXE;
     DataTable.dwImageBase := imgNtHeaders.OptionalHeader.ImageBase;
     DataTable.dwOrgEntryPoint := imgNtHeaders.OptionalHeader.AddressOfEntryPoint;
     DataTable.dwImportVAddr := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
     if (imgNtHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then
     begin
      DataTable.dwRelocationVAddr := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
      DataTable.dwRelocationSize  := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
     end;
     pData := ReturnToBytePtr(pNewSection, DYN_LOADER_START_DATA1);
     if imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress <> 0 then
     begin
      CopyMemory(@DataTable.imgTLSDirectory,@imgTLSDirectory,sizeof(IMAGE_TLS_DIRECTORY32));
      dwOffset := DWORD(pData) - DWORD(pNewSection);
      dwOffset := dwOffset + sizeof(DataTable) - sizeof(IMAGE_TLS_DIRECTORY32);
      imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress := dwVirtualAddress + dwOffset;
     end;
     CopyMemory(pData,@DataTable, sizeof(TData));
     dwOffset := sizeof(TDATA);
     i := 0; APINum := 0; temp := 0;
     repeat
      len := Length(szWindowsAPIs[i]) + 1;
      CopyMemory(Pointer(DWORD(pData) + dwOffset),@szWindowsAPIs[i][1],len);
      dwOffset := dwOffset + len;
      repeat
       i := i + 1;
       if szWindowsAPIs[i] <> '' then
       begin
        len := length(szWindowsAPIs[i]) + 1;
        CopyMemory(Pointer(DWORD(pData) + dwOffset), @szWindowsAPIs[i][1],len);
        dwOffset := dwOffset + len;
        APINum := APINum + 1;
       end
       else
       begin
        CopyMemory(Pointer(DWORD(pData) + dwOffset), @temp, 1);
        dwOffset := dwOffset + 1;
       end;
      until szWindowsAPIs[i] = '';
      i := i + 1;
     until szWindowsAPIs[i] = '';
    end;
    
    
    procedure TPE.SetSectionsWritePermission;
    var
     i  : integer;
    begin
     for i:=0 to imgNTHeaders.FileHeader.NumberOfSections - 1 do
       imgSectionHeaders[i].Characteristics := $C0000040;
    end;
    
    
    {******************************************************************************}
    
    
                                                    
    constructor TImportTableMaker.Create(iType : integer);
    begin
     ImportTable := TList.Create;
     init(iType);
     dwSize := GetIATSize;
     GetMem(pMem,dwSize);
    end;
    
    destructor TImportTableMaker.Destroy;
    var
     imgImport : PImageImport;
    begin
     while ImportTable.Count > 0 do
     begin
      imgImport := PImageImport(ImportTable.Items[0]);
      while imgImport.ThunksList.Count > 0 do
      begin
       freeMem(imgImport.ThunksList.Items[0],32);
       imgImport.ThunksList.Delete(0);
      end;
      imgImport.ThunksList.Free;
      dispose(imgImport);
      ImportTable.Delete(0);
     end;
     ImportTable.Free;
     FreeMem(pMem,dwSize);
    end;
    
    procedure TImportTableMaker.Init(iType : integer);
    var
     i         : integer;
     IATString : pointer;
     imgImport : PImageImport;
     imgThunk  : PChar;
     function IsStringsEnd(inx : integer) : boolean;
     begin
       result := false;
       case iType of
        IMPORT_TABLE_EXE:
              begin
               if szIATEXEStrings[inx] = '' then
                result := true;
              end;
        IMPORT_TABLE_DLL:
              begin
               if szIATDLLStrings[inx] = '' then
                result := true;
              end;
       end;
     end;
    begin
     i := 0;
     repeat
      New(imgImport);
      imgImport.ThunksList := TList.Create;
      case iType of
       IMPORT_TABLE_EXE:   copyMemory(@imgImport.szLibrary[0], @szIATEXEStrings[i][1],32);
       IMPORT_TABLE_DLL:   copyMemory(@imgImport.szLibrary[0], @szIATDLLStrings[i][1],32);
      end;
      repeat
       i := i + 1;
       if not IsStringsEnd(i) then
       begin
        getMem(imgThunk,32);
        fillchar(imgTHunk^,32,#0);
        case iType of
         IMPORT_TABLE_EXE:  copyMemory(imgThunk,@szIATEXEStrings[i][1],32);
         IMPORT_TABLE_DLL:  copyMemory(imgThunk,@szIATDLLStrings[i][1],32);
        end;
        imgImport.ThunksList.Add(imgThunk);
       end;
      until IsStringsEnd(i);
      ImportTable.Add(imgImport);
      i := i + 1;
     until IsStringsEnd(i);
    end;
    
    function TImportTableMaker.GetIATSize : DWORD;
    var
     i        : integer;
     j        : integer;
     dwDLLNum : DWORD;
     dwFuncNum : DWORD;
     dwszDLLSize : DWORD;
     dwszFuncSize : DWORD;
     dwImportSize : DWORD;
     imgImport    : PImageImport;
    begin
     dwDLLNum := 0; dwFuncNum := 0; dwszDLLSize := 0; dwszFuncSize := 0; dwImportSize := 0;
     for i:= 0 to ImportTable.Count - 1 do
     begin
      imgImport := ImportTable.Items[i];
      dwszDLLSize := dwszDLLSize + strlen(imgimport.szLibrary) + 1;
      for j:=0 to imgImport.ThunksList.Count - 1 do
      begin
       dwszFuncSize := dwszFuncSize + 2 + strlen(PChar(imgimport.ThunksList.Items[j])) + 1;
       dwFuncNum := dwFuncNum + 1;
      end;
      dwFuncNum := dwFuncNum + 1;
      dwDLLNum  := dwDLLNum + 1;
     end;
     dwDLLNum := dwDLLNum + 1;
     dwImportSize := dwDLLnum * 20 + dwFuncNum * 4 + dwSzDLLSize + dwszFuncSize;
     result := dwImportSize;
    end;
    
    
    procedure TImportTableMaker.Build(baseRVA : DWORD);
    var
     i             : integer;
     j             : integer;
     pITBaseRVA   : DWORD;
     temp          : DWORD;
     dwDLLNum      : DWORD;
     dwDLLName     : DWORD;
     dwDLLFirst    : DWORD;
     dwszDLLSize   : DWORD;
     dwIIDNum      : DWORD;
     dwFunNum      : DWORD;
     dwFunFirst    : DWORD;
     dwszFuncSize  : DWORD;
     dwFirstThunk  : DWORD;
     dwImportSize  : DWORD;
     imgImport     : PImageImport;
     importDesc    : TImageImportDecriptor;
    begin
     pITBaseRVA := baseRVA;    
     importDesc.Union.OriginalFirstThunk := 0;
     importDesc.TimeDateStamp := 0;
     importDesc.ForwarderChain := 0;
     importDesc.Name := 0;
     importDesc.FirstThunk := 0;
     dwDLLNum := 0; dwDLLName := 0; dwDLLFirst := 0; dwszDLLSize := 0;
     dwIIDNum := 0; dwFunNum := 0; dwFunFirst := 0; dwszFuncSize := 0;
     dwFirstThunk := 0; dwImportSize := 0;
    
     for i:= 0 to importTable.Count -1 do
     begin
      imgImport := PImageImport(importTable.Items[i]);
      dwszDLLSize := dwszDLLSize + strlen(imgImport.szLibrary) + 1;  
      for j:= 0 to imgImport.ThunksList.Count - 1 do
      begin
       dwszFuncSize := dwszFuncSize + 2 + strlen(PChar(imgImport.ThunksList.Items[j])) + 1;
       dwFunNum := dwFunNum + 1;
      end;
      dwFunNum := dwFunNum + 1;
      dwDLLNum := dwDLLNum + 1;
     end;
     dwDLLNum := dwDLLNum + 1;
     dwImportSize := dwDLLNum * 20 + dwFunNum * 4 + dwszDLLSize + dwszFuncSize;
     FillMemory(pMem,dwImportSize, 0);
    
     dwFirstThunk := dwDLLNum * 20;              
     dwDLLFirst := dwDLLNum * 20 + dwFunNum * 4;  
     dwFunFirst := dwDLLNum * 20 + dwFunNum * 4 + dwszDLLSize;  
     for i := 0 to importTable.Count - 1 do
     begin
      imgImport := importTable.Items[i];
      importDesc.Name := pITBaseRVA + dwDLLFirst;
      importDesc.FirstThunk := pITBaseRVA  + dwFirstThunk;
      CopyMemory(Pointer(DWORD(pMem) + dwIIDNum * sizeof(IMAGE_IMPORT_DESCRIPTOR)),@importDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR));
      CopyMemory(Pointer(DWORD(pMem) + dwDLLFirst),@imgImport.szLibrary[0],strlen(imgImport.szLibrary) + 1);
      for j:=0 to imgimport.ThunksList.Count - 1 do
      begin
       temp := pITBaseRVA + dwFunFirst;
       CopyMemory(Pointer(DWORD(pMem) + dwFirstThunk),@temp,4);
       CopyMemory(Pointer(DWORD(pMem) + dwFunFirst + 2), PChar(imgImport.ThunksList.Items[j]),strlen(imgImport.ThunksList.Items[j]) + 1);
       dwFunFirst := dwFunFirst + 2 + strlen(imgImport.ThunksList.Items[j]) + 1;
       dwFirstThunk := dwFirstThunk + 4;
      end;
      temp := 0;
      CopyMemory(Pointer(DWORD(pMem) + dwFirstThunk),@temp, 4);
      dwFirstThunk := dwFirstTHunk + 4;
      dwDLLFirst := dwDLLFirst + strlen(imgImport.szLibrary) + 1;
      dwIIDNum := dwIIDNum + 1;
     end;
     importDesc.Name := 0;
     importDesc.FirstThunk := 0;
     CopyMemory(Pointer(DWORD(pMem)+dwIIDNum * sizeof(IMAGE_IMPORT_DESCRIPTOR)), @importDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR));
    end;
    
    end.
    
    
    {************************************************************************************************************}
    
    PEint单元
    
    
    unit PEInit;
    
    interface
    uses windows;
    
    procedure InitPE; stdcall;
    
    implementation
    
    {一段要嵌入到PE文件中的指令}
    {标志位的作用是用来找到找到从开始标志位后到结束标志位之间的指令大小及开始地址}
    {这段代码如果用在VC中,则要设置链接选项/INCREMENTAL LINK OFF}
    procedure InitPE; stdcall;
    begin
     asm
      {开始标志位}
      DB $A9 DB $51 DB $DE DB $C0
    @Main_0:
      pushad;
      call @Main_1
    @Main_1:
      pop ebp
      sub ebp, offset @main_1 
    
      {**********************支持DLL,OCX等****************************************}
    @_support_dll_0:
      jmp @_support_dll_1 {// nop; nop; // in the secon time OEP  第一次加载后,}
                                              {这句会被改成 nop; nop;在DLL被卸载的时候,会直接调用jmp @_support_dll_2}
      jmp @_support_dll_2
    @_support_dll_1:                          
      test [ebp + @_p_dwFileType],0001h  // IMPORT_TABLE_DLL
      jz @_no_dll_pe_file_0
      mov eax,[esp+24h]                 
      mov ebx,[esp+34h]                 
      cmp eax,ebx                       
      ja @_no_dll_pe_file_0
      cmp word ptr [eax], IMAGE_DOS_SIGNATURE
      jne @_no_dll_pe_file_0                  
      mov [ebp + @_RO_dwImageBase],eax       
    
    @_no_dll_pe_file_0:
    
      // 获取输入表中的LoadLibrary 和 GetProcAddress来建立函数跳转表
      mov eax, DWORD PTR [ebp + @_RO_dwImageBase] 
    
      add eax, [eax + 03Ch]  
    
      add eax, 080h                
      mov ecx, [eax] 
      add ecx, [ebp + @_RO_dwImageBase] 
      add ecx, 010h 
      mov eax, [ecx]
      add eax, [ebp + @_RO_dwImageBase] 
      mov ebx, [eax] 
      mov [ebp + @_p_LoadLibrary],ebx  
      add eax, 04h
      mov ebx, [eax]
      mov [ebp + @_p_GetProcAddress], ebx
    
      call @_api_load  // 加载插入功能代码所需要的DLL和函数跳转表
    
      //***************************功能性代码***************************************
      push MB_OK or MB_ICONINFORMATION
      lea eax,[ebp + @_p_szCaption]
      push eax
      lea eax,[ebp + @_p_szText]
      push eax
      push 0000h
      call @_jmp_MessageBox
      //****************************************************************************
    
      {将在内存中的PE文件的NTHeader头改为可读写}     
      mov edi, [ebp + @_RO_dwImageBase]
      add edi, [edi + 03Ch]
      lea eax, [ebp + @_p_ptempbuffer] 
      push eax
      push PAGE_READWRITE              
      push [edi + 54h]                 
      push [ebp + @_RO_dwImageBase]    
      call @_jmp_VirtualProtect       
    
      call @_it_fixup                  // 为被插入的程序建立内存中的输入表
    
      {判断是否是DLL}
      mov edi,[ebp + @_RO_dwImageBase]
      add edi,[edi+03Ch]
      mov ax,word ptr [edi+016h]     
                           
      test ax,IMAGE_FILE_DLL
      jz @_no_dll_pe_file_1
    
      call @_reloc_fixup              // 为被捆绑的程序修正重定位表.因为EXE一般不需要,只在DLL的时候需要。
    
      mov ax,9090h                    // 为DLL建立卸载时候的入口点
      mov word ptr [ebp + @_support_dll_0],ax
    @_no_dll_pe_file_1:
    
    @_support_dll_2:
    
    //--------- 利用SEH异常转入程序入口点 ---------
      mov eax, [ebp + @_RO_dwImageBase]
      add eax, DWORD PTR [ebp + @_RO_dwOrgEntryPoint]
      mov DWORD PTR [esp + 10h], eax
      lea eax, [ebp + @_except_handler1_oep_jump]
      mov DWORD PTR [esp + 1ch],eax
      popad
      push eax
      xor eax,eax
      push DWORD PTR FS:[0]
      mov DWORD PTR FS:[0], ESP
      {注册完异常处理回调函数,开始调用INT 3 触发异常,异常发生后,}
      {线程的栈被保护起来,原来存有真正OEP地址的EBX也被保存起来}
      DB $CC
      DB $CC
      DB $CC
      DB $CC
    
    {eax中返回字符串的长度}
    @_strlen:
      push ebp
      mov ebp,esp
      push ecx
      push esi
      push ebx
      mov esi,[ebp+08h]
    
      mov ecx,255// -> Length
      xor ebx,ebx
    @_strlenloop:
      lods byte ptr ds:[esi]
      cmp al,00h
      jz @_endbufstrlen
      inc ebx
      loop @_strlenloop
    @_endbufstrlen:
      mov eax,ebx
      inc eax
      pop ebx
      pop esi
      pop ecx
      mov esp,ebp
      pop ebp
      ret
    
    
    {*********************为被插入代码的程序修正重定位表*******************************}
    @_reloc_fixup:
     mov eax,[ebp + @_RO_dwImageBase]
     mov edx,eax
     mov ebx,eax
     add ebx,[ebx+3Ch]     
     mov ebx,[ebx+034h]    
     sub edx,ebx           
     je @_reloc_fixup_end   
     mov ebx,[ebp + @_p_dwRelocationVirtualAddress] 
     test ebx,ebx
     jz @_reloc_fixup_end                           
     add ebx,eax                                   
    @_reloc_fixup_block:
     mov eax,[ebx+004h]   
     test eax,eax
     jz @_reloc_fixup_end                    
     lea ecx,[eax-008h]   
     shr ecx,001h    
     lea edi,[ebx+008h]   
    @_reloc_fixup_do_entry:
     movzx eax,word ptr [edi]                
     push edx
     mov edx,eax
     shr eax,00Ch            
    
     mov esi,[ebp + @_RO_dwImageBase]            
     and dx,00FFFh
     add esi,[ebx]           
     add esi,edx    
     pop edx
    
    @_reloc_fixup_HIGH:
      dec eax
      jnz @_reloc_fixup_LOW
      mov eax,edx
      shr eax,010h  //HIWORD(Delta)
      jmp @_reloc_fixup_LOW_fixup
    
    @_reloc_fixup_LOW:
      dec eax
      jnz @_reloc_fixup_HIGHLOW
      movzx eax,dx   //LOWORD(Delta)
    @_reloc_fixup_LOW_fixup:
      add word ptr [esi],ax
      jmp @_reloc_fixup_next_entry
    
    @_reloc_fixup_HIGHLOW:
      dec eax
      jnz @_reloc_fixup_next_entry
      add [esi],edx
    
    @_reloc_fixup_next_entry:
      inc edi
      inc edi      //Entry++
      loop @_reloc_fixup_do_entry
    
    @_reloc_fixup_next_base:
     add ebx,[ebx+004h]    //ImageBaseRelocation + ImageBaseRelocation.SizeOfBlock
     jmp @_reloc_fixup_block
    @_reloc_fixup_end:
     ret
    
    
      {**************为捆绑的程序在内存中建立IAT表*********************************}
      {1. 加载输入表中对应的DLL。                                                  }
      {2. 加载输入表里对应DLL的输入函数。                                          }
      {3. 讲函数的内存地址放入输入表的FirstThunk里,建立IAT表                      }
    @_it_fixup:
      mov ebx,[ebp + @_p_dwImportVirtualAddress]  
      test ebx,ebx                                
      jz @_it_fixup_end                 
      mov esi,[ebp + @_RO_dwImageBase]
      add ebx,esi                        
    @_it_fixup_get_lib_address_loop:
      mov eax,[ebx+00Ch]        
      test eax,eax                               
      jz @_it_fixup_end              
    
      mov ecx,[ebx+010h]        
      add ecx,esi                                
      mov [ebp + @_p_dwThunk],ecx       
      mov ecx,[ebx]         
      test ecx,ecx                               
      jnz @_it_fixup_table                       
      mov ecx,[ebx + 010h]                      
    @_it_fixup_table:
      add ecx,esi                                
      mov [ebp + @_p_dwHintName],ecx      
      add eax,esi        
      push eax         
      mov eax,offset @_p_LoadLibrary
      call [ebp+eax]       
    
      test eax,eax
      jz @_it_fixup_end                        
      mov edi,eax                              
    @_it_fixup_get_proc_address_loop:
      mov ecx,[ebp + @_p_dwHintName]     
      mov edx,[ecx]        
      test edx,edx                              
      jz @_it_fixup_next_module                 
      test edx,80000000h       
      jz @_it_fixup_by_name                     
      and edx,07FFFFFFFh       
      jmp @_it_fixup_get_addr
    @_it_fixup_by_name:
      add edx,esi        
      inc edx                                   
      inc edx       
    @_it_fixup_get_addr:
      push edx               
      push edi        
      mov eax,offset @_p_GetProcAddress
      call [ebp+eax]             
    
      mov ecx,[ebp + @_p_dwThunk]             
      mov [ecx],eax                            
      add dword ptr [ebp + @_p_dwThunk],004h 
      add dword ptr [ebp + @_p_dwHintName],004h     
      jmp @_it_fixup_get_proc_address_loop
    @_it_fixup_next_module:
      add ebx,014h     
      jmp @_it_fixup_get_lib_address_loop
    @_it_fixup_end:
      ret
    
      {***************加载动态库,然后建立其输入函数的跳转表***********************}
    @_api_load:
      lea edi, [ebp + @_p_szKernel32]        
      lea ebx, [ebp + @_p_GetModuleHandle]   
      lea ecx, [ebp + @_jmp_GetModuleHandle] 
      add ecx, 02h                          
    @_api_get_lib_address_loop:
      push ecx                               
      push edi                               
      mov eax, offset @_p_LoadLibrary
      call [ebp + eax]                       
      pop ecx                               
      mov esi, eax                          
      push edi
      call @_strlen
      add  esp, 04h
      add  edi, eax                         
    @_api_get_proc_address_loop:
      push ecx                               
      push edi                               
      push esi                               
      mov eax, offset @_p_GetProcAddress
      call [ebp + eax]                       
      pop ecx                                
      mov [ebx], eax                        
      mov [ecx], ebx                         
      add ebx, 04h                          
      add ecx, 06h                           
      push edi                               
      call @_strlen
      add esp, 04h
      add edi, eax                           
      mov al, byte ptr [edi]                 
      test al,al
      jnz @_api_get_proc_address_loop
      inc edi
      mov al, byte ptr [edi]
      test al, al
      jnz @_api_get_lib_address_loop
      ret
    
     
      {SEH异常处理回调函数的有四个参数,分别为ExceptionRecord, SEH, Context,       }
      {DispatcherContext,先压入下一个指令的地址,然后根据被压入栈的这四个参数中    }
      {Context的

    四、测试。

    可以对EXE文件和DLL文件进行代码插入。当被插入的EXE文件或DLL文件运行或被调用的时候,都会先跳出一个对话框:

    然后再运行或调用被插入的EXE或DLL文件。

    http://blog.csdn.net/suiyunonghen/article/details/3860206

  • 相关阅读:
    Java new关键字的对象内存分配原理
    Android idleHandler
    Android Perffto工具
    Android Systrace工具
    Android TraceView工具
    Android App启动时间测量
    Android App启动分类
    Android线程的消息队列
    2018.2.28(延迟加载和缓存)
    2018.2.27(关联查询)
  • 原文地址:https://www.cnblogs.com/findumars/p/5037660.html
Copyright © 2020-2023  润新知