Pe Memory Loader by ErazerZ

posted 17 Jul 2010, 10:40 by Delphi Basics
This code adds a new section to the pe file, so when its run the file its decrypted and loaded in memory

program PeLoader;

{
  Example of a Pe Loader by ErazerZ
  3rd May 2006
}

uses
  Windows,
  Dialogs,
  untPeFile; { PE File Unit by ErazerZ }

var
  Pe: TPeFile;
  Open: TOpenDialog;

procedure AddExeLoader;
  procedure _load_iat; stdcall; forward;
  procedure _load_code(lpLoadLibrary, lpGetProcAddress: Pointer; lpSectionBegin: DWORD); stdcall; forward;
  procedure _loader; stdcall;
  asm
    call _load_iat
    call _load_code
  end;

  procedure _load_iat;
  asm
    pop eax

    mov edx, eax
    mov edx, eax
    and eax, $fffff000

    push eax

    add eax, $55

    lea eax, [eax]
    push [eax]

    lea eax, [eax+4]
    push [eax]

    push edx
  end;
  procedure _load_code(
    lpLoadLibrary,
    lpGetProcAddress: Pointer;
    lpSectionBegin: DWORD); stdcall;
  var
    xLoadLibraryA: function(lpLibFileName: PChar): HMODULE; stdcall;
    xGetProcAddress: function(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
    ImageBase, OldEntryPoint, OldIAT, EncryptStart, EncryptEnd, EncryptCounter: DWORD;
    ImportDesc: PImageImportDescriptor;
    lpDllName: PChar;
    hDll: THandle;
    ImageThunk: ^PImageThunkData;
    ImageThunkWrite: ^Pointer;
  begin
    @xLoadLibraryA := lpLoadLibrary;
    @xGetProcAddress := lpGetProcAddress;
    ImageBase := DWORD(Pointer(DWORD(lpSectionBegin + $61))^);
    OldEntryPoint := DWORD(Pointer(DWORD(lpSectionBegin + $65))^) + ImageBase;
    OldIAT := DWORD(Pointer(DWORD(lpSectionBegin + $69))^) + ImageBase;
    EncryptStart := DWORD(Pointer(DWORD(lpSectionBegin + $6D))^) + ImageBase;
    EncryptEnd := DWORD(Pointer(DWORD(lpSectionBegin + $71))^) + ImageBase;

    for EncryptCounter := EncryptStart to EncryptEnd do
    begin
      PByte(EncryptCounter)^ := PByte(EncryptCounter)^ xor $FF;
    end;

    ImportDesc := PImageImportDescriptor(OldIAT);
    while (ImportDesc^.Name <> 0) do
    begin
      lpDllName := PChar(ImportDesc^.Name + ImageBase);
      hDll := xLoadLibraryA(lpDllName);
      if (ImportDesc^.OriginalFirstThunk <> 0) then
        ImageThunk := Pointer(ImportDesc^.OriginalFirstThunk + ImageBase)
      else
        ImageThunk := Pointer(ImportDesc^.FirstThunk + ImageBase);
      ImageThunkWrite := Pointer(ImportDesc^.FirstThunk + ImageBase);
      while (ImageThunk^ <> nil) do
      begin
        if ((Cardinal(ImageThunk^) and $80000000) <> 0) then
          ImageThunkWrite^ := xGetProcAddress(hDll, PChar(Cardinal(ImageThunk^) and $FFFF))
        else
          ImageThunkWrite^ := xGetProcAddress(hDll, PChar(ImageBase + Cardinal(ImageThunk^) + SizeOf(Word)));
        Inc(ImageThunk);
        Inc(ImageThunkWrite);
      end;
      Inc(ImportDesc);
    end;

    asm
      jmp OldEntryPoint
    end;
  end;
  procedure _loader_end; begin end;

var
  dwOldIATVA, lsPointerToRawData, lpTemp, EncryptCounter, EncryptStart, EncryptEnd: Cardinal;
  ImportDescriptor: TImageImportDescriptor;
  ImageThunk: array[0..1] of TImageThunkData;
  x: Word;
const
  szIAT_DLL_KERNEL: string = 'kernel32.dll'#0;
  szIAT_FUNC_GETPROCADDR: string = #0#0'GetProcAddress'#0;
  szIAT_FUNC_LOADLIBRARY: string = #0#0'LoadLibraryA'#0;
begin
  dwOldIATVA := Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

  if Pe.AddSection('.edi', $200) then
  begin
    FillChar(ImportDescriptor, SizeOf(TImageImportDescriptor), #0);
    FillChar(ImageThunk, SizeOf(TImageThunkData), #0);

    lsPointerToRawData := Pe.ImageSections[High(Pe.ImageSections)].PointerToRawData;


    lpTemp := 0;
    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, Pointer(szIAT_DLL_KERNEL), Length(szIAT_DLL_KERNEL));
    ImportDescriptor.Name := Pe.FileOffsetToRva(lsPointerToRawData);
    Inc(lpTemp, Length(szIAT_DLL_KERNEL));


    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, Pointer(szIAT_FUNC_GETPROCADDR), Length(szIAT_FUNC_GETPROCADDR));
    ImageThunk[0].Name := Pe.FileOffsetToRva(lsPointerToRawData + lpTemp);
    Inc(lpTemp, Length(szIAT_FUNC_GETPROCADDR));


    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, Pointer(szIAT_FUNC_LOADLIBRARY), Length(szIAT_FUNC_LOADLIBRARY));
    ImageThunk[1].Name := Pe.FileOffsetToRva(lsPointerToRawData + lpTemp);
    Inc(lpTemp, Length(szIAT_FUNC_LOADLIBRARY));


    ImportDescriptor.FirstThunk := Pe.FileOffsetToRva(lsPointerToRawData + lpTemp + (SizeOf(TImageImportDescriptor) * 2));
    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, @ImportDescriptor, SizeOf(TImageImportDescriptor));
    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress := Pe.FileOffsetToRva(lsPointerToRawData + lpTemp);
    Inc(lpTemp, SizeOf(TImageImportDescriptor) * 2);


    Pe.CopyMemoryBuffer((lsPointerToRawData + lpTemp), @ImageThunk, SizeOf(ImageThunk));
    Inc(lpTemp, SizeOf(ImageThunk) + SizeOf(TImageThunkData));


    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size := lpTemp;


    Pe.CopyMemoryBuffer((lsPointerToRawData + lpTemp), PDWORD(@Pe.ImageNtHeaders^.OptionalHeader.ImageBase), SizeOf(DWORD));
    Inc(lpTemp, SizeOf(DWORD));


    Pe.CopyMemoryBuffer((lsPointerToRawData + lpTemp), PDWORD(@Pe.ImageNtHeaders^.OptionalHeader.AddressOfEntryPoint), SizeOf(DWORD));
    Inc(lpTemp, SizeOf(DWORD));


    Pe.CopyMemoryBuffer((lsPointerToRawData + lpTemp), PDWORD(@dwOldIATVA), SizeOf(DWORD));
    Inc(lpTemp, SizeOf(DWORD));


    EncryptStart := Pe.ImageSections[Pe.GetCodeSection].VirtualAddress;
    Pe.CopyMemoryBuffer((lsPointerToRawData + lpTemp), PDWORD(@EncryptStart), SizeOf(DWORD));
    Inc(lpTemp, SizeOf(DWORD));


    EncryptEnd := EncryptStart + Pe.ImageSections[Pe.GetCodeSection].Misc.VirtualSize;
    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, PDWORD(@EncryptEnd), SizeOf(DWORD));
    Inc(lpTemp, SizeOf(DWORD));

    EncryptStart := Pe.RvaToVa(EncryptStart);
    EncryptEnd := Pe.RvaToVa(EncryptEnd);


    for EncryptCounter := EncryptStart to EncryptEnd do
    begin
      PByte(EncryptCounter)^ := PByte(EncryptCounter)^ xor $FF;
    end;


    Pe.ImageNtHeaders^.OptionalHeader.AddressOfEntryPoint := Pe.FileOffsetToRva(lsPointerToRawData + lpTemp);
    Pe.CopyMemoryBuffer(lsPointerToRawData + lpTemp, @_loader, DWORD(@_loader_end) - DWORD(@_loader));


    for x := Low(Pe.ImageSections) to High(Pe.ImageSections) do
      Pe.ImageSections[x].Characteristics := Pe.ImageSections[x].Characteristics or IMAGE_SCN_MEM_WRITE;


    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress := 0;
    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size := 0;
    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress := 0;
    Pe.ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size := 0;
    Pe.ImageNtHeaders^.OptionalHeader.BaseOfCode := lsPointerToRawData;
    Pe.ImageNtHeaders^.OptionalHeader.BaseOfData := lsPointerToRawData;
  end;
end;


begin
  Pe := TPeFile.Create;
  Open := TOpenDialog.Create(Self);
  if OpenDialog.Execute then
  begin
    Pe.LoadFromFile(Open.FileName);
    AddExeLoader;
    Pe.SaveToFile(Open.FileName);
  end;
  Open.Free;
  Pe.Free;
end.
Comments