-
Notifications
You must be signed in to change notification settings - Fork 45
/
MemoryModuleHook.pas
171 lines (141 loc) · 4.43 KB
/
MemoryModuleHook.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Unit that hooks LoadLibrary, GetProcAddress, FreeLibrary for MemoryModule
// to allow transparent DLL loading.
unit MemoryModuleHook;
interface
uses
Windows,
MemoryModule, FuncHook;
type
// Callback function that is called from LoadLibraryHook to determine
// an address of library data.
// lpLibFileName: name of library to load
// Returns:
// Pointer to library data; nil to bypass MemoryModule and use WinAPI
TGetLibPtrProc = function (lpLibFileName: PWideChar): Pointer;
function InstallHook(AGetLibPtrCallback: TGetLibPtrProc): Boolean;
function UninstallHook: Boolean;
implementation
var
HookInstalled: Boolean = False;
GetLibPtrCallback: TGetLibPtrProc;
LoadedModules: array of HMODULE;
CS: RTL_CRITICAL_SECTION;
LoadLibrary_Old: function (lpLibFileName: PWideChar): HMODULE; stdcall;
GetProcAddress_Old: function (hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
FreeLibrary_Old: function (hLibModule: HMODULE): BOOL; stdcall;
HI_LL, HI_GPA, HI_FL: THookInfo;
function IndexOfLoadedModule(hModule: HMODULE): Integer;
var i: Integer;
begin
EnterCriticalSection(CS);
try
for i := Low(LoadedModules) to High(LoadedModules) do
if LoadedModules[i] = hModule then
Exit(i);
Result := -1;
finally
LeaveCriticalSection(CS);
end;
end;
// Try to get library address and load it, run WinAPI routine otherwise.
function LoadLibraryHook(lpLibFileName: PWideChar): HMODULE; stdcall;
var
LibPtr: Pointer;
begin
Result := 0;
LibPtr := GetLibPtrCallback(lpLibFileName);
if LibPtr = nil then
begin
LoadLibrary_Old(lpLibFileName);
Exit;
end;
Result := HMODULE(MemoryLoadLibary(LibPtr));
if Result <> 0 then
try
EnterCriticalSection(CS);
SetLength(LoadedModules, Length(LoadedModules) + 1);
LoadedModules[Length(LoadedModules) - 1] := Result;
finally
LeaveCriticalSection(CS);
end;
end;
// If hModule was loaded via MM, run MM's routine. Otherwise, run WinAPI one.
function GetProcAddressHook(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
begin
if IndexOfLoadedModule(hModule) <> -1 then
Result := FARPROC(MemoryGetProcAddress(TMemoryModule(hModule), lpProcName))
else
Result := GetProcAddress_Old(hModule, lpProcName);
end;
// If hLibModule was loaded via MM, run MM's routine. Otherwise, run WinAPI one.
function FreeLibraryHook(hLibModule: HMODULE): BOOL; stdcall;
var idx: Integer;
begin
idx := IndexOfLoadedModule(hLibModule);
if idx <> -1 then
begin
MemoryFreeLibrary(TMemoryModule(hLibModule));
Result := BOOL(True);
// Remove from the list
try
EnterCriticalSection(CS);
LoadedModules[idx] := 0;
if idx < Length(LoadedModules) - 1 then
Move(LoadedModules[idx + 1], LoadedModules[idx], (Length(LoadedModules) - idx + 1)*SizeOf(HMODULE));
SetLength(LoadedModules, Length(LoadedModules) - 1);
finally
LeaveCriticalSection(CS);
end;
end
else
Result := FreeLibrary_Old(hLibModule);
end;
function InstallHook(AGetLibPtrCallback: TGetLibPtrProc): Boolean;
begin
Result := False;
if not Assigned(AGetLibPtrCallback) then Exit;
EnterCriticalSection(CS);
try
if HookInstalled then Exit;
if not HookProcedure(False, HI_LL) or
not HookProcedure(False, HI_GPA) or
not HookProcedure(False, HI_FL) then Exit;
LoadLibrary_Old := HI_LL.OrigProc;
GetProcAddress_Old := HI_GPA.OrigProc;
FreeLibrary_Old := HI_FL.OrigProc;
HookInstalled := True;
GetLibPtrCallback := AGetLibPtrCallback;
Result := True;
finally
if not Result then
UninstallHook;
LeaveCriticalSection(CS);
end;
end;
function UninstallHook: Boolean;
begin
Result := False;
EnterCriticalSection(CS);
try
if not HookInstalled then Exit;
while Length(LoadedModules) > 0 do
FreeLibrary(LoadedModules[0]);
Result :=
UnhookProcedure(HI_LL) and
UnhookProcedure(HI_GPA) and
UnhookProcedure(HI_FL);
GetLibPtrCallback := nil;
HookInstalled := False;
finally
LeaveCriticalSection(CS);
end;
end;
initialization
InitializeCriticalSection(CS);
HI_LL.Init(@LoadLibrary, @LoadLibraryHook);
HI_GPA.Init(@GetProcAddress, @GetProcAddressHook);
HI_FL.Init(@FreeLibrary, @FreeLibraryHook);
finalization
UninstallHook;
DeleteCriticalSection(CS);
end.