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

posted @ 2015-12-10 22:59  findumars  Views(955)  Comments(0Edit  收藏  举报