Skip to content

Commit 82b71e5

Browse files
committed
Test project to add Beep import to existing exe and create new section calling Beep and going to OEP.
1 parent 5fa7c8a commit 82b71e5

File tree

2 files changed

+746
-0
lines changed

2 files changed

+746
-0
lines changed

Test/test.dpr

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
program test;
2+
3+
{$APPTYPE CONSOLE}
4+
5+
{$R *.res}
6+
7+
uses
8+
Windows,
9+
SysUtils,
10+
PE.Common,
11+
PE.Image,
12+
PE.Imports.Lib,
13+
PE.Imports.Func,
14+
PE.Build,
15+
PE.Section;
16+
17+
const
18+
NORMAL_EXIT_CODE = $C0DE;
19+
SRC_FILENAME = 'test.exe';
20+
DST_FILENAME = 'test.out.exe';
21+
22+
procedure Log(text: string);
23+
begin
24+
WriteLn(Format('[%4x] %s', [GetCurrentProcessId(), text]));
25+
end;
26+
27+
function RunWithParam(exe: string; param: string = ''): boolean;
28+
var
29+
cmdLine: string;
30+
si: TStartupInfo;
31+
pi: TProcessInformation;
32+
code: dword;
33+
begin
34+
cmdLine := param;
35+
36+
ZeroMemory(@si, sizeof(si));
37+
si.cb := sizeof(si);
38+
39+
ZeroMemory(@pi, sizeof(pi));
40+
41+
if (CreateProcess(Pointer(exe), Pointer(cmdLine), nil, nil, false, 0, nil, nil, si, pi)) then
42+
begin
43+
WaitForSingleObject(pi.hProcess, INFINITE);
44+
if (GetExitCodeProcess(pi.hProcess, code)) then
45+
begin
46+
CloseHandle(pi.hThread);
47+
CloseHandle(pi.hProcess);
48+
exit(code = NORMAL_EXIT_CODE);
49+
end;
50+
end;
51+
52+
exit(false);
53+
end;
54+
55+
procedure WritePushDword(img: TPEImage; value: dword);
56+
var
57+
rec: packed record
58+
op: byte;
59+
value: dword;
60+
end;
61+
begin
62+
rec.op := $68;
63+
rec.value := value;
64+
img.Write(rec, sizeof(rec));
65+
end;
66+
67+
function GetIatEntryAddr(img: TPEImage; lib: TPEImportLibrary; fn: TPEImportFunction): NativeUInt;
68+
var
69+
i: integer;
70+
begin
71+
for i := 0 to lib.Functions.Count - 1 do
72+
if (lib.Functions[i] = fn) then
73+
exit(lib.IatRva + i * img.ImageWordSize);
74+
75+
raise Exception.Create('Function not found');
76+
end;
77+
78+
procedure WriteCall(img: TPEImage; lib: TPEImportLibrary; fn: TPEImportFunction);
79+
var
80+
rec: packed record
81+
op1, op2: byte;
82+
addr: NativeUInt;
83+
end;
84+
begin
85+
rec.op1 := $FF;
86+
rec.op2 := $15;
87+
rec.addr := img.RVAToVA(GetIatEntryAddr(img, lib, fn));
88+
img.Write(rec, sizeof(rec));
89+
end;
90+
91+
procedure WriteJmpRel(img: TPEImage; dst: TRVA);
92+
var
93+
rec: packed record
94+
op: byte;
95+
delta: dword;
96+
end;
97+
begin
98+
rec.op := $E9;
99+
rec.delta := dst - (img.PositionRVA + sizeof(rec));
100+
img.Write(rec, sizeof(rec));
101+
end;
102+
103+
procedure TestImportRebuilding();
104+
var
105+
img: TPEImage;
106+
oep: TRVA;
107+
sec: TPESection;
108+
lib: TPEImportLibrary;
109+
fn: TPEImportFunction;
110+
begin
111+
img := TPEImage.Create();
112+
try
113+
if (img.LoadFromFile(SRC_FILENAME)) then
114+
begin
115+
lib := img.Imports.NewLib(kernel32);
116+
fn := lib.NewFunction('Beep');
117+
118+
if (ReBuildDirData(img, DDIR_IMPORT, true) <> nil) then
119+
begin
120+
// Make some code to call beep at new entry point (in new section).
121+
// Then jump to original entry point.
122+
// Without relocations to make it simpler.
123+
oep := img.EntryPointRVA;
124+
sec := img.Sections.AddNew('.my', 32, $60000020, nil);
125+
img.EntryPointRVA := sec.RVA;
126+
127+
img.SeekRVA(sec.RVA);
128+
WritePushDword(img, 1000); // dwDuration
129+
WritePushDword(img, 5000); // dwFreq
130+
WriteCall(img, lib, fn);
131+
WriteJmpRel(img, oep);
132+
133+
// Save to file and try to run.
134+
img.SaveToFile(DST_FILENAME);
135+
136+
if (RunWithParam(DST_FILENAME)) then
137+
begin
138+
Log('Import rebuilt OK');
139+
end
140+
else
141+
begin
142+
Log('Rebuilt image failed');
143+
end;
144+
end
145+
else
146+
begin
147+
Log('Failed to rebuld imports');
148+
end;
149+
end
150+
else
151+
begin
152+
Log('Failed to parse image');
153+
end;
154+
finally
155+
img.Free();
156+
end;
157+
158+
RunWithParam(SRC_FILENAME);
159+
end;
160+
161+
begin
162+
if (ParamStr(1) = 'test') then
163+
begin
164+
Log('Test call');
165+
TestImportRebuilding();
166+
end
167+
else
168+
begin
169+
Log('Normal call');
170+
Halt(NORMAL_EXIT_CODE);
171+
end;
172+
end.

0 commit comments

Comments
 (0)