Search code examples
delphiresourcesdelphi-7

Delphi - Possible to write to resources of an application withing another application?


Just out of curiosity, do you think this is possible: Writing to the resources of a file, stored in the resources of the same file. Let's say we have a builder and a stub. Usually you would use the builder to write settings to the resources of another extracted file named "stub.exe".

Now I want to know, is it possible(in delphi 7) to write the settings to the resources of "stub.exe" when stored in the resources of the builder? Sounds better when I ask it in my head, hope you understand what I mean.


Solution

  • The resources of a file are stored in read only memory. In order to be able to write to them you would need to use VirtualProtect to make the memory writeable. This simple program proves the concept:

    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      SysUtils, Math, Windows, Classes;
    
    procedure DumpResource(const ResName: string; ResType: PChar);
    const
      ChunkSize = 32;
    var
      i, Count: Integer;
      Stream: TResourceStream;
      Buffer: array [0..ChunkSize-1] of Byte;
      HexBuffer: array [0..2*ChunkSize-1] of Char;
      Text: string;
    begin
      Stream := TResourceStream.Create(HInstance, ResName, ResType);
      try
        while Stream.Position < Stream.Size do
        begin
          Count := Min(ChunkSize, Stream.Size - Stream.Position);
          Stream.ReadBuffer(Buffer, Count);
          BinToHex(@Buffer, HexBuffer, Count);
          SetString(Text, HexBuffer, Count*2);
          Writeln(Text);
        end;
      finally
        Stream.Free;
      end;
    end;
    
    procedure ZeroiseResource(const ResName: string; ResType: PChar);
    var
      Res: HRSRC;
      ResHandle: HGLOBAL;
      Ptr: Pointer;
      OldProtect: DWORD;
    begin
      Res := FindResource(HInstance, PChar(ResName), ResType);
      Win32Check(Res <> 0);
    
      ResHandle := LoadResource(HInstance, Res);
      Win32Check(ResHandle <> 0);
    
      Ptr := LockResource(ResHandle);
      Win32Check(Ptr <> nil);
    
      Win32Check(VirtualProtect(Ptr, SizeofResource(HInstance, Res), PAGE_READWRITE, 
        OldProtect));
      ZeroMemory(Ptr, SizeofResource(HInstance, Res));
      Win32Check(VirtualProtect(Ptr, SizeofResource(HInstance, Res), OldProtect, 
        OldProtect));
    end;
    
    procedure Main;
    begin
      Writeln('Original resource');
      DumpResource('MAINICON', RT_GROUP_ICON);
    
      ZeroiseResource('MAINICON', RT_GROUP_ICON);
    
      Writeln('Modified resource');
      DumpResource('MAINICON', RT_GROUP_ICON);
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    end.
    

    However, I don't think that I would take this path. I would do the following.

    • Allocate memory in your builder process to hold a copy of the executable being built.
    • Copy the version of the executable stored in the resource to the memory you just allocated.
    • Modify the executable in that memory.
    • Write the executable from memory to disk.

    Note that I'm assuming in all this that your goal is to make the modifications before you save the executable to disk.