|
Antwort |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.184 Beiträge Delphi 12 Athens |
#1
Heute mal keine Frage,
ich wollte euch nur mal etwas vorstellen was ich mir vor kurzem hab einfallen lassen. Und zwar einen code, welcher die EXE auf Veränderungen prüft. Das Ding entdeckt also Dateifehler, welche z.B. durch einen fehlerhaften Download oder andere Dinge entstehen können. Ein guter Schutz gegen das Patchen einer Datei ist es nicht wirklich, da jeder erfahrene Programmierer dieses "leicht" umgehen kann. Funktionieren sollte es seit Windows 2000 Pro (Windows Vista, Windows XP or Windows 2000 Professional) Wenn man das FileMapping durch "normale" Lesezugriffe ersetzt, dann sollte es auch unter älteren Windowsversionen laufen. Die Funktion: Es wird nach einer bestimmten Signatur in der Programmdatei gesucht, wo einen MD5-Hash ausgelesen und mit dem Hash der Programmdatei verglichen wird. Beim Kompilieren wird ein Leerhash einkompiliert, welcher selbstständig beim ersten Programmstart angepaßt wird (also vor Weitergabe des Programmes sollte dieses mindestens einmal gestartet werden). Aktuell ist keine Selbstlöschroutine eingebaut, weswegen nur das Programm geändert, aber die alte/ungeschützte Version (*.exe.org) nicht gelöscht wird ... dieses müßt/könnt ihr selber machen. Wer möchte daß die "neue" Programmdatei sofort gestartet wird (ist aber nicht notwendig), der kann die zwei Zeilen mit ShellExecute auskommentieren, damit wird das aktuelle Programm beendet und die neue Version samt aller übergebener Parameter gestartet.
Delphi-Quellcode:
Zum Verwenden der Funktion muß sie nur aufgerufen und das Funktionsereignis ausgewertet werden.
Function SelfCheck: Boolean;
Const SelfCheckSigLen = 25; SelfCheckData: packed Array[0..44] of AnsiChar = 'S'#0'e'#1'l'#2'f'#3'C'#4'h'#5'e'#5'c'#4'k'#3'D'#2'a'#1't'#0'a' + '>>'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'<<'; Var FileName: WideString; H, Hm: THandle; FileSize, i, i2: Integer; P: PChar; MD5: MD5_CTX; B: Boolean; W: Cardinal; Begin Result := False; SetLength(FileName, MAX_PATH); SetLength(FileName, GetModuleFileNameW(0, PWideChar(FileName), MAX_PATH)); H := CreateFileW(PWideChar(FileName), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); FileSize := GetFileSize(H, nil); Hm := CreateFileMapping(H, nil, PAGE_READONLY, 0, 0, nil); P := MapViewOfFile(Hm, FILE_MAP_READ, 0, 0, 0); CloseHandle(H); Try If P = nil Then Exit; For i := 0 to FileSize - Length(SelfCheckData) do If (P + i)^ = SelfCheckData[0] Then Begin B := True; For i2 := 1 to SelfCheckSigLen + 1 do If (P + i + i2)^ <> SelfCheckData[i2] Then Begin B := False; Break; End; For i2 := SelfCheckSigLen + 2 + SizeOf(MD5.digest) to SelfCheckSigLen + 3 + SizeOf(MD5.digest) do If (P + i + i2)^ <> SelfCheckData[i2] Then B := False; If B Then Begin MD5Init(MD5); MD5Update(MD5, P, i); MD5Update(MD5, P + i + Length(SelfCheckData), FileSize - i - Length(SelfCheckData)); MD5Final(MD5); Result := True; For i2 := 0 to High(MD5.digest) do If PByte(P + i + SelfCheckSigLen + 2 + i2)^ <> 0 Then Begin Result := False; Break; End; If Result Then Begin DeleteFileW(PWideChar(FileName + '.old')); MoveFileW(PWideChar(FileName), PWideChar(FileName + '.old')); CopyFileW(PWideChar(FileName + '.old'), PWideChar(FileName), False); H := CreateFileW(PWideChar(FileName), GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0); If Integer(SetFilePointer(H, i + SelfCheckSigLen + 2, nil, FILE_BEGIN)) = i + SelfCheckSigLen + 2 Then WriteFile(H, @MD5.digest, SizeOf(MD5.digest), @W, nil); CloseHandle(H); //ShellExecuteW(0, 'open', PWideChar(FileName), GetCommandLineW, nil, SW_SHOW); //Halt; Exit; End; Result := True; For i2 := 0 to High(MD5.digest) do If PByte(P + i + SelfCheckSigLen + 2 + i2)^ <> MD5.digest[i2] Then Begin Result := False; Break; End; Exit; End; End; Finally UnmapViewOfFile(P); CloseHandle(Hm); End; End; Hier eine einfache VCL-lose Version, welche bei einer geänderten/defekten Programmdatei eine MessageBox anzeigt und das Programm beendet.
Delphi-Quellcode:
Wem eine MD5-Implementation fehlt, der kann gern auf eine seit Win2000pro verfügbare windowsinterne Variante zurückgreifen:
Var Params: TMsgBoxParamsA;
If not SelfCheck Then Begin ZeroMemory(@Params, SizeOf(TMsgBoxParamsA)); Params.cbSize := SizeOf(TMsgBoxParamsA); Params.hInstance := HInstance; Params.lpszText := 'self check: file is corrupt'#13#10'{Link zu einer intakten Programmversion}'; Params.lpszCaption := '{euer Programmname als Überschrift}'; Params.dwStyle := MB_OK or MB_ICONERROR or MB_SETFOREGROUND; MessageBoxIndirectA(Params); Halt; End; > MD5Update
Delphi-Quellcode:
Type MD5_CTX = packed Record
i: Array[0.. 1] of LongWord; buf: Array[0.. 3] of LongWord; input: Array[0..63] of Byte; digest: Array[0..15] of Byte; End; Procedure MD5Init(Var Context: MD5_CTX); StdCall; External 'advapi32.dll' Name 'MD5Init'; Procedure MD5Update(Var Context: MD5_CTX; Input: Pointer; inLen: LongWord); StdCall; External 'advapi32.dll' Name 'MD5Update'; Procedure MD5Final(Var Context: MD5_CTX); StdCall; External 'advapi32.dll' Name 'MD5Final';
$2B or not $2B
|
Zitat |
Registriert seit: 2. Mär 2004 5.508 Beiträge Delphi 5 Professional |
#2
SEHR interessant!!
Ich denke mal, die Suche nach SelfCheckData wäre schneller und verständlicher, wenn man die (Assembler-) Funktion CompareMem aus Unit SysUtils verwendet. NonVCL-Freaks können ja die Routine kopieren.
Andreas
|
Zitat |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.184 Beiträge Delphi 12 Athens |
#3
Upps, bevor wer meckert,
ich verwende 'ne etwas andere (PSDK-äquivalente) Implementation von WriteFile, als die von Delphi kann's oben nicht mehr Editieren, aber ihr müßt einfach nur die zwei @ entfernen: WriteFile(H, MD5.digest, SizeOf(MD5.digest), W, nil); @shmia: Na ob sich das soviel auswirkt, aber du hast schon etwas Recht und vielleicht sieht es jetzt auch noch etwas netter aus Aber die 2 Schleifen werden ja eh nur bei jedem (etwa) 256-ten Zeichen durchlaufen. Tja, jetzt sind da 2 Funktionsaufrufe (inclusive einiger Parametertests) statt der 2 (etwas optimierten) Pascalschleifen. Im Prinzip kann man das ganze eigentlich nur "großartig" optimieren, wenn man meinen ersten Code gegen eine Assemblerversion ersetzt, aber da diese eh nur ein einziges Mal bei Programmstart ausgeführt wird und nun doch nicht soooo langsam ist, hatte ich mir das gesparrt. Was optimierenswert wäre, das wär eine binäre Pos-Version, womit man die Suche (IF+Schleife) ersetzen könnte. extra für dich mit CompareMem, aber immernoch mit der kleinen IF ((P + i)^ = SelfCheckData[0]), wär ja blöd, wenn jetzt bei jedem Zeichen die Funktionen aufgerufen würden:
Delphi-Quellcode:
Type MD5_CTX = packed Record
i: Array[0.. 1] of LongWord; buf: Array[0.. 3] of LongWord; input: Array[0..63] of Byte; digest: Array[0..15] of Byte; End; Procedure MD5Init(Var Context: MD5_CTX); StdCall; External 'advapi32.dll' Name 'MD5Init'; Procedure MD5Update(Var Context: MD5_CTX; Input: Pointer; inLen: LongWord); StdCall; External 'advapi32.dll' Name 'MD5Update'; Procedure MD5Final(Var Context: MD5_CTX); StdCall; External 'advapi32.dll' Name 'MD5Final'; Function SelfCheck: Boolean; Const SelfCheckSigLen = 25; SelfCheckData: packed Array[0..44] of AnsiChar = 'S'#0'e'#1'l'#2'f'#3'C'#4'h'#5'e'#5'c'#4'k'#3'D'#2'a'#1't'#0'a' + '>>'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'<<'; Var FileName: WideString; H, Hm: THandle; FileSize, i, i2: Integer; P: PChar; MD5: MD5_CTX; W: Cardinal; Begin Result := False; SetLength(FileName, MAX_PATH); SetLength(FileName, GetModuleFileNameW(0, PWideChar(FileName), MAX_PATH)); H := CreateFileW(PWideChar(FileName), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); FileSize := GetFileSize(H, nil); Hm := CreateFileMapping(H, nil, PAGE_READONLY, 0, 0, nil); P := MapViewOfFile(Hm, FILE_MAP_READ, 0, 0, 0); CloseHandle(H); Try If P = nil Then Exit; For i := 0 to FileSize - Length(SelfCheckData) do If ((P + i)^ = SelfCheckData[0]) and CompareMem(P + i, @SelfCheckData[0], SelfCheckSigLen + 2) and CompareMem(P + i + SelfCheckSigLen + 2 + SizeOf(MD5.digest), @SelfCheckData[SelfCheckSigLen + 2 + SizeOf(MD5.digest)], 2) Then Begin MD5Init(MD5); MD5Update(MD5, P, i); MD5Update(MD5, P + i + Length(SelfCheckData), FileSize - i - Length(SelfCheckData)); MD5Final(MD5); Result := True; For i2 := 0 to High(MD5.digest) do If PByte(P + i + SelfCheckSigLen + 2 + i2)^ <> 0 Then Begin Result := False; Break; End; If Result Then Begin DeleteFileW(PWideChar(FileName + '.old')); MoveFileW(PWideChar(FileName), PWideChar(FileName + '.old')); CopyFileW(PWideChar(FileName + '.old'), PWideChar(FileName), False); H := CreateFileW(PWideChar(FileName), GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0); If Integer(SetFilePointer(H, i + SelfCheckSigLen + 2, nil, FILE_BEGIN)) = i + SelfCheckSigLen + 2 Then WriteFile(H, MD5.digest, SizeOf(MD5.digest), W, nil); CloseHandle(H); //ShellExecuteW(0, 'open', PWideChar(FileName), GetCommandLineW, nil, SW_SHOW); //Halt; Exit; End; Result := True; For i2 := 0 to High(MD5.digest) do If PByte(P + i + SelfCheckSigLen + 2 + i2)^ <> MD5.digest[i2] Then Begin Result := False; Break; End; Exit; End; Finally UnmapViewOfFile(P); CloseHandle(Hm); End; End; If not SelfCheck Then Error...
Zitat:
NonVCL-Freaks können ja die Routine kopieren.
PS: gerade die extrem aufblähende SysUtils hatte ich bei mir ja entfernt
$2B or not $2B
|
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |