{
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.dll'
name '
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.