Einzelnen Beitrag anzeigen

Benutzerbild von ErazerZ
ErazerZ

Registriert seit: 27. Mai 2005
Ort: Baden
315 Beiträge
 
Delphi 2007 Enterprise
 
#14

Re: Alle Resourcen aus fremder EXE richtig entfernen

  Alt 2. Feb 2007, 21:46
Ja also, ich hab mal heute das gemacht, getestet habe ich es nur mit meinem kleinen nonVCL programm, das einfach einen text aus einer Resource ladet und in einer MessageBox ausgibt. Die funktion die ich gemacht habe, entfernt dabei die ganze Sektionen aus einer PE-Datei. Und hier ist der ganze Code.
Delphi-Quellcode:
{
  Friday, 2nd February 2007 (15:00 - 22:30)
  by ErazerZ ( ErazerZ[at]gmail[dot]com )
  Music listening while coding: 
    Bishop Lamont
    Busta Rhymes: The Big Bang
    Dr. Dre - 2001
    Eminem - Marshall Mathers LP
}


program SectionEraser;

uses
  Windows;

function ShellExecute(hWnd: HWND; Operation, FileName, Parameters, Directory: PChar; ShowCmd: Integer): HINST; stdcall; external 'shell32.dllname 'ShellExecuteA';

function RemoveSection(sFilename: String; wSection: Word): Boolean;
  function Align(Value, Align: Cardinal): Cardinal;
  begin
    if ((Value mod Align) = 0) then
      Result := Value
    else
      Result := ((Value + Align - 1) div Align) * Align;
  end;
  
  function RvaToFileOffset(Address: Cardinal; NtHeaders: PImageNtHeaders): Cardinal;
  var
    i: Word;
    Section: PImageSectionHeader;
  begin
    Result := 0;
    Section := PImageSectionHeader(Cardinal(NtHeaders) + sizeof(TImageNtHeaders));
    for i := 0 to NtHeaders^.FileHeader.NumberOfSections -1 do
    begin
      if (Address >= Section^.VirtualAddress) and (Address <= Section^.VirtualAddress + Section^.SizeOfRawData) then
      begin
        Result := Address - Section^.VirtualAddress + Section^.PointerToRawData;
        Break;
      end;
      Inc(Section);
    end;
  end;
  
  function FileOffsetToRva(Address: Cardinal; NtHeaders: PImageNtHeaders): Cardinal;
  var
    i: Word;
    Section: PImageSectionHeader;
  begin
    Result := 0;
    Section := PImageSectionHeader(Cardinal(NtHeaders) + sizeof(TImageNtHeaders));
    for i := 0 to NtHeaders^.FileHeader.NumberOfSections -1 do
    begin
      if (Address >= Section^.PointerToRawData) and (Address <= Section^.PointerToRawData + Section^.SizeOfRawData) then
      begin
        Result := Address + Section^.PointerToRawData + Section^.VirtualAddress + NtHeaders^.OptionalHeader.ImageBase;
        Break;
      end;
      Inc(Section);
    end;
  end;

  function CutFile(hFile: THandle; FromOffset, Count: Cardinal): Cardinal;
  var
    dwSize, dwCopyFrom, dwCopyLength,
    lpNumberOfBytesRead: Cardinal;
    lpBuffer: Pointer;
  begin
    Result := Cardinal(-1);
    if (hFile <> INVALID_HANDLE_VALUE) then
    begin
      dwSize := GetFileSize(hFile, nil);
      if (dwSize > (FromOffset + Count)) then
      begin
        dwCopyFrom := FromOffset + Count;
        dwCopyLength := dwSize - (FromOffset + Count);
        if dwCopyLength = 0 then
        begin
          SetFilePointer(hFile, FromOffset, nil, FILE_BEGIN);
          SetEndOfFile(hFile);
          Result := dwSize - Count;
        end else
        begin
          lpBuffer := VirtualAlloc(nil, dwCopyLength, MEM_COMMIT, PAGE_READWRITE);
          if (lpBuffer <> nil) then
          begin
            SetFilePointer(hFile, dwCopyFrom, nil, FILE_BEGIN);
            ReadFile(hFile, lpBuffer^, dwCopyLength, lpNumberOfBytesRead, nil);
            if (lpNumberOfBytesRead = dwCopyLength) then
            begin
              SetFilePointer(hFile, FromOffset, nil, FILE_BEGIN);
              SetEndOfFile(hFile);
              WriteFile(hFile, lpBuffer^, dwCopyLength, lpNumberOfBytesRead, nil);
              if (lpNumberOfBytesRead = dwCopyLength) then
              begin
                VirtualFree(lpBuffer, 0, MEM_RELEASE);
                Result := dwSize - Count;
              end;
            end;
          end;
        end;
      end else
      begin
        if (FromOffset < dwSize) then
        begin
          SetFilePointer(hFile, FromOffset, nil, FILE_BEGIN);
          SetEndOfFile(hFile);
          Result := FromOffset;
        end;
      end;
    end;
  end;
