-
Notifications
You must be signed in to change notification settings - Fork 87
/
Copy pathAntiDumpFix.pas
119 lines (98 loc) · 3.71 KB
/
AntiDumpFix.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
unit AntiDumpFix;
interface
uses Windows, Utils;
type
// This fixes only one type of anti dump, and it's not guaranteed that it'll be the type used for the OEP.
// If your binary uses virtualization in other parts of the program, it will very likely crash.
// Other anti dump types check various fields in the PE header of kernel32.dll. Dumps won't run
// on other systems/after rebooting because the DLL base will have changed.
TAntiDumpFixer = class
private
FhProcess: THandle;
FImageBase: NativeUInt;
function RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
public
constructor Create(hProcess: THandle; AImageBase: NativeUInt);
procedure RedirectOEP(OEP, IAT: NativeUInt);
end;
implementation
{ TAntiDumpFixer }
constructor TAntiDumpFixer.Create(hProcess: THandle; AImageBase: NativeUInt);
begin
FhProcess := hProcess;
FImageBase := AImageBase;
end;
function TAntiDumpFixer.RPM(Address: NativeUInt; Buf: Pointer; BufSize: NativeUInt): Boolean;
begin
Result := ReadProcessMemory(FhProcess, Pointer(Address), Buf, BufSize, BufSize);
end;
procedure TAntiDumpFixer.RedirectOEP(OEP, IAT: NativeUInt);
const
PUSH_ARGS_RW_PROTECT: array[0..14] of Byte = ($6A, $00, $54, $6A, $04, $68, $00, $04, $00, $00, $68, $00, $00, $40, $00);
PUSH_ARGS_OLD_PROTECT: array[0..14] of Byte = ($54, $FF, $74, $24, $04, $68, $00, $04, $00, $00, $68, $00, $00, $40, $00);
var
Displ: UInt32;
NewCode: packed record
PushArgs1: array[0..High(PUSH_ARGS_RW_PROTECT)] of Byte;
CallInstr1: UInt16;
VirtualProtectAddr1: UInt32;
MovInstr: UInt16;
OptHdrEntrypoint: UInt32;
Entrypoint: UInt32;
PushArgs2: array[0..High(PUSH_ARGS_OLD_PROTECT)] of Byte;
CallInstr2: UInt16;
VirtualProtectAddr2: UInt32;
PopStack: Byte;
JmpInstr: Byte;
JmpDispl: UInt32;
end;
LfaNew: UInt32;
VProtectAddr: NativeUInt;
VProtectIAT, i: UInt32;
IATData: array[0..511] of NativeUInt;
begin
RPM(OEP + 1, @Displ, 4);
VProtectAddr := NativeUInt(GetProcAddress(GetModuleHandle(kernel32), 'VirtualProtect'));
VProtectIAT := 0;
RPM(IAT, @IATData, SizeOf(IATData));
for i := 0 to High(IATData) do
if IATData[i] = VProtectAddr then
begin
VProtectIAT := IAT + i * 4;
Break;
end;
if VProtectIAT = 0 then
begin
Log(ltFatal, 'VirtualProtect not found in IAT');
Exit;
end;
// VirtualProtect($400000, $400, PAGE_READWRITE, OldProtect)
Move(PUSH_ARGS_RW_PROTECT, NewCode.PushArgs1, Length(NewCode.PushArgs1));
NewCode.CallInstr1 := $15FF;
NewCode.VirtualProtectAddr1 := VProtectIAT;
// mov dword ptr [AddressOfEntryPoint], ThemidaEntrypoint
NewCode.MovInstr := $05C7;
if not RPM(FImageBase + $3C, @LfaNew, 4) or not RPM(FImageBase + LfaNew + $28, @NewCode.Entrypoint, 4) then
begin
Log(ltFatal, 'ReadProcessMemory failed');
Exit;
end;
NewCode.OptHdrEntrypoint := FImageBase + LfaNew + $28;
// VirtualProtect($400000, $400, OldProtect, _)
Move(PUSH_ARGS_OLD_PROTECT, NewCode.PushArgs2, Length(NewCode.PushArgs2));
NewCode.CallInstr2 := $15FF;
NewCode.VirtualProtectAddr2 := VProtectIAT;
// pop eax (undo initial "push 0" for OldProtect)
NewCode.PopStack := $58;
// jmp vm
NewCode.JmpInstr := $E9;
NewCode.JmpDispl := Displ - (SizeOf(NewCode) - 5);
if WriteProcessMemory(FhProcess, Pointer(OEP), @NewCode, SizeOf(NewCode), NativeUInt(nil^)) then
begin
Log(ltGood, 'Installed VM anti-dump mitigation at OEP');
Log(ltInfo, 'NOTE: We assume there is enough space at the entrypoint, which may not be the case in every binary.');
end
else
Log(ltFatal, 'WriteProcessMemory failed');
end;
end.