Add New Section to PE File

posted 16 Mar 2010, 08:30 by Delphi Basics   [ updated 4 Jan 2011, 15:08 ]
{
  Unit: uAddSection
  Author: steve10120
  Description: Add a new section to a PE file.
  Thanks: Nacho_dj
  Website: ic0de.org
  History: First try
             Bugfix - SetLength(bDataBuff, dwNewSectionSize);

unit uAddSection;
//steve10120
interface

uses
  Windows;

function AddSection(szFileName:string; szNewSectionName:string; dwNewSectionSize:DWORD; dwNewSectionCharacteristics:DWORD):Boolean;

implementation

function Align(dwValue:DWORD; dwAlign:DWORD):DWORD;
begin
  if dwAlign <> 0 then
  begin
    if dwValue mod dwAlign <> 0 then
    begin
      Result := (dwValue + dwAlign) - (dwValue mod dwAlign);
      Exit;
    end;
  end;
  Result := dwValue;
end;

function LastSectionRaw(Sections: array of TImageSectionHeader):DWORD;
var
  i:    integer;
  Ret:  DWORD;
begin
  Ret := 0;
  for i := Low(Sections) to High(Sections) do
  begin
    if Sections[i].SizeOfRawData + Sections[i].PointerToRawData > Ret then
      Ret := Sections[i].SizeOfRawData + Sections[i].PointerToRawData;
  end;
  Result := Ret;
end;

function LastSectionVirtual(Sections: array of TImageSectionHeader):DWORD;
var
  i:   integer;
  Ret: DWORD;
begin
  Ret := 0;
  for i := Low(Sections) to High(Sections) do
  begin
    if Sections[i].Misc.VirtualSize + Sections[i].VirtualAddress > Ret then
      Ret := Sections[i].Misc.VirtualSize + Sections[i].VirtualAddress;
  end;
  Result := Ret;
end;

function AddSection(szFileName:string; szNewSectionName:string; dwNewSectionSize:DWORD; dwNewSectionCharacteristics:DWORD):Boolean;
var
  hFile:  DWORD;
  x, i, k:  integer;
  IDH:      TImageDosHeader;
  INH:      TImageNtHeaders;
  Sections: array of TImageSectionHeader;
  dwRead:   DWORD;
  bDataBuff:  array of Byte;
const
  szError:  string = 'Add Section Error';
begin
  Result := FALSE;
  if Length(szNewSectionName) > 1 then
  begin
    if Length(szNewSectionName) > 8 then
      szNewSectionName := Copy(szNewSectionName, 1, 8);

    hFile := CreateFile(PChar(szFileName), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      SetFilePointer(hFile, 0, nil, FILE_BEGIN);
      ReadFile(hFile, IDH, 64, dwRead, nil);
      if IDH.e_magic = IMAGE_DOS_SIGNATURE then
      begin
        SetFilePointer(hFile, IDH._lfanew, nil, FILE_BEGIN);
        ReadFile(hFile, INH, 248, dwRead, nil);
        if INH.Signature = IMAGE_NT_SIGNATURE then
        begin
          k := INH.FileHeader.NumberOfSections;
          SetLength(Sections, k);
          x := IDH._lfanew + 24 + INH.FileHeader.SizeOfOptionalHeader;
          for i := Low(Sections) to High(Sections) do
          begin
            SetFilePointer(hFile, x, nil, FILE_BEGIN);
            ReadFile(hFile, Sections[i], 40, dwRead, nil);
            Inc(x, 40);
          end;
          if INH.OptionalHeader.SizeOfHeaders >= (x + 40) then
          begin
            Inc(INH.FileHeader.NumberOfSections, 1);
            SetLength(Sections, INH.FileHeader.NumberOfSections);

            with Sections[INH.FileHeader.NumberOfSections - 1] do
            begin
              CopyMemory(@Name[0], @szNewSectionName[1], 8);
              Characteristics := dwNewSectionCharacteristics;
              PointerToRawData := Align(LastSectionRaw(Sections), INH.OptionalHeader.FileAlignment);
              SizeOfRawData := Align(dwNewSectionSize, INH.OptionalHeader.FileAlignment);
              VirtualAddress := Align(LastSectionVirtual(Sections), INH.OptionalHeader.SectionAlignment);
              Misc.VirtualSize := Align(dwNewSectionSize, INH.OptionalHeader.SectionAlignment);
            end;

            INH.OptionalHeader.DataDirectory[11].VirtualAddress := 0;
            INH.OptionalHeader.DataDirectory[11].Size := 0;

            Inc(INH.OptionalHeader.SizeOfImage, Sections[INH.FileHeader.NumberOfSections - 1].Misc.VirtualSize);

            SetFilePointer(hFile, IDH._lfanew, nil, FILE_BEGIN);
            WriteFile(hFile, INH, 248, dwRead, nil);
            SetFilePointer(hFile, x, nil, FILE_BEGIN);
            WriteFile(hFile, Sections[INH.FileHeader.NumberOfSections - 1], 40, dwRead, nil);
            SetLength(Sections, 0);

            dwNewSectionSize := Align(dwNewSectionSize, INH.OptionalHeader.FileAlignment);
            SetLength(bDataBuff, dwNewSectionSize);

            SetFilePointer(hFile, 0, nil, FILE_END);
            WriteFile(hFile, bDataBuff[0], dwNewSectionSize, dwRead, nil);
            CloseHandle(hFile);
            Result := TRUE;
          end;
        end
        else
          MessageBox(0, PChar('Bad PE signature.'), PChar(szError), MB_ICONEXCLAMATION);
      end
      else
        MessageBox(0, PChar('Bad MZ signature.'), PChar(szError), MB_ICONEXCLAMATION);
    end
    else
      MessageBox(0, PChar('Error opening file.'), PChar(szError), MB_ICONEXCLAMATION);
  end;
end;

end.

Usage:
if AddSection('hellovb6.exe', '.test', 100, IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_WRITE) then
  MessageBox(0, PChar('Section added successfully.'), PChar('Success'), MB_ICONINFORMATION);
Comments