Skip to content

Commit 79359b6

Browse files
author
vdisasmdev
committed
* Some resource code refactoring
+ MakeIntResource * Units for special resource parsing, like PE.Resources.Windows.Bitmap should parse from given stream position. Position must be properly initialized before parsing. + PE.Resources.Windows.Strings unit (to parse RT_STRING/string bundles) + [temp] can be moved to other units later: + PeGetFileVersionInfo (analogue to Windows GetFileVersionInfo) + PeVerQueryValueFixed (analogue to Windows VerQueryValue for fixed ver. info.)
1 parent c925c61 commit 79359b6

8 files changed

+352
-59
lines changed

PE.ExecutableLoader.pas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ function TExecutableModule.LoadImports: TMapStatus;
342342
end;
343343

344344
// Patch.
345-
va := FInstance + rva;
345+
va := FInstance + RVA;
346346
if FPE.Is32bit then
347347
PUINT(va)^ := UInt32(proc)
348348
else if FPE.Is64bit then
@@ -351,7 +351,7 @@ function TExecutableModule.LoadImports: TMapStatus;
351351
inc(RVA, FPE.ImageWordSize);
352352
end;
353353

354-
inc(RVA, FPE.ImageWordSize); // null
354+
// inc(RVA, FPE.ImageWordSize); // null
355355
end;
356356
Result := msOK;
357357
end;

PE.Image.x86.pas

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface
99

1010
uses
1111
System.Generics.Collections,
12+
System.SysUtils,
1213
PE.Common,
1314
PE.Image,
1415
PE.Section;

PE.Resources.VersionInfo.pas

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,9 @@ interface
1414
PE.Common,
1515
PE.Utils;
1616

17-
type
18-
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx
19-
VS_FIXEDFILEINFO = packed record
20-
dwSignature: uint32; // 0xFEEF04BD
21-
dwStrucVersion: uint32;
22-
dwFileVersionMS: uint32;
23-
dwFileVersionLS: uint32;
24-
dwProductVersionMS: uint32;
25-
dwProductVersionLS: uint32;
26-
dwFileFlagsMask: uint32;
27-
dwFileFlags: uint32; // VS_FF...
28-
dwFileOS: uint32;
29-
dwFileType: uint32;
30-
dwFileSubtype: uint32;
31-
dwFileDateMS: uint32;
32-
dwFileDateLS: uint32;
33-
end;
17+
{$i 'VerRsrc.inc'}
3418

19+
type
3520
TBlock = class;
3621
TBlockList = TObjectList<TBlock>;
3722
TBlockClass = class of TBlock;
@@ -102,37 +87,6 @@ TPEVersionInfo = class
10287

10388
implementation
10489

105-
const
106-
SIG_VS_FIXEDFILEINFO = $FEEF04BD;
107-
108-
// dwFileFlags
109-
VS_FF_DEBUG = $1;
110-
VS_FF_PRERELEASE = $2;
111-
VS_FF_PATCHED = $4;
112-
VS_FF_PRIVATEBUILD = $8;
113-
VS_FF_INFOINFERRED = $10;
114-
VS_FF_SPECIALBUILD = $20;
115-
116-
// dwFileOS
117-
VOS_UNKNOWN = $00000000;
118-
VOS__WINDOWS16 = $00000001;
119-
VOS__PM16 = $00000002;
120-
VOS__PM32 = $00000003;
121-
VOS__WINDOWS32 = $00000004;
122-
VOS_DOS = $00010000;
123-
VOS_OS216 = $00020000;
124-
VOS_OS232 = $00030000;
125-
VOS_NT = $00040000;
126-
127-
// dwFileType
128-
VFT_UNKNOWN = $00000000;
129-
VFT_APP = $00000001;
130-
VFT_DLL = $00000002;
131-
VFT_DRV = $00000003;
132-
VFT_FONT = $00000004;
133-
VFT_VXD = $00000005;
134-
VFT_STATIC_LIB = $00000007;
135-
13690
type
13791
TVersionInfoBlockHeader = packed record
13892
Length: uint16; // block length w/o padding

PE.Resources.Windows.Bitmap.pas

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ function ParseBitmapResource(const Stream: TStream): TStream;
4444
BmpHdr: TBitmapFileHeader;
4545
InfoHdr: TBitmapInfoHeader;
4646
begin
47-
Stream.Position := 0;
4847
if not StreamRead(Stream, InfoHdr, SizeOf(InfoHdr)) then
4948
raise Exception.Create('Stream too small.');
5049

