Skip to content

Commit a9e6273

Browse files
committed
lib: dll delayload/loadwithalteredsearchpath flags were added in v23, add version check for this
tests: add test for v22 script with dll imports. please note bytecode used here came from a malware sample!
1 parent 8108a88 commit a9e6273

File tree

8 files changed

+3278
-14
lines changed

8 files changed

+3278
-14
lines changed

IFPSLib.Tests/CompiledCode_v22.bin

2.59 KB
Binary file not shown.

IFPSLib.Tests/CompiledCode_v22.txt

Lines changed: 3175 additions & 0 deletions
Large diffs are not rendered by default.

IFPSLib.Tests/IFPSLib.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
<ItemGroup>
6060
<None Include="app.config" />
6161
<None Include="CompiledCode.bin" />
62+
<None Include="CompiledCode_v22.bin" />
6263
<None Include="packages.config" />
6364
</ItemGroup>
6465
<ItemGroup>
@@ -81,6 +82,9 @@
8182
<ItemGroup>
8283
<None Include="CompiledCode.txt" />
8384
</ItemGroup>
85+
<ItemGroup>
86+
<None Include="CompiledCode_v22.txt" />
87+
</ItemGroup>
8488
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
8589
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
8690
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

IFPSLib.Tests/Properties/Resources.Designer.cs

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

IFPSLib.Tests/Properties/Resources.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,10 @@
124124
<data name="CompiledCodeDisasm" type="System.Resources.ResXFileRef, System.Windows.Forms">
125125
<value>..\CompiledCode.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
126126
</data>
127+
<data name="CompiledCodeDisasm_v22" type="System.Resources.ResXFileRef, System.Windows.Forms">
128+
<value>..\CompiledCode_v22.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
129+
</data>
130+
<data name="CompiledCode_v22" type="System.Resources.ResXFileRef, System.Windows.Forms">
131+
<value>..\CompiledCode_v22.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
132+
</data>
127133
</root>

IFPSLib.Tests/ScriptTest.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace IFPSLib.Tests
1111
public class ScriptTest
1212
{
1313
private static readonly string origB64 = Convert.ToBase64String(Resources.CompiledCode);
14+
private static readonly string origB64_22 = Convert.ToBase64String(Resources.CompiledCode_v22);
1415

1516
[TestMethod]
1617
public void TestLoadSave()
@@ -44,5 +45,38 @@ public void TestAsm()
4445
var savedB64 = Convert.ToBase64String(script.Save());
4546
Assert.AreEqual(savedB64, origB64);
4647
}
48+
49+
[TestMethod]
50+
public void TestLoadSaveV22()
51+
{
52+
// Load the script.
53+
var script = Script.Load(Resources.CompiledCode_v22);
54+
// Ensure it's not null.
55+
Assert.IsNotNull(script);
56+
// For an official script (compiled by inno setup), the entrypoint is the first function.
57+
Assert.AreEqual(script.EntryPoint, script.Functions[0]);
58+
// Save the script.
59+
var savedBytes = script.Save();
60+
// Convert to base64 for later.
61+
var saved = Convert.ToBase64String(savedBytes);
62+
// Load the saved script.
63+
var scriptSaved = Script.Load(savedBytes);
64+
// Save again.
65+
var savedTwice = Convert.ToBase64String(scriptSaved.Save());
66+
// Ensure both saved scripts equal each other.
67+
Assert.AreEqual(saved, savedTwice);
68+
// Ensure the saved script equals the original.
69+
Assert.AreEqual(saved, origB64_22);
70+
// Ensure the disassemblies are equal.
71+
Assert.AreEqual(script.Disassemble(), scriptSaved.Disassemble());
72+
}
73+
74+
[TestMethod]
75+
public void TestAsmV22()
76+
{
77+
var script = Assembler.Assemble(Resources.CompiledCodeDisasm_v22);
78+
var savedB64 = Convert.ToBase64String(script.Save());
79+
Assert.AreEqual(savedB64, origB64);
80+
}
4781
}
4882
}

IFPSLib/Emit/ExternalFunction.cs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public abstract class Base
2727
protected const string ClassString = "class:";
2828
protected const string ComString = "intf:.";
2929

