-
Notifications
You must be signed in to change notification settings - Fork 35
/
NtUtils.ImageHlp.DbgHelp.pas
155 lines (124 loc) · 3.48 KB
/
NtUtils.ImageHlp.DbgHelp.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
unit NtUtils.ImageHlp.DbgHelp;
{
This module provides lightweight functionality for working with debug symbols
directly exported by executable images. For PDB symbols, use
NtUtils.DbgHelp instead.
}
interface
uses
NtUtils, NtUtils.Ldr, NtUtils.Files, DelphiApi.Reflection;
type
TImageHlpSymbol = record
[Hex] RVA: Cardinal;
Name: String;
end;
TRtlxBestMatchSymbol = record
Module: TLdrxModuleInfo;
Symbol: TImageHlpSymbol;
[Hex] Offset: Cardinal;
function ToString: String;
end;
// Lookup all exported symbols in a module
function RtlxEnumSymbols(
out Symbols: TArray<TImageHlpSymbol>;
const Image: TMemory;
MappedAsImage: Boolean;
RangeChecks: Boolean = True
): TNtxStatus;
// Lookup all exported symbols in a file
function RtlxEnumSymbolsFile(
out Symbols: TArray<TImageHlpSymbol>;
const FileParameters: IFileParameters
): TNtxStatus;
// Find a nearest symbol in a module
function RtlxFindBestMatchModule(
const Module: TLdrxModuleInfo;
const Symbols: TArray<TImageHlpSymbol>;
RVA: Cardinal
): TRtlxBestMatchSymbol;
implementation
uses
NtUtils.SysUtils, NtUtils.ImageHlp, NtUtils.Sections, DelphiUtils.Arrays;
{$BOOLEVAL OFF}
{$IFOPT R+}{$DEFINE R+}{$ENDIF}
{$IFOPT Q+}{$DEFINE Q+}{$ENDIF}
function TRtlxBestMatchSymbol.ToString;
begin
Result := Module.BaseDllName;
if Symbol.Name <> '' then
Result := Result + '!' + Symbol.Name;
if Offset <> 0 then
begin
if Result <> '' then
Result := Result + '+';
Result := Result + RtlxUInt64ToStr(Offset, nsHexadecimal);
end;
end;
function RtlxEnumSymbols;
var
ExportEntries: TArray<TExportEntry>;
begin
Result := RtlxEnumerateExportImage(ExportEntries, Image, MappedAsImage,
RangeChecks);
if not Result.IsSuccess then
Exit;
// Capture all non-forwarder exports
Symbols := TArray.Convert<TExportEntry, TImageHlpSymbol>(ExportEntries,
function (const Entry: TExportEntry; out Symbol: TImageHlpSymbol): Boolean
begin
Result := not Entry.Forwards;
if not Result then
Exit;
Symbol.RVA := Entry.VirtualAddress;
if Entry.Name <> '' then
Symbol.Name := String(Entry.Name)
else
Symbol.Name := 'Ordinal#' + RtlxUIntToStr(Entry.Ordinal);
end
);
// Sort them to allow binary search
TArray.SortInline<TImageHlpSymbol>(Symbols,
function (const A, B: TImageHlpSymbol): Integer
begin
{$Q-}{$R-}
Cardinal(Result) := A.RVA - B.RVA;
{$IFDEF R+}{$R+}{$ENDIF}{$IFDEF Q+}{$Q+}{$ENDIF}
end
);
end;
function RtlxEnumSymbolsFile;
var
MappedFile: IMemory;
begin
Result := RtlxMapFileByName(FileParameters, NtxCurrentProcess, MappedFile);
if not Result.IsSuccess then
Exit;
Result := RtlxEnumSymbols(Symbols, MappedFile.Region, False);
end;
function RtlxFindBestMatchModule;
var
BestMatch: Integer;
begin
// We expect the symbols to be sorted
BestMatch := TArray.BinarySearchEx<TImageHlpSymbol>(Symbols,
function (const Entry: TImageHlpSymbol): Integer
begin
{$Q-}{$R-}
Cardinal(Result) := Entry.RVA - RVA;
{$IFDEF R+}{$R+}{$ENDIF}{$IFDEF Q+}{$Q+}{$ENDIF}
end
);
if BestMatch = -1 then
begin
// Make a pseudo-symbol for the entire module
Result.Symbol.RVA := 0;
Result.Symbol.Name := '';
end
else if BestMatch >= 0 then
Result.Symbol := Symbols[BestMatch] // Exact match
else
Result.Symbol := Symbols[-(BestMatch + 2)]; // Nearest symbol below
Result.Module := Module;
Result.Offset := RVA - Result.Symbol.RVA;
end;
end.