PE.Resources.Windows.Strings.pas

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
unit PE.Resources.Windows.Strings;
2+
3+
interface
4+
5+
uses
6+
System.Classes,
7+
System.SysUtils;
8+
9+
type
10+
TStringBundleID = uint32;
11+
12+
TResourceStringBundle = class
13+
public
14+
id: TStringBundleID;
15+
Strings: TStringList;
16+
17+
function GetStringId(stringNumber: cardinal): cardinal;
18+
19+
constructor Create(id: TStringBundleID);
20+
destructor Destroy; override;
21+
22+
procedure LoadFromStream(Stream: TStream);
23+
end;
24+
25+
function BundleToStringId(bundleID: TStringBundleID): cardinal; inline;
26+
27+
// Parse string bundle.
28+
function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle;
29+
30+
implementation
31+
32+
{
33+
see
34+
https://msdn.microsoft.com/en-us/library/windows/desktop/aa381050
35+
http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx
36+
}
37+
38+
// Bundle id to first string id in block of 16 strings.
39+
function BundleToStringId(bundleID: TStringBundleID): cardinal;
40+
begin
41+
if bundleID < 1 then
42+
raise Exception.Create('Wrong bundle id.');
43+
result := (bundleID - 1) * 16;
44+
end;
45+
46+
{ TResourceStringBundle }
47+
48+
constructor TResourceStringBundle.Create(id: TStringBundleID);
49+
begin
50+
self.id := id;
51+
self.Strings := TStringList.Create;
52+
self.Strings.Capacity := 16;
53+
end;
54+
55+
destructor TResourceStringBundle.Destroy;
56+
begin
57+
Strings.Free;
58+
inherited;
59+
end;
60+
61+
function TResourceStringBundle.GetStringId(stringNumber: cardinal): cardinal;
62+
begin
63+
result := BundleToStringId(id) + stringNumber;
64+
end;
65+
66+
procedure TResourceStringBundle.LoadFromStream(Stream: TStream);
67+
var
68+
dwLen: uint16;
69+
allocLen: integer;
70+
bytes: TBytes;
71+
str: string;
72+
begin
73+
self.Strings.Clear;
74+
75+
while Stream.Position < Stream.Size do
76+
begin
77+
if Stream.Read(dwLen, 2) <> 2 then
78+
raise Exception.Create('Failed to read string length.');
79+
80+
if dwLen = 0 then
81+
begin
82+
continue;
83+
end;
84+
85+
dwLen := dwLen * 2; // 2 bytes per char
86+
87+
if length(bytes) < dwLen then
88+
begin
89+
allocLen := ((dwLen + 128) div 128) * 128;
90+
setlength(bytes, allocLen);
91+
end;
92+
93+
if Stream.Read(bytes, dwLen) <> dwLen then
94+
raise Exception.Create('String read error.');
95+
96+
str := TEncoding.Unicode.GetString(bytes, 0, dwLen);
97+
98+
Strings.Add(str);
99+
end;
100+
end;
101+
102+
function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle;
103+
begin
104+
result := TResourceStringBundle.Create(bundleID);
105+
try
106+
result.LoadFromStream(Stream);
107+
except
108+
result.Free;
109+
result := nil;
110+
end;
111+
end;
112+
113+
end.

PE.Resources.Windows.pas

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ interface
1313
uses
1414
System.Classes,
1515
PE.Image,
16-
PE.Resources;
16+
PE.Resources,
17+
PE.Resources.VersionInfo;
1718

1819
{ Values for Windows PE. }
1920

@@ -77,8 +78,7 @@ interface
7778
type
7879
TWindowsResourceTree = class
7980
private
80-
function FindResourceInternal(lpType, lpName: PChar; Language: word;
81-
Depth: cardinal): TResourceTreeNode;
81+
function FindResourceInternal(lpType, lpName: PChar; Language: word; Depth: cardinal): TResourceTreeNode;
8282
protected
8383
FResourceTree: TResourceTree;
8484
public
@@ -101,8 +101,16 @@ TWindowsResourceTree = class
101101
function RemoveResource(lpType, lpName: PChar; Language: word): Boolean;
102102
end;
103103

104-
function IsIntResource(lpszType: PChar): Boolean;
105-
function GetIntResource(lpszType: PChar): word;
104+
function IsIntResource(lpszType: PChar): Boolean; inline;
105+
function GetIntResource(lpszType: PChar): word; inline;
106+
function MakeIntResource(wInteger: uint16): PChar; inline;
107+
108+
// See Windows GetFileVersionInfo function.
109+
// Find RT_VERSION raw data or nil if failed.
110+
// Don't Free returned stream because it's part of ResourceTree.
111+
function PeGetFileVersionInfo(img: TPEImage): TMemoryStream;
112+
113+
function PeVerQueryValueFixed(stream: TStream; out value: VS_FIXEDFILEINFO): Boolean;
106114

