Compare commits

..

145 Commits
1.5.1 ... 1.7.0

Author SHA1 Message Date
Matt Nadareski
93e450c2bf Update README for IS-Z 2021-07-21 14:21:39 -07:00
Matt Nadareski
cc762754c5 Add support of IS-Z archives 2021-07-21 13:40:32 -07:00
Matt Nadareski
7065436033 Update nuget packages 2021-07-21 13:33:52 -07:00
Matt Nadareski
debe091502 Update protection list 2021-07-19 23:02:04 -07:00
Matt Nadareski
80905b56cd Better attempt at narrowing down 2021-07-19 21:56:31 -07:00
Matt Nadareski
0a7cd8a69e Comment out broader UPX (NOS) check 2021-07-19 21:38:19 -07:00
Matt Nadareski
c3957977a2 Reorder StarForce 3-5 checks for accuracy 2021-07-18 21:56:15 -07:00
Matt Nadareski
ff602c77ed Improve GFWL support
Adds support for the previously-undetected Games for Windows LIVE - Zero Day Piracy Protection Module as well as adding a generic check for any other modules
2021-07-18 21:50:58 -07:00
Matt Nadareski
3667a5b57a Concurrent protection scans per file (#52)
* Move to ConcurrentDictionary

* Convert to ConcurrentQueue
2021-07-18 09:44:23 -07:00
Matt Nadareski
3ac57b1c0c Fix static matcher issues (fixes #51)
Note: This may result in slower, but more accurate, scans
2021-07-17 23:40:16 -07:00
Matt Nadareski
957d82b2f7 Add new SecuROM PA detection 2021-07-17 23:06:11 -07:00
Matt Nadareski
6d0817ad15 Path protections separator-agnostic (fixes #47) 2021-07-17 22:31:29 -07:00
Matt Nadareski
5b10e6d614 Add check note for Tivola 2021-07-17 21:54:47 -07:00
Matt Nadareski
2d39b8c532 Add more GFWL checks 2021-07-17 21:45:37 -07:00
Matt Nadareski
2ae860e8ca Add Tivola Ring Protection detection (fixes #45) 2021-07-17 21:17:45 -07:00
Matt Nadareski
9e21c28e52 Temporary fix for StarForce directory scan 2021-07-17 21:11:38 -07:00
Matt Nadareski
2f5053b49f Make StarForce checks AND not OR (fixes #46) 2021-07-17 17:08:15 -07:00
Matt Nadareski
7024136919 Make large file parsing safer (fixes #44) 2021-07-15 09:57:06 -07:00
SilasLaspada
c74b5b3d29 Improve Bitpool detection (#43)
* Improve Bitpool detection

* Address comments
2021-07-02 10:16:06 -07:00
SilasLaspada
9c3201aa4b Improve XCP detection to prevent false positives (#42)
* Improve XCP detection to prevent false positives

* Address comments
2021-07-01 20:51:40 -07:00
SilasLaspada
dfd1141635 Vastly improve WTM detection (#41)
* Fix false positive in WTM detection

* Forgot to improve part of the detection

* Vastly improve detection
2021-06-30 09:36:02 -07:00
SilasLaspada
1188cad5e6 Slightly improve PE Compact version detection (#40)
* Slightly improve PE Compact version detection

* Address comments

* Address comments
2021-06-24 11:58:38 -07:00
SilasLaspada
65fa2f8481 Greatly improve WinZip SFX version detection (#39) 2021-06-21 21:48:25 -07:00
SilasLaspada
475e0b9d91 Add support for detecting Installer VISE (#38)
* Add support for detecting Installer VISE

* Add comment about extraction
2021-06-05 15:08:10 -07:00
SilasLaspada
b76d09aa20 Improve Inno Setup detection (#37)
* Improve Inno Setup detection

* Split "GetVersion"

* Remove unneeded check

* Make version detection more robust

* Add Unicode version detection

* Address review comments
2021-06-05 11:46:04 -07:00
Matt Nadareski
9a931eae67 Bump version 2021-04-14 09:09:48 -07:00
Matt Nadareski
47caa714c4 Remove pause from Valve entirely 2021-04-14 09:08:36 -07:00
Matt Nadareski
6740011c11 Bump version to 1.6.0 2021-04-09 09:32:12 -07:00
SilasLaspada
732078f24d Improve Steam detection (#35)
* Improve Steam detection

* Alphabetize the order of detections
2021-04-03 21:25:22 -07:00
Matt Nadareski
5218aaaeb1 Remove all uses of Pause in Valve 2021-04-03 20:49:53 -07:00
Matt Nadareski
6b9df94613 Remove unused library from README 2021-04-02 16:02:39 -07:00
Matt Nadareski
b1ac88fc20 Use submodule for WixToolset.Dtf 2021-04-02 16:01:23 -07:00
Matt Nadareski
ca83019a58 Move wix mirror to backup 2021-04-02 15:51:46 -07:00
Matt Nadareski
d68272a5bb Use submodule for stormlibsharp
This also gets CascLibSharp for free. Maybe keep that in mind
2021-04-02 15:48:57 -07:00
Matt Nadareski
6ab0fd5e3b Move StormLibSharp mirror to backup 2021-04-02 15:38:59 -07:00
Matt Nadareski
a0034b8fa8 Use submodule for hllib 2021-04-02 15:34:47 -07:00
Matt Nadareski
a884737242 Move HLLib mirror to backup 2021-04-02 15:19:00 -07:00
Matt Nadareski
c7b3776386 Use submodule for libmspack4n 2021-04-02 15:17:26 -07:00
Matt Nadareski
b387c77179 Move libmspack4n mirror to backup 2021-04-02 15:09:56 -07:00
Matt Nadareski
f6b58223de Replace LessIO code mirror with submodule 2021-04-02 15:08:05 -07:00
Matt Nadareski
8960ad3b16 Backup current LessIO code mirror 2021-04-02 14:54:46 -07:00
Matt Nadareski
28e95f9eb7 Slight SolidShield cleanup 2021-04-01 15:00:22 -07:00
Matt Nadareski
0bf5065cbc Add future work note 2021-04-01 14:53:25 -07:00
Matt Nadareski
579c9c0f84 Fix missing SafeDisc version 2021-04-01 11:38:32 -07:00
Matt Nadareski
b2e8b66eae Fix SmartE overmatching 2021-04-01 11:20:13 -07:00
Matt Nadareski
80e71f43de Try to make structs more marshalable 2021-04-01 11:09:20 -07:00
Matt Nadareski
e0497e6fee Migrate SafeDisc to modern path checking 2021-04-01 10:38:50 -07:00
Matt Nadareski
18a78f44c0 Make EVORE a bit safer 2021-04-01 10:36:03 -07:00
Matt Nadareski
f9e7fd5725 Fix marshalling issue 2021-04-01 10:34:53 -07:00
Matt Nadareski
e9c1a170ad Move generic CD key to own file 2021-03-31 19:07:00 -07:00
SilasLaspada
9ce84c75dd Comment out an overmatching definition (#34) 2021-03-31 18:58:34 -07:00
Matt Nadareski
0bd5339b78 Update to UnshieldSharp 1.5.0 2021-03-29 14:35:06 -07:00
Matt Nadareski
e06b1987b9 Update to WiseUnpacker 1.0.2 2021-03-29 14:17:42 -07:00
Matt Nadareski
c8b271ac76 Port over executable header code from Wise 2021-03-25 15:53:45 -07:00
Matt Nadareski
1672c73a57 Fix PECompact scanning
Thanks Silas for noticing the regression
2021-03-25 15:25:15 -07:00
Matt Nadareski
32f6e0e8fc Further making test executable a bit nicer 2021-03-24 20:50:58 -07:00
Matt Nadareski
5c21de5a0f Make the test executable a bit nicer 2021-03-23 16:55:19 -07:00
Matt Nadareski
9f40a8c4c0 Perform some post-removal cleanup 2021-03-23 16:43:23 -07:00
Matt Nadareski
c179f29e2e Remove .NET Framework 4.7.2, update SharpCompress 2021-03-23 16:37:21 -07:00
Matt Nadareski
f9d6fce3bd Reduce boilerplate for directory checks 2021-03-23 13:35:12 -07:00
Matt Nadareski
aa83896963 Final batch of first pass for path check conversions 2021-03-23 10:36:14 -07:00
Matt Nadareski
7d13b8c9db Optimize checking with better caching 2021-03-23 10:04:09 -07:00
Matt Nadareski
921292e077 Static list of content matchers
This also includes some more path matcher conversions that I couldn't reasonably split out
2021-03-23 09:52:09 -07:00
Matt Nadareski
c3e7f0b99f Return empty not null 2021-03-23 08:47:36 -07:00
Matt Nadareski
b9cc5e9ada Second batch of path check conversions 2021-03-22 23:02:01 -07:00
Matt Nadareski
76d76b2bf2 Convert a few more path checks 2021-03-22 22:23:55 -07:00
Matt Nadareski
532e912a2d Accidental comment issue 2021-03-22 22:12:25 -07:00
Matt Nadareski
8ada667dfe Be consistent with var naming 2021-03-22 22:11:01 -07:00
Matt Nadareski
28a4f7ce82 File path should only get first match 2021-03-22 22:09:35 -07:00
Matt Nadareski
3a66183d0e Convert AACS to use new matching 2021-03-22 22:07:14 -07:00
Matt Nadareski
7f91346878 Fix assumptions for path matching 2021-03-22 22:06:55 -07:00
Matt Nadareski
2af0dc4a8c Don't include PDBs 2021-03-22 21:38:49 -07:00
Matt Nadareski
5240f2eb70 Simplify util method naming 2021-03-22 21:32:58 -07:00
Matt Nadareski
f25800510b MatchSet is abstract 2021-03-22 21:30:30 -07:00
Matt Nadareski
6400c954ef Split matchers more cleanly, comment better 2021-03-22 21:25:14 -07:00
Matt Nadareski
e43423d2c9 Fix misleading version results 2021-03-22 16:25:40 -07:00
Matt Nadareski
bc613a0413 Fix build 2021-03-22 11:44:16 -07:00
Matt Nadareski
e47a52dbe0 Use framework in even more content protections 2021-03-22 11:43:51 -07:00
Matt Nadareski
da165345b6 Use framework for more content protections 2021-03-22 11:13:14 -07:00
Matt Nadareski
8ea54328ef Use framework for WZ-SFX v2 checks 2021-03-22 10:22:56 -07:00
Matt Nadareski
a4aeebee68 Split content and path version checks 2021-03-22 10:04:33 -07:00
Matt Nadareski
95a61c3b28 Add path matching to util 2021-03-22 09:55:29 -07:00
Matt Nadareski
9aadf5e948 Add invariance 2021-03-22 01:26:33 -07:00
Matt Nadareski
129ac1bb78 More granular on path search 2021-03-22 01:18:49 -07:00
Matt Nadareski
e4278c55b7 Add path matching matcher 2021-03-22 01:11:59 -07:00
Matt Nadareski
7aca58a6c9 Better split matching code, fix UPX name 2021-03-22 00:41:18 -07:00
Matt Nadareski
ea022de022 Fix a couple things:
- Fix PECompact 2 version string
- Fix UPX (NOS Variant) over-matching
2021-03-21 23:14:37 -07:00
Matt Nadareski
bb4f16d91f Use content matching helper, part 6 2021-03-21 22:45:06 -07:00
Matt Nadareski
f1c165845f Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-21 22:37:25 -07:00
Matt Nadareski
15ae2441c3 Use content matching helper, part 5 2021-03-21 22:37:16 -07:00
SilasLaspada
6b8f8957de Add Advanced Installer Detection (#32)
* Add Advanced Installer Detection

* Updated README

* Address comments
2021-03-21 22:36:01 -07:00
Matt Nadareski
cf9bd99f3d Use content matching helper, part 4 2021-03-21 22:19:38 -07:00
SilasLaspada
557114d92d Add CExe detection (#30)
* Add CExe detection

* Optimize check
2021-03-21 21:39:01 -07:00
Matt Nadareski
d01826ffa4 Use content matching helper, part 3 2021-03-21 15:34:19 -07:00
Matt Nadareski
7e3ef544f0 Use content matching helper, part 2 2021-03-21 15:24:23 -07:00
Matt Nadareski
ab07eb96ce Use content matching helper, part 1 2021-03-21 14:30:37 -07:00
Matt Nadareski
7c53eaab13 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-21 14:04:19 -07:00
SilasLaspada
fad7d87282 Add WinRAR SFX detection and extraction (#31) 2021-03-21 14:03:47 -07:00
Matt Nadareski
578519169a Add helper method for simple content matches 2021-03-20 22:37:56 -07:00
Matt Nadareski
fe106d23ec Fix BD+ in reverse 2021-03-20 22:28:57 -07:00
Matt Nadareski
e1669f031f BD+ using BitConverter 2021-03-20 22:00:38 -07:00
SilasLaspada
9bff6d5fe1 Improve version detection (#29)
* Improve version detection

* Address comments

* Address comments

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2021-03-20 21:29:19 -07:00
Matt Nadareski
544aaed9da Modify array finding, part 2 2021-03-20 20:47:56 -07:00
Matt Nadareski
b6b7a5e7aa Clean up terminology 2021-03-20 19:23:59 -07:00
Matt Nadareski
cdc4d509ee Modify array finding, part 1 2021-03-20 19:00:22 -07:00
Matt Nadareski
07882f7632 Create and use manifesr version utility 2021-03-20 17:34:31 -07:00
Matt Nadareski
deb3c01362 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-20 16:26:19 -07:00
SilasLaspada
a51b16aed2 Add Setup Factory detection (#28)
* Add Setup Factory detection

* Improve version detection

* Address comments
2021-03-20 16:18:17 -07:00
Matt Nadareski
0e7d98158e Split out generic online registration 2021-03-20 13:29:46 -07:00
Matt Nadareski
56d8518ee4 Comment out over-matching EA check 2021-03-19 17:31:53 -07:00
Matt Nadareski
8897fd8650 Make SafeDisc more like Tages path check 2021-03-19 15:56:07 -07:00
Matt Nadareski
6f811e43d0 Split method in Scanner too 2021-03-19 15:48:53 -07:00
Matt Nadareski
a2888e3371 Split IPathCheck method 2021-03-19 15:41:49 -07:00
SilasLaspada
30d3312d87 Added BD+ version detection (#26)
* Added BD+ version detection

* Address Comments

* Address comment

* Remove unnecessary assignment
2021-03-18 10:50:45 -07:00
SilasLaspada
854a257fd6 Implement AACS version detection (#25)
* Implement AACS version detection

* Address comments

* Address more comments

* Address comment
2021-03-17 22:27:37 -07:00
Matt Nadareski
28344c6e3f Add WinZip SFX to readme 2021-03-14 14:39:31 -07:00
SilasLaspada
11a82addd8 Implement BD+ detection (#24) 2021-03-14 14:23:24 -07:00
Matt Nadareski
152f6c7051 Reduce size of 32-bit checks 2021-03-14 14:16:54 -07:00
Matt Nadareski
bedbceafa7 Use NE headers for all 16-bit versions 2021-03-14 13:55:26 -07:00
Matt Nadareski
2f19bf7ceb SFX cleanup and add missing check 2021-03-14 00:19:10 -08:00
SilasLaspada
a39ae9facf Add support for WinZip SFX archives (#23)
* Add inital check for WinZip SFX archives

Every version of WinZip SFX has the string "WinZip Self-Extractor" in it,

* Add basic version detection

Versions 3+ and 2.x are identified radically differently, so make separate methods for them.

* Implement version 3+ detection

Should be very thorough detection, detects every 3+ file I have accurately.

* Cleanup code

General clanup

* Improve version 3+ detection

Use an XML string to determine the version.

* Harden against false positives

* Implement basic extraction

* Partial 2.X version detection

Very crude but effective 2.X detection for 2.0 versions

* Add version detection for 2.1 RC2 variants

* Add 2.1 version detection

* Add 2.2 version detection

Aside from clean-ups, this is the final functional addition

* Address comments
2021-03-13 20:18:03 -08:00
Matt Nadareski
56b234bc96 A little cleanup 2021-03-02 15:21:14 -08:00
Matt Nadareski
633fe23b80 Reflection
This change eliminates the need to explicitly list out every single protection in the same way now that we have interfaces that we can rely on.
2021-03-02 15:10:52 -08:00
Matt Nadareski
2867ce2e9a Add more EA CDKey checks (fixes #21) 2021-03-02 13:48:10 -08:00
Matt Nadareski
ac0e5e95a9 Add note to RPT scan 2021-03-02 13:34:15 -08:00
Matt Nadareski
e3bed19e79 Import WixToolset code as external 2021-03-02 13:09:15 -08:00
Matt Nadareski
73aae8118f Wrap in libmspack4n and LessIO as external code 2021-03-02 12:14:14 -08:00
Matt Nadareski
b3671a430e Swap order of params for IPathCheck 2021-02-26 11:02:10 -08:00
Matt Nadareski
54465ff4e7 Move both installers to packers 2021-02-26 09:34:07 -08:00
Matt Nadareski
52eef84374 Make InnoSetup like WiseInstaller 2021-02-26 09:32:41 -08:00
Matt Nadareski
f4310206e9 Add IScannable interface 2021-02-26 09:26:23 -08:00
Matt Nadareski
7cfa9649e4 Add IContentCheck interface 2021-02-26 01:26:49 -08:00
Matt Nadareski
c6eaafebbe Add IPathCheck interface 2021-02-26 00:32:09 -08:00
Matt Nadareski
df1e14b6c9 Rename NOS variant of UPX 2021-02-25 13:38:13 -08:00
Matt Nadareski
ad2d854969 Add versioned NOS check, fix naming 2021-02-25 11:27:08 -08:00
Matt Nadareski
61202a87fb Add UPX detection for odd cases 2021-02-25 11:13:57 -08:00
Matt Nadareski
9ebbeaed0f Make EA CDKey checks more robust 2021-02-23 13:16:25 -08:00
Matt Nadareski
aebc139d52 I lied, keep it separate 2021-02-20 22:13:48 -08:00
Matt Nadareski
0e82eea891 Origin is an EA protection 2021-02-20 22:06:18 -08:00
Matt Nadareski
7ec76acf2f Remove Cucko until more investigation 2021-02-20 13:16:52 -08:00
Matt Nadareski
21f17791ff No... that's not right 2021-02-19 21:26:49 -08:00
Matt Nadareski
fff5f2610a Add Cucko notes 2021-02-19 10:14:02 -08:00
Matt Nadareski
d574fb5e44 Fix link to MPF in README 2021-01-25 09:53:18 -08:00
Matt Nadareski
d8aacbcc5d Treat Wise internally a bit strangely 2021-01-25 09:51:16 -08:00
Matt Nadareski
6467ef97d5 Only scan Wise internals if scanning archives 2021-01-24 21:23:05 -08:00
165 changed files with 8346 additions and 7260 deletions

15
.gitmodules vendored Normal file
View File

@@ -0,0 +1,15 @@
[submodule "BurnOutSharp/External/LessIO"]
path = BurnOutSharp/External/LessIO
url = https://github.com/activescott/LessIO.git
[submodule "BurnOutSharp/External/libmspack4n"]
path = BurnOutSharp/External/libmspack4n
url = https://github.com/activescott/libmspack4n.git
[submodule "BurnOutSharp/External/hllib"]
path = BurnOutSharp/External/hllib
url = https://github.com/RavuAlHemio/hllib.git
[submodule "BurnOutSharp/External/stormlibsharp"]
path = BurnOutSharp/External/stormlibsharp
url = https://github.com/robpaveza/stormlibsharp.git
[submodule "BurnOutSharp/External/WixToolset"]
path = BurnOutSharp/External/WixToolset
url = https://github.com/wixtoolset/Dtf.git

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1;net5.0</TargetFrameworks>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<PlatformTarget>x86</PlatformTarget>
<Title>BurnOutSharp</Title>
<AssemblyName>BurnOutSharp</AssemblyName>
@@ -11,9 +11,9 @@
<Copyright>Copyright (c)2005-2010 Gernot Knippen, Copyright (c)2018-2021 Matt Nadareski</Copyright>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
<Version>1.5.1</Version>
<AssemblyVersion>1.5.1</AssemblyVersion>
<FileVersion>1.5.1</FileVersion>
<Version>1.7.0</Version>
<AssemblyVersion>1.7.0</AssemblyVersion>
<FileVersion>1.7.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
@@ -21,20 +21,34 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
<DefineConstants>NET_FRAMEWORK</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LessIO" Version="1.0.34" Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'" />
<PackageReference Include="libmspack4n" Version="0.9.10" Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'" />
<PackageReference Include="SharpCompress" Version="0.26.0" />
<PackageReference Include="UnshieldSharp" Version="1.4.2.4" />
<PackageReference Include="WiseUnpacker" Version="1.0.1" />
<PackageReference Include="wix-libs" Version="3.11.1" Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'" />
<PackageReference Include="SharpCompress" Version="0.28.3" />
<PackageReference Include="UnshieldSharp" Version="1.6.0" />
<PackageReference Include="WiseUnpacker" Version="1.0.2" />
</ItemGroup>
<!-- These are needed for dealing with submodules -->
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
**\AssemblyInfo.cs;
External\hllib\HLExtract\**\*;
External\hllib\HLExtract.Net\Program.cs;
External\hllib\HLLib\**\*;
External\LessIO\src\LessIO.Tests\**\*;
External\libmspack4n\lib\**\*;
External\libmspack4n\libmspack4ntest\**\*;
External\stormlibsharp\lib\**;
External\stormlibsharp\TestConsole\**;
External\WixToolset\src\Samples\**;
External\WixToolset\src\Tools\**;
External\WixToolset\src\WixToolset.Dtf.MSBuild\**;
External\WixToolset\src\WixToolset.Dtf.Resources\**;
External\WixToolset\src\WixToolsetTests.*\**
</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE.txt" Pack="true" PackagePath="$(PackageLicenseFile)" />
</ItemGroup>
@@ -45,12 +59,6 @@
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</None>
<None Include="*.pdb" Pack="true">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</None>
</ItemGroup>
</ItemGroup>
</Project>

BIN
BurnOutSharp/CascLib.dll Normal file

Binary file not shown.

View File

@@ -37,10 +37,7 @@ namespace BurnOutSharp
short Characteristics = BitConverter.ToInt16(fileContent, PEHeaderOffset + 22);
// Check if file is dll
if ((Characteristics & 0x2000) == 0x2000)
return false;
else
return true;
return (Characteristics & 0x2000) != 0x2000;
}
/// <summary>
@@ -165,14 +162,14 @@ namespace BurnOutSharp
return startingprocess;
}
private static IMAGE_SECTION_HEADER?[] ReadSections(byte[] fileContent)
private static IMAGE_SECTION_HEADER[] ReadSections(byte[] fileContent)
{
if (fileContent == null)
return null;
uint PEHeaderOffset = BitConverter.ToUInt32(fileContent, 60);
ushort NumberOfSections = BitConverter.ToUInt16(fileContent, (int)PEHeaderOffset + 6);
var sections = new IMAGE_SECTION_HEADER?[NumberOfSections];
var sections = new IMAGE_SECTION_HEADER[NumberOfSections];
int index = (int)PEHeaderOffset + 120 + 16 * 8;
for (int i = 0; i < NumberOfSections; i++)
{
@@ -182,56 +179,63 @@ namespace BurnOutSharp
return sections;
}
private static IMAGE_SECTION_HEADER? ReadSection(byte[] fileContent, int ptr)
private static IMAGE_SECTION_HEADER ReadSection(byte[] fileContent, int ptr)
{
// Get the size of a section header for later
int sectionSize = Marshal.SizeOf<IMAGE_SECTION_HEADER>();
// If the contents are null or the wrong size, we can't read a section
if (fileContent == null || fileContent.Length < sectionSize)
return null;
// Create a new section and try our best to read one
IMAGE_SECTION_HEADER? section = null;
IntPtr tempPtr = IntPtr.Zero;
try
{
// Get the pointer to where the section will go
tempPtr = Marshal.AllocHGlobal(sectionSize);
// If we couldn't get the space, just return null
if (tempPtr == IntPtr.Zero)
// Get the size of a section header for later
int sectionSize = Marshal.SizeOf<IMAGE_SECTION_HEADER>();
// If the contents are null or the wrong size, we can't read a section
if (fileContent == null || fileContent.Length < sectionSize)
return null;
// Copy from the array to the new space
Marshal.Copy(fileContent, ptr, tempPtr, sectionSize);
// Create a new section and try our best to read one
IMAGE_SECTION_HEADER section = null;
IntPtr tempPtr = IntPtr.Zero;
try
{
// Get the pointer to where the section will go
tempPtr = Marshal.AllocHGlobal(sectionSize);
// If we couldn't get the space, just return null
if (tempPtr == IntPtr.Zero)
return null;
// Get the new section and return
section = Marshal.PtrToStructure<IMAGE_SECTION_HEADER>(tempPtr);
// Copy from the array to the new space
Marshal.Copy(fileContent, ptr, tempPtr, sectionSize);
// Get the new section and return
section = Marshal.PtrToStructure<IMAGE_SECTION_HEADER>(tempPtr);
}
catch
{
// We don't care what the error was
return null;
}
finally
{
if (tempPtr != IntPtr.Zero)
Marshal.FreeHGlobal(tempPtr);
}
return section;
}
catch
{
// We don't care what the error was
return null;
}
finally
{
if (tempPtr != IntPtr.Zero)
Marshal.FreeHGlobal(tempPtr);
}
return section;
}
private static uint RVA2Offset(uint RVA, IMAGE_SECTION_HEADER?[] sections)
private static uint RVA2Offset(uint RVA, IMAGE_SECTION_HEADER[] sections)
{
for (int i = 0; i < sections.Length; i++)
{
if (!sections[i].HasValue)
if (sections[i] == null)
continue;
var section = sections[i].Value;
if (section.VirtualAddress <= RVA && section.VirtualAddress + section.PhysicalAddressOrVirtualSize > RVA)
var section = sections[i];
if (section.VirtualAddress <= RVA && section.VirtualAddress + section.PhysicalAddress > RVA)
return RVA - section.VirtualAddress + section.PointerToRawData;
}

View File

@@ -0,0 +1,99 @@
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// All constant values needed for file header reading
/// </summary>
internal static class Constants
{
public const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
public const ushort IMAGE_OS2_SIGNATURE = 0x454E; // NE
public const ushort IMAGE_OS2_SIGNATURE_LE = 0x454C; // LE
public const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
#region IMAGE_DOS_HEADER
public const ushort ENEWEXE = 0x40; // Value of E_LFARLC for new .EXEs
public const ushort ENEWHDR = 0x003C; // Offset in old hdr. of ptr. to new
public const ushort ERESWDS = 0x0010; // No. of reserved words (OLD)
public const ushort ERES1WDS = 0x0004; // No. of reserved words in e_res
public const ushort ERES2WDS = 0x000A; // No. of reserved words in e_res2
public const ushort ECP = 0x0004; // Offset in struct of E_CP
public const ushort ECBLP = 0x0002; // Offset in struct of E_CBLP
public const ushort EMINALLOC = 0x000A; // Offset in struct of E_MINALLOC
#endregion
#region IMAGE_OS2_HEADER
public const ushort NERESWORDS = 3; // 6 bytes reserved
public const ushort NECRC = 8; //Offset into new header of NE_CRC
#endregion
#region NewSeg
public const ushort NSALIGN = 9; // Segment data aligned on 512 byte boundaries
public const ushort NSLOADED = 0x0004; // ns_sector field contains memory addr
#endregion
#region RsrcNameInfo
public const ushort RSORDID = 0x8000; /* if high bit of ID set then integer id */
/* otherwise ID is offset of string from
the beginning of the resource table */
/* Ideally these are the same as the */
/* corresponding segment flags */
public const ushort RNMOVE = 0x0010; /* Moveable resource */
public const ushort RNPURE = 0x0020; /* Pure (read-only) resource */
public const ushort RNPRELOAD = 0x0040; /* Preloaded resource */
public const ushort RNDISCARD = 0xF000; /* Discard priority level for resource */
#endregion
#region IMAGE_OPTIONAL_HEADER
public const ushort IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
/* Directory Entries */
/* Export Directory */
public const byte IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
/* Import Directory */
public const byte IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
/* Resource Directory */
public const byte IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
/* Exception Directory */
public const byte IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3;
/* Security Directory */
public const byte IMAGE_DIRECTORY_ENTRY_SECURITY = 4;
/* Base Relocation Table */
public const byte IMAGE_DIRECTORY_ENTRY_BASERELOC = 5;
/* Debug Directory */
public const byte IMAGE_DIRECTORY_ENTRY_DEBUG = 6;
/* Description String */
public const byte IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7;
/* Machine Value (MIPS GP) */
public const byte IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8;
/* TLS Directory */
public const byte IMAGE_DIRECTORY_ENTRY_TLS = 9;
/* Load Configuration Directory */
public const byte IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10;
#endregion
#region IMAGE_SECTION_HEADER
public const int IMAGE_SIZEOF_SHORT_NAME = 8;
#endregion
#region IMAGE_RESOURCE_DATA_ENTRY
public const uint IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000;
public const uint IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000;
#endregion
}
}

View File

@@ -0,0 +1,384 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System;
namespace BurnOutSharp.ExecutableType.Microsoft
{
internal enum ExecutableType
{
Unknown,
NE,
PE,
}
/// <summary>
/// Format of NE_FLAGS(x):
///
/// p Not-a-process
/// x Unused
/// e Errors in image
/// x Unused
/// b Bound as family app
/// ttt Application type
/// f Floating-point instructions
/// 3 386 instructions
/// 2 286 instructions
/// 0 8086 instructions
/// P Protected mode only
/// p Per-process library initialization
/// i Instance data
/// s Solo data
/// </summary>
[Flags]
internal enum NeFlags : ushort
{
/// <summary>
/// Not a process
/// </summary>
NENOTP = 0x8000,
/// <summary>
/// Errors in image
/// </summary>
NEIERR = 0x2000,
/// <summary>
/// Bound as family app
/// </summary>
NEBOUND = 0x0800,
/// <summary>
/// Application type mask
/// </summary>
NEAPPTYP = 0x0700,
/// <summary>
/// Not compatible with P.M. Windowing
/// </summary>
NENOTWINCOMPAT = 0x0100,
/// <summary>
/// Compatible with P.M. Windowing
/// </summary>
NEWINCOMPAT = 0x0200,
/// <summary>
/// Uses P.M. Windowing API
/// </summary>
NEWINAPI = 0x0300,
/// <summary>
/// Floating-point instructions
/// </summary>
NEFLTP = 0x0080,
/// <summary>
/// 386 instructions
/// </summary>
NEI386 = 0x0040,
/// <summary>
/// 286 instructions
/// </summary>
NEI286 = 0x0020,
/// <summary>
/// 8086 instructions
/// </summary>
NEI086 = 0x0010,
/// <summary>
/// Runs in protected mode only
/// </summary>
NEPROT = 0x0008,
/// <summary>
/// Per-Process Library Initialization
/// </summary>
NEPPLI = 0x0004,
/// <summary>
/// Instance data
/// </summary>
NEINST = 0x0002,
/// <summary>
/// Solo data
/// </summary>
NESOLO = 0x0001,
}
/// <summary>
/// Format of NR_FLAGS(x):
///
/// xxxxx Unused
/// a Additive fixup
/// rr Reference type
/// </summary>
[Flags]
internal enum NrFlags : byte
{
/// <summary>
/// Additive fixup
/// </summary>
NRADD = 0x04,
/// <summary>
/// Reference type mask
/// </summary>
NRRTYP = 0x03,
/// <summary>
/// Internal reference
/// </summary>
NRRINT = 0x00,
/// <summary>
/// Import by ordinal
/// </summary>
NRRORD = 0x01,
/// <summary>
/// Import by name
/// </summary>
NRRNAM = 0x02,
/// <summary>
/// Operating system fixup
/// </summary>
NRROSF = 0x03,
}
/// <summary>
/// Format of NR_STYPE(x):
///
/// xxxxx Unused
/// sss Source type
////
/// </summary>
[Flags]
internal enum NrStype : byte
{
/// <summary>
/// Source type mask
/// </summary>
NRSTYP = 0x0f,
/// <summary>
/// lo byte
/// </summary>
NRSBYT = 0x00,
/// <summary>
/// 16-bit segment
/// </summary>
NRSSEG = 0x02,
/// <summary>
/// 32-bit pointer
/// </summary>
NRSPTR = 0x03,
/// <summary>
/// 16-bit offset
/// </summary>
NRSOFF = 0x05,
/// <summary>
/// 48-bit pointer
/// </summary>
NRSPTR48 = 0x0B,
/// <summary>
/// 32-bit offset
/// </summary>
NRSOFF32 = 0x0D,
}
/// <summary>
/// Format of NS_FLAGS(x)
///
/// x Unused
/// h Huge segment
/// c 32-bit code segment
/// d Discardable segment
/// DD I/O privilege level (286 DPL bits)
/// c Conforming segment
/// r Segment has relocations
/// e Execute/read only
/// p Preload segment
/// P Pure segment
/// m Movable segment
/// i Iterated segment
/// ttt Segment type
/// </summary>
[Flags]
internal enum NsFlags : ushort
{
/// <summary>
/// Segment type mask
/// </summary>
NSTYPE = 0x0007,
/// <summary>
/// Code segment
/// </summary>
NSCODE = 0x0000,
/// <summary>
/// Data segment
/// </summary>
NSDATA = 0x0001,
/// <summary>
/// Iterated segment flag
/// </summary>
NSITER = 0x0008,
/// <summary>
/// Movable segment flag
/// </summary>
NSMOVE = 0x0010,
/// <summary>
/// Shared segment flag
/// </summary>
NSSHARED = 0x0020,
/// <summary>
/// For compatibility
/// </summary>
NSPURE = 0x0020,
/// <summary>
/// Preload segment flag
/// </summary>
NSPRELOAD = 0x0040,
/// <summary>
/// Execute-only (code segment), or read-only (data segment)
/// </summary>
NSEXRD = 0x0080,
/// <summary>
/// Segment has relocations
/// </summary>
NSRELOC = 0x0100,
/// <summary>
/// Conforming segment
/// </summary>
NSCONFORM = 0x0200,
/// <summary>
/// I/O privilege level (286 DPL bits)
/// </summary>
NSDPL = 0x0C00,
/// <summary>
/// Left shift count for SEGDPL field
/// </summary>
SHIFTDPL = 10,
/// <summary>
/// Segment is discardable
/// </summary>
NSDISCARD = 0x1000,
/// <summary>
/// 32-bit code segment
/// </summary>
NS32BIT = 0x2000,
/// <summary>
/// Huge memory segment, length of segment and minimum allocation size are in segment sector units
/// </summary>
NSHUGE = 0x4000,
}
/// <summary>
/// Predefined Resource Types
/// </summary>
internal enum ResourceTypes : ushort
{
RT_CURSOR = 1,
RT_BITMAP = 2,
RT_ICON = 3,
RT_MENU = 4,
RT_DIALOG = 5,
RT_STRING = 6,
RT_FONTDIR = 7,
RT_FONT = 8,
RT_ACCELERATOR = 9,
RT_RCDATA = 10,
RT_MESSAGELIST = 11, // RT_MESSAGETABLE
RT_GROUP_CURSOR = 12,
RT_RESERVED_1 = 13, // Undefined
RT_GROUP_ICON = 14,
RT_RESERVED_2 = 15, // Undefined
RT_VERSION = 16,
RT_DLGINCLUDE = 17,
RT_PLUGPLAY = 19,
RT_VXD = 20,
RT_ANICURSOR = 21,
RT_NEWRESOURCE = 0x2000,
RT_NEWBITMAP = (RT_BITMAP |RT_NEWRESOURCE),
RT_NEWMENU = (RT_MENU |RT_NEWRESOURCE),
RT_NEWDIALOG = (RT_DIALOG |RT_NEWRESOURCE),
RT_ERROR = 0x7fff,
}
[Flags]
internal enum SectionCharacteristics : uint
{
CodeSection = 0x00000020,
InitializedDataSection = 0x00000040,
UninitializedDataSection = 0x00000080,
SectionCannotBeCached = 0x04000000,
SectionIsNotPageable = 0x08000000,
SectionIsShared = 0x10000000,
ExecutableSection = 0x20000000,
ReadableSection = 0x40000000,
WritableSection = 0x80000000,
}
[Flags]
internal enum TargetOperatingSystems : byte
{
/// <summary>
/// Unknown (any "new-format" OS)
/// </summary>
NE_UNKNOWN = 0x0,
/// <summary>
/// Microsoft/IBM OS/2 (default)
/// </summary>
NE_OS2 = 0x1,
/// <summary>
/// Microsoft Windows
/// </summary>
NE_WINDOWS = 0x2,
/// <summary>
/// Microsoft MS-DOS 4.x
/// </summary>
NE_DOS4 = 0x3,
/// <summary>
/// Windows 386
/// </summary>
NE_WIN386 = 0x4,
}
}

View File

@@ -1,12 +1,34 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_DATA_DIRECTORY
internal class IMAGE_DATA_DIRECTORY
{
public uint VirtualAddress;
public uint Size;
public static IMAGE_DATA_DIRECTORY Deserialize(Stream stream)
{
var idd = new IMAGE_DATA_DIRECTORY();
idd.VirtualAddress = stream.ReadUInt32();
idd.Size = stream.ReadUInt32();
return idd;
}
}
}
}

View File

@@ -1,30 +1,81 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// DOS 1, 2, 3 .EXE header
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_DOS_HEADER
internal class IMAGE_DOS_HEADER
{
public ushort e_magic; /* 00: MZ Header signature */
public ushort e_cblp; /* 02: Bytes on last page of file */
public ushort e_cp; /* 04: Pages in file */
public ushort e_crlc; /* 06: Relocations */
public ushort e_cparhdr; /* 08: Size of header in paragraphs */
public ushort e_minalloc; /* 0a: Minimum extra paragraphs needed */
public ushort e_maxalloc; /* 0c: Maximum extra paragraphs needed */
public ushort e_ss; /* 0e: Initial (relative) SS value */
public ushort e_sp; /* 10: Initial SP value */
public ushort e_csum; /* 12: Checksum */
public ushort e_ip; /* 14: Initial IP value */
public ushort e_cs; /* 16: Initial (relative) CS value */
public ushort e_lfarlc; /* 18: File address of relocation table */
public ushort e_ovno; /* 1a: Overlay number */
public ushort[] e_res; /* 1c: Reserved words [4] */
public ushort e_oemid; /* 24: OEM identifier (for e_oeminfo) */
public ushort e_oeminfo; /* 26: OEM information; e_oemid specific */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public ushort[] e_res2; /* 28: Reserved words [10] */
public uint e_lfanew; /* 3c: Offset to extended header */
public ushort Magic; // 00 Magic number
public ushort LastPageBytes; // 02 Bytes on last page of file
public ushort Pages; // 04 Pages in file
public ushort Relocations; // 06 Relocations
public ushort HeaderParagraphSize; // 08 Size of header in paragraphs
public ushort MinimumExtraParagraphs; // 0A Minimum extra paragraphs needed
public ushort MaximumExtraParagraphs; // 0C Maximum extra paragraphs needed
public ushort InitialSSValue; // 0E Initial (relative) SS value
public ushort InitialSPValue; // 10 Initial SP value
public ushort Checksum; // 12 Checksum
public ushort InitialIPValue; // 14 Initial IP value
public ushort InitialCSValue; // 16 Initial (relative) CS value
public ushort RelocationTableAddr; // 18 File address of relocation table
public ushort OverlayNumber; // 1A Overlay number
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES1WDS)]
public ushort[] Reserved1; // 1C Reserved words
public ushort OEMIdentifier; // 24 OEM identifier (for e_oeminfo)
public ushort OEMInformation; // 26 OEM information; e_oemid specific
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.ERES2WDS)]
public ushort[] Reserved2; // 28 Reserved words
public int NewExeHeaderAddr; // 3C File address of new exe header
public static IMAGE_DOS_HEADER Deserialize(Stream stream)
{
IMAGE_DOS_HEADER idh = new IMAGE_DOS_HEADER();
idh.Magic = stream.ReadUInt16();
idh.LastPageBytes = stream.ReadUInt16();
idh.Pages = stream.ReadUInt16();
idh.Relocations = stream.ReadUInt16();
idh.HeaderParagraphSize = stream.ReadUInt16();
idh.MinimumExtraParagraphs = stream.ReadUInt16();
idh.MaximumExtraParagraphs = stream.ReadUInt16();
idh.InitialSSValue = stream.ReadUInt16();
idh.InitialSPValue = stream.ReadUInt16();
idh.Checksum = stream.ReadUInt16();
idh.InitialIPValue = stream.ReadUInt16();
idh.InitialCSValue = stream.ReadUInt16();
idh.RelocationTableAddr = stream.ReadUInt16();
idh.OverlayNumber = stream.ReadUInt16();
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = stream.ReadUInt16();
}
idh.OEMIdentifier = stream.ReadUInt16();
idh.OEMInformation = stream.ReadUInt16();
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = stream.ReadUInt16();
}
idh.NewExeHeaderAddr = stream.ReadInt32();
return idh;
}
}
}

View File

@@ -1,10 +1,22 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_FILE_HEADER
internal class IMAGE_FILE_HEADER
{
public ushort Machine;
public ushort NumberOfSections;
@@ -12,6 +24,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft
public uint PointerToSymbolTable;
public uint NumberOfSymbols;
public ushort SizeOfOptionalHeader;
public FileCharacteristics Characteristics;
public ushort Characteristics;
public static IMAGE_FILE_HEADER Deserialize(Stream stream)
{
var ifh = new IMAGE_FILE_HEADER();
ifh.Machine = stream.ReadUInt16();
ifh.NumberOfSections = stream.ReadUInt16();
ifh.TimeDateStamp = stream.ReadUInt32();
ifh.PointerToSymbolTable = stream.ReadUInt32();
ifh.NumberOfSymbols = stream.ReadUInt32();
ifh.SizeOfOptionalHeader = stream.ReadUInt16();
ifh.Characteristics = stream.ReadUInt16();
return ifh;
}
}
}
}

View File

@@ -1,13 +0,0 @@
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS32
{
public uint Signature; /* "PE"\0\0 */ /* 0x00 */
public IMAGE_FILE_HEADER FileHeader; /* 0x04 */
public IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */
}
}

View File

@@ -1,13 +0,0 @@
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS64
{
public uint Signature;
public IMAGE_FILE_HEADER FileHeader;
public IMAGE_OPTIONAL_HEADER64 OptionalHeader;
}
}

View File

@@ -0,0 +1,103 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_OPTIONAL_HEADER
{
// Standard fields
public ushort Magic;
public byte MajorLinkerVersion;
public byte MinorLinkerVersion;
public uint SizeOfCode;
public uint SizeOfInitializedData;
public uint SizeOfUninitializedData;
public uint AddressOfEntryPoint;
public uint BaseOfCode;
public uint BaseOfData;
// NT additional fields.
public uint ImageBase;
public uint SectionAlignment;
public uint FileAlignment;
public ushort MajorOperatingSystemVersion;
public ushort MinorOperatingSystemVersion;
public ushort MajorImageVersion;
public ushort MinorImageVersion;
public ushort MajorSubsystemVersion;
public ushort MinorSubsystemVersion;
public uint Reserved1;
public uint SizeOfImage;
public uint SizeOfHeaders;
public uint CheckSum;
public ushort Subsystem;
public ushort DllCharacteristics;
public uint SizeOfStackReserve;
public uint SizeOfStackCommit;
public uint SizeOfHeapReserve;
public uint SizeOfHeapCommit;
public uint LoaderFlags;
public uint NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
public IMAGE_DATA_DIRECTORY[] DataDirectory;
public static IMAGE_OPTIONAL_HEADER Deserialize(Stream stream)
{
var ioh = new IMAGE_OPTIONAL_HEADER();
ioh.Magic = stream.ReadUInt16();
ioh.MajorLinkerVersion = stream.ReadByteValue();
ioh.MinorLinkerVersion = stream.ReadByteValue();
ioh.SizeOfCode = stream.ReadUInt32();
ioh.SizeOfInitializedData = stream.ReadUInt32();
ioh.SizeOfUninitializedData = stream.ReadUInt32();
ioh.AddressOfEntryPoint = stream.ReadUInt32();
ioh.BaseOfCode = stream.ReadUInt32();
ioh.BaseOfData = stream.ReadUInt32();
ioh.ImageBase = stream.ReadUInt32();
ioh.SectionAlignment = stream.ReadUInt32();
ioh.FileAlignment = stream.ReadUInt32();
ioh.MajorOperatingSystemVersion = stream.ReadUInt16();
ioh.MinorOperatingSystemVersion = stream.ReadUInt16();
ioh.MajorImageVersion = stream.ReadUInt16();
ioh.MinorImageVersion = stream.ReadUInt16();
ioh.MajorSubsystemVersion = stream.ReadUInt16();
ioh.MinorSubsystemVersion = stream.ReadUInt16();
ioh.Reserved1 = stream.ReadUInt32();
ioh.SizeOfImage = stream.ReadUInt32();
ioh.SizeOfHeaders = stream.ReadUInt32();
ioh.CheckSum = stream.ReadUInt32();
ioh.Subsystem = stream.ReadUInt16();
ioh.DllCharacteristics = stream.ReadUInt16();
ioh.SizeOfStackReserve = stream.ReadUInt32();
ioh.SizeOfStackCommit = stream.ReadUInt32();
ioh.SizeOfHeapReserve = stream.ReadUInt32();
ioh.SizeOfHeapCommit = stream.ReadUInt32();
ioh.LoaderFlags = stream.ReadUInt32();
ioh.NumberOfRvaAndSizes = stream.ReadUInt32();
ioh.DataDirectory = new IMAGE_DATA_DIRECTORY[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectory[i] = IMAGE_DATA_DIRECTORY.Deserialize(stream);
}
return ioh;
}
}
}

View File

@@ -1,48 +0,0 @@
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER32
{
/* Standard fields */
public ushort Magic; /* 0x10b or 0x107 */ /* 0x00 */
public byte MajorLinkerVersion;
public byte MinorLinkerVersion;
public uint SizeOfCode;
public uint SizeOfInitializedData;
public uint SizeOfUninitializedData;
public uint AddressOfEntryPoint; /* 0x10 */
public uint BaseOfCode;
public uint BaseOfData;
/* NT additional fields */
public uint ImageBase;
public uint SectionAlignment; /* 0x20 */
public uint FileAlignment;
public ushort MajorOperatingSystemVersion;
public ushort MinorOperatingSystemVersion;
public ushort MajorImageVersion;
public ushort MinorImageVersion;
public ushort MajorSubsystemVersion; /* 0x30 */
public ushort MinorSubsystemVersion;
public uint Win32VersionValue;
public uint SizeOfImage;
public uint SizeOfHeaders;
public uint CheckSum; /* 0x40 */
public ushort Subsystem;
public DllCharacteristics DllCharacteristics;
public uint SizeOfStackReserve;
public uint SizeOfStackCommit;
public uint SizeOfHeapReserve; /* 0x50 */
public uint SizeOfHeapCommit;
public uint LoaderFlags;
public uint NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
public IMAGE_DATA_DIRECTORY[] DataDirectory; /* 0x60, [IMAGE_NUMBEROF_DIRECTORY_ENTRIES] */
/* 0xE0 */
}
}

View File

@@ -1,41 +0,0 @@
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER64
{
public ushort Magic; /* 0x20b */
public byte MajorLinkerVersion;
public byte MinorLinkerVersion;
public uint SizeOfCode;
public uint SizeOfInitializedData;
public uint SizeOfUninitializedData;
public uint AddressOfEntryPoint;
public uint BaseOfCode;
public ulong ImageBase;
public uint SectionAlignment;
public uint FileAlignment;
public ushort MajorOperatingSystemVersion;
public ushort MinorOperatingSystemVersion;
public ushort MajorImageVersion;
public ushort MinorImageVersion;
public ushort MajorSubsystemVersion;
public ushort MinorSubsystemVersion;
public uint Win32VersionValue;
public uint SizeOfImage;
public uint SizeOfHeaders;
public uint CheckSum;
public ushort Subsystem;
public DllCharacteristics DllCharacteristics;
public ulong SizeOfStackReserve;
public ulong SizeOfStackCommit;
public ulong SizeOfHeapReserve;
public ulong SizeOfHeapCommit;
public uint LoaderFlags;
public uint NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES)]
public IMAGE_DATA_DIRECTORY[] DataDirectory; // [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
}
}

View File

@@ -1,40 +1,96 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// New .EXE header
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OS2_HEADER
internal class IMAGE_OS2_HEADER
{
public ushort ne_magic; /* 00 NE signature 'NE' */
public byte ne_ver; /* 02 Linker version number */
public byte ne_rev; /* 03 Linker revision number */
public ushort ne_enttab; /* 04 Offset to entry table relative to NE */
public ushort ne_cbenttab; /* 06 Length of entry table in bytes */
public uint ne_crc; /* 08 Checksum */
public ushort ne_flags; /* 0c Flags about segments in this file */
public ushort ne_autodata; /* 0e Automatic data segment number */
public ushort ne_heap; /* 10 Initial size of local heap */
public ushort ne_stack; /* 12 Initial size of stack */
public uint ne_csip; /* 14 Initial CS:IP */
public uint ne_sssp; /* 18 Initial SS:SP */
public ushort ne_cseg; /* 1c # of entries in segment table */
public ushort ne_cmod; /* 1e # of entries in module reference tab. */
public ushort ne_cbnrestab; /* 20 Length of nonresident-name table */
public ushort ne_segtab; /* 22 Offset to segment table */
public ushort ne_rsrctab; /* 24 Offset to resource table */
public ushort ne_restab; /* 26 Offset to resident-name table */
public ushort ne_modtab; /* 28 Offset to module reference table */
public ushort ne_imptab; /* 2a Offset to imported name table */
public uint ne_nrestab; /* 2c Offset to nonresident-name table */
public ushort ne_cmovent; /* 30 # of movable entry points */
public ushort ne_align; /* 32 Logical sector alignment shift count */
public ushort ne_cres; /* 34 # of resource segments */
public byte ne_exetyp; /* 36 Flags indicating target OS */
public byte ne_flagsothers; /* 37 Additional information flags */
public ushort ne_pretthunks; /* 38 Offset to return thunks */
public ushort ne_psegrefbytes; /* 3a Offset to segment ref. bytes */
public ushort ne_swaparea; /* 3c Reserved by Microsoft */
public ushort ne_expver; /* 3e Expected Windows version number */
public ushort Magic; // 00 Magic number NE_MAGIC
public byte LinkerVersion; // 02 Linker Version number
public byte LinkerRevision; // 03 Linker Revision number
public ushort EntryTableOffset; // 04 Offset of Entry Table
public ushort EntryTableSize; // 06 Number of bytes in Entry Table
public uint CrcChecksum; // 08 Checksum of whole file
public ushort Flags; // 0C Flag word
public ushort Autodata; // 0E Automatic data segment number
public ushort InitialHeapAlloc; // 10 Initial heap allocation
public ushort InitialStackAlloc; // 12 Initial stack allocation
public uint InitialCSIPSetting; // 14 Initial CS:IP setting
public uint InitialSSSPSetting; // 18 Initial SS:SP setting
public ushort FileSegmentCount; // 1C Count of file segments
public ushort ModuleReferenceTableSize; // 1E Entries in Module Reference Table
public ushort NonResidentNameTableSize; // 20 Size of non-resident name table
public ushort SegmentTableOffset; // 22 Offset of Segment Table
public ushort ResourceTableOffset; // 24 Offset of Resource Table
public ushort ResidentNameTableOffset; // 26 Offset of resident name table
public ushort ModuleReferenceTableOffset; // 28 Offset of Module Reference Table
public ushort ImportedNamesTableOffset; // 2A Offset of Imported Names Table
public uint NonResidentNamesTableOffset; // 2C Offset of Non-resident Names Table
public ushort MovableEntriesCount; // 30 Count of movable entries
public ushort SegmentAlignmentShiftCount; // 32 Segment alignment shift count
public ushort ResourceEntriesCount; // 34 Count of resource entries
public byte TargetOperatingSystem; // 36 Target operating system
public byte AdditionalFlags; // 37 Additional flags
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.NERESWORDS)]
public ushort[] Reserved; // 38 3 reserved words
public byte WindowsSDKRevision; // 3E Windows SDK revison number
public byte WindowsSDKVersion; // 3F Windows SDK version number
public static IMAGE_OS2_HEADER Deserialize(Stream stream)
{
var ioh = new IMAGE_OS2_HEADER();
ioh.Magic = stream.ReadUInt16();
ioh.LinkerVersion = stream.ReadByteValue();
ioh.LinkerRevision = stream.ReadByteValue();
ioh.EntryTableOffset = stream.ReadUInt16();
ioh.EntryTableSize = stream.ReadUInt16();
ioh.CrcChecksum = stream.ReadUInt32();
ioh.Flags = stream.ReadUInt16();
ioh.Autodata = stream.ReadUInt16();
ioh.InitialHeapAlloc = stream.ReadUInt16();
ioh.InitialStackAlloc = stream.ReadUInt16();
ioh.InitialCSIPSetting = stream.ReadUInt32();
ioh.InitialSSSPSetting = stream.ReadUInt32();
ioh.FileSegmentCount = stream.ReadUInt16();
ioh.ModuleReferenceTableSize = stream.ReadUInt16();
ioh.NonResidentNameTableSize = stream.ReadUInt16();
ioh.SegmentTableOffset = stream.ReadUInt16();
ioh.ResourceTableOffset = stream.ReadUInt16();
ioh.ResidentNameTableOffset = stream.ReadUInt16();
ioh.ModuleReferenceTableOffset = stream.ReadUInt16();
ioh.ImportedNamesTableOffset = stream.ReadUInt16();
ioh.NonResidentNamesTableOffset = stream.ReadUInt32();
ioh.MovableEntriesCount = stream.ReadUInt16();
ioh.SegmentAlignmentShiftCount = stream.ReadUInt16();
ioh.ResourceEntriesCount = stream.ReadUInt16();
ioh.TargetOperatingSystem = stream.ReadByteValue();
ioh.AdditionalFlags = stream.ReadByteValue();
ioh.Reserved = new ushort[Constants.NERESWORDS];
for (int i = 0; i < Constants.NERESWORDS; i++)
{
ioh.Reserved[i] = stream.ReadUInt16();
}
ioh.WindowsSDKRevision = stream.ReadByteValue();
ioh.WindowsSDKVersion = stream.ReadByteValue();
return ioh;
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_RESOURCE_DATA_ENTRY
{
public uint OffsetToData;
public uint Size;
public uint CodePage;
public uint Reserved;
public static IMAGE_RESOURCE_DATA_ENTRY Deserialize(Stream stream)
{
var irde = new IMAGE_RESOURCE_DATA_ENTRY();
irde.OffsetToData = stream.ReadUInt32();
irde.Size = stream.ReadUInt32();
irde.CodePage = stream.ReadUInt32();
irde.Reserved = stream.ReadUInt32();
return irde;
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_RESOURCE_DIRECTORY
{
public uint Characteristics;
public uint TimeDateStamp;
public ushort MajorVersion;
public ushort MinorVersion;
public ushort NumberOfNamedEntries;
public ushort NumberOfIdEntries;
public static IMAGE_RESOURCE_DIRECTORY Deserialize(Stream stream)
{
var ird = new IMAGE_RESOURCE_DIRECTORY();
ird.Characteristics = stream.ReadUInt32();
ird.TimeDateStamp = stream.ReadUInt32();
ird.MajorVersion = stream.ReadUInt16();
ird.MinorVersion = stream.ReadUInt16();
ird.NumberOfNamedEntries = stream.ReadUInt16();
ird.NumberOfIdEntries = stream.ReadUInt16();
return ird;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_RESOURCE_DIRECTORY_ENTRY
{
public uint Name;
public uint OffsetToData;
public static IMAGE_RESOURCE_DIRECTORY_ENTRY Deserialize(Stream stream)
{
var irde = new IMAGE_RESOURCE_DIRECTORY_ENTRY();
irde.Name = stream.ReadUInt32();
irde.OffsetToData = stream.ReadUInt32();
return irde;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class IMAGE_RESOURCE_DIR_STRING_U
{
public ushort Length;
public char[] NameString;
public static IMAGE_RESOURCE_DIR_STRING_U Deserialize(Stream stream)
{
var irdsu = new IMAGE_RESOURCE_DIR_STRING_U();
irdsu.Length = stream.ReadUInt16();
irdsu.NameString = stream.ReadChars(irdsu.Length);
return irdsu;
}
}
}

View File

@@ -1,14 +1,30 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_SECTION_HEADER
internal class IMAGE_SECTION_HEADER
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.IMAGE_SIZEOF_SHORT_NAME)]
public byte[] Name; // [IMAGE_SIZEOF_SHORT_NAME];
public uint PhysicalAddressOrVirtualSize; // Misc
public byte[] Name;
// Misc
public uint PhysicalAddress;
public uint VirtualSize;
public uint VirtualAddress;
public uint SizeOfRawData;
public uint PointerToRawData;
@@ -17,5 +33,27 @@ namespace BurnOutSharp.ExecutableType.Microsoft
public ushort NumberOfRelocations;
public ushort NumberOfLinenumbers;
public SectionCharacteristics Characteristics;
public static IMAGE_SECTION_HEADER Deserialize(Stream stream)
{
var ish = new IMAGE_SECTION_HEADER();
ish.Name = stream.ReadBytes(Constants.IMAGE_SIZEOF_SHORT_NAME);
// Misc
ish.PhysicalAddress = stream.ReadUInt32();
ish.VirtualSize = ish.PhysicalAddress;
ish.VirtualAddress = stream.ReadUInt32();
ish.SizeOfRawData = stream.ReadUInt32();
ish.PointerToRawData = stream.ReadUInt32();
ish.PointerToRelocations = stream.ReadUInt32();
ish.PointerToLinenumbers = stream.ReadUInt32();
ish.NumberOfRelocations = stream.ReadUInt16();
ish.NumberOfLinenumbers = stream.ReadUInt16();
ish.Characteristics = (SectionCharacteristics)stream.ReadUInt32();
return ish;
}
}
}
}

View File

@@ -1,62 +0,0 @@
using System.Runtime.InteropServices;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_VXD_HEADER
{
public ushort e32_magic;
public byte e32_border;
public byte e32_worder;
public uint e32_level;
public ushort e32_cpu;
public ushort e32_os;
public uint e32_ver;
public uint e32_mflags;
public uint e32_mpages;
public uint e32_startobj;
public uint e32_eip;
public uint e32_stackobj;
public uint e32_esp;
public uint e32_pagesize;
public uint e32_lastpagesize;
public uint e32_fixupsize;
public uint e32_fixupsum;
public uint e32_ldrsize;
public uint e32_ldrsum;
public uint e32_objtab;
public uint e32_objcnt;
public uint e32_objmap;
public uint e32_itermap;
public uint e32_rsrctab;
public uint e32_rsrccnt;
public uint e32_restab;
public uint e32_enttab;
public uint e32_dirtab;
public uint e32_dircnt;
public uint e32_fpagetab;
public uint e32_frectab;
public uint e32_impmod;
public uint e32_impmodcnt;
public uint e32_impproc;
public uint e32_pagesum;
public uint e32_datapage;
public uint e32_preload;
public uint e32_nrestab;
public uint e32_cbnrestab;
public uint e32_nressum;
public uint e32_autodata;
public uint e32_debuginfo;
public uint e32_debuglen;
public uint e32_instpreload;
public uint e32_instdemand;
public uint e32_heapsize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] e32_res3; // [12]
public uint e32_winresoff;
public uint e32_winreslen;
public ushort e32_devid;
public ushort e32_ddkver;
}
}

View File

@@ -0,0 +1,42 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class NAMEINFO
{
public ushort Offset;
public ushort Length;
public ushort Flags;
public ushort ID;
public ushort Handle;
public ushort Usage;
public static NAMEINFO Deserialize(Stream stream)
{
var ni = new NAMEINFO();
ni.Offset = stream.ReadUInt16();
ni.Length = stream.ReadUInt16();
ni.Flags = stream.ReadUInt16();
ni.ID = stream.ReadUInt16();
ni.Handle = stream.ReadUInt16();
ni.Usage = stream.ReadUInt16();
return ni;
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Relocation item
/// </summary>
/// TODO: Fix this because Marshal will not work since it's not a direct read
[StructLayout(LayoutKind.Sequential)]
internal class NewRlc
{
public char SourceType; // Source type
public char Flags; // Flag byte
public ushort SourceOffset; // Source offset
// nr_intref - Internal Reference
public char TargetSegmentNumber; // Target segment number
public char Reserved1; // Reserved
public ushort TargetEntryTableOffset; // Target Entry Table offset
// nr_import - Import
public ushort ModuleReferenceTableIndex; // Index into Module Reference Table
public ushort ProcedureOffset; // Procedure ordinal or name offset
// nr_osfix - Operating system fixup
public ushort OperatingSystemFixupType; // OSFIXUP type
public ushort Reserved2; // Reserved
public static NewRlc Deserialize(Stream stream)
{
var nr = new NewRlc();
nr.SourceType = stream.ReadChar();
nr.Flags = stream.ReadChar();
nr.SourceOffset = stream.ReadUInt16();
// nr_intref
nr.TargetSegmentNumber = stream.ReadChar();
nr.Reserved1 = stream.ReadChar();
nr.TargetEntryTableOffset = stream.ReadUInt16();
// nr_import
nr.ModuleReferenceTableIndex = BitConverter.ToUInt16(new byte[] { (byte)nr.SourceType, (byte)nr.Flags }, 0);
nr.ProcedureOffset = nr.TargetEntryTableOffset;
// nr_osfix
nr.OperatingSystemFixupType = nr.ModuleReferenceTableIndex;
nr.Reserved2 = nr.ProcedureOffset;
return nr;
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Relocation info
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NewRlcInfo
{
/// <summary>
/// Number of relocation items that follow
/// </summary>
public ushort RelocationItemCount;
public static NewRlcInfo Deserialize(Stream stream)
{
var nri = new NewRlcInfo();
nri.RelocationItemCount = stream.ReadUInt16();
return nri;
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource table
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NewRsrc
{
/// <summary>
/// Alignment shift count for resources
/// </summary>
public ushort AlignmentShiftCount;
public RsrcTypeInfo TypeInfo;
public static NewRsrc Deserialize(Stream stream)
{
var nr = new NewRsrc();
nr.AlignmentShiftCount = stream.ReadUInt16();
nr.TypeInfo = RsrcTypeInfo.Deserialize(stream);
return nr;
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// New .EXE segment table entry
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class NewSeg
{
/// <summary>
/// File sector of start of segment
/// </summary>
public ushort StartFileSector;
/// <summary>
/// Number of bytes in file
/// </summary>
public ushort BytesInFile;
/// <summary>
/// Attribute flags
/// </summary>
public ushort Flags;
/// <summary>
/// Minimum allocation in bytes
/// </summary>
public ushort MinimumAllocation;
public static NewSeg Deserialize(Stream stream)
{
var ns = new NewSeg();
ns.StartFileSector = stream.ReadUInt16();
ns.BytesInFile = stream.ReadUInt16();
ns.Flags = stream.ReadUInt16();
ns.MinimumAllocation = stream.ReadUInt16();
return ns;
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Segment data
/// </summary>
/// TODO: Fix this because Marshal will not work since it's not a direct read
[StructLayout(LayoutKind.Sequential)]
internal class NewSegdata
{
#region ns_iter
/// <summary>
/// Number of iterations
/// </summary>
public ushort Iterations;
/// <summary>
/// Number of bytes
/// </summary>
public ushort TotalBytes;
/// <summary>
/// Iterated data bytes
/// </summary>
public char IteratedDataBytes;
#endregion
#region ns_noiter
/// <summary>
/// Data bytes
/// </summary>
public char DataBytes;
#endregion
public static NewSegdata Deserialize(Stream stream)
{
var nsd = new NewSegdata();
nsd.Iterations = stream.ReadUInt16();
nsd.TotalBytes = stream.ReadUInt16();
nsd.IteratedDataBytes = stream.ReadChar();
nsd.DataBytes = (char)BitConverter.GetBytes(nsd.Iterations)[0];
return nsd;
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class ResourceTable
{
public ushort rscAlignShift;
public TYPEINFO TypeInfo;
public ushort rscEndTypes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)]
public sbyte[][] rscResourceNames;
public byte rscEndNames;
public static ResourceTable Deserialize(Stream stream)
{
var rt = new ResourceTable();
rt.rscAlignShift = stream.ReadUInt16();
rt.TypeInfo = TYPEINFO.Deserialize(stream);
rt.rscEndTypes = stream.ReadUInt16();
rt.rscResourceNames = null; // TODO: Figure out size
rt.rscEndNames = stream.ReadByteValue();
return rt;
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource name information block
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class RsrcNameInfo
{
/*
* The following two fields must be shifted left by the value of
* the rs_align field to compute their actual value. This allows
* resources to be larger than 64k, but they do not need to be
* aligned on 512 byte boundaries, the way segments are.
*/
/// <summary>
/// File offset to resource data
/// </summary>
public ushort Offset;
/// <summary>
/// Length of resource data
/// </summary>
public ushort Length;
/// <summary>
/// Resource flags
/// </summary>
public ushort Flags;
/// <summary>
/// Resource name id
/// </summary>
public ushort NameID;
/// <summary>
/// If loaded, then global handle
/// </summary>
public ushort Handle;
/// <summary>
/// Initially zero. Number of times the handle for this resource has been given out
/// </summary>
public ushort UsageCount;
public static RsrcNameInfo Deserialize(Stream stream)
{
var rni = new RsrcNameInfo();
rni.Offset = stream.ReadUInt16();
rni.Length = stream.ReadUInt16();
rni.Flags = stream.ReadUInt16();
rni.NameID = stream.ReadUInt16();
rni.Handle = stream.ReadUInt16();
rni.UsageCount = stream.ReadUInt16();
return rni;
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource type or name string
/// </summary>
/// TODO: Fix this because SizeConst = 0 is not valid
[StructLayout(LayoutKind.Sequential)]
internal class RsrcString
{
/// <summary>
/// Number of bytes in string
/// </summary>
public byte Length;
/// <summary>
/// Next of string
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)]
public char[] Text;
public static RsrcString Deserialize(Stream stream)
{
var rs = new RsrcString();
rs.Length = stream.ReadByteValue();
rs.Text = stream.ReadChars(rs.Length);
return rs;
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// Resource type information block
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal class RsrcTypeInfo
{
public ushort ID;
public ushort rt_nres;
public uint rt_proc;
public static RsrcTypeInfo Deserialize(Stream stream)
{
var rti = new RsrcTypeInfo();
rti.ID = stream.ReadUInt16();
rti.rt_nres = stream.ReadUInt16();
rti.rt_proc = stream.ReadUInt32();
return rti;
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* NEWEXE.H (C) Copyright Microsoft Corp 1984-1987
*
* Data structure definitions for the OS/2 & Windows
* executable file format.
*
* Modified by IVS on 24-Jan-1991 for Resource DeCompiler
* (C) Copyright IVS 1991
*
* http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h
*/
using System.IO;
using System.Runtime.InteropServices;
namespace BurnOutSharp.ExecutableType.Microsoft
{
[StructLayout(LayoutKind.Sequential)]
internal class TYPEINFO
{
public ushort TypeID;
public ushort ResourceCount;
public uint Reserved;
public NAMEINFO NameInfo;
public static TYPEINFO Deserialize(Stream stream)
{
var ti = new TYPEINFO();
ti.TypeID = stream.ReadUInt16();
ti.ResourceCount = stream.ReadUInt16();
ti.Reserved = stream.ReadUInt32();
ti.NameInfo = NAMEINFO.Deserialize(stream);
return ti;
}
}
}

View File

@@ -1,203 +0,0 @@
using System;
// Converted from https://github.com/wine-mirror/wine/blob/master/include/winnt.h
namespace BurnOutSharp.ExecutableType.Microsoft
{
internal enum DirectoryEntries
{
IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,
IMAGE_DIRECTORY_ENTRY_SECURIT = 4,
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,
IMAGE_DIRECTORY_ENTRY_DEBUG = 6,
IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7,
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, // (MIPS GP)
IMAGE_DIRECTORY_ENTRY_TLS = 9,
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,
IMAGE_DIRECTORY_ENTRY_IAT = 12, // Import Address Table
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14,
}
[Flags]
internal enum DllCharacteristics : ushort
{
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040,
IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100,
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000,
}
[Flags]
internal enum FileCharacteristics : ushort
{
IMAGE_FILE_RELOCS_STRIPPED = 0x0001, /* No relocation info */
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004,
IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008,
IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010,
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
IMAGE_FILE_16BIT_MACHINE = 0x0040,
IMAGE_FILE_BYTES_REVERSED_LO = 0x0080,
IMAGE_FILE_32BIT_MACHINE = 0x0100,
IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400,
IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800,
IMAGE_FILE_SYSTEM = 0x1000,
IMAGE_FILE_DLL = 0x2000,
IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000,
IMAGE_FILE_BYTES_REVERSED_HI = 0x8000,
}
internal enum MachineSettings : ushort
{
IMAGE_FILE_MACHINE_UNKNOWN = 0,
IMAGE_FILE_MACHINE_TARGET_HOST = 0x0001,
IMAGE_FILE_MACHINE_I860 = 0x014d,
IMAGE_FILE_MACHINE_I386 = 0x014c,
IMAGE_FILE_MACHINE_R3000 = 0x0162,
IMAGE_FILE_MACHINE_R4000 = 0x0166,
IMAGE_FILE_MACHINE_R10000 = 0x0168,
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x0169,
IMAGE_FILE_MACHINE_ALPHA = 0x0184,
IMAGE_FILE_MACHINE_SH3 = 0x01a2,
IMAGE_FILE_MACHINE_SH3DSP = 0x01a3,
IMAGE_FILE_MACHINE_SH3E = 0x01a4,
IMAGE_FILE_MACHINE_SH4 = 0x01a6,
IMAGE_FILE_MACHINE_SH5 = 0x01a8,
IMAGE_FILE_MACHINE_ARM = 0x01c0,
IMAGE_FILE_MACHINE_THUMB = 0x01c2,
IMAGE_FILE_MACHINE_ARMNT = 0x01c4,
IMAGE_FILE_MACHINE_ARM64 = 0xaa64,
IMAGE_FILE_MACHINE_AM33 = 0x01d3,
IMAGE_FILE_MACHINE_POWERPC = 0x01f0,
IMAGE_FILE_MACHINE_POWERPCFP = 0x01f1,
IMAGE_FILE_MACHINE_IA64 = 0x0200,
IMAGE_FILE_MACHINE_MIPS16 = 0x0266,
IMAGE_FILE_MACHINE_ALPHA64 = 0x0284,
IMAGE_FILE_MACHINE_MIPSFPU = 0x0366,
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x0466,
IMAGE_FILE_MACHINE_AXP64 = 0x0284,
IMAGE_FILE_MACHINE_TRICORE = 0x0520,
IMAGE_FILE_MACHINE_CEF = 0x0cef,
IMAGE_FILE_MACHINE_EBC = 0x0ebc,
IMAGE_FILE_MACHINE_AMD64 = 0x8664,
IMAGE_FILE_MACHINE_M32R = 0x9041,
IMAGE_FILE_MACHINE_CEE = 0xc0ee,
}
[Flags]
internal enum SectionCharacteristics : uint
{
IMAGE_SCN_TYPE_REG = 0x00000000, // Reserved
IMAGE_SCN_TYPE_DSECT = 0x00000001, // Reserved
IMAGE_SCN_TYPE_NOLOAD = 0x00000002, // Reserved
IMAGE_SCN_TYPE_GROUP = 0x00000004, // Reserved
IMAGE_SCN_TYPE_NO_PAD = 0x00000008, // Reserved
IMAGE_SCN_TYPE_COPY = 0x00000010, // Reserved
IMAGE_SCN_CNT_CODE = 0x00000020,
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
IMAGE_SCN_LNK_OTHER = 0x00000100,
IMAGE_SCN_LNK_INFO = 0x00000200,
IMAGE_SCN_TYPE_OVER = 0x00000400, // Reserved
IMAGE_SCN_LNK_REMOVE = 0x00000800,
IMAGE_SCN_LNK_COMDAT = 0x00001000,
/* 0x00002000 - Reserved */
IMAGE_SCN_MEM_PROTECTED = 0x00004000, // Obsolete
IMAGE_SCN_MEM_FARDATA = 0x00008000,
IMAGE_SCN_MEM_SYSHEAP = 0x00010000, // Obsolete
IMAGE_SCN_MEM_PURGEABLE = 0x00020000,
IMAGE_SCN_MEM_16BIT = 0x00020000,
IMAGE_SCN_MEM_LOCKED = 0x00040000,
IMAGE_SCN_MEM_PRELOAD = 0x00080000,
IMAGE_SCN_ALIGN_1BYTES = 0x00100000,
IMAGE_SCN_ALIGN_2BYTES = 0x00200000,
IMAGE_SCN_ALIGN_4BYTES = 0x00300000,
IMAGE_SCN_ALIGN_8BYTES = 0x00400000,
IMAGE_SCN_ALIGN_16BYTES = 0x00500000, // Default
IMAGE_SCN_ALIGN_32BYTES = 0x00600000,
IMAGE_SCN_ALIGN_64BYTES = 0x00700000,
IMAGE_SCN_ALIGN_128BYTES = 0x00800000,
IMAGE_SCN_ALIGN_256BYTES = 0x00900000,
IMAGE_SCN_ALIGN_512BYTES = 0x00A00000,
IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000,
IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000,
IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000,
IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000,
/* 0x00F00000 - Unused */
IMAGE_SCN_ALIGN_MASK = 0x00F00000,
IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000,
IMAGE_SCN_MEM_DISCARDABLE = 0x02000000,
IMAGE_SCN_MEM_NOT_CACHED = 0x04000000,
IMAGE_SCN_MEM_NOT_PAGED = 0x08000000,
IMAGE_SCN_MEM_SHARED = 0x10000000,
IMAGE_SCN_MEM_EXECUTE = 0x20000000,
IMAGE_SCN_MEM_READ = 0x40000000,
IMAGE_SCN_MEM_WRITE = 0x80000000,
}
internal enum Subsystem : ushort
{
IMAGE_SUBSYSTEM_UNKNOWN = 0,
IMAGE_SUBSYSTEM_NATIVE = 1,
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Windows GUI subsystem
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Windows character subsystem
IMAGE_SUBSYSTEM_OS2_CUI = 5,
IMAGE_SUBSYSTEM_POSIX_CUI = 7,
IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8, // native Win9x driver
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9, // Windows CE subsystem
IMAGE_SUBSYSTEM_EFI_APPLICATION = 10,
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
IMAGE_SUBSYSTEM_EFI_ROM = 13,
IMAGE_SUBSYSTEM_XBOX = 14,
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16,
}
internal static class Constants
{
public const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; /* MZ */
public const ushort IMAGE_OS2_SIGNATURE = 0x454E; /* NE */
public const ushort IMAGE_OS2_SIGNATURE_LE = 0x454C; /* LE */
public const ushort IMAGE_OS2_SIGNATURE_LX = 0x584C; /* LX */
public const ushort IMAGE_VXD_SIGNATURE = 0x454C; /* LE */
public const uint IMAGE_NT_SIGNATURE = 0x00004550; /* PE00 */
public const int IMAGE_SIZEOF_FILE_HEADER = 20;
public const int IMAGE_SIZEOF_ROM_OPTIONAL_HEADER = 56;
public const int IMAGE_SIZEOF_STD_OPTIONAL_HEADER = 28;
public const int IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224;
public const int IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240;
public const int IMAGE_SIZEOF_SHORT_NAME = 8;
public const int IMAGE_SIZEOF_SECTION_HEADER = 40;
public const int IMAGE_SIZEOF_SYMBOL = 18;
public const int IMAGE_SIZEOF_AUX_SYMBOL = 18;
public const int IMAGE_SIZEOF_RELOCATION = 10;
public const int IMAGE_SIZEOF_BASE_RELOCATION = 8;
public const int IMAGE_SIZEOF_LINENUMBER = 6;
public const int IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60;
// Possible Magic values
public const ushort IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
public const ushort IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
public const ushort IMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x107;
public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
}
}

109
BurnOutSharp/Extensions.cs Normal file
View File

@@ -0,0 +1,109 @@
using System;
using System.IO;
using System.Text;
namespace BurnOutSharp
{
internal static class Ebuffertensions
{
/// <summary>
/// Read a byte from the stream
/// </summary>
public static byte ReadByteValue(this Stream stream)
{
byte[] buffer = new byte[1];
stream.Read(buffer, 0, 1);
return buffer[0];
}
/// <summary>
/// Read a byte array from the stream
/// </summary>
public static byte[] ReadBytes(this Stream stream, int count)
{
byte[] buffer = new byte[count];
stream.Read(buffer, 0, count);
return buffer;
}
/// <summary>
/// Read a character from the stream
/// </summary>
public static char ReadChar(this Stream stream)
{
byte[] buffer = new byte[1];
stream.Read(buffer, 0, 1);
return (char)buffer[0];
}
/// <summary>
/// Read a character array from the stream
/// </summary>
public static char[] ReadChars(this Stream stream, int count)
{
byte[] buffer = new byte[count];
stream.Read(buffer, 0, count);
return Encoding.Default.GetString(buffer).ToCharArray();
}
/// <summary>
/// Read a short from the stream
/// </summary>
public static short ReadInt16(this Stream stream)
{
byte[] buffer = new byte[2];
stream.Read(buffer, 0, 2);
return BitConverter.ToInt16(buffer, 0);
}
/// <summary>
/// Read a ushort from the stream
/// </summary>
public static ushort ReadUInt16(this Stream stream)
{
byte[] buffer = new byte[2];
stream.Read(buffer, 0, 2);
return BitConverter.ToUInt16(buffer, 0);
}
/// <summary>
/// Read an int from the stream
/// </summary>
public static int ReadInt32(this Stream stream)
{
byte[] buffer = new byte[4];
stream.Read(buffer, 0, 4);
return BitConverter.ToInt32(buffer, 0);
}
/// <summary>
/// Read a uint from the stream
/// </summary>
public static uint ReadUInt32(this Stream stream)
{
byte[] buffer = new byte[4];
stream.Read(buffer, 0, 4);
return BitConverter.ToUInt32(buffer, 0);
}
/// <summary>
/// Read a long from the stream
/// </summary>
public static long ReadInt64(this Stream stream)
{
byte[] buffer = new byte[8];
stream.Read(buffer, 0, 8);
return BitConverter.ToInt64(buffer, 0);
}
/// <summary>
/// Read a ulong from the stream
/// </summary>
public static ulong ReadUInt64(this Stream stream)
{
byte[] buffer = new byte[8];
stream.Read(buffer, 0, 8);
return BitConverter.ToUInt64(buffer, 0);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
BurnOutSharp/External/LessIO vendored Submodule

View File

@@ -1,414 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp
{
public class MpqArchive : IDisposable
{
private MpqArchiveSafeHandle _handle;
private List<MpqFileStream> _openFiles = new List<MpqFileStream>();
private FileAccess _accessType;
private List<MpqArchiveCompactingEventHandler> _compactCallbacks = new List<MpqArchiveCompactingEventHandler>();
private SFILE_COMPACT_CALLBACK _compactCallback;
#region Constructors / Factories
public MpqArchive(string filePath, FileAccess accessType)
{
_accessType = accessType;
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(filePath, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
public MpqArchive(MemoryMappedFile file, FileAccess accessType)
{
_accessType = accessType;
string fileName = Win32Methods.GetFileNameOfMemoryMappedFile(file);
if (fileName == null)
throw new ArgumentException("Could not retrieve the name of the file to initialize.");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsMemoryMapped;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(fileName, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
private MpqArchive(string filePath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes, MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
if (maxFileCount < 0)
throw new ArgumentException("maxFileCount");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile | SFileOpenArchiveFlags.AccessReadWriteShare;
flags |= (SFileOpenArchiveFlags)version;
//SFILE_CREATE_MPQ create = new SFILE_CREATE_MPQ()
//{
// cbSize = unchecked((uint)Marshal.SizeOf(typeof(SFILE_CREATE_MPQ))),
// dwMaxFileCount = unchecked((uint)maxFileCount),
// dwMpqVersion = (uint)version,
// dwFileFlags1 = (uint)listfileAttributes,
// dwFileFlags2 = (uint)attributesFileAttributes,
// dwStreamFlags = (uint)flags,
//};
//if (!NativeMethods.SFileCreateArchive2(filePath, ref create, out _handle))
// throw new Win32Exception();
if (!NativeMethods.SFileCreateArchive(filePath, (uint)flags, int.MaxValue, out _handle))
throw new Win32Exception();
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version)
{
return CreateNew(mpqPath, version, MpqFileStreamAttributes.None, MpqFileStreamAttributes.None, int.MaxValue);
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes,
MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
return new MpqArchive(mpqPath, version, listfileAttributes, attributesFileAttributes, maxFileCount);
}
#endregion
#region Properties
// TODO: Move to common location.
// This is a global setting, not per-archive setting.
//public int Locale
//{
// get
// {
// throw new NotImplementedException();
// }
// set
// {
// throw new NotImplementedException();
// }
//}
public long MaxFileCount
{
get
{
VerifyHandle();
return NativeMethods.SFileGetMaxFileCount(_handle);
}
set
{
if (value < 0 || value > uint.MaxValue)
throw new ArgumentException("value");
VerifyHandle();
if (!NativeMethods.SFileSetMaxFileCount(_handle, unchecked((uint)value)))
throw new Win32Exception();
}
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid)
throw new ObjectDisposedException("MpqArchive");
}
public bool IsPatchedArchive
{
get
{
VerifyHandle();
return NativeMethods.SFileIsPatchedArchive(_handle);
}
}
#endregion
public void Flush()
{
VerifyHandle();
if (!NativeMethods.SFileFlushArchive(_handle))
throw new Win32Exception();
}
public int AddListFile(string listfileContents)
{
VerifyHandle();
return NativeMethods.SFileAddListFile(_handle, listfileContents);
}
public void AddFileFromDisk(string filePath, string archiveName)
{
VerifyHandle();
if (!NativeMethods.SFileAddFile(_handle, filePath, archiveName, 0))
throw new Win32Exception();
}
public void Compact(string listfile)
{
VerifyHandle();
if (!NativeMethods.SFileCompactArchive(_handle, listfile, false))
throw new Win32Exception();
}
private void _OnCompact(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes)
{
MpqArchiveCompactingEventArgs args = new MpqArchiveCompactingEventArgs(dwWorkType, bytesProcessed, totalBytes);
OnCompacting(args);
}
protected virtual void OnCompacting(MpqArchiveCompactingEventArgs e)
{
foreach (var cb in _compactCallbacks)
{
cb(this, e);
}
}
public event MpqArchiveCompactingEventHandler Compacting
{
add
{
VerifyHandle();
_compactCallback = _OnCompact;
if (!NativeMethods.SFileSetCompactCallback(_handle, _compactCallback, IntPtr.Zero))
throw new Win32Exception();
_compactCallbacks.Add(value);
}
remove
{
_compactCallbacks.Remove(value);
VerifyHandle();
if (_compactCallbacks.Count == 0)
{
if (!NativeMethods.SFileSetCompactCallback(_handle, null, IntPtr.Zero))
{
// Don't do anything here. Remove shouldn't fail hard.
}
}
}
}
// TODO: Determine if SFileGetAttributes/SFileSetAttributes/SFileUpdateFileAttributes deserves a projection.
// It's unclear - these seem to affect the (attributes) file but I can't figure out exactly what that means.
public void AddPatchArchive(string patchPath)
{
VerifyHandle();
if (!NativeMethods.SFileOpenPatchArchive(_handle, patchPath, null, 0))
throw new Win32Exception();
}
public void AddPatchArchives(IEnumerable<string> patchPaths)
{
if (patchPaths == null)
throw new ArgumentNullException("patchPaths");
VerifyHandle();
foreach (string path in patchPaths)
{
// Don't sublet to AddPatchArchive to avoid having to repeatedly call VerifyHandle()
if (!NativeMethods.SFileOpenPatchArchive(_handle, path, null, 0))
throw new Win32Exception();
}
}
public bool HasFile(string fileToFind)
{
VerifyHandle();
return NativeMethods.SFileHasFile(_handle, fileToFind);
}
public MpqFileStream OpenFile(string fileName)
{
VerifyHandle();
MpqFileSafeHandle fileHandle;
if (!NativeMethods.SFileOpenFileEx(_handle, fileName, 0, out fileHandle))
throw new Win32Exception();
MpqFileStream fs = new MpqFileStream(fileHandle, _accessType, this);
_openFiles.Add(fs);
return fs;
}
public void ExtractFile(string fileToExtract, string destinationPath)
{
VerifyHandle();
if (!NativeMethods.SFileExtractFile(_handle, fileToExtract, destinationPath, 0))
throw new Win32Exception();
}
public MpqFileVerificationResults VerifyFile(string fileToVerify)
{
VerifyHandle();
return (MpqFileVerificationResults)NativeMethods.SFileVerifyFile(_handle, fileToVerify, 0);
}
// TODO: Consider SFileVerifyRawData
public MpqArchiveVerificationResult VerifyArchive()
{
VerifyHandle();
return (MpqArchiveVerificationResult)NativeMethods.SFileVerifyArchive(_handle);
}
#region IDisposable implementation
public void Dispose()
{
Dispose(true);
}
~MpqArchive()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Release owned files first.
if (_openFiles != null)
{
foreach (var file in _openFiles)
{
file.Dispose();
}
_openFiles.Clear();
_openFiles = null;
}
// Release
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
}
}
internal void RemoveOwnedFile(MpqFileStream file)
{
_openFiles.Remove(file);
}
#endregion
}
public enum MpqArchiveVersion
{
Version1 = 0,
Version2 = 0x01000000,
Version3 = 0x02000000,
Version4 = 0x03000000,
}
[Flags]
public enum MpqFileStreamAttributes
{
None = 0x0,
}
[Flags]
public enum MpqFileVerificationResults
{
/// <summary>
/// There were no errors with the file.
/// </summary>
Verified = 0,
/// <summary>
/// Failed to open the file
/// </summary>
Error = 0x1,
/// <summary>
/// Failed to read all data from the file
/// </summary>
ReadError = 0x2,
/// <summary>
/// File has sector CRC
/// </summary>
HasSectorCrc = 0x4,
/// <summary>
/// Sector CRC check failed
/// </summary>
SectorCrcError = 0x8,
/// <summary>
/// File has CRC32
/// </summary>
HasChecksum = 0x10,
/// <summary>
/// CRC32 check failed
/// </summary>
ChecksumError = 0x20,
/// <summary>
/// File has data MD5
/// </summary>
HasMd5 = 0x40,
/// <summary>
/// MD5 check failed
/// </summary>
Md5Error = 0x80,
/// <summary>
/// File has raw data MD5
/// </summary>
HasRawMd5 = 0x100,
/// <summary>
/// Raw MD5 check failed
/// </summary>
RawMd5Error = 0x200,
}
public enum MpqArchiveVerificationResult
{
/// <summary>
/// There is no signature in the MPQ
/// </summary>
NoSignature = 0,
/// <summary>
/// There was an error during verifying signature (like no memory)
/// </summary>
VerificationFailed = 1,
/// <summary>
/// There is a weak signature and sign check passed
/// </summary>
WeakSignatureVerified = 2,
/// <summary>
/// There is a weak signature but sign check failed
/// </summary>
WeakSignatureFailed = 3,
/// <summary>
/// There is a strong signature and sign check passed
/// </summary>
StrongSignatureVerified = 4,
/// <summary>
/// There is a strong signature but sign check failed
/// </summary>
StrongSignatureFailed = 5,
}
}

View File

@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp
{
public delegate void MpqArchiveCompactingEventHandler(MpqArchive sender, MpqArchiveCompactingEventArgs e);
public class MpqArchiveCompactingEventArgs : EventArgs
{
internal MpqArchiveCompactingEventArgs(uint dwWorkType, ulong processed, ulong total)
{
unchecked
{
WorkType = (MpqCompactingWorkType)dwWorkType;
BytesProcessed = (long)processed;
TotalBytes = (long)total;
}
}
public MpqCompactingWorkType WorkType
{
get;
private set;
}
public long BytesProcessed
{
get;
private set;
}
public long TotalBytes
{
get;
private set;
}
}
public enum MpqCompactingWorkType
{
CheckingFiles = 1,
CheckingHashTable = 2,
CopyingNonMpqData = 3,
CompactingFiles = 4,
ClosingArchive = 5,
}
}

View File

@@ -1,185 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace StormLibSharp
{
public class MpqFileStream : Stream
{
private MpqFileSafeHandle _handle;
private FileAccess _accessType;
private MpqArchive _owner;
internal MpqFileStream(MpqFileSafeHandle handle, FileAccess accessType, MpqArchive owner)
{
_handle = handle;
_accessType = accessType;
_owner = owner;
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid || _handle.IsClosed)
throw new ObjectDisposedException("MpqFileStream");
}
public override bool CanRead
{
get { VerifyHandle(); return true; }
}
public override bool CanSeek
{
get { VerifyHandle(); return true; }
}
public override bool CanWrite
{
get { VerifyHandle(); return _accessType != FileAccess.Read; }
}
public override void Flush()
{
VerifyHandle();
_owner.Flush();
}
public override long Length
{
get
{
VerifyHandle();
uint high = 0;
uint low = NativeMethods.SFileGetFileSize(_handle, ref high);
ulong val = (high << 32) | low;
return unchecked((long)val);
}
}
public override long Position
{
get
{
VerifyHandle();
return NativeMethods.SFileGetFilePointer(_handle);
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
public override unsafe int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
uint read;
fixed (byte* pb = &buffer[offset])
{
NativeOverlapped overlapped = default(NativeOverlapped);
success = NativeMethods.SFileReadFile(_handle, new IntPtr(pb), unchecked((uint)count), out read, ref overlapped);
}
if (!success)
{
int lastError = Win32Methods.GetLastError();
if (lastError != 38) // EOF
throw new Win32Exception(lastError);
}
return unchecked((int)read);
}
public override long Seek(long offset, SeekOrigin origin)
{
VerifyHandle();
uint low, high;
low = unchecked((uint)(offset & 0xffffffffu));
high = unchecked((uint)(offset >> 32));
return NativeMethods.SFileSetFilePointer(_handle, low, ref high, (uint)origin);
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override unsafe void Write(byte[] buffer, int offset, int count)
{
VerifyHandle();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
fixed (byte* pb = &buffer[offset])
{
success = NativeMethods.SFileWriteFile(_handle, new IntPtr(pb), unchecked((uint)count), 0u);
}
if (!success)
throw new Win32Exception();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
if (_owner != null)
{
_owner.RemoveOwnedFile(this);
_owner = null;
}
}
}
// TODO: Seems like the right place for SFileGetFileInfo, but will need to determine
// what value add these features have except for sophisticated debugging purposes
// (like in Ladis' MPQ Editor app).
public int ChecksumCrc32
{
get
{
throw new NotImplementedException();
}
}
public byte[] GetMd5Hash()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_DOWNLOAD_CALLBACK(IntPtr pvUserData, ulong byteOffset, uint dwTotalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_COMPACT_CALLBACK(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_ADDFILE_CALLBACK(IntPtr pvUserData, uint dwBytesWritte, uint dwTotalBytes, bool bFinalCall);
}

View File

@@ -1,26 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqArchiveSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqArchiveSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqArchiveSafeHandle()
: base(true) { }
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseArchive(this.handle);
}
}
}

View File

@@ -1,27 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqFileSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqFileSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqFileSafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseFile(this.handle);
}
}
}

View File

@@ -1,497 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class NativeMethods
{
private const string STORMLIB = "stormlib.dll";
#region Functions for manipulation with StormLib global flags
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetLocale();
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetLocale(uint lcNewLocale);
#endregion
#region Functions for archive manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwPriority,
SFileOpenArchiveFlags dwFlags,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwCreateFlags,
uint dwMaxFileCount,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive2(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
ref SFILE_CREATE_MPQ pCreateInfo,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDownloadCallback(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.FunctionPtr)] SFILE_DOWNLOAD_CALLBACK pfnCallback,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFlushArchive(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(IntPtr hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Adds another listfile into MPQ.
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileAddListFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
#endregion
#region Archive compacting
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetCompactCallback(
MpqArchiveSafeHandle hMpq,
SFILE_COMPACT_CALLBACK compactCB,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCompactArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
bool bReserved
);
#endregion
#region Maximum file count
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetMaxFileCount(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetMaxFileCount(MpqArchiveSafeHandle hMpq, uint dwMaxFileCount);
#endregion
#region Changing (attributes) file
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetAttributes(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAttributes(MpqArchiveSafeHandle hMpq, uint dwFlags);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileUpdateFileAttributes(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
#endregion
#region Functions for manipulation with patch archives
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenPatchArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szPatchMpqName,
[MarshalAs(UnmanagedType.LPStr)] string szPatchPathPrefix,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileIsPatchedArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileHasFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope,
out MpqFileSafeHandle phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetFileSize(MpqFileSafeHandle hFile, ref uint pdwFileSizeHigh);
public static unsafe uint SFileGetFilePointer(
MpqFileSafeHandle hFile
)
{
if (hFile.IsInvalid || hFile.IsClosed)
throw new InvalidOperationException();
IntPtr handle = hFile.DangerousGetHandle();
_TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
return header->dwFilePos;
}
//public static unsafe uint SFileGetFileSize(
// MpqFileSafeHandle hFile
// )
//{
// if (hFile.IsInvalid || hFile.IsClosed)
// throw new InvalidOperationException();
// IntPtr handle = hFile.DangerousGetHandle();
// _TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
// return header->pFileEntry->dwFileSize;
//}
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetFilePointer(
MpqFileSafeHandle hFile,
uint lFilePos,
ref uint plFilePosHigh,
uint dwMoveMethod
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileReadFile(
MpqFileSafeHandle hFile,
IntPtr lpBuffer,
uint dwToRead,
out uint pdwRead,
ref System.Threading.NativeOverlapped lpOverlapped
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(IntPtr hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(MpqFileSafeHandle hFile);
#region Retrieving info about a file in the archive
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
IntPtr hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqArchiveSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqFileSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileName(
MpqFileSafeHandle hFile,
[MarshalAs(UnmanagedType.LPStr)] out string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFreeFileInfo(
IntPtr pvFileInfo,
SFileInfoClass infoClass
);
#endregion
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileExtractFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szToExtract,
[MarshalAs(UnmanagedType.LPTStr)] string szExtracted,
uint dwSearchScope
);
#endregion
#region Functions for file and archive verification
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileChecksums(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
out uint pdwCrc32,
IntPtr pMD5
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileVerifyRawData(
MpqArchiveSafeHandle hMpq,
uint dwWhatToVerify,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file searching
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
out _SFILE_FIND_DATA lpFindFileData,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindClose(IntPtr hFind);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SListFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindClose(IntPtr hFind);
#endregion
#region Locale support
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileEnumLocales(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
IntPtr plcLocales,
ref uint pdwMaxLocales,
uint dwSearchScope
);
#endregion
#region Support for adding files to the MPQ
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szArchiveName,
ulong fileTime,
uint dwFileSize,
uint lcLocale,
uint dwFlags,
out IntPtr phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileWriteFile(
MpqFileSafeHandle hFile,
IntPtr pvData,
uint dwSize,
uint dwCompression
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFinishFile(MpqFileSafeHandle hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwCompression,
uint dwCompressionNext
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddWave(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwQuality
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRemoveFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRenameFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szOldFileName,
[MarshalAs(UnmanagedType.LPStr)] string szNewFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetFileLocale(
MpqFileSafeHandle hFile,
uint lcNewLocale
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDataCompression(uint DataCompression);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAddFileCallback(
MpqArchiveSafeHandle hMpq,
SFILE_ADDFILE_CALLBACK AddFileCB,
IntPtr pvUserData
);
#endregion
#region Compression and decompression
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompImplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompExplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompCompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer,
uint uCompressionMask,
int nCmpType,
int nCmpLevel
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress2(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
#endregion
}
#pragma warning disable 0169,0649
internal struct SFILE_CREATE_MPQ
{
public uint cbSize;
public uint dwMpqVersion;
private IntPtr pvUserData;
private uint cbUserData;
public uint dwStreamFlags;
public uint dwFileFlags1;
public uint dwFileFlags2;
public uint dwAttrFlags;
public uint dwSectorSize;
public uint dwRawChunkSize;
public uint dwMaxFileCount;
}
internal unsafe struct _SFILE_FIND_DATA
{
public fixed char cFileName[260]; // Full name of the found file
public IntPtr szPlainName; // Plain name of the found file
public uint dwHashIndex; // Hash table index for the file
public uint dwBlockIndex; // Block table index for the file
public uint dwFileSize; // File size in bytes
public uint dwFileFlags; // MPQ file flags
public uint dwCompSize; // Compressed file size
public uint dwFileTimeLo; // Low 32-bits of the file time (0 if not present)
public uint dwFileTimeHi; // High 32-bits of the file time (0 if not present)
public uint lcLocale; // Locale version
}
internal unsafe struct _TFileEntry
{
public ulong FileNameHash;
public ulong ByteOffset;
public ulong FileTime;
public uint dwHashIndex;
public uint dwFileSize;
public uint dwCmpSize;
public uint dwFlags;
public ushort lcLocale;
public ushort wPlatform;
public uint dwCrc32;
public fixed byte md5[16];
public IntPtr szFileName;
}
// Provides enough of _TMPQFile to get to the file size and current position.
internal unsafe struct _TMPQFileHeader
{
public IntPtr pStream;
public IntPtr ha;
public _TFileEntry* pFileEntry;
public uint dwFileKey;
public uint dwFilePos;
}
#pragma warning restore 0169,0649
}

View File

@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal enum SFileInfoClass
{
// Info classes for archives
SFileMpqFileName, // Name of the archive file (TCHAR [])
SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE [])
SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG)
SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData)
SFileMpqUserData, // MPQ USer data, without the header (BYTE [])
SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG)
SFileMpqHeaderSize, // Fixed size of the MPQ header
SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader)
SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG)
SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG)
SFileMpqHetHeader, // HET table header (TMPQHetHeader)
SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG)
SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG)
SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[])
SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG)
SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG)
SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD)
SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock [])
SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG)
SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG)
SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD)
SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock [])
SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG)
SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG)
SFileMpqHiBlockTable, // The hi-block table (USHORT [])
SFileMpqSignatures, // Signatures present in the MPQ (DWORD)
SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG)
SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD)
SFileMpqStrongSignature, // The strong signature (BYTE [])
SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG)
SFileMpqArchiveSize, // Archive size from the header (DWORD)
SFileMpqMaxFileCount, // Max number of files in the archive (DWORD)
SFileMpqFileTableSize, // Number of entries in the file table (DWORD)
SFileMpqSectorSize, // Sector size (DWORD)
SFileMpqNumberOfFiles, // Number of files (DWORD)
SFileMpqRawChunkSize, // Size of the raw data chunk for MD5
SFileMpqStreamFlags, // Stream flags (DWORD)
SFileMpqIsReadOnly, // Nonzero if the MPQ is read only (DWORD)
// Info classes for files
SFileInfoPatchChain, // Chain of patches where the file is (TCHAR [])
SFileInfoFileEntry, // The file entry for the file (TFileEntry)
SFileInfoHashEntry, // Hash table entry for the file (TMPQHash)
SFileInfoHashIndex, // Index of the hash table entry (DWORD)
SFileInfoNameHash1, // The first name hash in the hash table (DWORD)
SFileInfoNameHash2, // The second name hash in the hash table (DWORD)
SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG)
SFileInfoLocale, // File locale (DWORD)
SFileInfoFileIndex, // Block index (DWORD)
SFileInfoByteOffset, // File position in the archive (ULONGLONG)
SFileInfoFileTime, // File time (ULONGLONG)
SFileInfoFileSize, // Size of the file (DWORD)
SFileInfoCompressedSize, // Compressed file size (DWORD)
SFileInfoFlags, // File flags from (DWORD)
SFileInfoEncryptionKey, // File encryption key
SFileInfoEncryptionKeyRaw, // Unfixed value of the file key
}
}

View File

@@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
[Flags]
internal enum SFileOpenArchiveFlags : uint
{
None = 0,
TypeIsFile = None,
TypeIsMemoryMapped = 1,
TypeIsHttp = 2,
AccessReadOnly = 0x100,
AccessReadWriteShare = 0x200,
AccessUseBitmap = 0x400,
DontOpenListfile = 0x10000,
DontOpenAttributes = 0x20000,
DontSearchHeader = 0x40000,
ForceVersion1 = 0x80000,
CheckSectorCRC = 0x100000,
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class Win32Methods
{
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetMappedFileName(
IntPtr hProcess,
IntPtr fileHandle,
IntPtr lpFilename,
uint nSize
);
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetFinalPathNameByHandle(
IntPtr hFile,
IntPtr lpszFilePath,
uint cchFilePath,
uint dwFlags
);
[DllImport("kernel32", SetLastError = false, ExactSpelling = false)]
public static extern int GetLastError();
public static string GetFileNameOfMemoryMappedFile(MemoryMappedFile file)
{
const uint size = 522;
IntPtr path = Marshal.AllocCoTaskMem(unchecked((int)size)); // MAX_PATH + 1 char
string result = null;
try
{
// constant 0x2 = VOLUME_NAME_NT
uint test = GetFinalPathNameByHandle(file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size, 0x2);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
catch
{
uint test = GetMappedFileName(Process.GetCurrentProcess().Handle, file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
return result;
}
}
}

1
BurnOutSharp/External/hllib vendored Submodule

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using SharpCompress.Compressors;
@@ -7,17 +7,31 @@ using SharpCompress.Compressors.Deflate;
namespace BurnOutSharp.FileType
{
internal class BFPK
internal class BFPK : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x42, 0x46, 0x50, 0x4b }))
if (magic.StartsWith(new byte?[] { 0x42, 0x46, 0x50, 0x4b }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the BFPK file itself fails
try

View File

@@ -1,25 +1,39 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
namespace BurnOutSharp.FileType
{
internal class BZip2
internal class BZip2 : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x42, 0x52, 0x68 }))
if (magic.StartsWith(new byte?[] { 0x42, 0x52, 0x68 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
// If the 7-zip file itself fails
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the BZip2 file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

View File

@@ -1,298 +1,128 @@
using System.Collections.Generic;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using BurnOutSharp.PackerType;
using BurnOutSharp.ProtectionType;
using System.Threading.Tasks;
namespace BurnOutSharp.FileType
{
internal class Executable
internal class Executable : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
private static readonly IEnumerable<IContentCheck> contentCheckClasses = InitContentCheckClasses();
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// DOS MZ executable file format (and descendants)
if (magic.StartsWith(new byte[] { 0x4d, 0x5a }))
if (magic.StartsWith(new byte?[] { 0x4d, 0x5a }))
return true;
// Executable and Linkable Format
if (magic.StartsWith(new byte[] { 0x7f, 0x45, 0x4c, 0x46 }))
if (magic.StartsWith(new byte?[] { 0x7f, 0x45, 0x4c, 0x46 }))
return true;
// Mach-O binary (32-bit)
if (magic.StartsWith(new byte[] { 0xfe, 0xed, 0xfa, 0xce }))
if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xce }))
return true;
// Mach-O binary (32-bit, reverse byte ordering scheme)
if (magic.StartsWith(new byte[] { 0xce, 0xfa, 0xed, 0xfe }))
if (magic.StartsWith(new byte?[] { 0xce, 0xfa, 0xed, 0xfe }))
return true;
// Mach-O binary (64-bit)
if (magic.StartsWith(new byte[] { 0xfe, 0xed, 0xfa, 0xcf }))
if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xcf }))
return true;
// Mach-O binary (64-bit, reverse byte ordering scheme)
if (magic.StartsWith(new byte[] { 0xcf, 0xfa, 0xed, 0xfe }))
if (magic.StartsWith(new byte?[] { 0xcf, 0xfa, 0xed, 0xfe }))
return true;
// Prefrred Executable File Format
if (magic.StartsWith(new byte[] { 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66 }))
if (magic.StartsWith(new byte?[] { 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream, string file = null)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Files can be protected in multiple ways
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
// Load the current file content
byte[] fileContent = null;
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
try
{
fileContent = br.ReadBytes((int)stream.Length);
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
{
fileContent = br.ReadBytes((int)stream.Length);
}
}
catch
{
Utilities.AppendToDictionary(protections, file, "[File too large to be scanned]");
return protections;
}
// If we can, seek to the beginning of the stream
if (stream.CanSeek)
stream.Seek(0, SeekOrigin.Begin);
// Files can be protected in multiple ways
var protections = new Dictionary<string, List<string>>();
var subProtections = new Dictionary<string, List<string>>();
string protection;
#region Protections
// 3PLock
protection = ThreePLock.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// 321Studios Online Activation
protection = ThreeTwoOneStudios.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// ActiveMARK
protection = ActiveMARK.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Alpha-ROM
protection = AlphaROM.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Cactus Data Shield
protection = CactusDataShield.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// CD-Cops
protection = CDCops.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// CD-Lock
protection = CDLock.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// CDSHiELD SE
protection = CDSHiELDSE.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// CD Check
protection = CDCheck.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Cenega ProtectDVD
protection = CengaProtectDVD.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Code Lock
protection = CodeLock.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// CopyKiller
protection = CopyKiller.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// DVD-Cops
protection = DVDCops.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// EA Protections
protection = ElectronicArts.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Games for Windows - Live
protection = GFWL.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Impulse Reactor
protection = ImpulseReactor.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Inno Setup
protection = InnoSetup.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// INTENIUM Trial & Buy Protection
protection = Intenium.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// JoWooD X-Prot
protection = JoWooDXProt.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Key-Lock (Dongle)
protection = KeyLock.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// LaserLock
protection = LaserLock.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// MediaMax CD-3
protection = MediaMaxCD3.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// ProtectDisc
protection = ProtectDisc.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Ring PROTECH
protection = RingPROTECH.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SafeDisc / SafeCast
protection = SafeDisc.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SafeLock
protection = SafeLock.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SecuROM
protection = SecuROM.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SmartE
protection = SmartE.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SolidShield
protection = SolidShield.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// StarForce
protection = StarForce.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// SVK Protector
protection = SVKProtector.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Sysiphus / Sysiphus DVD
protection = Sysiphus.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// TAGES
protection = Tages.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// VOB ProtectCD/DVD
protection = VOBProtectCDDVD.CheckContents(file, fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Wise Installer
subProtections = WiseInstaller.CheckContents(scanner, file, fileContent);
if (subProtections != null && subProtections.Count > 0)
Utilities.AppendToDictionary(protections, subProtections);
// WTM CD Protect
protection = WTMCDProtect.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// XCP 1/2
protection = XCP.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// Xtreme-Protector
protection = XtremeProtector.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
#endregion
#region Packers
// If we're looking for packers too, run scans
if (scanner.ScanPackers)
// Iterate through all content checks
Parallel.ForEach(contentCheckClasses, contentCheckClass =>
{
string protection = contentCheckClass.CheckContents(file, fileContent, scanner.IncludePosition);
// Armadillo
protection = Armadillo.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// If we have a valid content check based on settings
if (!contentCheckClass.GetType().Namespace.ToLowerInvariant().Contains("packertype") || scanner.ScanPackers)
{
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
}
// dotFuscator
protection = dotFuscator.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// EXE Stealth
protection = EXEStealth.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// NSIS
protection = NSIS.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// PE Compact
protection = PECompact.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
// UPX
protection = UPX.CheckContents(fileContent, scanner.IncludePosition);
if (!string.IsNullOrWhiteSpace(protection))
Utilities.AppendToDictionary(protections, file, protection);
}
#endregion
// If we have an IScannable implementation
if (contentCheckClass is IScannable)
{
IScannable scannable = contentCheckClass as IScannable;
if (file != null && !string.IsNullOrEmpty(protection))
{
var subProtections = scannable.Scan(scanner, null, file);
Utilities.PrependToKeys(subProtections, file);
Utilities.AppendToDictionary(protections, subProtections);
}
}
});
return protections;
}
/// <summary>
/// Initialize all IContentCheck implementations
/// </summary>
private static IEnumerable<IContentCheck> InitContentCheckClasses()
{
return Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.IsClass && t.GetInterface(nameof(IContentCheck)) != null)
.Select(t => Activator.CreateInstance(t) as IContentCheck);
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Archives;
@@ -6,17 +7,31 @@ using SharpCompress.Archives.GZip;
namespace BurnOutSharp.FileType
{
internal class GZIP
internal class GZIP : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x1f, 0x8b }))
if (magic.StartsWith(new byte?[] { 0x1f, 0x8b }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the gzip file itself fails
try

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnshieldSharp.Archive;
namespace BurnOutSharp.FileType
{
internal class InstallShieldArchiveV3 : IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte?[] { 0x13, 0x5D, 0x65, 0x8C }))
return true;
return false;
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Get the name of the first cabinet file or header
string directory = Path.GetDirectoryName(file);
string noExtension = Path.GetFileNameWithoutExtension(file);
string filenamePattern = Path.Combine(directory, noExtension);
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr"));
bool shouldScanCabinet = cabinetHeaderExists
? file.Equals(Path.Combine(directory, filenamePattern + "1.hdr"), StringComparison.OrdinalIgnoreCase)
: file.Equals(Path.Combine(directory, filenamePattern + "1.cab"), StringComparison.OrdinalIgnoreCase);
// If we have the first file
if (shouldScanCabinet)
{
// If the cab file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file);
foreach (CompressedFile cfile in archive.Files.Select(kvp => kvp.Value))
{
// If an individual entry fails
try
{
string tempFile = Path.Combine(tempPath, cfile.FullPath);
if (!Directory.Exists(Path.GetDirectoryName(tempFile)))
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
(byte[] fileContents, string error) = archive.Extract(cfile.FullPath);
if (!string.IsNullOrWhiteSpace(error))
continue;
using (FileStream fs = File.OpenWrite(tempFile))
{
fs.Write(fileContents, 0, fileContents.Length);
}
}
catch { }
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch { }
}
return null;
}
}
}

View File

@@ -1,23 +1,37 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text.RegularExpressions;
using UnshieldSharp;
using UnshieldSharp.Cabinet;
namespace BurnOutSharp.FileType
{
internal class InstallShieldCAB
internal class InstallShieldCAB : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x49, 0x53, 0x63 }))
if (magic.StartsWith(new byte?[] { 0x49, 0x53, 0x63 }))
return true;
return false;
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
public static Dictionary<string, List<string>> Scan(Scanner scanner, string file)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Get the name of the first cabinet file or header
string directory = Path.GetDirectoryName(file);
@@ -39,7 +53,7 @@ namespace BurnOutSharp.FileType
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
UnshieldCabinet cabfile = UnshieldCabinet.Open(file);
InstallShieldCabinet cabfile = InstallShieldCabinet.Open(file);
for (int i = 0; i < cabfile.FileCount; i++)
{
// If an individual entry fails

View File

@@ -1,22 +1,37 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using StormLibSharp;
namespace BurnOutSharp.FileType
{
internal class MPQ
internal class MPQ : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x4d, 0x50, 0x51, 0x1a }))
if (magic.StartsWith(new byte?[] { 0x4d, 0x50, 0x51, 0x1a }))
return true;
return false;
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
public static Dictionary<string, List<string>> Scan(Scanner scanner, string file)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the mpq file itself fails
try

View File

@@ -1,28 +1,38 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
#if NET_FRAMEWORK
using Microsoft.Deployment.WindowsInstaller;
#endif
using WixToolset.Dtf.WindowsInstaller;
namespace BurnOutSharp.FileType
{
internal class MSI
internal class MSI : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
#if NET_FRAMEWORK
if (magic.StartsWith(new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }))
if (magic.StartsWith(new byte?[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }))
return true;
#endif
return false;
}
// TODO: Add stream opening support
public static Dictionary<string, List<string>> Scan(Scanner scanner, string file)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
#if NET_FRAMEWORK
// If the MSI file itself fails
try
{
@@ -50,7 +60,6 @@ namespace BurnOutSharp.FileType
return protections;
}
catch { }
#endif
return null;
}

View File

@@ -1,29 +1,39 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
#if NET_FRAMEWORK
using LibMSPackN;
#endif
namespace BurnOutSharp.FileType
{
// Specification available at http://download.microsoft.com/download/5/0/1/501ED102-E53F-4CE0-AA6B-B0F93629DDC6/Exchange/%5BMS-CAB%5D.pdf
internal class MicrosoftCAB
internal class MicrosoftCAB : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
#if NET_FRAMEWORK
if (magic.StartsWith(new byte[] { 0x4d, 0x53, 0x43, 0x46 }))
if (magic.StartsWith(new byte?[] { 0x4d, 0x53, 0x43, 0x46 }))
return true;
#endif
return false;
}
// TODO: Add stream opening support
public static Dictionary<string, List<string>> Scan(Scanner scanner, string file)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
#if NET_FRAMEWORK
// If the cab file itself fails
try
{
@@ -61,7 +71,6 @@ namespace BurnOutSharp.FileType
return protections;
}
catch { }
#endif
return null;
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Archives;
@@ -6,26 +7,40 @@ using SharpCompress.Archives.Zip;
namespace BurnOutSharp.FileType
{
internal class PKZIP
internal class PKZIP : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// PKZIP
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x03, 0x04 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x03, 0x04 }))
return true;
// PKZIP (Empty Archive)
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x05, 0x06 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x05, 0x06 }))
return true;
// PKZIP (Spanned Archive)
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x07, 0x08 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x07, 0x08 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the zip file itself fails
try

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Archives;
@@ -6,22 +7,36 @@ using SharpCompress.Archives.Rar;
namespace BurnOutSharp.FileType
{
internal class RAR
internal class RAR : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// RAR archive version 1.50 onwards
if (magic.StartsWith(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }))
return true;
// RAR archive version 5.0 onwards
if (magic.StartsWith(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the rar file itself fails
try

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Archives;
@@ -6,17 +7,31 @@ using SharpCompress.Archives.SevenZip;
namespace BurnOutSharp.FileType
{
internal class SevenZip
internal class SevenZip : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))
if (magic.StartsWith(new byte?[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the 7-zip file itself fails
try

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Archives;
@@ -6,20 +7,34 @@ using SharpCompress.Archives.Tar;
namespace BurnOutSharp.FileType
{
internal class TapeArchive
internal class TapeArchive : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 }))
if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 }))
return true;
if (magic.StartsWith(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the tar file itself fails
try

View File

@@ -1,40 +1,67 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace BurnOutSharp.FileType
{
internal class Textfile
internal class Textfile : IScannable
{
public static bool ShouldScan(byte[] magic, string extension)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
return ShouldScan(magic, null);
}
/// <summary>
/// Determine if a file signature or extension matches one of the expected values
/// </summary>
/// <param name="magic">Byte array representing the file header</param>
/// <param name="extension">Extension for the file being checked</param>
/// <returns>True if the signature is valid, false otherwise</returns>
public bool ShouldScan(byte[] magic, string extension)
{
// Rich Text File
if (magic.StartsWith(new byte[] { 0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31 }))
if (magic.StartsWith(new byte?[] { 0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31 }))
return true;
// HTML
if (magic.StartsWith(new byte[] { 0x3c, 0x68, 0x74, 0x6d, 0x6c }))
if (magic.StartsWith(new byte?[] { 0x3c, 0x68, 0x74, 0x6d, 0x6c }))
return true;
// HTML and XML
if (magic.StartsWith(new byte[] { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45 }))
if (magic.StartsWith(new byte?[] { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45 }))
return true;
// Microsoft Office File (old)
if (magic.StartsWith(new byte[] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }))
if (magic.StartsWith(new byte?[] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }))
return true;
// Generic textfile (no header)
if (string.Equals(extension.TrimStart('.'), "txt", StringComparison.OrdinalIgnoreCase))
if (string.Equals(extension?.TrimStart('.'), "txt", StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public static List<string> Scan(Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Files can be protected in multiple ways
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
try
{
@@ -47,13 +74,17 @@ namespace BurnOutSharp.FileType
// CD-Key
if (fileContent.Contains("a valid serial number is required"))
protections.Add("CD-Key / Serial");
Utilities.AppendToDictionary(protections, file, "CD-Key / Serial");
else if (fileContent.Contains("serial number is located"))
protections.Add("CD-Key / Serial");
Utilities.AppendToDictionary(protections, file, "CD-Key / Serial");
// MediaMax
if (fileContent.Contains("MediaMax technology"))
protections.Add("MediaMax CD-3");
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
// XCP
if (fileContent.Contains("http://cp.sonybmg.com/xcp/"))
Utilities.AppendToDictionary(protections, file, "XCP");
}
catch
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,36 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Compressors.Xz;
namespace BurnOutSharp.FileType
{
internal class XZ
internal class XZ : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 }))
if (magic.StartsWith(new byte?[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 }))
return true;
return false;
}
public static Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the xz file itself fails
try

View File

@@ -0,0 +1,15 @@
namespace BurnOutSharp
{
internal interface IContentCheck
{
/// <summary>
/// Check a path for protections based on file contents
/// </summary>
/// <param name="file">File to check for protection indicators</param>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
/// TODO: This should be replaced with a "GenerateMatchers" that produces a list of matchers to be run instead
string CheckContents(string file, byte[] fileContent, bool includePosition);
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace BurnOutSharp
{
internal interface IPathCheck
{
/// <summary>
/// Check a file path for protections based on path name
/// </summary>
/// <param name="path">Path to check for protection indicators</param>
/// <param name="files">Enumerable of strings representing files in a directory</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use IContentCheck instead, if possible</remarks>
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files);
/// <summary>
/// Check a file path for protections based on path name
/// </summary>
/// <param name="path">Path to check for protection indicators</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use IContentCheck instead, if possible</remarks>
string CheckFilePath(string path);
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Concurrent;
using System.IO;
namespace BurnOutSharp
{
internal interface IScannable
{
/// <summary>
/// Determine if a file signature matches one of the expected values
/// </summary>
/// <param name="magic">Byte array representing the file header</param>
/// <returns>True if the signature is valid, false otherwise</returns>
bool ShouldScan(byte[] magic);
/// <summary>
/// Scan a file for all internal protections
/// </summary>
/// <param name="scanner">Scanner object for state tracking</param>
/// <param name="file">Path to the input file</param>
/// <returns>Dictionary mapping paths to protection lists</returns>
/// <remarks>Ideally, this should just point to the other scan implementation</remarks>
ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file);
/// <summary>
/// Scan a stream for all internal protections
/// </summary>
/// <param name="scanner">Scanner object for state tracking</param>
/// <param name="stream">Stream representing the input file</param>
/// <param name="file">Path to the input file</param>
/// <returns>Dictionary mapping paths to protection lists</returns>
ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string filename);
}
}

View File

@@ -0,0 +1,104 @@
namespace BurnOutSharp.Matching
{
/// <summary>
/// Content matching criteria
/// </summary>
internal class ContentMatch : IMatch<byte?[]>
{
/// <summary>
/// Content to match
/// </summary>
public byte?[] Needle { get; set; }
/// <summary>
/// Starting index for matching
/// </summary>
public int Start { get; set; }
/// <summary>
/// Ending index for matching
/// </summary>
public int End { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="needle">Byte array representing the search</param>
/// <param name="start">Optional starting index</param>
/// <param name="end">Optional ending index</param>
public ContentMatch(byte?[] needle, int start = -1, int end = -1)
{
Needle = needle;
Start = start;
End = end;
}
#region Matching
/// <summary>
/// Get if this match can be found in a stack
/// </summary>
/// <param name="stack">Array to search for the given content</param>
/// <param name="reverse">True to search from the end of the array, false from the start</param>
/// <returns>Tuple of success and found position</returns>
public (bool success, int position) Match(byte[] stack, bool reverse = false)
{
// If either array is null or empty, we can't do anything
if (stack == null || stack.Length == 0 || Needle == null || Needle.Length == 0)
return (false, -1);
// If the needle array is larger than the stack array, it can't be contained within
if (Needle.Length > stack.Length)
return (false, -1);
// If start or end are not set properly, set them to defaults
if (Start < 0)
Start = 0;
if (End < 0)
End = stack.Length - Needle.Length;
for (int i = reverse ? End : Start; reverse ? i > Start : i < End; i += reverse ? -1 : 1)
{
// If we somehow have an invalid end and we haven't matched, return
if (i > stack.Length)
return (false, -1);
// Check to see if the values are equal
if (EqualAt(stack, i))
return (true, i);
}
return (false, -1);
}
/// <summary>
/// Get if a stack at a certain index is equal to a needle
/// </summary>
/// <param name="stack">Array to search for the given content</param>
/// <param name="index">Starting index to check equality</param>
/// <returns>True if the needle matches the stack at a given index</returns>
private bool EqualAt(byte[] stack, int index)
{
// If the index is invalid, we can't do anything
if (index < 0)
return false;
// If we're too close to the end of the stack, return false
if (Needle.Length >= stack.Length - index)
return false;
for (int i = 0; i < Needle.Length; i++)
{
// A null value is a wildcard
if (Needle[i] == null)
continue;
else if (stack[i + index] != Needle[i])
return false;
}
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BurnOutSharp.Matching
{
/// <summary>
/// A set of content matches that work together
/// </summary>
internal class ContentMatchSet : MatchSet<ContentMatch, byte?[]>
{
/// <summary>
/// Function to get a content version
/// </summary>
/// <remarks>
/// A content version method takes the file path, the file contents,
/// and a list of found positions and returns a single string. That
/// string is either a version string, in which case it will be appended
/// to the protection name, or `null`, in which case it will cause
/// the protection to be omitted.
/// </remarks>
public Func<string, byte[], List<int>, string> GetVersion { get; set; }
#region Constructors
public ContentMatchSet(byte?[] needle, string protectionName)
: this(new List<byte?[]> { needle }, null, protectionName) { }
public ContentMatchSet(List<byte?[]> needles, string protectionName)
: this(needles, null, protectionName) { }
public ContentMatchSet(byte?[] needle, Func<string, byte[], List<int>, string> getVersion, string protectionName)
: this(new List<byte?[]> { needle }, getVersion, protectionName) { }
public ContentMatchSet(List<byte?[]> needles, Func<string, byte[], List<int>, string> getVersion, string protectionName)
: this(needles.Select(n => new ContentMatch(n)).ToList(), getVersion, protectionName) { }
public ContentMatchSet(ContentMatch needle, string protectionName)
: this(new List<ContentMatch>() { needle }, null, protectionName) { }
public ContentMatchSet(List<ContentMatch> needles, string protectionName)
: this(needles, null, protectionName) { }
public ContentMatchSet(ContentMatch needle, Func<string, byte[], List<int>, string> getVersion, string protectionName)
: this(new List<ContentMatch>() { needle }, getVersion, protectionName) { }
public ContentMatchSet(List<ContentMatch> needles, Func<string, byte[], List<int>, string> getVersion, string protectionName)
{
Matchers = needles;
GetVersion = getVersion;
ProtectionName = protectionName;
}
#endregion
#region Matching
/// <summary>
/// Determine whether all content matches pass
/// </summary>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <returns>Tuple of passing status and matching positions</returns>
public (bool, List<int>) MatchesAll(byte[] fileContent)
{
// If no content matches are defined, we fail out
if (Matchers == null || !Matchers.Any())
return (false, new List<int>());
// Initialize the position list
List<int> positions = new List<int>();
// Loop through all content matches and make sure all pass
foreach (var contentMatch in Matchers)
{
(bool match, int position) = contentMatch.Match(fileContent);
if (!match)
return (false, new List<int>());
else
positions.Add(position);
}
return (true, positions);
}
/// <summary>
/// Determine whether any content matches pass
/// </summary>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <returns>Tuple of passing status and first matching position</returns>
public (bool, int) MatchesAny(byte[] fileContent)
{
// If no content matches are defined, we fail out
if (Matchers == null || !Matchers.Any())
return (false, -1);
// Loop through all content matches and make sure all pass
foreach (var contentMatch in Matchers)
{
(bool match, int position) = contentMatch.Match(fileContent);
if (match)
return (true, position);
}
return (false, -1);
}
#endregion
}
}

View File

@@ -0,0 +1,7 @@
namespace BurnOutSharp.Matching
{
internal interface IMatch<T>
{
T Needle { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
namespace BurnOutSharp.Matching
{
/// <summary>
/// Wrapper for a single set of matching criteria
/// </summary>
internal abstract class MatchSet<T, U> where T : IMatch<U>
{
/// <summary>
/// Set of all matchers
/// </summary>
public IEnumerable<T> Matchers { get; set; }
/// <summary>
/// Name of the protection to show
/// </summary>
public string ProtectionName { get; set; }
}
}

View File

@@ -0,0 +1,238 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace BurnOutSharp.Matching
{
/// <summary>
/// Helper class for matching
/// </summary>
internal static class MatchUtil
{
#region Content Matching
/// <summary>
/// Get all content matches for a given list of matchers
/// </summary>
/// <param name="file">File to check for matches</param>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
public static ConcurrentQueue<string> GetAllMatches(
string file,
byte[] fileContent,
IEnumerable<ContentMatchSet> matchers,
bool includePosition = false)
{
return FindAllMatches(file, fileContent, matchers, includePosition, false);
}
/// <summary>
/// Get first content match for a given list of matchers
/// </summary>
/// <param name="file">File to check for matches</param>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <returns>String representing the matched protection, null otherwise</returns>
public static string GetFirstMatch(
string file,
byte[] fileContent,
IEnumerable<ContentMatchSet> matchers,
bool includePosition = false)
{
var contentMatches = FindAllMatches(file, fileContent, matchers, includePosition, true);
if (contentMatches == null || !contentMatches.Any())
return null;
return contentMatches.First();
}
/// <summary>
/// Get the required set of content matches on a per Matcher basis
/// </summary>
/// <param name="file">File to check for matches</param>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
private static ConcurrentQueue<string> FindAllMatches(
string file,
byte[] fileContent,
IEnumerable<ContentMatchSet> matchers,
bool includePosition,
bool stopAfterFirst)
{
// If there's no mappings, we can't match
if (matchers == null || !matchers.Any())
return null;
// Initialize the queue of matched protections
var matchedProtections = new ConcurrentQueue<string>();
// Loop through and try everything otherwise
foreach (var matcher in matchers)
{
// Determine if the matcher passes
(bool passes, List<int> positions) = matcher.MatchesAll(fileContent);
if (!passes)
continue;
// Format the list of all positions found
string positionsString = string.Join(", ", positions);
// If we there is no version method, just return the protection name
if (matcher.GetVersion == null)
{
matchedProtections.Enqueue((matcher.ProtectionName ?? "Unknown Protection") + (includePosition ? $" (Index {positionsString})" : string.Empty));
}
// Otherwise, invoke the version method
else
{
// A null version returned means the check didn't pass at the version step
string version = matcher.GetVersion(file, fileContent, positions);
if (version == null)
continue;
matchedProtections.Enqueue($"{matcher.ProtectionName ?? "Unknown Protection"} {version}".TrimEnd() + (includePosition ? $" (Index {positionsString})" : string.Empty));
}
// If we're stopping after the first protection, bail out here
if (stopAfterFirst)
return matchedProtections;
}
return matchedProtections;
}
#endregion
#region Path Matching
/// <summary>
/// Get all path matches for a given list of matchers
/// </summary>
/// <param name="file">File path to check for matches</param>
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
/// <param name="any">True if any path match is a success, false if all have to match</param>
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
public static ConcurrentQueue<string> GetAllMatches(string file, IEnumerable<PathMatchSet> matchers, bool any = false)
{
return FindAllMatches(new List<string> { file }, matchers, any, false);
}
// <summary>
/// Get all path matches for a given list of matchers
/// </summary>
/// <param name="files">File paths to check for matches</param>
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
/// <param name="any">True if any path match is a success, false if all have to match</param>
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
public static ConcurrentQueue<string> GetAllMatches(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any = false)
{
return FindAllMatches(files, matchers, any, false);
}
/// <summary>
/// Get first path match for a given list of matchers
/// </summary>
/// <param name="file">File path to check for matches</param>
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
/// <param name="any">True if any path match is a success, false if all have to match</param>
/// <returns>String representing the matched protection, null otherwise</returns>
public static string GetFirstMatch(string file, IEnumerable<PathMatchSet> matchers, bool any = false)
{
var contentMatches = FindAllMatches(new List<string> { file }, matchers, any, true);
if (contentMatches == null || !contentMatches.Any())
return null;
return contentMatches.First();
}
/// <summary>
/// Get first path match for a given list of matchers
/// </summary>
/// <param name="files">File paths to check for matches</param>
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
/// <param name="any">True if any path match is a success, false if all have to match</param>
/// <returns>String representing the matched protection, null otherwise</returns>
public static string GetFirstMatch(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any = false)
{
var contentMatches = FindAllMatches(files, matchers, any, true);
if (contentMatches == null || !contentMatches.Any())
return null;
return contentMatches.First();
}
/// <summary>
/// Get the required set of path matches on a per Matcher basis
/// </summary>
/// <param name="files">File paths to check for matches</param>
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
/// <param name="any">True if any path match is a success, false if all have to match</param>
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
private static ConcurrentQueue<string> FindAllMatches(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any, bool stopAfterFirst)
{
// If there's no mappings, we can't match
if (matchers == null || !matchers.Any())
return new ConcurrentQueue<string>();
// Initialize the list of matched protections
var matchedProtections = new ConcurrentQueue<string>();
// Loop through and try everything otherwise
foreach (var matcher in matchers)
{
// Determine if the matcher passes
bool passes;
string firstMatchedString;
if (any)
{
(bool anyPasses, string matchedString) = matcher.MatchesAny(files);
passes = anyPasses;
firstMatchedString = matchedString;
}
else
{
(bool allPasses, List<string> matchedStrings) = matcher.MatchesAll(files);
passes = allPasses;
firstMatchedString = matchedStrings.FirstOrDefault();
}
// If we don't have a pass, just continue
if (!passes)
continue;
// If we there is no version method, just return the protection name
if (matcher.GetVersion == null)
{
matchedProtections.Enqueue(matcher.ProtectionName ?? "Unknown Protection");
}
// Otherwise, invoke the version method
else
{
// A null version returned means the check didn't pass at the version step
string version = matcher.GetVersion(firstMatchedString, files);
if (version == null)
continue;
matchedProtections.Enqueue($"{matcher.ProtectionName ?? "Unknown Protection"} {version}".TrimEnd());
}
// If we're stopping after the first protection, bail out here
if (stopAfterFirst)
return matchedProtections;
}
return matchedProtections;
}
#endregion
}
}

View File

@@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.Linq;
namespace BurnOutSharp.Matching
{
/// <summary>
/// Path matching criteria
/// </summary>
internal class PathMatch : IMatch<string>
{
/// <summary>
/// String to match
/// </summary>
public string Needle { get; set; }
/// <summary>
/// Match exact casing instead of invariant
/// </summary>
public bool MatchExact { get; set; }
/// <summary>
/// Match that values end with the needle and not just contains
/// </summary>
public bool UseEndsWith { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="needle">String representing the search</param>
/// <param name="matchExact">True to match exact casing, false otherwise</param>
/// <param name="useEndsWith">True to match the end only, false for all contents</param>
public PathMatch(string needle, bool matchExact = false, bool useEndsWith = false)
{
Needle = needle;
MatchExact = matchExact;
UseEndsWith = useEndsWith;
}
#region Matching
/// <summary>
/// Get if this match can be found in a stack
/// </summary>
/// <param name="stack">List of strings to search for the given content</param>
/// <returns>Tuple of success and matched item</returns>
public (bool, string) Match(IEnumerable<string> stack)
{
// If either array is null or empty, we can't do anything
if (stack == null || !stack.Any() || Needle == null || Needle.Length == 0)
return (false, null);
// Preprocess the needle, if necessary
string procNeedle = MatchExact ? Needle : Needle.ToLowerInvariant();
foreach (string stackItem in stack)
{
// Preprocess the stack item, if necessary
string procStackItem = MatchExact ? stackItem : stackItem.ToLowerInvariant();
if (UseEndsWith && procStackItem.EndsWith(procNeedle))
return (true, stackItem);
else if (!UseEndsWith && procStackItem.Contains(procNeedle))
return (true, stackItem);
}
return (false, null);
}
#endregion
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BurnOutSharp.Matching
{
/// <summary>
/// A set of path matches that work together
/// </summary>
internal class PathMatchSet : MatchSet<PathMatch, string>
{
/// <summary>
/// Function to get a path version for this Matcher
/// </summary>
/// <remarks>
/// A path version method takes the matched path and an enumerable of files
/// and returns a single string. That string is either a version string,
/// in which case it will be appended to the protection name, or `null`,
/// in which case it will cause the protection to be omitted.
/// </remarks>
public Func<string, IEnumerable<string>, string> GetVersion { get; set; }
#region Constructors
public PathMatchSet(string needle, string protectionName)
: this(new List<string> { needle }, null, protectionName) { }
public PathMatchSet(List<string> needles, string protectionName)
: this(needles, null, protectionName) { }
public PathMatchSet(string needle, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
: this(new List<string> { needle }, getVersion, protectionName) { }
public PathMatchSet(List<string> needles, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
: this(needles.Select(n => new PathMatch(n)).ToList(), getVersion, protectionName) { }
public PathMatchSet(PathMatch needle, string protectionName)
: this(new List<PathMatch>() { needle }, null, protectionName) { }
public PathMatchSet(List<PathMatch> needles, string protectionName)
: this(needles, null, protectionName) { }
public PathMatchSet(PathMatch needle, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
: this(new List<PathMatch>() { needle }, getVersion, protectionName) { }
public PathMatchSet(List<PathMatch> needles, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
{
Matchers = needles;
GetVersion = getVersion;
ProtectionName = protectionName;
}
#endregion
#region Matching
/// <summary>
/// Determine whether all path matches pass
/// </summary>
/// <param name="stack">List of strings to try to match</param>
/// <returns>Tuple of passing status and matching values</returns>
public (bool, List<string>) MatchesAll(IEnumerable<string> stack)
{
// If no path matches are defined, we fail out
if (Matchers == null || !Matchers.Any())
return (false, new List<string>());
// Initialize the value list
List<string> values = new List<string>();
// Loop through all path matches and make sure all pass
foreach (var pathMatch in Matchers)
{
(bool match, string value) = pathMatch.Match(stack);
if (!match)
return (false, new List<string>());
else
values.Add(value);
}
return (true, values);
}
/// <summary>
/// Determine whether any path matches pass
/// </summary>
/// <param name="stack">List of strings to try to match</param>
/// <returns>Tuple of passing status and first matching value</returns>
public (bool, string) MatchesAny(IEnumerable<string> stack)
{
// If no path matches are defined, we fail out
if (Matchers == null || !Matchers.Any())
return (false, null);
// Loop through all path matches and make sure all pass
foreach (var pathMatch in Matchers)
{
(bool match, string value) = pathMatch.Match(stack);
if (match)
return (true, value);
}
return (false, null);
}
#endregion
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
// TODO: Add extraction and verify that all versions are detected
public class AdvancedInstaller : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// Software\Caphyon\Advanced Installer
new ContentMatchSet(new byte?[]
{
0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
0x5C, 0x43, 0x61, 0x70, 0x68, 0x79, 0x6F, 0x6E,
0x5C, 0x41, 0x64, 0x76, 0x61, 0x6E, 0x63, 0x65,
0x64, 0x20, 0x49, 0x6E, 0x73, 0x74, 0x61, 0x6C,
0x6C, 0x65, 0x72
}, "Caphyon Advanced Installer"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -1,20 +1,23 @@
namespace BurnOutSharp.PackerType
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class Armadillo
public class Armadillo : IContentCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// ".nicode" + (char)0x00
byte[] check = new byte[] { 0x2E, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00 };
if (fileContent.Contains(check, out int position))
return $"Armadillo" + (includePosition ? $" (Index {position})" : string.Empty);
var matchers = new List<ContentMatchSet>
{
// .nicode + (char)0x00
new ContentMatchSet(new byte?[] { 0x2E, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00 }, "Armadillo"),
// "ARMDEBUG"
check = new byte[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 };
if (fileContent.Contains(check, out position))
return $"Armadillo" + (includePosition ? $" (Index {position})" : string.Empty);
// ARMDEBUG
new ContentMatchSet(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, "Armadillo"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -0,0 +1,55 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
// The official website for CExe also includes the source code (which does have to be retrieved by the Wayback Machine)
// http://www.scottlu.com/Content/CExe.html
public class CExe : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// %Wo<57>a6.<2E>a6.<2E>a6.<2E>a6.<2E>{6.<2E>.).<2E>f6.<2E><>).<2E>`6.<2E><>0.<2E>`6.<2E>
new ContentMatchSet(
new ContentMatch(new byte?[]
{
0x25, 0x57, 0x6F, 0xC1, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x01, 0x92, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x00, 0x92, 0x7B, 0x36, 0x01, 0x92,
0x03, 0x29, 0x12, 0x92, 0x66, 0x36, 0x01, 0x92,
0x89, 0x29, 0x0A, 0x92, 0x60, 0x36, 0x01, 0x92,
0xD9, 0x30, 0x07, 0x92, 0x60, 0x36, 0x01, 0x92
}, end: 200), "CExe"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
// TODO: Add extraction if viable
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
return null;
}
}
}

View File

@@ -1,15 +1,27 @@
namespace BurnOutSharp.PackerType
{
public class EXEStealth
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
{
// "??[[__[[_" + (char)0x00 + "{{" + (char)0x0 + (char)0x00 + "{{" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "?;??;??"
byte[] check = new byte[] { 0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B, 0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F, 0x3F };
if (fileContent.Contains(check, out int position))
return $"EXE Stealth" + (includePosition ? $" (Index {position})" : string.Empty);
using System.Collections.Generic;
using BurnOutSharp.Matching;
return null;
namespace BurnOutSharp.PackerType
{
public class EXEStealth : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new ContentMatchSet(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
0x3F
}, "EXE Stealth"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class InnoSetup : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// Inno Setup Setup Data (
new ContentMatchSet(new byte?[]
{
0x49, 0x6E, 0x6E, 0x6F, 0x20, 0x53, 0x65, 0x74,
0x75, 0x70, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70,
0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x28
}, GetVersion, "Inno Setup"),
// Inno
new ContentMatchSet(
new ContentMatch(new byte?[] { 0x49, 0x6E, 0x6E, 0x6F }, start: 0x30, end: 0x31),
GetOldVersion,
"Inno Setup"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TOOO: Add Inno Setup extraction
// https://github.com/dscharrer/InnoExtract
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
return null;
}
public static string GetOldVersion(string file, byte[] fileContent, List<int> positions)
{
var matchers = new List<ContentMatchSet>
{
// "rDlPtS02" + (char)0x87 + "eVx"
new ContentMatchSet(new byte?[] { 0x72, 0x44, 0x6C, 0x50, 0x74, 0x53, 0x30, 0x32, 0x87, 0x65, 0x56, 0x78 }, "1.2.16 or earlier"),
};
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, false);
return match ?? "Unknown 1.X";
}
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
try
{
int index = positions[0];
index += 23;
var versionBytes = new ReadOnlySpan<byte>(fileContent, index, 16).ToArray();
var onlyVersion = versionBytes.TakeWhile(b => b != ')').ToArray();
index += onlyVersion.Length + 2;
var unicodeBytes = new ReadOnlySpan<byte>(fileContent, index, 3).ToArray();
string version = Encoding.ASCII.GetString(onlyVersion);
if (unicodeBytes.SequenceEqual(new byte[] { 0x28, 0x75, 0x29 }))
return (version + " (Unicode)");
return version;
}
catch
{
return "(Unknown Version)";
}
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class InstallerVISE : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
//TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds.
// ViseMain
new ContentMatchSet(
new ContentMatch(new byte?[] { 0x56, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, start: 0xE0A4, end: 0xE0A5),
"Installer VISE"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
// TODO: Add Installer VISE extraction
// https://github.com/Bioruebe/UniExtract2
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
return null;
}
}
}

View File

@@ -1,35 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class NSIS
public class NSIS : IContentCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// Nullsoft Install System
byte[] check = new byte[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d };
if (fileContent.Contains(check, out int position))
var matchers = new List<ContentMatchSet>
{
string version = GetVersion(fileContent, position);
return $"NSIS {version}" + (includePosition ? $" (Index {position})" : string.Empty);
}
// Nullsoft Install System
new ContentMatchSet(new byte?[]
{
0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74,
0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c,
0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d
}, GetVersion, "NSIS"),
// NullsoftInst
check = new byte[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x49, 0x6e, 0x73, 0x74 };
if (fileContent.Contains(check, out position))
{
return $"NSIS" + (includePosition ? $" (Index {position})" : string.Empty);
}
// NullsoftInst
new ContentMatchSet(new byte?[]
{
0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74,
0x49, 0x6e, 0x73, 0x74
}, "NSIS"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
private static string GetVersion(byte[] fileContent, int index)
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
try
{
int index = positions[0];
index += 24;
if (fileContent[index] != 'v')
return "(Unknown Version)";

View File

@@ -1,15 +1,42 @@
namespace BurnOutSharp.PackerType
{
public class PECompact
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
{
// "PEC2"
byte[] check = new byte[] { 0x50, 0x45, 0x43, 0x32 };
if (fileContent.Contains(check, out int position))
return "PE Compact 2" + (includePosition ? $" (Index {position})" : string.Empty);
using System;
using System.Collections.Generic;
using BurnOutSharp.Matching;
return null;
namespace BurnOutSharp.PackerType
{
// TODO: Add extraction and better version detection
public class PECompact : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// Another possible version string for version 1 is "PECO" (50 45 43 4F)
var matchers = new List<ContentMatchSet>
{
// pec1
new ContentMatchSet(new ContentMatch(new byte?[] { 0x70, 0x65, 0x63, 0x31 }, end: 2048), "PE Compact 1"),
// PEC2
new ContentMatchSet(new ContentMatch(new byte?[] { 0x50, 0x45, 0x43, 0x32 }, end: 2048), GetVersion, "PE Compact 2"),
// PECompact2
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63,
0x74, 0x32
}, "PE Compact 2"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
// TODO: Improve version detection, Protection ID is able to detect ranges of versions. For example, 1.66-1.84 or 2.20-3.02.
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
short version = BitConverter.ToInt16(fileContent, positions[0] + 4);
if (version == 0)
return string.Empty;
return $"(Internal Version {version})";
}
}
}

View File

@@ -0,0 +1,86 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class SetupFactory : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// S.e.t.u.p. .F.a.c.t.o.r.y.
new ContentMatchSet(new byte?[]
{
0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00,
0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00,
0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00,
0x79, 0x00
}, GetVersion, "Setup Factory"),
// Longer version of the check that can be used if false positves become an issue:
// S.e.t.u.p. .F.a.c.t.o.r.y. .i.s. .a. .t.r.a.d.e.m.a.r.k. .o.f. .I.n.d.i.g.o. .R.o.s.e. .C.o.r.p.o.r.a.t.i.o.n.
// new ContentMatchSet(new byte?[]
// {
// 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00,
// 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00,
// 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00,
// 0x79, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00,
// 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x74, 0x00,
// 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00,
// 0x6D, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6B, 0x00,
// 0x20, 0x00, 0x6F, 0x00, 0x66, 0x00, 0x20, 0x00,
// 0x49, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x69, 0x00,
// 0x67, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x52, 0x00,
// 0x6F, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00,
// 0x43, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x70, 0x00,
// 0x6F, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00,
// 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00
// }, GetVersion, "Setup Factory"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
// TODO: Add extraction, which is possible but the only tools available that can
// do this seem to be Universal Extractor 2 and InstallExplorer (https://totalcmd.net/plugring/InstallExplorer.html)
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
return null;
}
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
// Check the manifest version first
string version = Utilities.GetManifestVersion(fileContent);
if (!string.IsNullOrEmpty(version))
return version;
// Then check the file version
version = Utilities.GetFileVersion(file);
if (!string.IsNullOrEmpty(version))
return version;
return "(Unknown Version)";
}
}
}

View File

@@ -1,26 +1,58 @@
using System.Collections.Generic;
using System.Text;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
public class UPX
public class UPX : IContentCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// UPX!
byte[] check = new byte[] { 0x55, 0x50, 0x58, 0x21 };
if (fileContent.Contains(check, out int position))
var matchers = new List<ContentMatchSet>
{
string version = GetVersion(fileContent, position);
return $"UPX {version}" + (includePosition ? $" (Index {position})" : string.Empty);
}
// UPX!
new ContentMatchSet(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "UPX"),
return null;
// NOS
new ContentMatchSet(
new ContentMatch(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, end: 2048),
GetVersion,
"UPX (NOS Variant)"),
new ContentMatchSet(
new List<byte?[]>
{
// UPX0
new byte?[] { 0x55, 0x50, 0x58, 0x30 },
// UPX1
new byte?[] { 0x55, 0x50, 0x58, 0x31 },
},
"UPX (Unknown Version)"
),
new ContentMatchSet(
new List<byte?[]>
{
// NOS0
new byte?[] { 0x4E, 0x4F, 0x53, 0x30 },
// NOS1
new byte?[] { 0x4E, 0x4F, 0x53, 0x31 },
},
"UPX (NOS Variant) (Unknown Version)"
),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
private static string GetVersion(byte[] fileContent, int index)
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
try
{
int index = positions[0];
index -= 5;
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (!char.IsNumber(versionString[0]))

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
namespace BurnOutSharp.PackerType
{
public class WinRARSFX : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// Software\WinRAR SFX
new ContentMatchSet(new byte?[]
{
0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
0x5C, 0x57, 0x69, 0x6E, 0x52, 0x41, 0x52, 0x20,
0x53, 0x46, 0x58
}, "WinRAR SFX"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the rar file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Should be using stream instead of file, but stream fails to extract anything. My guess is that the executable portion of the archive is causing stream to fail, but not file.
using (RarArchive zipFile = RarArchive.Open(file, new SharpCompress.Readers.ReaderOptions() {LookForHeader = true}))
{
foreach (var entry in zipFile.Entries)
{
// If an individual entry fails
try
{
// If we have a directory, skip it
if (entry.IsDirectory)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch { }
}
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch { }
return null;
}
}
}

View File

@@ -0,0 +1,687 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
namespace BurnOutSharp.PackerType
{
public class WinZipSFX : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// WinZip Self-Extractor
new ContentMatchSet(new byte?[]
{
0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
0x61, 0x63, 0x74, 0x6F, 0x72
}, GetVersion, "WinZip SFX"),
// _winzip_
new ContentMatchSet(new byte?[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F }, GetVersion, "WinZip SFX"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
// TODO: Find a way to generically detect 2.X versions and improve exact version detection for SFX PE versions bundled with WinZip 11+
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the zip file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Should be using stream instead of file, but stream fails to extract anything. My guess is that the executable portion of the archive is causing stream to fail, but not file.
using (ZipArchive zipFile = ZipArchive.Open(file))
{
foreach (var entry in zipFile.Entries)
{
// If an individual entry fails
try
{
// If we have a directory, skip it
if (entry.IsDirectory)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch { }
}
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch { }
return null;
}
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
// Check the manifest version first
string version = Utilities.GetManifestVersion(fileContent);
string description = Utilities.GetManifestDescription(fileContent);
if (description != "WinZip Self-Extractor")
return GetV2Version(file, fileContent);
if (!string.IsNullOrEmpty(version))
return GetV3PlusVersion(file, fileContent, version);
// Assume an earlier version
return GetV2Version(file, fileContent);
}
private static string GetV2Version(string file, byte[] fileContent)
{
var matchers = new List<ContentMatchSet>
{
#region 16-bit NE Header Checks
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0xE6, 0x2B, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6C, 0x00, 0xB8, 0x44, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.0 (MS-DOS/16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0x74, 0x31, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6C, 0x00, 0x98, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.0 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0xA0, 0x24, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Compact 2.0 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xCD, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0xFA, 0x36, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x97, 0x00,
0xA3, 0x00, 0xAD, 0x00, 0xDF, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Software Installation 2.0 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0x86, 0x33, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6C, 0x00, 0xC8, 0x43, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.1 RC2 (MS-DOS/16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0x56, 0x3E, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.1 RC2 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0x84, 0x2B, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Compact 2.1 RC2 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0xAC, 0x43, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Software Installation 2.1 RC2 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x3A, 0x96, 0x33, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6C, 0x00, 0xC8, 0x43, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.1 (MS-DOS/16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x3A, 0x7E, 0x3E, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "2.1 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x3A, 0x90, 0x2B, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Compact 2.1 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x3A, 0x08, 0x44, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Software Installation 2.1 (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x40, 0x7C, 0x31, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
0x64, 0x00, 0x6C, 0x00, 0x98, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Personal Edition (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0x00, 0x20, 0x00, 0x3C, 0x7C, 0x3E, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Personal Edition 32-bit (16-bit)"),
new ContentMatchSet(new byte?[]
{
0x4E, 0x45, 0x11, 0x20, 0xC6, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
0xDC, 0x43, 0x08, 0x27, 0xDC, 0x4A, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00,
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
0x9C, 0x00, 0xA6, 0x00, 0xD8, 0x01, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
}, "Personal Edition 32-bit Build 1260/1285 (16-bit)"),
// WZ-SE-01
new ContentMatchSet(new byte?[]
{
0x57, 0x5A, 0x2D, 0x53, 0x45, 0x2D, 0x30, 0x31
}, "Unknow Version (16-bit)"),
#endregion
#region 32-bit SFX Header Checks
// .............8<EFBFBD>92....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9C, 0x39,
0x32, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "2.0 (32-bit)"),
// .............]<5D>92....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x9C, 0x39,
0x32, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
0x2E, 0x53, 0x46, 0x58,
}, "Software Installation 2.0 (32-bit)"),
// .............<2E><><EFBFBD>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x82, 0x94,
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "2.1 RC2 (32-bit)"),
// .............<2E><><EFBFBD>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x82, 0x94,
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
0x2E, 0x53, 0x46, 0x58,
}, "Software Installation 2.1 RC2 (32-bit)"),
// .............U<><55>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xCD, 0xCC,
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "2.1 (32-bit)"),
// .............{<7B><>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0xCC,
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
0x2E, 0x53, 0x46, 0x58,
}, "Software Installation 2.1 (32-bit)"),
// .............ñ½;5....ˆ`..............ˆ`..ˆ`..ˆ`..SI32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xBD, 0x3B,
0x35, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x88, 0x60, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x53, 0x49, 0x33, 0x32, 0x45, 0x2E, 0x53,
0x46, 0x58,
}, "Software Installation 2.2.1110 (32-bit)"),
// .............á.^2....ˆP..............ˆP..ˆP..ˆP..VW95LE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x9D, 0x5E,
0x32, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x4C, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "Personal Edition (32-bit)"),
// .............ïAÁ3....ˆP..............ˆP..ˆP..ˆP..VW95LE.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x41, 0xC1,
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
0x00, 0x56, 0x57, 0x39, 0x35, 0x4C, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "Personal Edition 32-bit (32-bit)"),
// .............'..6....ˆ`..............ˆ`..ˆ`..ˆ`..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x0F, 0x01,
0x36, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x88, 0x60, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x50, 0x45, 0x33, 0x32, 0x45, 0x2E, 0x53,
0x46, 0x58,
}, "Personal Edition 32-bit Build 1260 (32-bit)"),
// .............Ó‘(6....ˆ`..............ˆ`..ˆ`..ˆ`..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x91, 0x28,
0x36, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x88, 0x60, 0x00, 0x00, 0x88, 0x60, 0x00,
0x00, 0x50, 0x45, 0x33, 0x32, 0x45, 0x2E, 0x53,
0x46, 0x58,
}, "Personal Edition 32-bit Build 1285 (32-bit)"),
// ......]ïý8....˜z..............˜z..˜z..˜z..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0xEF,
0xFD, 0x38, 0x00, 0x00, 0x00, 0x00, 0x98, 0x7A,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x7A,
0x00, 0x00, 0x98, 0x7A, 0x00, 0x00, 0x98, 0x7A,
0x00, 0x00, 0x50, 0x45, 0x33, 0x32, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "Personal Edition 32-bit Build 3063"),
// ...................½û;....ˆj..............ˆj..ˆj..ˆj..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1F, 0xBD, 0xFB, 0x3B, 0x00, 0x00,
0x00, 0x00, 0x88, 0x6A, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x88, 0x6A, 0x00, 0x00, 0x88, 0x6A,
0x00, 0x00, 0x88, 0x6A, 0x00, 0x00, 0x50, 0x45,
0x33, 0x32, 0x45, 0x2E, 0x53, 0x46, 0x58,
}, "Personal Edition 32-bit Build 4325"),
// ................rS*@....Xƒ..............Xƒ..Xƒ..Xƒ..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x72, 0x53, 0x2A, 0x40, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x58, 0x83, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x50, 0x45, 0x33, 0x32,
0x45, 0x2E, 0x53, 0x46, 0x58,
}, "Personal Edition 32-bit Build 6028"),
// ................±.!A....Xƒ..............Xƒ..Xƒ..Xƒ..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB1, 0x1A, 0x21, 0x41, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x58, 0x83, 0x00, 0x00,
0x58, 0x83, 0x00, 0x00, 0x50, 0x45, 0x33, 0x32,
0x45, 0x2E, 0x53, 0x46, 0x58,
}, "Personal Edition 32-bit Build 6224"),
// ................¯D.C....x„..............x„..x„..x„..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xAF, 0x44, 0x0F, 0x43, 0x00, 0x00, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x78, 0x84, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x50, 0x45, 0x33, 0x32,
0x45, 0x2E, 0x53, 0x46,
}, "Personal Edition 32-bit Build 6604"),
//................·Å\C....x„..............x„..x„..x„..PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB7, 0xC5, 0x5C, 0x43, 0x00, 0x00, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x78, 0x84, 0x00, 0x00,
0x78, 0x84, 0x00, 0x00, 0x50, 0x45, 0x33, 0x32,
0x45, 0x2E, 0x53, 0x46, 0x58,
}, "Personal Edition 32-bit Build 6663"),
// VW95SE.SFX
new ContentMatchSet(new byte?[]
{
0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E, 0x53,
0x46, 0x58,
}, "Unknown Version (32-bit)"),
// VW95SRE.SFX
new ContentMatchSet(new byte?[]
{
0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45, 0x2E,
0x53, 0x46, 0x58,
}, "Unknown Version Software Installation (32-bit)"),
// VW95LE.SFX
new ContentMatchSet(new byte?[]
{
0x56, 0x57, 0x39, 0x35, 0x4C, 0x45, 0x2E, 0x53,
0x46, 0x58,
}, "Unknown Version before build 1285 Personal Edition (32-bit)"),
// PE32E.SFX
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x33, 0x32, 0x45, 0x2E, 0x53, 0x46,
0x58,
}, "Unknown Version after 1285 Personal Edition (32-bit)"),
#endregion
#region 32-bit PE Header Checks
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0xC9, 0x7A, 0xBE, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x05, 0x0A, 0x00, 0x5C, 0x00, 0x00,
0x00, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x71, 0x3E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
}, "2.2.3063"),
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0x69, 0x1B, 0x5B, 0x3A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x05, 0x0A, 0x00, 0x4A, 0x00, 0x00,
0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xD8, 0x39, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
}, "2.2.4003"),
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0x81, 0x1B, 0x5B, 0x3A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x05, 0x0A, 0x00, 0x56, 0x00, 0x00,
0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x8F, 0x3F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
}, "Software Installation 2.2.4003"),
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0xFA, 0xB8, 0xFB, 0x3B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00,
0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x3E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
}, "2.2.4325"),
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0xAD, 0xFC, 0x2A, 0x3D, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x07, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x54, 0x45, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, }, "2.2.5196"),
new ContentMatchSet(new byte?[]
{
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
0x76, 0xF7, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
0x0B, 0x01, 0x07, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x46, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
}, "2.2.6202"),
#endregion
// WinZip Self-Extractor header corrupt.
new ContentMatchSet(new byte?[]
{
0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
0x61, 0x63, 0x74, 0x6F, 0x72, 0x20, 0x68, 0x65,
0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x72,
0x72, 0x75, 0x70, 0x74, 0x2E,
}, "Unknown 2.x version"),
// winzip\shell\open\command
new ContentMatchSet(new byte?[]
{
0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5C, 0x73,
0x68, 0x65, 0x6C, 0x6C, 0x5C, 0x6F, 0x70, 0x65,
0x6E, 0x5C, 0x63, 0x6F, 0x6D, 0x6D, 0x61, 0x6E,
0x64,
}, "Unknown 2.x version"),
};
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, false);
return match ?? null;
}
private static string GetV3PlusVersion(string file, byte[] fileContent, string version)
{
// Some version strings don't exactly match the public version number
switch (version)
{
case "2.3.6594.0":
return "Personal Edition Build 6604";
case "2.3.6602.0":
return "Personal Edition Build 6663";
case "2.3.7305.0":
return "Personal Edition Build 7305";
case "2.3.7382.0":
return "Personal Edition Build 7452+";
case "3.0.7158.0":
return "3.0.7158";
case "3.0.7454.0":
return "3.0.7454+";
case "3.0.7212.0":
return "3.0.7212";
case "3.1.7556.0":
return "3.1.7556";
case "3.1.8421.0":
return "4.0.8421";
case "4.0.8421.0":
return "4.0.8421";
case "3.1.8672.0":
return "4.0.8672";
case "4.0.1221.0":
return "4.0.12218";
default:
return $"(Unknown - internal version {version})";
}
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
using Wise = WiseUnpacker.WiseUnpacker;
namespace BurnOutSharp.PackerType
{
public class WiseInstaller : IContentCheck, IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// WiseMain
new ContentMatchSet(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the installer file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
Wise unpacker = new Wise();
unpacker.ExtractTo(file, tempPath);
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch { }
return null;
}
}
}

