[DUG] DLL memory leaks
Paul Heinz
paul at accredo.co.nz
Mon Aug 8 09:45:59 NZST 2011
Ross wrote:
> I didn't know that was possible. I'll investigate.
PE Explorer is probably one of the best tools for this. It's also
written in Delphi I believe.
You can download a fully functional 30-day trial version.
http://www.heaventools.com/download-pe-explorer.htm
Alternatively, if you want to point me at the DLL, I can have a look at
it's import table for you.
Import Address Table (or IAT) patching is a pretty standard albeit
'low-level' technique.
If you look for sample code around the web, it's often more involved
that it needs to be since it's often written in the context of injecting
DLLs into other processes you don't control to patch their main import
table.
Since you'll be patching the import table of a DLL you've loaded into
your own process, it's much simpler.
Here's the routine I use. It's using HInstance rather than the module
handle for a loaded DLL since I used for patching the main executable's
import table. You'll want to pass the module handle of your DLL by
calling GetModuleHandle. It returns the current IAT entry so you can
easily forward chain.
There's a whole bunch of stanard PE table record type definitions this
code depends on which I've left out.
function InstallWin32Hook(const ModuleName, FuncName: string; HookFunc:
Pointer): Pointer;
var
NTHeader: PImageNTHeaders;
ImportDesc: PImageImportDescriptor;
Thunk: PImageThunkData;
begin
Result := GetProcAddress(GetModuleHandle(PChar(ModuleName)),
PChar(FuncName));
if Result <> nil then
begin
NTHeader := PImageNTHeaders(DWord(HInstance) +
PImageDosHeader(HInstance).e_lfanew);
ImportDesc := PImageImportDescriptor(DWord(HInstance) +
NTHeader.OptionalHeader.DataDirectory[ImageDirectoryEntryImport].Virtual
Address);
while ImportDesc.Name <> 0 do begin
if StriComp(PAnsiChar(DWord(HInstance) + ImportDesc.Name),
PAnsiChar(AnsiString(ModuleName))) = 0 then
begin
Thunk := PImageThunkData(DWord(HInstance) +
DWord(ImportDesc.FirstThunk));
while Thunk.Funct <> nil do begin
if Thunk.Funct = Result then
Thunk.Funct := HookFunc;
Inc(Thunk)
end
end;
Inc(ImportDesc)
end
end
end;
And here's how its used with a sample shim:
var
OldRaiseException: procedure (dwExceptionCode, dwExceptionFlags,
nNumberOfArguments: DWord;
const lpArguments: DWord); stdcall;
OldRaiseException := InstallWin32Hook(Kernel32, 'RaiseException',
@HookRaiseException);
procedure HookRaiseException(dwExceptionCode, dwExceptionFlags,
nNumberOfArguments: DWord;
const lpArguments: DWord); stdcall;
begin
{
If this is a real Delphi exception and has the arguments as we
expect from
System._RaiseExcept then we can crack the argument structure and
determine
if we need to take a stack trace. Note that this may change from
version to
version of Delphi.
}
if (dwExceptionCode = cDelphiException) and (lpArguments <> 0) and
(nNumberOfArguments = 7) and
not InHookRaise then
with PDelphiExceptionArguments(lpArguments)^ do
try
InHookRaise := True;
if not IgnoreException(ExceptObject) then
HookStackTrace(ExceptAddress, EBP, ESP, False);
finally
InHookRaise := False;
end;
if Assigned(OldRaiseException) then
OldRaiseException(dwExceptionCode, dwExceptionFlags,
nNumberOfArguments, lpArguments);
end;
Cheers,
Paul.
More information about the Delphi
mailing list