Thema: Delphi MBR überschreiben?

Einzelnen Beitrag anzeigen

CCRDude
Online

Registriert seit: 9. Jun 2011
677 Beiträge
 
FreePascal / Lazarus
 
#1

MBR überschreiben?

  Alt 5. Jan 2012, 16:49
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.
Miniaturansicht angehängter Grafiken
discalyzer2-mbr-code.png   discalyzer2-mbr-disassembler.png   discalyzer2-mbr-replaceselection.png  
  Mit Zitat antworten Zitat