30-
internal static Base Load(BinaryReader br)
30+
internal static Base Load(BinaryReader br, Script script)
3131
{
3232
var fdeclLen = br.Read<uint>();
3333
using (var fdeclMem = new NativeMemoryArray<byte>(fdeclLen, true))
@@ -39,21 +39,21 @@ internal static Base Load(BinaryReader br)
3939
if (fdeclSpan.EqualsAsciiString(0, DllString))
4040
{
4141
brDecl.BaseStream.Position = DllString.Length;
42-
return DLL.Load(brDecl);
42+
return DLL.Load(brDecl, script);
4343
}
4444
else if (fdeclSpan.EqualsAsciiString(0, ClassString))
4545
{
4646
brDecl.BaseStream.Position = ClassString.Length;
47-
return Class.Load(brDecl);
47+
return Class.Load(brDecl, script);
4848
}
4949
else if (fdeclSpan.EqualsAsciiString(0, ComString))
5050
{
5151
brDecl.BaseStream.Position = ComString.Length;
52-
return COM.Load(brDecl);
52+
return COM.Load(brDecl, script);
5353
}
5454
else
5555
{
56-
return Internal.Load(brDecl);
56+
return Internal.Load(brDecl, script);
5757
}
5858
}
5959
}
@@ -124,14 +124,17 @@ public sealed class DLL : BaseCC
124124

125125
internal override string Name => string.Format("{0}!{1}", DllName, ProcedureName);
126126

127-
internal static new DLL Load(BinaryReader br)
127+
internal static new DLL Load(BinaryReader br, Script script)
128128
{
129129
var ret = new DLL();
130130
ret.DllName = br.ReadAsciiStringTerminated();
131131
ret.ProcedureName = br.ReadAsciiStringTerminated();
132132
ret.CallingConvention = (NativeCallingConvention)br.ReadByte();
133-
ret.DelayLoad = br.ReadByte() != 0;
134-
ret.LoadWithAlteredSearchPath = br.ReadByte() != 0;
133+
if (script.FileVersion >= Script.VERSION_MIN_DLL_LOAD_FLAGS)
134+
{
135+
ret.DelayLoad = br.ReadByte() != 0;
136+
ret.LoadWithAlteredSearchPath = br.ReadByte() != 0;
137+
}
135138

136139
ret.LoadArguments(br);
137140

@@ -164,8 +167,11 @@ internal override void SaveCore(BinaryWriter bw, Script.SaveContext ctx)
164167
bw.WriteAsciiStringTerminated(DllName);
165168
bw.WriteAsciiStringTerminated(ProcedureName);
166169
bw.Write(CallingConvention);
167-
bw.Write<byte>((byte)(DelayLoad ? 1 : 0));
168-
bw.Write<byte>((byte)(LoadWithAlteredSearchPath ? 1 : 0));
170+
if (ctx.FileVersion >= Script.VERSION_MIN_DLL_LOAD_FLAGS)
171+
{
172+
bw.Write<byte>((byte)(DelayLoad ? 1 : 0));
173+
bw.Write<byte>((byte)(LoadWithAlteredSearchPath ? 1 : 0));
174+
}
169175
SaveArguments(bw);
170176
}
171177
}
@@ -181,7 +187,7 @@ public sealed class Class : BaseCC
181187

182188
private const byte TERMINATOR = (byte)'|';
183189

184-
internal static new Class Load(BinaryReader br)
190+
internal static new Class Load(BinaryReader br, Script script)
185191
{
186192
var ret = new Class();
187193

@@ -297,7 +303,7 @@ public sealed class COM : BaseCC
297303

298304
internal override string Name => string.Format("CoInterface->vtbl[{0}]", VTableIndex);
299305

300-
internal static new COM Load(BinaryReader br)
306+
internal static new COM Load(BinaryReader br, Script script)
301307
{
302308
var ret = new COM();
303309
ret.VTableIndex = br.Read<uint>();
@@ -325,7 +331,7 @@ internal override void SaveCore(BinaryWriter bw, Script.SaveContext ctx)
325331

326332
public sealed class Internal : Base
327333
{
328-
internal static new Internal Load(BinaryReader br)
334+
internal static new Internal Load(BinaryReader br, Script script)
329335
{
330336
var ret = new Internal();
331337
ret.LoadArguments(br);
@@ -378,7 +384,7 @@ internal static ExternalFunction Load(BinaryReader br, Script script, bool expor
378384
ret.Name = br.ReadAsciiString(namelen);
379385
if (exported)
380386
{
381-
ret.Declaration = FDecl.Base.Load(br);
387+
ret.Declaration = FDecl.Base.Load(br, script);
382388
if (ret.Declaration.HasReturnArgument) ret.ReturnArgument = UnknownType.Instance;
383389
if (string.IsNullOrEmpty(ret.Name)) ret.Name = ret.Declaration.Name;
384390
}

IFPSLib/Script.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public sealed class Script
2020

2121
internal const int VERSION_MIN_ATTRIBUTES = 21;
2222
internal const int VERSION_MAX_SETSTACKTYPE = 22; // Is this correct?
23+
internal const int VERSION_MIN_DLL_LOAD_FLAGS = 23;
2324
internal const int VERSION_MIN_STATICARRAYSTART = 23;
2425

2526
/// <summary>

0 commit comments

Comments
 (0)