var
  lpBuffer: Pointer;
  x: Word;
  { PE-Stuff }
  NtHeaders: PImageNtHeaders;
  Sections: array of TImageSectionHeader;
  SectionHeader: TImageSectionHeader;
  SectionOffset, SectionSize, // FileOffset of the Section ...
  SectionAlign: Cardinal; // Alignment of Section
  ImageSize: Cardinal;
  { Datei öffnen und laden }
  hFile: THandle;
  FileSize: Cardinal;
  lpNumberOfBytesWritten,
  lpNumberOfBytesRead: DWORD;
begin
  Result := False;
  hFile := CreateFile(PChar(sFilename), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  FileSize := GetFileSize(hFile, nil);
  GetMem(lpBuffer, FileSize);
  ReadFile(hFile, lpBuffer^, FileSize, lpNumberOfBytesRead, nil);
  if (lpBuffer = nil) then
  begin
    DeleteFile(PChar(sFilename));
    ExitProcess(0);
  end;
  NtHeaders := PImageNtHeaders(Cardinal(lpBuffer) + Cardinal(PImageDosHeader(lpBuffer)._lfanew));
  if NtHeaders.Signature <> IMAGE_NT_SIGNATURE then
  begin
    DeleteFile(PChar(sFilename));
    ExitProcess(0);
  end else
  begin
    if (wSection >= NtHeaders^.FileHeader.NumberOfSections) then
    begin
      DeleteFile(PChar(sFilename));
      ExitProcess(0);
    end;
    // alle TImageSectionHeaders zwischenspeichern (leichter und übersichtlicher)
    SetLength(Sections, NtHeaders^.FileHeader.NumberOfSections);
    for x := 0 to NtHeaders^.FileHeader.NumberOfSections -1 do
      CopyMemory(@Sections[x], Pointer(Cardinal(NtHeaders) + SizeOf(TImageNtHeaders) + (SizeOf(TImageSectionHeader) * x)), SizeOf(TImageSectionHeader));
    SectionHeader := Sections[wSection];
    SectionOffset := SectionHeader.PointerToRawData;
    SectionSize := SectionHeader.SizeOfRawData;
    SectionAlign := NtHeaders^.OptionalHeader.SectionAlignment;
    if (CutFile(hFile, SectionOffset, SectionSize) <> Cardinal(-1)) then
    begin
      // Sektionen die danach sind anpassen, also deren PointerToRawData updaten
      // es müssen keine berechnungen durchgeführt werden da sowieso bei einer ausführbaren datei alles bereits berechnet ist
      // wir müssen einfach nur abziehen
      for x := 0 to wSection -1 do
      begin
        Sections[x].Misc.VirtualSize := Align(Sections[x].Misc.VirtualSize, SectionAlign);
        // Ich weiß es auch nicht warum der aufeinmal so will und nicht anders ..
        if (x = wSection -1) then
          Sections[x].Misc.VirtualSize := Align(Sections[x].Misc.VirtualSize + SectionAlign, SectionAlign);
        SetFilePointer(hFile, PImageDosHeader(lpBuffer)._lfanew + SizeOf(TImageNtHeaders) + (SizeOf(TImageSectionHeader) * x), nil, FILE_BEGIN);
        WriteFile(hFile, Sections[x], SizeOf(TImageSectionHeader), lpNumberOfBytesWritten, nil);
      end;
      // Die danach folgenden Sektionen anpassen, VirtualSize muss nicht geupdated werden, anscheinend ..
      // nur PointerToRawData updaten, einfach die größe der zu löschendenen Sektion abziehen
      // wir müssen nichts berechnen weil es bereits vom compiler getan wurde ..
      for x := wSection +1 to (NtHeaders^.FileHeader.NumberOfSections -1) do
      begin
        Sections[x].PointerToRawData := Sections[x].PointerToRawData - SectionSize;
        SetFilePointer(hFile, PImageDosHeader(lpBuffer)._lfanew + SizeOf(TImageNtHeaders) + (SizeOf(TImageSectionHeader) * (x -1)), nil, FILE_BEGIN);
        WriteFile(hFile, Sections[x], SizeOf(TImageSectionHeader), lpNumberOfBytesWritten, nil);
      end;
      // Directorys müssen nicht abgezogen werden, nur die wenns z.b. Resource ist dann auf 0 setzen
      for x := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES -1 do
      begin
        if (NtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress <> 0) and (NtHeaders^.OptionalHeader.DataDirectory[x].Size <> 0) then
        begin
          if (RvaToFileOffset(NtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress, NtHeaders) = SectionOffset) then
          begin
            NtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress := 0;
            NtHeaders^.OptionalHeader.DataDirectory[x].Size := 0;
            break;
          end;
        end;
      end;
      // ImageSize anpassen
      if (NtHeaders^.OptionalHeader.SizeOfHeaders mod SectionAlign = 0) then
        ImageSize := NtHeaders^.OptionalHeader.SizeOfHeaders
      else
        ImageSize := Align(NtHeaders^.OptionalHeader.SizeOfHeaders, SectionAlign);
      for x := 0 to NtHeaders^.FileHeader.NumberOfSections -1 do
      begin
        if (x <> wSection) then
        begin
          ImageSize := ImageSize + Align(Sections[x].Misc.VirtualSize, SectionAlign)
        end;
      end;
      NtHeaders^.OptionalHeader.SizeOfImage := ImageSize;
      Dec(NtHeaders^.FileHeader.NumberOfSections);
      // NtHeader noch updaten ..
      SetFilePointer(hFile, PImageDosHeader(lpBuffer)._lfanew, nil, FILE_BEGIN);
      WriteFile(hFile, NtHeaders^, SizeOf(TImageNtHeaders), lpNumberOfBytesWritten, nil);
      if (lpNumberOfBytesWritten = SizeOf(TImageNtHeaders)) then
        Result := True;
    end;
  end;
  CloseHandle(hFile);
  FreeMem(lpBuffer, FileSize);
  // Testen ob es läuft ..
  ShellExecute(0, 'open', PChar(sFilename), nil, nil, SW_SHOWNORMAL);
end;

function ExtractFilePath(s: string): string;
var
  i: Integer;
begin
  i := Length(s);
  while ((s[i] <> '\') and (s[i] <> '/')) do
    if (i > 0) then
      Dec(i)
    else
      Break;
  if i > 0 then
    Result := Copy(s, 1, i);
end;
  
const
  SectionToRemove = 6;
var
  sFilename: String;
begin
  sFilename := ExtractFilePath(ParamStr(0));
  sFilename := sFilename + 'Resource_Test.exe';
  DeleteFile(PChar(sFilename + '_.exe'));
  CopyFile(PChar(sFilename), PChar(sFilename + '_.exe'), False);
  sFilename := sFilename + '_.exe';
  if not RemoveSection(sFilename, SectionToRemove) then
    MessageBox(HWND_DESKTOP, 'Die Sektion konnte nicht entfernt werden!', 'Fehler', MB_ICONERROR);
end.
Falls irgendjemand irgendwelche Fehler findet oder Verbesserungsvorschläge dann schreibt mir eine mail oder postet es hier!
  Mit Zitat antworten Zitat