View File

@@ -1,15 +1,25 @@
namespace BurnOutSharp.PackerType
{
public class dotFuscator
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
{
// "DotfuscatorAttribute"
byte[] check = new byte[] { 0x44, 0x6F, 0x74, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x6F, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65 };
if (fileContent.Contains(check, out int position))
return "dotFuscator" + (includePosition ? $" (Index {position})" : string.Empty);
using System.Collections.Generic;
using BurnOutSharp.Matching;
return null;
namespace BurnOutSharp.PackerType
{
public class dotFuscator : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// DotfuscatorAttribute
new ContentMatchSet(new byte?[]
{
0x44, 0x6F, 0x74, 0x66, 0x75, 0x73, 0x63, 0x61,
0x74, 0x6F, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x65
}, "dotFuscator"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -1,33 +1,59 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class AACS
public class AACS : IPathCheck
{
public static string CheckPath(string path, IEnumerable<string> files, bool isDirectory)
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
if (isDirectory)
var matchers = new List<PathMatchSet>
{
if (files.Any(f => f.Contains(Path.Combine("aacs", "VTKF000.AACS")))
&& files.Any(f => f.Contains(Path.Combine("AACS", "CPSUnit00001.cci"))))
{
return "AACS";
}
}
else
{
string filename = Path.GetFileName(path);
if (filename.Equals("VTKF000.AACS", StringComparison.OrdinalIgnoreCase)
|| filename.Equals("CPSUnit00001.cci", StringComparison.OrdinalIgnoreCase))
{
return "AACS";
}
}
// BD-ROM
new PathMatchSet(Path.Combine("AACS", "MKB_RO.inf").Replace("\\", "/"), GetVersion, "AACS"),
return null;
// HD-DVD
new PathMatchSet(Path.Combine("AACS", "MKBROM.AACS").Replace("\\", "/"), GetVersion, "AACS"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// BD-ROM
new PathMatchSet(new PathMatch("MKB_RO.inf", useEndsWith: true), GetVersion, "AACS"),
// HD-DVD
new PathMatchSet(new PathMatch("MKBROM.AACS", useEndsWith: true), GetVersion, "AACS"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
public static string GetVersion(string firstMatchedString, IEnumerable<string> files)
{
if (!File.Exists(firstMatchedString))
return "(Unknown Version)";
try
{
using (var fs = File.OpenRead(firstMatchedString))
{
fs.Seek(0xB, SeekOrigin.Begin);
return fs.ReadByte().ToString();
}
}
catch
{
return "(Unknown Version)";
}
}
}
}

View File

@@ -1,20 +1,28 @@
namespace BurnOutSharp.ProtectionType
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class ActiveMARK
public class ActiveMARK : IContentCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// "TMSAMVOF"
byte[] check = new byte[] { 0x54, 0x4D, 0x53, 0x41, 0x4D, 0x56, 0x4F, 0x46 };
if (fileContent.Contains(check, out int position))
return "ActiveMARK" + (includePosition ? $" (Index {position})" : string.Empty);
var matchers = new List<ContentMatchSet>
{
// TMSAMVOF
new ContentMatchSet(new byte?[] { 0x54, 0x4D, 0x53, 0x41, 0x4D, 0x56, 0x4F, 0x46 }, "ActiveMARK"),
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x0 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
check = new byte[] { 0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00, 0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x0, 0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00 };
if (fileContent.Contains(check, out position))
return "ActiveMARK 5" + (includePosition ? $" (Index {position})" : string.Empty);
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new ContentMatchSet(new byte?[]
{
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -1,26 +1,31 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class AlphaDVD
public class AlphaDVD : IPathCheck
{
public static string CheckPath(string path, IEnumerable<string> files, bool isDirectory)
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
if (isDirectory)
var matchers = new List<PathMatchSet>
{
if (files.Any(f => Path.GetFileName(f).Equals("PlayDVD.exe", StringComparison.OrdinalIgnoreCase)))
return "Alpha-DVD";
}
else
{
if (Path.GetFileName(path).Equals("PlayDVD.exe", StringComparison.OrdinalIgnoreCase))
return "Alpha-DVD";
}
new PathMatchSet(new PathMatch("PlayDVD.exe", useEndsWith: true), "Alpha-DVD"),
};
return null;
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("PlayDVD.exe", useEndsWith: true), "Alpha-DVD"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,15 +1,20 @@
namespace BurnOutSharp.ProtectionType
{
public class AlphaROM
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
{
// "SETTEC"
byte[] check = new byte[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 };
if (fileContent.Contains(check, out int position))
return "Alpha-ROM" + (includePosition ? $" (Index {position})" : string.Empty);
using System.Collections.Generic;
using BurnOutSharp.Matching;
return null;
namespace BurnOutSharp.ProtectionType
{
public class AlphaROM : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// SETTEC
new ContentMatchSet(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 }, "Alpha-ROM"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class BDPlus : IPathCheck
{
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new List<string>
{
Path.Combine("BDSVM", "00000.svm").Replace("\\", "/"),
Path.Combine("BDSVM", "BACKUP", "00000.svm").Replace("\\", "/"),
}, GetVersion, "BD+"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("00000.svm", useEndsWith: true), GetVersion, "BD+"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
/// <remarks>
/// Version detection logic from libbdplus was used to implement this
/// </remarks>
public static string GetVersion(string firstMatchedString, IEnumerable<string> files)
{
if (!File.Exists(firstMatchedString))
return "(Unknown Version)";
try
{
using (var fs = File.OpenRead(firstMatchedString))
{
fs.Seek(0x0D, SeekOrigin.Begin);
byte[] date = new byte[4];
fs.Read(date, 0, 4); //yymd
short year = BitConverter.ToInt16(date.Reverse().ToArray(), 2);
// Do some rudimentary date checking
if (year < 2006 || year > 2100 || date[2] < 1 || date[2] > 12 || date[3] < 1 || date[3] > 31)
return "(Invalid Version)";
return $"{year:0000}/{date[2]:00}/{date[3]:00}";
}
}
catch
{
return "(Unknown Version)";
}
}
}
}

View File

@@ -1,26 +1,56 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class Bitpool
/// <summary>
/// Bitpool is a copy protection that seems to resemble SafeDisc in several ways, found mostly in German releases.
/// Makes use of bad sectors, and contains what appears to be an encrypted game executable always called "CD.IDX" (similar to SafeDisc ICD files), which seems to be present in every disc protected with it.
/// The "CD.IDX" appears to purposefully contain bad sectors in most, if not all, cases.
/// A "bitpool.rsc" file is present in some, but not all Bitpool protected games. The purpose of it is so far unclear.
/// </summary>
public class Bitpool : IContentCheck, IPathCheck
{
public static string CheckPath(string path, IEnumerable<string> files, bool isDirectory)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
if (isDirectory)
var matchers = new List<ContentMatchSet>
{
if (files.Any(f => Path.GetFileName(f).Equals("bitpool.rsc", StringComparison.OrdinalIgnoreCase)))
return "Bitpool";
}
else
{
if (Path.GetFileName(path).Equals("bitpool.rsc", StringComparison.OrdinalIgnoreCase))
return "Bitpool";
}
// Sometimes found in CD.IDX
// BITPOOL.RSC
new ContentMatchSet(new byte?[]
{
0x42, 0x49, 0x54, 0x50, 0x4F, 0x4F, 0x4C, 0x2E,
0x52, 0x53, 0x43
}, "Bitpool"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("bitpool.rsc", useEndsWith: true), "Bitpool"),
new PathMatchSet(new PathMatch("CD.IDX", useEndsWith: true), "Bitpool"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("bitpool.rsc", useEndsWith: true), "Bitpool"),
new PathMatchSet(new PathMatch("CD.IDX", useEndsWith: true), "Bitpool"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,32 +1,33 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class ByteShield
public class ByteShield : IPathCheck
{
public static string CheckPath(string path, IEnumerable<string> files, bool isDirectory)
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
if (isDirectory)
var matchers = new List<PathMatchSet>
{
if (files.Any(f => Path.GetFileName(f).Equals("Byteshield.dll", StringComparison.OrdinalIgnoreCase))
|| files.Any(f => Path.GetExtension(f).Trim('.').Equals("bbz", StringComparison.OrdinalIgnoreCase)))
{
return "ByteShield";
}
}
else
{
if (Path.GetFileName(path).Equals("Byteshield.dll", StringComparison.OrdinalIgnoreCase)
|| Path.GetExtension(path).Trim('.').Equals("bbz", StringComparison.OrdinalIgnoreCase))
{
return "ByteShield";
}
}
new PathMatchSet(new PathMatch("Byteshield.dll", useEndsWith: true), "ByteShield"),
new PathMatchSet(new PathMatch(".bbz", useEndsWith: true), "ByteShield"),
};
return null;
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("Byteshield.dll", useEndsWith: true), "ByteShield"),
new PathMatchSet(new PathMatch(".bbz", useEndsWith: true), "ByteShield"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,36 +1,51 @@
namespace BurnOutSharp.ProtectionType
{
public class CDCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
{
// MGS CDCheck
byte[] check = new byte[] { 0x4D, 0x47, 0x53, 0x20, 0x43, 0x44, 0x43, 0x68, 0x65, 0x63, 0x6B };
if (fileContent.Contains(check, out int position))
return "Microsoft Game Studios CD Check" + (includePosition ? $" (Index {position})" : string.Empty);
// CDCheck
check = new byte[] { 0x43, 0x44, 0x43, 0x68, 0x65, 0x63, 0x6B };
if (fileContent.Contains(check, out position))
return "Executable-Based CD Check" + (includePosition ? $" (Index {position})" : string.Empty);
using System.Collections.Generic;
using BurnOutSharp.Matching;
return null;
namespace BurnOutSharp.ProtectionType
{
public class CDCheck : IContentCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var matchers = new List<ContentMatchSet>
{
// MGS CDCheck
new ContentMatchSet(new byte?[]
{
0x4D, 0x47, 0x53, 0x20, 0x43, 0x44, 0x43, 0x68,
0x65, 0x63, 0x6B
}, "Microsoft Game Studios CD Check"),
// CDCheck
new ContentMatchSet(new byte?[] { 0x43, 0x44, 0x43, 0x68, 0x65, 0x63, 0x6B }, "Executable-Based CD Check"),
};
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
// These content checks are too broad to be useful
private static string CheckContentsBroad(byte[] fileContent, bool includePosition = false)
private static string CheckContentsBroad(string file, byte[] fileContent, bool includePosition = false)
{
// GetDriveType
byte[] check = new byte[] { 0x47, 0x65, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x54, 0x79, 0x70, 0x65 };
if (fileContent.Contains(check, out int position))
return "CD Check" + (includePosition ? $" (Index {position})" : string.Empty);
var matchers = new List<ContentMatchSet>
{
// GetDriveType
new ContentMatchSet(new byte?[]
{
0x47, 0x65, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65,
0x54, 0x79, 0x70, 0x65
}, "Executable-Based CD Check"),
// GetVolumeInformation
check = new byte[] { 0x47, 0x65, 0x74, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E };
if (fileContent.Contains(check, out position))
return "CD Check" + (includePosition ? $" (Index {position})" : string.Empty);
// GetVolumeInformation
new ContentMatchSet(new byte?[]
{
0x47, 0x65, 0x74, 0x56, 0x6F, 0x6C, 0x75, 0x6D,
0x65, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61,
0x74, 0x69, 0x6F, 0x6E
}, "Executable-Based CD Check"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -1,60 +1,68 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Matching;
namespace BurnOutSharp.ProtectionType
{
public class CDCops
public class CDCops : IContentCheck, IPathCheck
{
public static string CheckContents(byte[] fileContent, bool includePosition = false)
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// "CD-Cops, ver. "
byte[] check = new byte[] { 0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20 };
if (fileContent.Contains(check, out int position))
return $"CD-Cops {GetVersion(fileContent, position)}" + (includePosition ? $" (Index {position})" : string.Empty);
var matchers = new List<ContentMatchSet>
{
// CD-Cops, ver.
new ContentMatchSet(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops"),
// ".grand" + (char)0x00
check = new byte[] { 0x2E, 0x67, 0x72, 0x61, 0x6E, 0x64, 0x00};
if (fileContent.Contains(check, out position))
return "CD-Cops" + (includePosition ? $" (Index {position})" : string.Empty);
// .grand + (char)0x00
new ContentMatchSet(new byte?[] { 0x2E, 0x67, 0x72, 0x61, 0x6E, 0x64, 0x00 }, "CD-Cops"),
};
return null;
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
}
public static string CheckPath(string path, IEnumerable<string> files, bool isDirectory)
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
if (isDirectory)
// TODO: Original had "CDCOPS.DLL" required and all the rest in a combined OR
var matchers = new List<PathMatchSet>
{
if (files.Any(f => Path.GetFileName(f).Equals("CDCOPS.DLL", StringComparison.OrdinalIgnoreCase))
&& (files.Any(f => Path.GetExtension(f).Trim('.').Equals("GZ_", StringComparison.OrdinalIgnoreCase))
|| files.Any(f => Path.GetExtension(f).Trim('.').Equals("W_X", StringComparison.OrdinalIgnoreCase))
|| files.Any(f => Path.GetExtension(f).Trim('.').Equals("Qz", StringComparison.OrdinalIgnoreCase))
|| files.Any(f => Path.GetExtension(f).Trim('.').Equals("QZ_", StringComparison.OrdinalIgnoreCase))))
{
return "CD-Cops";
}
}
else
{
if (Path.GetFileName(path).Equals("CDCOPS.DLL", StringComparison.OrdinalIgnoreCase)
|| Path.GetExtension(path).Trim('.').Equals("GZ_", StringComparison.OrdinalIgnoreCase)
|| Path.GetExtension(path).Trim('.').Equals("W_X", StringComparison.OrdinalIgnoreCase)
|| Path.GetExtension(path).Trim('.').Equals("Qz", StringComparison.OrdinalIgnoreCase)
|| Path.GetExtension(path).Trim('.').Equals("QZ_", StringComparison.OrdinalIgnoreCase))
{
return "CD-Cops";
}
}
new PathMatchSet(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".GZ_", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".W_X", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".Qz", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".QZ_", useEndsWith: true), "CD-Cops"),
};
return null;
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
private static string GetVersion(byte[] fileContent, int position)
/// <inheritdoc/>
public string CheckFilePath(string path)
{
char[] version = new ArraySegment<byte>(fileContent, position + 15, 4).Select(b => (char)b).ToArray();
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".GZ_", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".W_X", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".Qz", useEndsWith: true), "CD-Cops"),
new PathMatchSet(new PathMatch(".QZ_", useEndsWith: true), "CD-Cops"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
{
char[] version = new ArraySegment<byte>(fileContent, positions[0] + 15, 4).Select(b => (char)b).ToArray();
if (version[0] == 0x00)
return "";
return string.Empty;
return new string(version);
}

Some files were not shown because too many files have changed in this diff Show More