107115
implementation
108116

@@ -119,6 +127,11 @@ function GetIntResource(lpszType: PChar): word; // inline;
119127
Result := NativeUInt(lpszType) and $FFFF;
120128
end;
121129

130+
function MakeIntResource(wInteger: uint16): PChar;
131+
begin
132+
Result := PChar(wInteger);
133+
end;
134+
122135
constructor TWindowsResourceTree.Create(ResourceTree: TResourceTree);
123136
begin
124137
FResourceTree := ResourceTree;
@@ -241,4 +254,54 @@ procedure TWindowsResourceTree.UpdateResource(lpType, lpName: PChar;
241254
nLang.UpdateData(lpData, cbData);
242255
end;
243256

257+
function PeGetFileVersionInfo(img: TPEImage): TMemoryStream;
258+
var
259+
rt: TWindowsResourceTree;
260+
versionBranch: TResourceTreeBranchNode;
261+
versionLeaf: TResourceTreeLeafNode;
262+
begin
263+
rt := TWindowsResourceTree.Create(img.ResourceTree);
264+
try
265+
versionBranch := rt.FindResource(MakeIntResource(RT_VERSION));
266+
if assigned(versionBranch) and versionBranch.IsBranch and (versionBranch.Children.Count > 0) then
267+
begin
268+
versionBranch := TResourceTreeBranchNode(versionBranch.Children.First.K);
269+
if assigned(versionBranch) and versionBranch.IsBranch and (versionBranch.Children.Count > 0) then
270+
begin
271+
versionLeaf := TResourceTreeLeafNode(versionBranch.Children.First.K);
272+
if assigned(versionLeaf) and versionLeaf.IsLeaf then
273+
begin
274+
exit(versionLeaf.Data);
275+
end;
276+
end;
277+
end;
278+
exit(nil);
279+
finally
280+
rt.Free;
281+
end;
282+
end;
283+
284+
function PeVerQueryValueFixed(stream: TStream; out value: VS_FIXEDFILEINFO): Boolean;
285+
var
286+
verInfo: TPEVersionInfo;
287+
block: TBlock;
288+
begin
289+
verInfo := TPEVersionInfo.Create;
290+
try
291+
verInfo.LoadFromStream(stream);
292+
293+
if assigned(verInfo.Root) then
294+
for block in verInfo.Root.Children do
295+
if block.ClassType = TBlockVersionInfo then
296+
begin
297+
value := TBlockVersionInfo(block).FixedInfo;
298+
exit(True);
299+
end;
300+
301+
exit(False);
302+
finally
303+
verInfo.Free;
304+
end;
305+
end;
306+
244307
end.

PE.Utils.pas

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function StreamWriteStringA(AStream: TStream; const S: string; AlignAfter: integ
3131
const
3232
PATTERN_PADDINGX: array [0 .. 7] of AnsiChar = ('P', 'A', 'D', 'D', 'I', 'N', 'G', 'X');
3333

34-
// Write pattern to stream. If Pattern is nil or size of patter is 0 then
35-
// nulls are written (default).
34+
// Write pattern to stream. If Pattern is nil or size of patter is 0 then
35+
// nulls are written (default).
3636
procedure WritePattern(AStream: TStream; Count: uint32; Pattern: Pointer = nil; PatternSize: integer = 0);
3737

3838
function StreamSeek(AStream: TStream; Offset: TFileOffset): boolean; inline;
@@ -54,6 +54,8 @@ function IsStringASCII(const S: String): boolean;
5454

5555
function CompareRVA(A, B: TRVA): integer; inline;
5656

57+
function ReplaceSpecialSymobls(const source: string): string;
58+
5759
implementation
5860

5961
{ Stream }
@@ -237,7 +239,7 @@ function AlignDown(Value: uint64; Align: uint32): uint64;
237239

238240
function IsStringASCII(const S: String): boolean;
239241
var
240-
c: char;
242+
c: Char;
241243
begin
242244
for c in S do
243245
if not(integer(c) in [32 .. 126]) then
@@ -255,4 +257,11 @@ function CompareRVA(A, B: TRVA): integer;
255257
exit(0);
256258
end;
257259

260+
function ReplaceSpecialSymobls(const source: string): string;
261+
begin
262+
Result := source.
263+
Replace(#10, '\n').
264+
Replace(#13, '\r');
265+
end;
266+
258267
end.

0 commit comments

Comments
 (0)