Vorweg: es geht nicht um einen Virus, im Gegenteil. Mein Code prüft den Hash des zu schreibenden MBRs (des Code-Anteils darin) gegen eine Liste von bekannten MBRs, bzw. akzeptiert noch solche, die als Teil eines gültig von MS signierten diskpart.exe, dmadmin.exe, etc. kommen, keine anderen.
Meine Frage: wie kann ich den MBR etwa von \\.\PhysicalDrive0 überschreiben? Ein einfaches CreateFile wie zum Lesen hilft scheinbar nicht. Wo ist der Fehler in meinem Code (weiter unten, keine Fehlermeldungen oder Exceptions vom System)?
Der Hintergrund: ein kleines Tool, das ich die letzte Woche geschrieben habe, zeigt mir Platteninhalte direkt vom Gerät, aber auch einfach nur den jeweiligen MBR, von einem Device oder aus einer Datei, an. Der komplette MBR-Inhalt wird strukturiert angezeigt, disassembliert, dazu kommen etwa SMART-Infos u.ä..
Nun will ich aber ein MBR-Restore einbauen, d.h. dem Benutzer die Möglichkeit geben, einen Original-MBR wiederherzustellen. Die Copyright-Frage umgehe ich, indem ich diesen in Betriebssystemdateien auffinde und von dort kopiere.
Mein Ansatz: zuerst den Lesecode kopiert und auf Schreiben umgebaut, d.h. ein TFileStream z.B. auf \\.\PhysicalDrive0, die ersten 512 Byte auslesen (sektorweise halt), im Ausgelesenen die ersten 440 Byte ersetzen (um Partitionstabelle und alles danach zu erhalten) und dann alles zurückzuschreiben.
Funktioniert super, wenn ich als Ziel eine Datei angebe, aber nicht mit \\.\PhysicalDrive0.
Ich bin dann auf CreateFile/ReadFile/WriteFile umgestiegen, das funktioniert aber auch nicht.
Delphi-Quellcode:
function TMasterBootRecordRecordStream.WriteToDrive(
const ADiskDeviceName:
string;
var AErrorCode: cardinal): boolean;
var
fs: TFileStream;
iBytesCopied: Int64;
ms: TMemoryStream;
cWritten, cRead: cardinal;
h: THandle;
p: Pointer;
begin
try
Seek(0, soFromBeginning);
fs := TFileStream.Create('
\\.\' + ADiskDeviceName, fmOpenReadWrite);
ms := TMemoryStream.Create;
try
fs.Seek(0, soFromBeginning);
ms.CopyFrom(fs, 512);
ms.Seek(0, soFromBeginning);
ms.CopyFrom(Self, MasterBootRecordCodeSize);
ms.Seek(0, soFromBeginning);
fs.Seek(0, soFromBeginning);
iBytesCopied := fs.CopyFrom(ms, 512);
Result := (iBytesCopied = 512);
(*
iBytesCopied := fs.CopyFrom(Self, MasterBootRecordCodeSize);
Result := (iBytesCopied = MasterBootRecordCodeSize);
*)
finally
ms.Free;
fs.Free;
end;
except
on E:
Exception do begin
Result := false;
ShowMessage(E.
Message);
end;
end;
end;
Self ist jeweils ein Stream, der den zu schreibenden Code enthält, MasterBootRecordCodeSize eine Konstante mit der Größe der Code-Anteils (440).
Erschwerend kommt hinzu, daß dieser Code keinerlei Fehler liefert (war schon mit etlichen Debugausgaben gespickt).
Testen tue ich u.a. auf einer frischen XP-VM, d.h. die erschwerten Schreibbedingungen von Vista & höher treffen hier nicht zu, und, da ganz frisch, auch kein hinderndes Antivirenprogramm.
Delphi-Quellcode:
function TMasterBootRecordRecordStream.WriteToDrive(
const ADiskDeviceName:
string;
var AErrorCode: cardinal): boolean;
var
fs: TFileStream;
iBytesCopied: Int64;
ms: TMemoryStream;
cWritten, cRead: cardinal;
h: THandle;
p: Pointer;
begin
try
Seek(0, soFromBeginning);
h := CreateFile(PChar('
\\.\' + ADiskDeviceName), GENERIC_READ
or GENERIC_WRITE, FILE_SHARE_READ
or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0);
// h := CreateFile(PChar('C:\testout.mbr'), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_ALWAYS, 0, 0);
ms := TMemoryStream.Create;
try
ms.SetSize(512);
p := ms.Memory;
Result := Windows.ReadFile(h, ms.Memory^, 512, cRead,
nil);
if Result
then begin
Result := (cRead = 512);
if Result
then begin
ms.Seek(0, soFromBeginning);
ms.CopyFrom(Self, MasterBootRecordCodeSize);
ms.Seek(0, soFromBeginning);
Result := Windows.WriteFile(h, Self.Memory^, 512, cWritten,
nil);
if Result
then begin
Result := (cWritten = 512);
end else begin
// TODO : improve error handling, not just ShowMessage('Error.3');
end;
end else begin
// TODO : improve error handling, not just ShowMessage('Error.2');
end;
end else begin
// TODO : improve error handling, not just ShowMessage('Error.1');
end;
finally
ms.Free;
Windows.CloseHandle(h);
end;
except
on E:
Exception do begin
Result := false;
ShowMessage(E.
Message);
end;
end;
end;
Die ShowMessage waren bereits drin, genauso wie weitere, die positive Ergebnisse zeigen sollten. Alle Calls liefern True.
PS: Die Suchfunktion habe ich natürlich schon bemüht, auch ein ähnliches Thema gefunden, aber keine Antwort auf genau diese Frage.