mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-04 13:45:28 +00:00
Compare commits
333 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66af2d83b8 | ||
|
|
fc3be76657 | ||
|
|
259a91dd77 | ||
|
|
e957b29bae | ||
|
|
33060d9787 | ||
|
|
71ca79a456 | ||
|
|
fc744d241a | ||
|
|
78b5b3dbc1 | ||
|
|
cb3846261a | ||
|
|
9a3dcf70de | ||
|
|
670c78302f | ||
|
|
f4cb97b3bf | ||
|
|
be6d44ed04 | ||
|
|
cfc9092479 | ||
|
|
d674ae5b1f | ||
|
|
864972e575 | ||
|
|
7d97850cb0 | ||
|
|
3e33f098a6 | ||
|
|
adf9ce5e2a | ||
|
|
0c5dff71e9 | ||
|
|
715f773672 | ||
|
|
a54b89d380 | ||
|
|
2085c306ab | ||
|
|
98b99da0bc | ||
|
|
e00238b24e | ||
|
|
aef2b756c9 | ||
|
|
f1f1e20a3e | ||
|
|
62a2fdeaa6 | ||
|
|
37c1852058 | ||
|
|
99c4a08d83 | ||
|
|
9d4bc6bfab | ||
|
|
71fd5af48e | ||
|
|
995521b789 | ||
|
|
5031985883 | ||
|
|
5759090291 | ||
|
|
008c1c89fb | ||
|
|
624eb40315 | ||
|
|
aaa12ae817 | ||
|
|
d37c90878c | ||
|
|
668a631c11 | ||
|
|
f06c0f4553 | ||
|
|
a0b13a6e6f | ||
|
|
1bd9f3fd88 | ||
|
|
93ba88a35f | ||
|
|
c86b1251a3 | ||
|
|
6f6954b270 | ||
|
|
1d4ed425f1 | ||
|
|
ba657e28ad | ||
|
|
7575353597 | ||
|
|
10d3c09cfa | ||
|
|
5001c4a881 | ||
|
|
7ecd0d1893 | ||
|
|
ae802d5d75 | ||
|
|
3b4266246d | ||
|
|
a801e720b2 | ||
|
|
a52d45f7c2 | ||
|
|
57eaa1f04c | ||
|
|
6cc2cc5be2 | ||
|
|
ebcdc08a77 | ||
|
|
7aebdf56fc | ||
|
|
6de36eb71c | ||
|
|
5ebd392c5b | ||
|
|
5fc2029725 | ||
|
|
45e4a01fc1 | ||
|
|
c4ea7891ea | ||
|
|
de871fb8c1 | ||
|
|
c322eebb98 | ||
|
|
ea6b0f1ca3 | ||
|
|
a35a9a4ab6 | ||
|
|
9a93c7b15d | ||
|
|
43eed75635 | ||
|
|
74ea6e6002 | ||
|
|
91e2157622 | ||
|
|
87961e5451 | ||
|
|
4ff203f393 | ||
|
|
410b2bef2b | ||
|
|
a9792fdff1 | ||
|
|
92e36527fd | ||
|
|
aa1d7d475c | ||
|
|
91185c4fe1 | ||
|
|
c527b1911f | ||
|
|
d1501b2e3e | ||
|
|
03ac117844 | ||
|
|
515be8b025 | ||
|
|
c3479450f5 | ||
|
|
611aa3229c | ||
|
|
5a865f3d08 | ||
|
|
9d8d5c23c8 | ||
|
|
3fed1a3282 | ||
|
|
f47387c3a4 | ||
|
|
133272acb7 | ||
|
|
c49ae98df5 | ||
|
|
a1672a9bc0 | ||
|
|
ffc2e23b2f | ||
|
|
c481e73418 | ||
|
|
06b3124b62 | ||
|
|
d7d81665a0 | ||
|
|
24c542c22f | ||
|
|
ec616fcdac | ||
|
|
24e9455733 | ||
|
|
58aaf46a0e | ||
|
|
54e92fe9c8 | ||
|
|
4bb83c5d86 | ||
|
|
2f9280460e | ||
|
|
30e8e79cf7 | ||
|
|
7bb0d4f39a | ||
|
|
046814b7c4 | ||
|
|
cf00348d46 | ||
|
|
8466edf80f | ||
|
|
ccdf539ed4 | ||
|
|
aeee6e9cda | ||
|
|
2af21cb245 | ||
|
|
96fb5a2f93 | ||
|
|
1eaefb16ba | ||
|
|
1c972a29a7 | ||
|
|
aa33c083fe | ||
|
|
a9454e96ed | ||
|
|
fb6fa85cd3 | ||
|
|
3c12bdc212 | ||
|
|
5eeee760f7 | ||
|
|
cfe889d5b3 | ||
|
|
3045c41eda | ||
|
|
d194ef9dd8 | ||
|
|
aeb379f307 | ||
|
|
cae0edfb49 | ||
|
|
e97558db1f | ||
|
|
06ecc1a571 | ||
|
|
adcf9ee27e | ||
|
|
a8c759be55 | ||
|
|
ecf97de439 | ||
|
|
f134de6609 | ||
|
|
d91ce3100b | ||
|
|
20de40014d | ||
|
|
a7f9a99d10 | ||
|
|
4bdfbabaab | ||
|
|
5465c57d96 | ||
|
|
5082c8f705 | ||
|
|
509fff4684 | ||
|
|
9d2c14f809 | ||
|
|
b023549b87 | ||
|
|
0983073538 | ||
|
|
815acf2ce0 | ||
|
|
6b8596466b | ||
|
|
1e5bb7df64 | ||
|
|
e920bfc69c | ||
|
|
a85c6f4028 | ||
|
|
a75bc15f29 | ||
|
|
659aa30fb3 | ||
|
|
54a11916d2 | ||
|
|
47f423d092 | ||
|
|
5c5e68e31d | ||
|
|
9e917e2bb9 | ||
|
|
4bd4d2f395 | ||
|
|
6406248840 | ||
|
|
3d8134bbd3 | ||
|
|
15310a6c47 | ||
|
|
450a8cd5bd | ||
|
|
088f99942f | ||
|
|
3e97bd8d2d | ||
|
|
866051c975 | ||
|
|
0be437f3cf | ||
|
|
11f3dec65d | ||
|
|
912d151164 | ||
|
|
863678f850 | ||
|
|
b82a6a8c5d | ||
|
|
ab2daf2a80 | ||
|
|
f734e3a58a | ||
|
|
212981fda9 | ||
|
|
c64e138ba7 | ||
|
|
c43353d126 | ||
|
|
d439ba9592 | ||
|
|
b7f06f0b59 | ||
|
|
60d666f8be | ||
|
|
4ff4c2afef | ||
|
|
655b8385f9 | ||
|
|
439c141c2c | ||
|
|
95755b930d | ||
|
|
9cf54c1f2d | ||
|
|
e118418a23 | ||
|
|
a3567d6eb2 | ||
|
|
a359143bc7 | ||
|
|
77b7a24d85 | ||
|
|
338b2593d5 | ||
|
|
ded5e27355 | ||
|
|
ee1b005d96 | ||
|
|
cd2673d1ba | ||
|
|
41d77085ae | ||
|
|
67059b2e43 | ||
|
|
f6157ef79b | ||
|
|
6e5d517e82 | ||
|
|
1dca51988a | ||
|
|
3c064bad55 | ||
|
|
d60a3ce05a | ||
|
|
f68438ff8c | ||
|
|
d351f1d08e | ||
|
|
70bdb8f37d | ||
|
|
3cd713e078 | ||
|
|
454655de5a | ||
|
|
268ed1a6a6 | ||
|
|
a42ce601b8 | ||
|
|
756b37ef6c | ||
|
|
ab7e708e02 | ||
|
|
326d916c0b | ||
|
|
db09bd931b | ||
|
|
d1e9eb90f1 | ||
|
|
20a5c4c78d | ||
|
|
499f9888b1 | ||
|
|
7bb3364b43 | ||
|
|
473cbc5694 | ||
|
|
e32b24c9f6 | ||
|
|
777fdc14c8 | ||
|
|
ffbb01c25c | ||
|
|
47380c2c1c | ||
|
|
51e9121a6b | ||
|
|
94f51d518d | ||
|
|
8fdc17b239 | ||
|
|
42bb29185f | ||
|
|
05ae0f4e80 | ||
|
|
092374a143 | ||
|
|
3cfb60430a | ||
|
|
370cc68fa4 | ||
|
|
8fe5046c19 | ||
|
|
37e7604441 | ||
|
|
7651b34855 | ||
|
|
4bf89b1d5f | ||
|
|
0287284909 | ||
|
|
a8453b3f21 | ||
|
|
2552564953 | ||
|
|
0d4d19559a | ||
|
|
52f4132ccb | ||
|
|
cb6440662b | ||
|
|
6293895611 | ||
|
|
f564fb6e9e | ||
|
|
3f2adfcf62 | ||
|
|
2c979f291e | ||
|
|
7e7b2ee64a | ||
|
|
87108405a8 | ||
|
|
9fb055cbff | ||
|
|
e690f0137e | ||
|
|
87c08d6fbd | ||
|
|
8c164d776e | ||
|
|
964271b4e1 | ||
|
|
e99ba48f07 | ||
|
|
62b1627b04 | ||
|
|
3a54997d42 | ||
|
|
7d95a43b4b | ||
|
|
23ea8710c0 | ||
|
|
0b62a52991 | ||
|
|
1143c8a8b7 | ||
|
|
a5b66caae6 | ||
|
|
b0b87d05fd | ||
|
|
cb3c666f64 | ||
|
|
12fdae7944 | ||
|
|
e76bc70ec6 | ||
|
|
e78bb8cb41 | ||
|
|
5153e73f42 | ||
|
|
7f36ff8a2b | ||
|
|
99a8a39dda | ||
|
|
adbf983e65 | ||
|
|
d7639495ac | ||
|
|
fbe09d9082 | ||
|
|
70468b72c3 | ||
|
|
90f4af1121 | ||
|
|
aa37449bbf | ||
|
|
c835e04722 | ||
|
|
29b999b8ed | ||
|
|
9ddd6cc317 | ||
|
|
3a694f0e31 | ||
|
|
080cbda588 | ||
|
|
fd066e8aae | ||
|
|
0fd0cf689a | ||
|
|
f85adda24c | ||
|
|
2d1e8e02aa | ||
|
|
371fbee7a4 | ||
|
|
a5bb95e7c1 | ||
|
|
53b5a443fe | ||
|
|
a230871f75 | ||
|
|
f560ce17e8 | ||
|
|
b96329bd33 | ||
|
|
913f7802de | ||
|
|
a9f61ed51e | ||
|
|
04c0835228 | ||
|
|
af7ff05ecf | ||
|
|
4ccf80189e | ||
|
|
b417229ee6 | ||
|
|
61457582b3 | ||
|
|
ecc1613f49 | ||
|
|
5ea89eefe8 | ||
|
|
661808826a | ||
|
|
342f78ffd0 | ||
|
|
cc6a65d5e4 | ||
|
|
068ee76983 | ||
|
|
b980b33019 | ||
|
|
4327ce7848 | ||
|
|
2c813e7b3d | ||
|
|
d69746f7ef | ||
|
|
ce8f73d30d | ||
|
|
d6602ac8a8 | ||
|
|
6478af03e7 | ||
|
|
f086e63914 | ||
|
|
6fbb6bd8dc | ||
|
|
008629b61f | ||
|
|
b7704dbe57 | ||
|
|
5aff2d0b1b | ||
|
|
771bbeed6a | ||
|
|
53dd1e9aa5 | ||
|
|
6b7ed456ac | ||
|
|
5e2185dffd | ||
|
|
b5d318013b | ||
|
|
07a926e50c | ||
|
|
78bbb63c11 | ||
|
|
1fd613c2b2 | ||
|
|
792833ebc8 | ||
|
|
7392fce770 | ||
|
|
6c621c743d | ||
|
|
50a7883958 | ||
|
|
3882db6fc6 | ||
|
|
c91691f79b | ||
|
|
17fbf1163d | ||
|
|
9a1bbd7e0d | ||
|
|
bf6f3bad46 | ||
|
|
b99b2a53cf | ||
|
|
1fec5c15d4 | ||
|
|
a8b13e60b6 | ||
|
|
4c0c44de6b | ||
|
|
af0623beea | ||
|
|
761b418d21 | ||
|
|
0316edb8cb | ||
|
|
48cf417d60 | ||
|
|
83af2926aa | ||
|
|
ddfa820004 | ||
|
|
80986978cb | ||
|
|
68283554e9 |
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "BurnOutSharp/External/stormlibsharp"]
|
||||
path = BurnOutSharp/External/stormlibsharp
|
||||
[submodule "BinaryObjectScanner/_EXTERNAL/stormlibsharp"]
|
||||
path = BinaryObjectScanner/_EXTERNAL/stormlibsharp
|
||||
url = https://github.com/robpaveza/stormlibsharp.git
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"dotnet.defaultSolution": "BinaryObjectScanner.sln"
|
||||
}
|
||||
6
.vscode/tasks.json
vendored
6
.vscode/tasks.json
vendored
@@ -7,7 +7,7 @@
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/BurnOutSharp.sln",
|
||||
"${workspaceFolder}/BinaryObjectScanner.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
@@ -19,7 +19,7 @@
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/BurnOutSharp.sln",
|
||||
"${workspaceFolder}/BinaryObjectScanner.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
@@ -32,7 +32,7 @@
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"${workspaceFolder}/BurnOutSharp.sln",
|
||||
"${workspaceFolder}/BinaryObjectScanner.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
|
||||
42
BinaryObjectScanner.sln
Normal file
42
BinaryObjectScanner.sln
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32407.343
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{88735BA2-778D-4192-8EB2-FFF6843719E2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{68D10531-99CB-40B1-8912-73FA286C9433}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
appveyor.yml = appveyor.yml
|
||||
Coding Guide.md = Coding Guide.md
|
||||
Developer Guide.md = Developer Guide.md
|
||||
LICENSE = LICENSE
|
||||
publish-nix.sh = publish-nix.sh
|
||||
publish-win.bat = publish-win.bat
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner", "BinaryObjectScanner\BinaryObjectScanner.csproj", "{341EA3F5-847C-4739-B86F-2B051FFE4EF2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0B343DD2-8852-47B0-9647-DFCFBEDF933C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
68
BinaryObjectScanner/BinaryObjectScanner.csproj
Normal file
68
BinaryObjectScanner/BinaryObjectScanner.csproj
Normal file
@@ -0,0 +1,68 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Version>2.9.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<PackageId>BurnOutSharp</PackageId> <!-- Temporary until official renaming -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Protection scanning library</Description>
|
||||
<Copyright>Copyright (c)2018-2023 Matt Nadareski</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>protection copy-protection scanning packer</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These are needed for dealing with submodules -->
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>
|
||||
$(DefaultItemExcludes);
|
||||
**\AssemblyInfo.cs;
|
||||
_EXTERNAL\stormlibsharp\lib\**;
|
||||
_EXTERNAL\stormlibsharp\src\TestConsole\**
|
||||
</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These are needed for dealing with native Windows DLLs -->
|
||||
<ItemGroup>
|
||||
<Content Include="*.dll">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>contentFiles;content</PackagePath>
|
||||
<IncludeInPackage>true</IncludeInPackage>
|
||||
<CopyToOutput>true</CopyToOutput>
|
||||
<BuildAction>Content</BuildAction>
|
||||
<copyToOutput>true</copyToOutput>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenMcdf" Version="2.3.0" />
|
||||
<PackageReference Include="SabreTools.Compression" Version="0.1.1" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.1.1" />
|
||||
<PackageReference Include="SabreTools.Matching" Version="1.1.1" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.1.5" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.1.7" />
|
||||
<PackageReference Include="SharpCompress" Version="0.34.1" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
||||
<PackageReference Include="UnshieldSharp" Version="1.6.9" />
|
||||
<PackageReference Include="WiseUnpacker" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
78
BinaryObjectScanner/Factory.cs
Normal file
78
BinaryObjectScanner/Factory.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
|
||||
namespace BinaryObjectScanner
|
||||
{
|
||||
public static class Factory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an instance of a detectable based on file type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static IDetectable CreateDetectable(SupportedFileType fileType)
|
||||
#else
|
||||
public static IDetectable? CreateDetectable(SupportedFileType fileType)
|
||||
#endif
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case SupportedFileType.AACSMediaKeyBlock: return new BinaryObjectScanner.FileType.AACSMediaKeyBlock();
|
||||
case SupportedFileType.BDPlusSVM: return new BinaryObjectScanner.FileType.BDPlusSVM();
|
||||
//case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
|
||||
case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
|
||||
case SupportedFileType.LDSCRYPT: return new BinaryObjectScanner.FileType.LDSCRYPT();
|
||||
//case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
|
||||
//case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
|
||||
case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
|
||||
case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
|
||||
case SupportedFileType.Textfile: return new BinaryObjectScanner.FileType.Textfile();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of an extractable based on file type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static IExtractable CreateExtractable(SupportedFileType fileType)
|
||||
#else
|
||||
public static IExtractable? CreateExtractable(SupportedFileType fileType)
|
||||
#endif
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case SupportedFileType.BFPK: return new BinaryObjectScanner.FileType.BFPK();
|
||||
case SupportedFileType.BSP: return new BinaryObjectScanner.FileType.BSP();
|
||||
case SupportedFileType.BZip2: return new BinaryObjectScanner.FileType.BZip2();
|
||||
case SupportedFileType.CFB: return new BinaryObjectScanner.FileType.CFB();
|
||||
//case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
|
||||
case SupportedFileType.GCF: return new BinaryObjectScanner.FileType.GCF();
|
||||
case SupportedFileType.GZIP: return new BinaryObjectScanner.FileType.GZIP();
|
||||
case SupportedFileType.InstallShieldArchiveV3: return new BinaryObjectScanner.FileType.InstallShieldArchiveV3();
|
||||
case SupportedFileType.InstallShieldCAB: return new BinaryObjectScanner.FileType.InstallShieldCAB();
|
||||
case SupportedFileType.MicrosoftCAB: return new BinaryObjectScanner.FileType.MicrosoftCAB();
|
||||
case SupportedFileType.MicrosoftLZ: return new BinaryObjectScanner.FileType.MicrosoftLZ();
|
||||
case SupportedFileType.MPQ: return new BinaryObjectScanner.FileType.MPQ();
|
||||
//case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
|
||||
//case SupportedFileType.NCF: return new BinaryObjectScanner.FileType.NCF();
|
||||
//case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
|
||||
case SupportedFileType.PAK: return new BinaryObjectScanner.FileType.PAK();
|
||||
case SupportedFileType.PFF: return new BinaryObjectScanner.FileType.PFF();
|
||||
case SupportedFileType.PKZIP: return new BinaryObjectScanner.FileType.PKZIP();
|
||||
//case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
|
||||
//case SupportedFileType.Quantum: return new BinaryObjectScanner.FileType.Quantum();
|
||||
case SupportedFileType.RAR: return new BinaryObjectScanner.FileType.RAR();
|
||||
case SupportedFileType.SevenZip: return new BinaryObjectScanner.FileType.SevenZip();
|
||||
case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
|
||||
case SupportedFileType.SGA: return new BinaryObjectScanner.FileType.SGA();
|
||||
case SupportedFileType.TapeArchive: return new BinaryObjectScanner.FileType.TapeArchive();
|
||||
case SupportedFileType.VBSP: return new BinaryObjectScanner.FileType.VBSP();
|
||||
case SupportedFileType.VPK: return new BinaryObjectScanner.FileType.VPK();
|
||||
case SupportedFileType.WAD: return new BinaryObjectScanner.FileType.WAD();
|
||||
case SupportedFileType.XZ: return new BinaryObjectScanner.FileType.XZ();
|
||||
case SupportedFileType.XZP: return new BinaryObjectScanner.FileType.XZP();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
BinaryObjectScanner/FileType/AACSMediaKeyBlock.cs
Normal file
59
BinaryObjectScanner/FileType/AACSMediaKeyBlock.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// AACS media key block
|
||||
/// </summary>
|
||||
public class AACSMediaKeyBlock : IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the MKB file itself fails
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var mkb = SabreTools.Serialization.Wrappers.AACSMediaKeyBlock.Create(stream);
|
||||
if (mkb == null)
|
||||
return null;
|
||||
|
||||
// Derive the version, if possible
|
||||
var typeAndVersion = mkb.Model.Records?.FirstOrDefault(r => r?.RecordType == SabreTools.Models.AACS.RecordType.TypeAndVersion);
|
||||
if (typeAndVersion == null)
|
||||
return "AACS (Unknown Version)";
|
||||
else
|
||||
return $"AACS {(typeAndVersion as SabreTools.Models.AACS.TypeAndVersionRecord)?.VersionNumber}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
BinaryObjectScanner/FileType/BDPlusSVM.cs
Normal file
57
BinaryObjectScanner/FileType/BDPlusSVM.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// BD+ SVM
|
||||
/// </summary>
|
||||
public class BDPlusSVM : IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the BD+ file itself fails
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var svm = SabreTools.Serialization.Wrappers.BDPlusSVM.Create(stream);
|
||||
if (svm == null)
|
||||
return null;
|
||||
|
||||
// Format the date
|
||||
string date = $"{svm.Model.Year:0000}/{svm.Model.Month:00}/{svm.Model.Day:00}";
|
||||
|
||||
// Return the formatted value
|
||||
return $"BD+ {date}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
148
BinaryObjectScanner/FileType/BFPK.cs
Normal file
148
BinaryObjectScanner/FileType/BFPK.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// BFPK custom archive format
|
||||
/// </summary>
|
||||
public class BFPK : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var bfpk = SabreTools.Serialization.Wrappers.BFPK.Create(stream);
|
||||
if (bfpk == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Extract all files
|
||||
ExtractAll(bfpk, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the BFPK to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.BFPK item, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Model.Files == null || item.Model.Files.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.Files.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the BFPK to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.BFPK item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Model.Files == null || item.Model.Files.Length == 0)
|
||||
return false;
|
||||
|
||||
// If we have an invalid index
|
||||
if (index < 0 || index >= item.Model.Files.Length)
|
||||
return false;
|
||||
|
||||
// Get the file information
|
||||
var file = item.Model.Files[index];
|
||||
if (file == null)
|
||||
return false;
|
||||
|
||||
// Get the read index and length
|
||||
int offset = file.Offset + 4;
|
||||
int compressedSize = file.CompressedSize;
|
||||
|
||||
// Some files can lack the length prefix
|
||||
if (compressedSize > item.GetEndOfFile())
|
||||
{
|
||||
offset -= 4;
|
||||
compressedSize = file.UncompressedSize;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Ensure the output directory exists
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
|
||||
// Create the output path
|
||||
string filePath = Path.Combine(outputDirectory, file.Name ?? $"file{index}");
|
||||
using (FileStream fs = File.OpenWrite(filePath))
|
||||
{
|
||||
// Read the data block
|
||||
var data = item.ReadFromDataSource(offset, compressedSize);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// If we have uncompressed data
|
||||
if (compressedSize == file.UncompressedSize)
|
||||
{
|
||||
fs.Write(data, 0, compressedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(data);
|
||||
ZlibStream zs = new ZlibStream(ms, CompressionMode.Decompress);
|
||||
zs.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using static BurnOutSharp.Models.BSP.Constants;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BurnOutSharp.Wrappers
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
public class BSP : WrapperBase
|
||||
/// <summary>
|
||||
/// Half-Life Level
|
||||
/// </summary>
|
||||
public class BSP : IExtractable
|
||||
{
|
||||
#region Pass-Through Properties
|
||||
|
||||
#region Header
|
||||
|
||||
/// <inheritdoc cref="Models.BSP.Header.Version"/>
|
||||
public uint Version => _file.Header.Version;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lumps
|
||||
|
||||
/// <inheritdoc cref="Models.BSP.File.Lumps"/>
|
||||
public Models.BSP.Lump[] Lumps => _file.Lumps;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Texture Header
|
||||
|
||||
/// <inheritdoc cref="Models.BSP.TextureHeader.TextureCount"/>
|
||||
public uint TextureCount => _file.TextureHeader.TextureCount;
|
||||
|
||||
/// <inheritdoc cref="Models.BSP.TextureHeader.Offsets"/>
|
||||
public uint[] Offsets => _file.TextureHeader.Offsets;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Textures
|
||||
|
||||
/// <inheritdoc cref="Models.BSP.File.Textures"/>
|
||||
public Models.BSP.Texture[] Textures => _file.Textures;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Instance Variables
|
||||
|
||||
/// <summary>
|
||||
/// Internal representation of the BSP
|
||||
/// </summary>
|
||||
private Models.BSP.File _file;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor
|
||||
/// </summary>
|
||||
private BSP() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a BSP from a byte array and offset
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the BSP</param>
|
||||
/// <param name="offset">Offset within the array to parse</param>
|
||||
/// <returns>A BSP wrapper on success, null on failure</returns>
|
||||
public static BSP Create(byte[] data, int offset)
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null)
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// If the offset is out of bounds
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
return null;
|
||||
|
||||
// Create a memory stream and use that
|
||||
MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset);
|
||||
return Create(dataStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a BSP from a Stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the BSP</param>
|
||||
/// <returns>An BSP wrapper on success, null on failure</returns>
|
||||
public static BSP Create(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
|
||||
return null;
|
||||
|
||||
var file = Builders.BSP.ParseFile(data);
|
||||
if (file == null)
|
||||
return null;
|
||||
|
||||
var wrapper = new BSP
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
_file = file,
|
||||
_dataSource = DataSource.Stream,
|
||||
_streamData = data,
|
||||
};
|
||||
return wrapper;
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Printing
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Print()
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
Console.WriteLine("BSP Information:");
|
||||
Console.WriteLine("-------------------------");
|
||||
Console.WriteLine();
|
||||
|
||||
PrintHeader();
|
||||
PrintLumps();
|
||||
PrintTextureHeader();
|
||||
PrintTextures();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print header information
|
||||
/// </summary>
|
||||
private void PrintHeader()
|
||||
{
|
||||
Console.WriteLine(" Header Information:");
|
||||
Console.WriteLine(" -------------------------");
|
||||
Console.WriteLine($" Version: {Version}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print lumps information
|
||||
/// </summary>
|
||||
private void PrintLumps()
|
||||
{
|
||||
Console.WriteLine(" Lumps Information:");
|
||||
Console.WriteLine(" -------------------------");
|
||||
if (Lumps == null || Lumps.Length == 0)
|
||||
try
|
||||
{
|
||||
Console.WriteLine(" No lumps");
|
||||
// Create the wrapper
|
||||
var bsp = SabreTools.Serialization.Wrappers.BSP.Create(stream);
|
||||
if (bsp == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAllLumps(bsp, tempPath);
|
||||
ExtractAllTextures(bsp, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
for (int i = 0; i < Lumps.Length; i++)
|
||||
{
|
||||
var lump = Lumps[i];
|
||||
string specialLumpName = string.Empty;
|
||||
switch (i)
|
||||
{
|
||||
case HL_BSP_LUMP_ENTITIES:
|
||||
specialLumpName = " (entities)";
|
||||
break;
|
||||
case HL_BSP_LUMP_TEXTUREDATA:
|
||||
specialLumpName = " (texture data)";
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine($" Lump {i}{specialLumpName}");
|
||||
Console.WriteLine($" Offset: {lump.Offset}");
|
||||
Console.WriteLine($" Length: {lump.Length}");
|
||||
}
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print texture header information
|
||||
/// </summary>
|
||||
private void PrintTextureHeader()
|
||||
{
|
||||
Console.WriteLine(" Texture Header Information:");
|
||||
Console.WriteLine(" -------------------------");
|
||||
Console.WriteLine($" Texture count: {TextureCount}");
|
||||
Console.WriteLine($" Offsets: {string.Join(", ", Offsets)}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print textures information
|
||||
/// </summary>
|
||||
private void PrintTextures()
|
||||
{
|
||||
Console.WriteLine(" Textures Information:");
|
||||
Console.WriteLine(" -------------------------");
|
||||
if (Textures == null || Textures.Length == 0)
|
||||
{
|
||||
Console.WriteLine(" No textures");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
var texture = Textures[i];
|
||||
Console.WriteLine($" Texture {i}");
|
||||
Console.WriteLine($" Name: {texture.Name}");
|
||||
Console.WriteLine($" Width: {texture.Width}");
|
||||
Console.WriteLine($" Height: {texture.Height}");
|
||||
Console.WriteLine($" Offsets: {string.Join(", ", texture.Offsets)}");
|
||||
// Skip texture data
|
||||
Console.WriteLine($" Palette size: {texture.PaletteSize}");
|
||||
// Skip palette data
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Extract all lumps from the BSP to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all lumps extracted, false otherwise</returns>
|
||||
public bool ExtractAllLumps(string outputDirectory)
|
||||
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.BSP item, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (Lumps == null || Lumps.Length == 0)
|
||||
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all lumps to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < Lumps.Length; i++)
|
||||
for (int i = 0; i < item.Model.Lumps.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractLump(i, outputDirectory);
|
||||
allExtracted &= ExtractLump(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
@@ -238,23 +84,23 @@ namespace BurnOutSharp.Wrappers
|
||||
/// <param name="index">Lump index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the lump extracted, false otherwise</returns>
|
||||
public bool ExtractLump(int index, string outputDirectory)
|
||||
public static bool ExtractLump(SabreTools.Serialization.Wrappers.BSP item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (Lumps == null || Lumps.Length == 0)
|
||||
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the lumps index is invalid
|
||||
if (index < 0 || index >= Lumps.Length)
|
||||
if (index < 0 || index >= item.Model.Lumps.Length)
|
||||
return false;
|
||||
|
||||
// Get the lump
|
||||
var lump = Lumps[index];
|
||||
var lump = item.Model.Lumps[index];
|
||||
if (lump == null)
|
||||
return false;
|
||||
|
||||
// Read the data
|
||||
byte[] data = ReadFromDataSource((int)lump.Offset, (int)lump.Length);
|
||||
var data = item.ReadFromDataSource((int)lump.Offset, (int)lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
@@ -262,10 +108,10 @@ namespace BurnOutSharp.Wrappers
|
||||
string filename = $"lump_{index}.bin";
|
||||
switch (index)
|
||||
{
|
||||
case HL_BSP_LUMP_ENTITIES:
|
||||
case SabreTools.Models.BSP.Constants.HL_BSP_LUMP_ENTITIES:
|
||||
filename = "entities.ent";
|
||||
break;
|
||||
case HL_BSP_LUMP_TEXTUREDATA:
|
||||
case SabreTools.Models.BSP.Constants.HL_BSP_LUMP_TEXTUREDATA:
|
||||
filename = "texture_data.bin";
|
||||
break;
|
||||
}
|
||||
@@ -278,7 +124,9 @@ namespace BurnOutSharp.Wrappers
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
@@ -302,17 +150,17 @@ namespace BurnOutSharp.Wrappers
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all textures extracted, false otherwise</returns>
|
||||
public bool ExtractAllTextures(string outputDirectory)
|
||||
public static bool ExtractAllTextures(SabreTools.Serialization.Wrappers.BSP item, string outputDirectory)
|
||||
{
|
||||
// If we have no textures
|
||||
if (Offsets == null || Offsets.Length == 0)
|
||||
if (item.Model.TextureHeader?.Offsets == null || item.Model.TextureHeader.Offsets.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all lumps to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < Offsets.Length; i++)
|
||||
for (int i = 0; i < item.Model.TextureHeader.Offsets.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractTexture(i, outputDirectory);
|
||||
allExtracted &= ExtractTexture(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
@@ -324,23 +172,23 @@ namespace BurnOutSharp.Wrappers
|
||||
/// <param name="index">Lump index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the texture extracted, false otherwise</returns>
|
||||
public bool ExtractTexture(int index, string outputDirectory)
|
||||
public static bool ExtractTexture(SabreTools.Serialization.Wrappers.BSP item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no textures
|
||||
if (Textures == null || Textures.Length == 0)
|
||||
if (item.Model.Textures == null || item.Model.Textures.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the texture index is invalid
|
||||
if (index < 0 || index >= Textures.Length)
|
||||
if (index < 0 || index >= item.Model.Textures.Length)
|
||||
return false;
|
||||
|
||||
// Get the texture
|
||||
var texture = Textures[index];
|
||||
var texture = item.Model.Textures[index];
|
||||
if (texture == null)
|
||||
return false;
|
||||
|
||||
// Read the data
|
||||
byte[] data = CreateTextureData(texture);
|
||||
var data = CreateTextureData(texture);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
@@ -355,7 +203,9 @@ namespace BurnOutSharp.Wrappers
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
@@ -379,14 +229,22 @@ namespace BurnOutSharp.Wrappers
|
||||
/// </summary>
|
||||
/// <param name="texture">Texture object to format</param>
|
||||
/// <returns>Byte array representing the texture as a bitmap</returns>
|
||||
private static byte[] CreateTextureData(Models.BSP.Texture texture)
|
||||
#if NET48
|
||||
private static byte[] CreateTextureData(SabreTools.Models.BSP.Texture texture)
|
||||
#else
|
||||
private static byte[]? CreateTextureData(SabreTools.Models.BSP.Texture texture)
|
||||
#endif
|
||||
{
|
||||
// If there's no palette data
|
||||
if (texture.PaletteData == null || texture.PaletteData.Length == 0)
|
||||
return null;
|
||||
|
||||
// If there's no texture data
|
||||
if (texture.TextureData == null || texture.TextureData.Length == 0)
|
||||
return null;
|
||||
|
||||
// Create the bitmap file header
|
||||
var fileHeader = new Models.BMP.BITMAPFILEHEADER()
|
||||
var fileHeader = new SabreTools.Models.BMP.BITMAPFILEHEADER()
|
||||
{
|
||||
Type = ('M' << 8) | 'B',
|
||||
Size = 14 + 40 + (texture.PaletteSize * 4) + (texture.Width * texture.Height),
|
||||
@@ -394,7 +252,7 @@ namespace BurnOutSharp.Wrappers
|
||||
};
|
||||
|
||||
// Create the bitmap info header
|
||||
var infoHeader = new Models.BMP.BITMAPINFOHEADER
|
||||
var infoHeader = new SabreTools.Models.BMP.BITMAPINFOHEADER
|
||||
{
|
||||
Size = 40,
|
||||
Width = (int)texture.Width,
|
||||
@@ -457,7 +315,5 @@ namespace BurnOutSharp.Wrappers
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
64
BinaryObjectScanner/FileType/BZip2.cs
Normal file
64
BinaryObjectScanner/FileType/BZip2.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// bzip2 archive
|
||||
/// </summary>
|
||||
public class BZip2 : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
using (BZip2Stream bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true))
|
||||
{
|
||||
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
|
||||
using (FileStream fs = File.OpenWrite(tempFile))
|
||||
{
|
||||
bz2File.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using OpenMcdf;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Microsoft installation package
|
||||
/// Compound File Binary
|
||||
/// </summary>
|
||||
public class MSI : IScannable
|
||||
public class CFB : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add stream opening support
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the MSI file itself fails
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -39,65 +44,62 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
msi.RootStorage.VisitEntries((e) =>
|
||||
{
|
||||
if (!e.IsStream)
|
||||
return;
|
||||
|
||||
var str = msi.RootStorage.GetStream(e.Name);
|
||||
if (str == null)
|
||||
return;
|
||||
|
||||
byte[] strData = str.GetData();
|
||||
if (strData == null)
|
||||
return;
|
||||
|
||||
string decoded = DecodeStreamName(e.Name).TrimEnd('\0');
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
|
||||
|
||||
// UTF-8 encoding of 0x4840.
|
||||
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
|
||||
decoded = decoded.Substring(3);
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
try
|
||||
{
|
||||
decoded = decoded.Replace(c, '_');
|
||||
if (!e.IsStream)
|
||||
return;
|
||||
|
||||
var str = msi.RootStorage.GetStream(e.Name);
|
||||
if (str == null)
|
||||
return;
|
||||
|
||||
byte[] strData = str.GetData();
|
||||
if (strData == null)
|
||||
return;
|
||||
|
||||
var decoded = DecodeStreamName(e.Name)?.TrimEnd('\0');
|
||||
if (decoded == null)
|
||||
return;
|
||||
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
|
||||
|
||||
// UTF-8 encoding of 0x4840.
|
||||
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
|
||||
decoded = decoded.Substring(3);
|
||||
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
decoded = decoded.Replace(c, '_');
|
||||
}
|
||||
|
||||
string filename = Path.Combine(tempPath, decoded);
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(strData, 0, strData.Length);
|
||||
}
|
||||
}
|
||||
|
||||
string filename = Path.Combine(tempPath, decoded);
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
catch (Exception ex)
|
||||
{
|
||||
fs.Write(strData, 0, strData.Length);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}, recursive: true);
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <remarks>Adapted from LibMSI</remarks>
|
||||
#if NET48
|
||||
public static string DecodeStreamName(string input)
|
||||
#else
|
||||
public static string? DecodeStreamName(string input)
|
||||
#endif
|
||||
{
|
||||
if (input == null)
|
||||
return null;
|
||||
482
BinaryObjectScanner/FileType/Executable.cs
Normal file
482
BinaryObjectScanner/FileType/Executable.cs
Normal file
@@ -0,0 +1,482 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Executable or library
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Due to the complexity of executables, all extraction handling
|
||||
/// another class that is used by the scanner
|
||||
/// </remarks>
|
||||
public class Executable : IDetectable
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Determines if game engines are counted as detected protections or not
|
||||
/// </summary>
|
||||
public bool IncludeGameEngines { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if packers are counted as detected protections or not
|
||||
/// </summary>
|
||||
public bool IncludePackers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IContentCheck> ContentCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (contentCheckClasses == null)
|
||||
contentCheckClasses = InitCheckClasses<IContentCheck>();
|
||||
|
||||
return contentCheckClasses ?? Enumerable.Empty<IContentCheck>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<ILinearExecutableCheck> LinearExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linearExecutableCheckClasses == null)
|
||||
linearExecutableCheckClasses = InitCheckClasses<ILinearExecutableCheck>();
|
||||
|
||||
return linearExecutableCheckClasses ?? Enumerable.Empty<ILinearExecutableCheck>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IMSDOSExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IMSDOSExecutableCheck> MSDOSExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (msdosExecutableCheckClasses == null)
|
||||
msdosExecutableCheckClasses = InitCheckClasses<IMSDOSExecutableCheck>();
|
||||
|
||||
return msdosExecutableCheckClasses ?? Enumerable.Empty<IMSDOSExecutableCheck>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<INewExecutableCheck> NewExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (newExecutableCheckClasses == null)
|
||||
newExecutableCheckClasses = InitCheckClasses<INewExecutableCheck>();
|
||||
|
||||
return newExecutableCheckClasses ?? Enumerable.Empty<INewExecutableCheck>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IPortableExecutableCheck> PortableExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portableExecutableCheckClasses == null)
|
||||
portableExecutableCheckClasses = InitCheckClasses<IPortableExecutableCheck>();
|
||||
|
||||
return portableExecutableCheckClasses ?? Enumerable.Empty<IPortableExecutableCheck>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Instances
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<IContentCheck> contentCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<IContentCheck>? contentCheckClasses;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<ILinearExecutableCheck> linearExecutableCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<ILinearExecutableCheck>? linearExecutableCheckClasses;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IMSDOSExecutableCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<IMSDOSExecutableCheck> msdosExecutableCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<IMSDOSExecutableCheck>? msdosExecutableCheckClasses;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<INewExecutableCheck> newExecutableCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<INewExecutableCheck>? newExecutableCheckClasses;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<IPortableExecutableCheck> portableExecutableCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<IPortableExecutableCheck>? portableExecutableCheckClasses;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Try to create a wrapper for the proper executable type
|
||||
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return null;
|
||||
|
||||
// Create the internal queue
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// Only use generic content checks if we're in debug mode
|
||||
if (includeDebug)
|
||||
{
|
||||
var subProtections = RunContentChecks(file, stream, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
|
||||
if (wrapper is MSDOS mz)
|
||||
{
|
||||
var subProtections = RunMSDOSExecutableChecks(file, stream, mz, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
var subProtections = RunLinearExecutableChecks(file, stream, lex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
var subProtections = RunNewExecutableChecks(file, stream, nex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
var subProtections = RunPortableExecutableChecks(file, stream, pex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
|
||||
return string.Join(";", protections);
|
||||
}
|
||||
|
||||
#region Check Runners
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all content check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
#if NET48
|
||||
public ConcurrentDictionary<IContentCheck, string> RunContentChecks(string file, Stream stream, bool includeDebug)
|
||||
#else
|
||||
public ConcurrentDictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If we have an invalid file
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
return null;
|
||||
else if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Read the file contents
|
||||
byte[] fileContent = new byte[0];
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
if (fileContent == null)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<IContentCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ContentCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var protection = checkClass.CheckContents(file, fileContent, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering on game engines
|
||||
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
|
||||
return;
|
||||
|
||||
// If we are filtering on packers
|
||||
if (CheckIfPacker(checkClass) && !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all linear executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="lex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<ILinearExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var protection = checkClass.CheckLinearExecutable(file, lex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering on game engines
|
||||
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
|
||||
return;
|
||||
|
||||
// If we are filtering on packers
|
||||
if (CheckIfPacker(checkClass) && !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all MS-DOS executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="mz">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<IMSDOSExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(MSDOSExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var protection = checkClass.CheckMSDOSExecutable(file, mz, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering on game engines
|
||||
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
|
||||
return;
|
||||
|
||||
// If we are filtering on packers
|
||||
if (CheckIfPacker(checkClass) && !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all new executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="nex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<INewExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering on game engines
|
||||
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
|
||||
return;
|
||||
|
||||
// If we are filtering on packers
|
||||
if (CheckIfPacker(checkClass) && !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all portable executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="pex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<IPortableExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering on game engines
|
||||
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
|
||||
return;
|
||||
|
||||
// If we are filtering on packers
|
||||
if (CheckIfPacker(checkClass) && !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initializers
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<T> InitCheckClasses<T>()
|
||||
#else
|
||||
private static IEnumerable<T>? InitCheckClasses<T>()
|
||||
#endif
|
||||
=> InitCheckClasses<T>(typeof(GameEngine._DUMMY).Assembly) ?? Enumerable.Empty<T>()
|
||||
.Concat(InitCheckClasses<T>(typeof(Packer._DUMMY).Assembly) ?? Enumerable.Empty<T>())
|
||||
.Concat(InitCheckClasses<T>(typeof(Protection._DUMMY).Assembly) ?? Enumerable.Empty<T>());
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<T> InitCheckClasses<T>(Assembly assembly)
|
||||
#else
|
||||
private static IEnumerable<T>? InitCheckClasses<T>(Assembly assembly)
|
||||
#endif
|
||||
{
|
||||
return assembly.GetTypes()?
|
||||
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)?
|
||||
#if NET48
|
||||
.Select(t => (T)Activator.CreateInstance(t))
|
||||
#else
|
||||
.Select(t => (T?)Activator.CreateInstance(t))
|
||||
#endif
|
||||
.Cast<T>() ?? Array.Empty<T>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if an implementation is a game engine using reflection
|
||||
/// </summary>
|
||||
/// <param name="impl">Implementation that was last used to check</param>
|
||||
private static bool CheckIfGameEngine(object impl)
|
||||
{
|
||||
return impl?.GetType()?.Namespace?.ToLowerInvariant()?.Contains("gameengine") ?? false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if an implementation is a packer using reflection
|
||||
/// </summary>
|
||||
/// <param name="impl">Implementation that was last used to check</param>
|
||||
private static bool CheckIfPacker(object impl)
|
||||
{
|
||||
return impl.GetType()?.Namespace?.ToLowerInvariant()?.Contains("packer") ?? false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
165
BinaryObjectScanner/FileType/GCF.cs
Normal file
165
BinaryObjectScanner/FileType/GCF.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Half-Life Game Cache File
|
||||
/// </summary>
|
||||
public class GCF : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var gcf = SabreTools.Serialization.Wrappers.GCF.Create(stream);
|
||||
if (gcf == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAll(gcf, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the GCF to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.GCF item, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Files == null || item.Files.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Files.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the GCF to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.GCF item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Files == null || item.Files.Length == 0 || item.DataBlockOffsets == null)
|
||||
return false;
|
||||
|
||||
// If the files index is invalid
|
||||
if (index < 0 || index >= item.Files.Length)
|
||||
return false;
|
||||
|
||||
// Get the file
|
||||
var file = item.Files[index];
|
||||
if (file?.BlockEntries == null || file.Size == 0)
|
||||
return false;
|
||||
|
||||
// If the file is encrypted -- TODO: Revisit later
|
||||
if (file.Encrypted)
|
||||
return false;
|
||||
|
||||
// Get all data block offsets needed for extraction
|
||||
var dataBlockOffsets = new List<long>();
|
||||
for (int i = 0; i < file.BlockEntries.Length; i++)
|
||||
{
|
||||
var blockEntry = file.BlockEntries[i];
|
||||
if (blockEntry == null)
|
||||
continue;
|
||||
|
||||
uint dataBlockIndex = blockEntry.FirstDataBlockIndex;
|
||||
long blockEntrySize = blockEntry.FileDataSize;
|
||||
while (blockEntrySize > 0)
|
||||
{
|
||||
long dataBlockOffset = item.DataBlockOffsets[dataBlockIndex++];
|
||||
dataBlockOffsets.Add(dataBlockOffset);
|
||||
blockEntrySize -= item.Model.DataBlockHeader?.BlockSize ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the filename
|
||||
var filename = file.Path;
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
// Now read the data sequentially and write out while we have data left
|
||||
long fileSize = file.Size;
|
||||
for (int i = 0; i < dataBlockOffsets.Count; i++)
|
||||
{
|
||||
int readSize = (int)Math.Min(item.Model.DataBlockHeader?.BlockSize ?? 0, fileSize);
|
||||
var data = item.ReadFromDataSource((int)dataBlockOffsets[i], readSize);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.GZip;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// gzip archive
|
||||
/// </summary>
|
||||
public class GZIP : IScannable
|
||||
public class GZIP : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the gzip file itself fails
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -38,7 +47,6 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
foreach (var entry in zipFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -50,35 +58,18 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using UnshieldSharp.Archive;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// InstallShield archive v3
|
||||
/// </summary>
|
||||
public class InstallShieldArchiveV3 : IScannable
|
||||
public class InstallShieldArchiveV3 : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add stream opening support
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the archive itself fails
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
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));
|
||||
var directoryName = Path.GetDirectoryName(tempFile);
|
||||
if (directoryName != null && !Directory.Exists(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
(byte[] fileContents, string error) = archive.Extract(cfile.FullPath);
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
@@ -57,34 +61,17 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
BinaryObjectScanner/FileType/InstallShieldCAB.cs
Normal file
108
BinaryObjectScanner/FileType/InstallShieldCAB.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using UnshieldSharp.Cabinet;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// InstallShield cabinet file
|
||||
/// </summary>
|
||||
public class InstallShieldCAB : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the name of the first cabinet file or header
|
||||
var directory = Path.GetDirectoryName(file);
|
||||
string noExtension = Path.GetFileNameWithoutExtension(file);
|
||||
|
||||
bool shouldScanCabinet;
|
||||
if (directory == null)
|
||||
{
|
||||
string filenamePattern = noExtension;
|
||||
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
|
||||
bool cabinetHeaderExists = File.Exists(filenamePattern + "1.hdr");
|
||||
shouldScanCabinet = cabinetHeaderExists
|
||||
? file.Equals(filenamePattern + "1.hdr", StringComparison.OrdinalIgnoreCase)
|
||||
: file.Equals(filenamePattern + "1.cab", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
string filenamePattern = Path.Combine(directory, noExtension);
|
||||
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
|
||||
bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr"));
|
||||
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 anything but the first file
|
||||
if (!shouldScanCabinet)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
InstallShieldCabinet cabfile = InstallShieldCabinet.Open(file);
|
||||
for (int i = 0; i < cabfile.FileCount; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if the file is valid first
|
||||
if (!cabfile.FileIsValid(i))
|
||||
continue;
|
||||
|
||||
string tempFile;
|
||||
try
|
||||
{
|
||||
string filename = cabfile.FileName(i);
|
||||
tempFile = Path.Combine(tempPath, filename);
|
||||
}
|
||||
catch
|
||||
{
|
||||
tempFile = Path.Combine(tempPath, $"BAD_FILENAME{i}");
|
||||
}
|
||||
|
||||
cabfile.FileSave(i, tempFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
BinaryObjectScanner/FileType/LDSCRYPT.cs
Normal file
52
BinaryObjectScanner/FileType/LDSCRYPT.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Link Data Security encrypted file
|
||||
/// </summary>
|
||||
public class LDSCRYPT : IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] magic = new byte[16];
|
||||
stream.Read(magic, 0, 16);
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x4C, 0x44, 0x53, 0x43, 0x52, 0x59, 0x50, 0x54 }))
|
||||
return "Link Data Security encrypted file";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
#if NET48
|
||||
using StormLibSharp;
|
||||
#endif
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// MoPaQ game data archive
|
||||
/// </summary>
|
||||
public class MPQ : IScannable
|
||||
public class MPQ : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add stream opening support
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
// Not supported for .NET 6.0 due to Windows DLL requirements
|
||||
return null;
|
||||
#else
|
||||
// If the MPQ file itself fails
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -45,7 +51,7 @@ namespace BurnOutSharp.FileType
|
||||
// Try to open the listfile
|
||||
string listfile = null;
|
||||
MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
|
||||
|
||||
|
||||
// If we can't read the listfile, we just return
|
||||
if (!listStream.CanRead)
|
||||
return null;
|
||||
@@ -62,7 +68,6 @@ namespace BurnOutSharp.FileType
|
||||
// Loop over each entry
|
||||
foreach (string sub in listfileLines)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
string tempFile = Path.Combine(tempPath, sub);
|
||||
@@ -71,35 +76,18 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
41
BinaryObjectScanner/FileType/MicrosoftCAB.cs
Normal file
41
BinaryObjectScanner/FileType/MicrosoftCAB.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Microsoft cabinet file
|
||||
/// </summary>
|
||||
/// <remarks>Specification available at <see href="http://download.microsoft.com/download/5/0/1/501ED102-E53F-4CE0-AA6B-B0F93629DDC6/Exchange/%5BMS-CAB%5D.pdf"/></remarks>
|
||||
/// <see href="https://github.com/wine-mirror/wine/tree/master/dlls/cabinet"/>
|
||||
public class MicrosoftCAB : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Compression;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Compression.LZ;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Microsoft LZ-compressed Files (LZ32)
|
||||
/// </summary>
|
||||
/// <remarks>This is treated like an archive type due to the packing style</remarks>
|
||||
public class MicrosoftLZ : IScannable
|
||||
public class MicrosoftLZ : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the LZ file itself fails
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
byte[] data = LZ.Decompress(stream);
|
||||
var data = Decompressor.Decompress(stream);
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// Create the temp filename
|
||||
string tempFile = "temp.bin";
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
{
|
||||
string expandedFilePath = LZ.GetExpandedName(file, out _);
|
||||
tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
|
||||
var expandedFilePath = Decompressor.GetExpandedName(file, out _);
|
||||
if (expandedFilePath != null)
|
||||
tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
|
||||
if (tempFile.EndsWith(".ex"))
|
||||
tempFile += "e";
|
||||
else if (tempFile.EndsWith(".dl"))
|
||||
@@ -56,30 +65,13 @@ namespace BurnOutSharp.FileType
|
||||
tempStream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
137
BinaryObjectScanner/FileType/PAK.cs
Normal file
137
BinaryObjectScanner/FileType/PAK.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Half-Life Package File
|
||||
/// </summary>
|
||||
public class PAK : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var pak = SabreTools.Serialization.Wrappers.PAK.Create(stream);
|
||||
if (pak == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAll(pak, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the PAK to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.PAK item, string outputDirectory)
|
||||
{
|
||||
// If we have no directory items
|
||||
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.DirectoryItems.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the PAK to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.PAK item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no directory items
|
||||
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the directory item index is invalid
|
||||
if (index < 0 || index >= item.Model.DirectoryItems.Length)
|
||||
return false;
|
||||
|
||||
// Get the directory item
|
||||
var directoryItem = item.Model.DirectoryItems[index];
|
||||
if (directoryItem == null)
|
||||
return false;
|
||||
|
||||
// Read the item data
|
||||
var data = item.ReadFromDataSource((int)directoryItem.ItemOffset, (int)directoryItem.ItemLength);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
var filename = directoryItem.ItemName;
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
BinaryObjectScanner/FileType/PFF.cs
Normal file
130
BinaryObjectScanner/FileType/PFF.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// NovaLogic Game Archive Format
|
||||
/// </summary>
|
||||
public class PFF : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var pff = SabreTools.Serialization.Wrappers.PFF.Create(stream);
|
||||
if (pff == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Extract all files
|
||||
ExtractAll(pff, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all segments from the PFF to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all segments extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.PFF item, string outputDirectory)
|
||||
{
|
||||
// If we have no segments
|
||||
if (item.Model.Segments == null || item.Model.Segments.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.Segments.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractSegment(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a segment from the PFF to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">Segment index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the segment extracted, false otherwise</returns>
|
||||
public static bool ExtractSegment(SabreTools.Serialization.Wrappers.PFF item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no segments
|
||||
if (item.Model.Header?.NumberOfFiles == null || item.Model.Header.NumberOfFiles == 0 || item.Model.Segments == null || item.Model.Segments.Length == 0)
|
||||
return false;
|
||||
|
||||
// If we have an invalid index
|
||||
if (index < 0 || index >= item.Model.Segments.Length)
|
||||
return false;
|
||||
|
||||
// Get the segment information
|
||||
var file = item.Model.Segments[index];
|
||||
if (file == null)
|
||||
return false;
|
||||
|
||||
// Get the read index and length
|
||||
int offset = (int)file.FileLocation;
|
||||
int size = (int)file.FileSize;
|
||||
|
||||
try
|
||||
{
|
||||
// Ensure the output directory exists
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
|
||||
// Create the output path
|
||||
string filePath = Path.Combine(outputDirectory, file.FileName ?? $"file{index}");
|
||||
using (FileStream fs = File.OpenWrite(filePath))
|
||||
{
|
||||
// Read the data block
|
||||
var data = item.ReadFromDataSource(offset, size);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Write the data -- TODO: Compressed data?
|
||||
fs.Write(data, 0, size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// PKWARE ZIP archive and derivatives
|
||||
/// </summary>
|
||||
public class PKZIP : IScannable
|
||||
public class PKZIP : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the zip file itself fails
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -38,7 +47,6 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
foreach (var entry in zipFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -46,40 +54,25 @@ namespace BurnOutSharp.FileType
|
||||
continue;
|
||||
|
||||
string tempFile = Path.Combine(tempPath, entry.Key);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
|
||||
var directoryName = Path.GetDirectoryName(tempFile);
|
||||
if (directoryName != null && !Directory.Exists(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
entry.WriteToFile(tempFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
BinaryObjectScanner/FileType/PLJ.cs
Normal file
52
BinaryObjectScanner/FileType/PLJ.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// PlayJ audio file
|
||||
/// </summary>
|
||||
public class PLJ : IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] magic = new byte[16];
|
||||
stream.Read(magic, 0, 16);
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0xFF, 0x9D, 0x53, 0x4B }))
|
||||
return "PlayJ Audio File";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
166
BinaryObjectScanner/FileType/Quantum.cs
Normal file
166
BinaryObjectScanner/FileType/Quantum.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Quantum Archive
|
||||
/// </summary>
|
||||
public class Quantum : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var quantum = SabreTools.Serialization.Wrappers.Quantum.Create(stream);
|
||||
if (quantum == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Extract all files
|
||||
ExtractAll(quantum, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the Quantum archive to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.Quantum item, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Model.FileList == null || item.Model.FileList.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.FileList.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the Quantum archive to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.Quantum item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no files
|
||||
if (item.Model.Header == null || item.Model.Header.FileCount == 0 || item.Model.FileList == null || item.Model.FileList.Length == 0)
|
||||
return false;
|
||||
|
||||
// If we have an invalid index
|
||||
if (index < 0 || index >= item.Model.FileList.Length)
|
||||
return false;
|
||||
|
||||
// Get the file information
|
||||
var fileDescriptor = item.Model.FileList[index];
|
||||
|
||||
// Read the entire compressed data
|
||||
int compressedDataOffset = (int)item.Model.CompressedDataOffset;
|
||||
int compressedDataLength = item.GetEndOfFile() - compressedDataOffset;
|
||||
var compressedData = item.ReadFromDataSource(compressedDataOffset, compressedDataLength);
|
||||
|
||||
// TODO: Figure out decompression
|
||||
// - Single-file archives seem to work
|
||||
// - Single-file archives with files that span a window boundary seem to work
|
||||
// - The first files in each archive seem to work
|
||||
return false;
|
||||
|
||||
// // Setup the decompression state
|
||||
// State state = new State();
|
||||
// Decompressor.InitState(state, TableSize, CompressionFlags);
|
||||
|
||||
// // Decompress the entire array
|
||||
// int decompressedDataLength = (int)FileList.Sum(fd => fd.ExpandedFileSize);
|
||||
// byte[] decompressedData = new byte[decompressedDataLength];
|
||||
// Decompressor.Decompress(state, compressedData.Length, compressedData, decompressedData.Length, decompressedData);
|
||||
|
||||
// // Read the data
|
||||
// int offset = (int)FileList.Take(index).Sum(fd => fd.ExpandedFileSize);
|
||||
// byte[] data = new byte[fileDescriptor.ExpandedFileSize];
|
||||
// Array.Copy(decompressedData, offset, data, 0, data.Length);
|
||||
|
||||
// // Loop through all files before the current
|
||||
// for (int i = 0; i < index; i++)
|
||||
// {
|
||||
// // Decompress the next block of data
|
||||
// byte[] tempData = new byte[FileList[i].ExpandedFileSize];
|
||||
// int lastRead = Decompressor.Decompress(state, compressedData.Length, compressedData, tempData.Length, tempData);
|
||||
// compressedData = new ReadOnlySpan<byte>(compressedData, (lastRead), compressedData.Length - (lastRead)).ToArray();
|
||||
// }
|
||||
|
||||
// // Read the data
|
||||
// byte[] data = new byte[fileDescriptor.ExpandedFileSize];
|
||||
// _ = Decompressor.Decompress(state, compressedData.Length, compressedData, data.Length, data);
|
||||
|
||||
// // Create the filename
|
||||
// string filename = fileDescriptor.FileName;
|
||||
|
||||
// // If we have an invalid output directory
|
||||
// if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
// return false;
|
||||
|
||||
// // Create the full output path
|
||||
// filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// // Ensure the output directory is created
|
||||
// Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
|
||||
// // Try to write the data
|
||||
// try
|
||||
// {
|
||||
// // Open the output file for writing
|
||||
// using (Stream fs = File.OpenWrite(filename))
|
||||
// {
|
||||
// fs.Write(data, 0, data.Length);
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Rar;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// RAR archive
|
||||
/// </summary>
|
||||
public class RAR : IScannable
|
||||
public class RAR : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the rar file itself fails
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -38,7 +47,6 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
foreach (var entry in rarFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -50,35 +58,18 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
BinaryObjectScanner/FileType/SFFS.cs
Normal file
79
BinaryObjectScanner/FileType/SFFS.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// StarForce Filesystem file
|
||||
/// </summary>
|
||||
/// <see href="https://forum.xentax.com/viewtopic.php?f=21&t=2084"/>
|
||||
public class SFFS : IExtractable, IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] magic = new byte[16];
|
||||
stream.Read(magic, 0, 16);
|
||||
|
||||
if (magic.StartsWith(new byte?[] { 0x53, 0x46, 0x46, 0x53 }))
|
||||
return "StarForce Filesystem Container";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
283
BinaryObjectScanner/FileType/SGA.cs
Normal file
283
BinaryObjectScanner/FileType/SGA.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// SGA game archive
|
||||
/// </summary>
|
||||
public class SGA : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var sga = SabreTools.Serialization.Wrappers.SGA.Create(stream);
|
||||
if (sga == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAll(sga, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the SGA to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.SGA item, string outputDirectory)
|
||||
{
|
||||
// Get the number of files
|
||||
int filesLength;
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?.Length ?? 0; break;
|
||||
case 5: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?.Length ?? 0; break;
|
||||
case 6: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?.Length ?? 0; break;
|
||||
case 7: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?.Length ?? 0; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// If we have no files
|
||||
if (filesLength == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < filesLength; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the SGA to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.SGA item, int index, string outputDirectory)
|
||||
{
|
||||
// Get the number of files
|
||||
int filesLength;
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?.Length ?? 0; break;
|
||||
case 5: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?.Length ?? 0; break;
|
||||
case 6: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?.Length ?? 0; break;
|
||||
case 7: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?.Length ?? 0; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// If we have no files
|
||||
if (filesLength == 0)
|
||||
return false;
|
||||
|
||||
// If the files index is invalid
|
||||
if (index < 0 || index >= filesLength)
|
||||
return false;
|
||||
|
||||
// Get the files
|
||||
#if NET48
|
||||
object file;
|
||||
#else
|
||||
object? file;
|
||||
#endif
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4: file = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?[index]; break;
|
||||
case 5: file = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?[index]; break;
|
||||
case 6: file = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?[index]; break;
|
||||
case 7: file = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?[index]; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
if (file == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
var filename = string.Empty;
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4:
|
||||
case 5: filename = (file as SabreTools.Models.SGA.File4)?.Name; break;
|
||||
case 6: filename = (file as SabreTools.Models.SGA.File6)?.Name; break;
|
||||
case 7: filename = (file as SabreTools.Models.SGA.File7)?.Name; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// Loop through and get all parent directories
|
||||
#if NET48
|
||||
var parentNames = new List<string> { filename };
|
||||
#else
|
||||
var parentNames = new List<string?> { filename };
|
||||
#endif
|
||||
|
||||
// Get the parent directory
|
||||
var folder = default(object);
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
#if NET48
|
||||
case 4: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Folders?.FirstOrDefault(f => index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 5: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Folders?.FirstOrDefault(f => index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 6: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Folders?.FirstOrDefault(f => index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 7: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Folders?.FirstOrDefault(f => index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
#else
|
||||
case 4: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 5: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 6: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
case 7: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
|
||||
#endif
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// If we have a parent folder
|
||||
if (folder != null)
|
||||
{
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4: parentNames.Add((folder as SabreTools.Models.SGA.Folder4)?.Name); break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7: parentNames.Add((folder as SabreTools.Models.SGA.Folder5)?.Name); break;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should the section name/alias be used in the path as well?
|
||||
|
||||
// Reverse and assemble the filename
|
||||
parentNames.Reverse();
|
||||
filename = Path.Combine(parentNames.Cast<string>().ToArray());
|
||||
|
||||
// Get the file offset
|
||||
long fileOffset;
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4:
|
||||
case 5: fileOffset = (file as SabreTools.Models.SGA.File4)?.Offset ?? 0; break;
|
||||
case 6: fileOffset = (file as SabreTools.Models.SGA.File6)?.Offset ?? 0; break;
|
||||
case 7: fileOffset = (file as SabreTools.Models.SGA.File7)?.Offset ?? 0; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// Adjust the file offset
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header4)?.FileDataOffset ?? 0; break;
|
||||
case 5: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header4)?.FileDataOffset ?? 0; break;
|
||||
case 6: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header6)?.FileDataOffset ?? 0; break;
|
||||
case 7: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header6)?.FileDataOffset ?? 0; break;
|
||||
default: return false;
|
||||
};
|
||||
|
||||
// Get the file sizes
|
||||
long fileSize, outputFileSize;
|
||||
switch (item.Model.Header?.MajorVersion)
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
fileSize = (file as SabreTools.Models.SGA.File4)?.SizeOnDisk ?? 0;
|
||||
outputFileSize = (file as SabreTools.Models.SGA.File4)?.Size ?? 0;
|
||||
break;
|
||||
case 6:
|
||||
fileSize = (file as SabreTools.Models.SGA.File6)?.SizeOnDisk ?? 0;
|
||||
outputFileSize = (file as SabreTools.Models.SGA.File6)?.Size ?? 0;
|
||||
break;
|
||||
case 7:
|
||||
fileSize = (file as SabreTools.Models.SGA.File7)?.SizeOnDisk ?? 0;
|
||||
outputFileSize = (file as SabreTools.Models.SGA.File7)?.Size ?? 0;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// Read the compressed data directly
|
||||
var compressedData = item.ReadFromDataSource((int)fileOffset, (int)fileSize);
|
||||
if (compressedData == null)
|
||||
return false;
|
||||
|
||||
// If the compressed and uncompressed sizes match
|
||||
byte[] data;
|
||||
if (fileSize == outputFileSize)
|
||||
{
|
||||
data = compressedData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decompress the data
|
||||
data = new byte[outputFileSize];
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.SetInput(compressedData);
|
||||
inflater.Inflate(data);
|
||||
}
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.SevenZip;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// 7-zip archive
|
||||
/// </summary>
|
||||
public class SevenZip : IScannable
|
||||
public class SevenZip : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the 7-zip file itself fails
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -38,7 +44,6 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
foreach (var entry in sevenZipFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -50,35 +55,18 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Tape archive
|
||||
/// </summary>
|
||||
public class TapeArchive : IScannable
|
||||
public class TapeArchive : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the tar file itself fails
|
||||
if (stream == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
@@ -38,7 +47,6 @@ namespace BurnOutSharp.FileType
|
||||
{
|
||||
foreach (var entry in tarFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -50,35 +58,18 @@ namespace BurnOutSharp.FileType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BurnOutSharp.FileType
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Various generic textfile formats
|
||||
/// </summary>
|
||||
public class Textfile : IScannable
|
||||
public class Textfile : IDetectable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Detect(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Detect(Stream stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Files can be protected in multiple ways
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
var protections = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
// Load the current file content
|
||||
string fileContent = null;
|
||||
var fileContent = string.Empty;
|
||||
using (var sr = new StreamReader(stream, Encoding.Default, true, 1024 * 1024, true))
|
||||
{
|
||||
fileContent = sr.ReadToEnd();
|
||||
@@ -42,57 +49,60 @@ namespace BurnOutSharp.FileType
|
||||
// AegiSoft License Manager
|
||||
// Found in "setup.ins" (Redump entry 73521/IA item "Nova_HoyleCasino99USA").
|
||||
if (fileContent.Contains("Failed to load the AegiSoft License Manager install program."))
|
||||
AppendToDictionary(protections, file, "AegiSoft License Manager");
|
||||
protections.Add("AegiSoft License Manager");
|
||||
|
||||
// CD-Key
|
||||
if (fileContent.Contains("a valid serial number is required"))
|
||||
AppendToDictionary(protections, file, "CD-Key / Serial");
|
||||
protections.Add("CD-Key / Serial");
|
||||
else if (fileContent.Contains("serial number is located"))
|
||||
AppendToDictionary(protections, file, "CD-Key / Serial");
|
||||
protections.Add("CD-Key / Serial");
|
||||
// Found in "Setup.Ins" ("Word Point 2002" in IA item "advantage-language-french-beginner-langmaster-2005").
|
||||
else if (fileContent.Contains("Please enter a valid registration number"))
|
||||
protections.Add("CD-Key / Serial");
|
||||
|
||||
// Freelock
|
||||
// Found in "FILE_ID.DIZ" distributed with Freelock.
|
||||
if (fileContent.Contains("FREELOCK 1.0"))
|
||||
AppendToDictionary(protections, file, "Freelock 1.0");
|
||||
protections.Add("Freelock 1.0");
|
||||
else if (fileContent.Contains("FREELOCK 1.2"))
|
||||
AppendToDictionary(protections, file, "Freelock 1.2");
|
||||
protections.Add("Freelock 1.2");
|
||||
else if (fileContent.Contains("FREELOCK 1.2a"))
|
||||
AppendToDictionary(protections, file, "Freelock 1.2a");
|
||||
protections.Add("Freelock 1.2a");
|
||||
else if (fileContent.Contains("FREELOCK 1.3"))
|
||||
AppendToDictionary(protections, file, "Freelock 1.3");
|
||||
protections.Add("Freelock 1.3");
|
||||
else if (fileContent.Contains("FREELOCK"))
|
||||
AppendToDictionary(protections, file, "Freelock");
|
||||
protections.Add("Freelock");
|
||||
|
||||
// MediaCloQ
|
||||
if (fileContent.Contains("SunnComm MediaCloQ"))
|
||||
AppendToDictionary(protections, file, "MediaCloQ");
|
||||
protections.Add("MediaCloQ");
|
||||
else if (fileContent.Contains("http://download.mediacloq.com/"))
|
||||
AppendToDictionary(protections, file, "MediaCloQ");
|
||||
protections.Add("MediaCloQ");
|
||||
else if (fileContent.Contains("http://www.sunncomm.com/mediacloq/"))
|
||||
AppendToDictionary(protections, file, "MediaCloQ");
|
||||
protections.Add("MediaCloQ");
|
||||
|
||||
// MediaMax
|
||||
if (fileContent.Contains("MediaMax technology"))
|
||||
AppendToDictionary(protections, file, "MediaMax CD-3");
|
||||
protections.Add("MediaMax CD-3");
|
||||
else if (fileContent.Contains("exclusive Cd3 technology"))
|
||||
AppendToDictionary(protections, file, "MediaMax CD-3");
|
||||
protections.Add("MediaMax CD-3");
|
||||
else if (fileContent.Contains("<PROTECTION-VENDOR>MediaMAX</PROTECTION-VENDOR>"))
|
||||
AppendToDictionary(protections, file, "MediaMax CD-3");
|
||||
protections.Add("MediaMax CD-3");
|
||||
else if (fileContent.Contains("MediaMax(tm)"))
|
||||
AppendToDictionary(protections, file, "MediaMax CD-3");
|
||||
protections.Add("MediaMax CD-3");
|
||||
|
||||
// phenoProtect
|
||||
if (fileContent.Contains("phenoProtect"))
|
||||
AppendToDictionary(protections, file, "phenoProtect");
|
||||
protections.Add("phenoProtect");
|
||||
|
||||
// Rainbow Sentinel
|
||||
// Found in "SENTW95.HLP" and "SENTINEL.HLP" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".
|
||||
if (fileContent.Contains("Rainbow Sentinel Driver Help"))
|
||||
AppendToDictionary(protections, file, "Rainbow Sentinel");
|
||||
protections.Add("Rainbow Sentinel");
|
||||
|
||||
// Found in "OEMSETUP.INF" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".
|
||||
if (fileContent.Contains("Sentinel Driver Disk"))
|
||||
AppendToDictionary(protections, file, "Rainbow Sentinel");
|
||||
protections.Add("Rainbow Sentinel");
|
||||
|
||||
// The full line from a sample is as follows:
|
||||
//
|
||||
@@ -102,22 +112,22 @@ namespace BurnOutSharp.FileType
|
||||
|
||||
// SecuROM
|
||||
if (fileContent.Contains("SecuROM protected application"))
|
||||
AppendToDictionary(protections, file, "SecuROM");
|
||||
protections.Add("SecuROM");
|
||||
|
||||
// Steam
|
||||
if (fileContent.Contains("All use of the Program is governed by the terms of the Steam Agreement as described below."))
|
||||
AppendToDictionary(protections, file, "Steam");
|
||||
protections.Add("Steam");
|
||||
|
||||
// XCP
|
||||
if (fileContent.Contains("http://cp.sonybmg.com/xcp/"))
|
||||
AppendToDictionary(protections, file, "XCP");
|
||||
protections.Add("XCP");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return protections;
|
||||
return string.Join(";", protections);
|
||||
}
|
||||
}
|
||||
}
|
||||
146
BinaryObjectScanner/FileType/VBSP.cs
Normal file
146
BinaryObjectScanner/FileType/VBSP.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Half-Life 2 Level
|
||||
/// </summary>
|
||||
public class VBSP : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var vbsp = SabreTools.Serialization.Wrappers.VBSP.Create(stream);
|
||||
if (vbsp == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAllLumps(vbsp, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex.ToString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all lumps from the VBSP to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all lumps extracted, false otherwise</returns>
|
||||
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.VBSP item, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (item.Model.Header?.Lumps == null || item.Model.Header.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all lumps to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.Header.Lumps.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractLump(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a lump from the VBSP to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">Lump index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the lump extracted, false otherwise</returns>
|
||||
public static bool ExtractLump(SabreTools.Serialization.Wrappers.VBSP item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (item.Model.Header?.Lumps == null || item.Model.Header.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the lumps index is invalid
|
||||
if (index < 0 || index >= item.Model.Header.Lumps.Length)
|
||||
return false;
|
||||
|
||||
// Get the lump
|
||||
var lump = item.Model.Header.Lumps[index];
|
||||
if (lump == null)
|
||||
return false;
|
||||
|
||||
// Read the data
|
||||
var data = item.ReadFromDataSource((int)lump.Offset, (int)lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
string filename = $"lump_{index}.bin";
|
||||
switch (index)
|
||||
{
|
||||
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_ENTITIES:
|
||||
filename = "entities.ent";
|
||||
break;
|
||||
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_PAKFILE:
|
||||
filename = "pakfile.zip";
|
||||
break;
|
||||
}
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
195
BinaryObjectScanner/FileType/VPK.cs
Normal file
195
BinaryObjectScanner/FileType/VPK.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.IO;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Valve Package File
|
||||
/// </summary>
|
||||
public class VPK : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var vpk = SabreTools.Serialization.Wrappers.VPK.Create(stream);
|
||||
if (vpk == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAll(vpk, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the VPK to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.VPK item, string outputDirectory)
|
||||
{
|
||||
// If we have no directory items
|
||||
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.DirectoryItems.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the VPK to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.VPK item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no directory items
|
||||
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the directory item index is invalid
|
||||
if (index < 0 || index >= item.Model.DirectoryItems.Length)
|
||||
return false;
|
||||
|
||||
// Get the directory item
|
||||
var directoryItem = item.Model.DirectoryItems[index];
|
||||
if (directoryItem?.DirectoryEntry == null)
|
||||
return false;
|
||||
|
||||
// If we have an item with no archive
|
||||
var data = new byte[0];
|
||||
if (directoryItem.DirectoryEntry.ArchiveIndex == SabreTools.Models.VPK.Constants.HL_VPK_NO_ARCHIVE)
|
||||
{
|
||||
if (directoryItem.PreloadData == null)
|
||||
return false;
|
||||
|
||||
data = directoryItem.PreloadData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have invalid archives
|
||||
if (item.ArchiveFilenames == null || item.ArchiveFilenames.Length == 0)
|
||||
return false;
|
||||
|
||||
// If we have an invalid index
|
||||
if (directoryItem.DirectoryEntry.ArchiveIndex < 0 || directoryItem.DirectoryEntry.ArchiveIndex >= item.ArchiveFilenames.Length)
|
||||
return false;
|
||||
|
||||
// Get the archive filename
|
||||
string archiveFileName = item.ArchiveFilenames[directoryItem.DirectoryEntry.ArchiveIndex];
|
||||
if (string.IsNullOrWhiteSpace(archiveFileName))
|
||||
return false;
|
||||
|
||||
// If the archive doesn't exist
|
||||
if (!File.Exists(archiveFileName))
|
||||
return false;
|
||||
|
||||
// Try to open the archive
|
||||
var archiveStream = default(Stream);
|
||||
try
|
||||
{
|
||||
// Open the archive
|
||||
archiveStream = File.OpenRead(archiveFileName);
|
||||
|
||||
// Seek to the data
|
||||
archiveStream.Seek(directoryItem.DirectoryEntry.EntryOffset, SeekOrigin.Begin);
|
||||
|
||||
// Read the directory item bytes
|
||||
data = archiveStream.ReadBytes((int)directoryItem.DirectoryEntry.EntryLength);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
archiveStream?.Close();
|
||||
}
|
||||
|
||||
// If we have preload data, prepend it
|
||||
if (data != null && directoryItem.PreloadData != null)
|
||||
data = directoryItem.PreloadData.Concat(data).ToArray();
|
||||
}
|
||||
|
||||
// If there is nothing to write out
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
string filename = $"{directoryItem.Name}.{directoryItem.Extension}";
|
||||
if (!string.IsNullOrWhiteSpace(directoryItem.Path))
|
||||
filename = Path.Combine(directoryItem.Path, filename);
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
137
BinaryObjectScanner/FileType/WAD.cs
Normal file
137
BinaryObjectScanner/FileType/WAD.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Half-Life Texture Package File
|
||||
/// </summary>
|
||||
public class WAD : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var wad = SabreTools.Serialization.Wrappers.WAD.Create(stream);
|
||||
if (wad == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAllLumps(wad, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all lumps from the WAD to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all lumps extracted, false otherwise</returns>
|
||||
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.WAD item, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all lumps to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.Lumps.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractLump(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a lump from the WAD to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">Lump index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the lump extracted, false otherwise</returns>
|
||||
public static bool ExtractLump(SabreTools.Serialization.Wrappers.WAD item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no lumps
|
||||
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the lumps index is invalid
|
||||
if (index < 0 || index >= item.Model.Lumps.Length)
|
||||
return false;
|
||||
|
||||
// Get the lump
|
||||
var lump = item.Model.Lumps[index];
|
||||
if (lump == null)
|
||||
return false;
|
||||
|
||||
// Read the data -- TODO: Handle uncompressed lumps (see BSP.ExtractTexture)
|
||||
var data = item.ReadFromDataSource((int)lump.Offset, (int)lump.Length);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
string filename = $"{lump.Name}.lmp";
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
BinaryObjectScanner/FileType/XZ.cs
Normal file
60
BinaryObjectScanner/FileType/XZ.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// xz archive
|
||||
/// </summary>
|
||||
public class XZ : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
using (XZStream xzFile = new XZStream(stream))
|
||||
{
|
||||
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
|
||||
using (FileStream fs = File.OpenWrite(tempFile))
|
||||
{
|
||||
xzFile.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
147
BinaryObjectScanner/FileType/XZP.cs
Normal file
147
BinaryObjectScanner/FileType/XZP.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// XBox Package File
|
||||
/// </summary>
|
||||
public class XZP : IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the wrapper
|
||||
var xzp = SabreTools.Serialization.Wrappers.XZP.Create(stream);
|
||||
if (xzp == null)
|
||||
return null;
|
||||
|
||||
// Create a temp output directory
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Loop through and extract all files
|
||||
ExtractAll(xzp, tempPath);
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract all files from the XZP to an output directory
|
||||
/// </summary>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if all files extracted, false otherwise</returns>
|
||||
public static bool ExtractAll(SabreTools.Serialization.Wrappers.XZP item, string outputDirectory)
|
||||
{
|
||||
// If we have no directory entries
|
||||
if (item.Model.DirectoryEntries == null || item.Model.DirectoryEntries.Length == 0)
|
||||
return false;
|
||||
|
||||
// Loop through and extract all files to the output
|
||||
bool allExtracted = true;
|
||||
for (int i = 0; i < item.Model.DirectoryEntries.Length; i++)
|
||||
{
|
||||
allExtracted &= ExtractFile(item, i, outputDirectory);
|
||||
}
|
||||
|
||||
return allExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract a file from the XZP to an output directory by index
|
||||
/// </summary>
|
||||
/// <param name="index">File index to extract</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <returns>True if the file extracted, false otherwise</returns>
|
||||
public static bool ExtractFile(SabreTools.Serialization.Wrappers.XZP item, int index, string outputDirectory)
|
||||
{
|
||||
// If we have no directory entries
|
||||
if (item.Model.DirectoryEntries == null || item.Model.DirectoryEntries.Length == 0)
|
||||
return false;
|
||||
|
||||
// If we have no directory items
|
||||
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the directory entry index is invalid
|
||||
if (index < 0 || index >= item.Model.DirectoryEntries.Length)
|
||||
return false;
|
||||
|
||||
// Get the directory entry
|
||||
var directoryEntry = item.Model.DirectoryEntries[index];
|
||||
if (directoryEntry == null)
|
||||
return false;
|
||||
|
||||
// Get the associated directory item
|
||||
var directoryItem = item.Model.DirectoryItems.Where(di => di?.FileNameCRC == directoryEntry.FileNameCRC).FirstOrDefault();
|
||||
if (directoryItem == null)
|
||||
return false;
|
||||
|
||||
// Load the item data
|
||||
var data = item.ReadFromDataSource((int)directoryEntry.EntryOffset, (int)directoryEntry.EntryLength);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Create the filename
|
||||
var filename = directoryItem.Name;
|
||||
|
||||
// If we have an invalid output directory
|
||||
if (string.IsNullOrWhiteSpace(outputDirectory))
|
||||
return false;
|
||||
|
||||
// Create the full output path
|
||||
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
|
||||
|
||||
// Ensure the output directory is created
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName != null)
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Try to write the data
|
||||
try
|
||||
{
|
||||
// Open the output file for writing
|
||||
using (Stream fs = File.OpenWrite(filename))
|
||||
{
|
||||
fs.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
BinaryObjectScanner/GameEngine/RenderWare.cs
Normal file
44
BinaryObjectScanner/GameEngine/RenderWare.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.GameEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// RenderWare (https://web.archive.org/web/20070214132346/http://www.renderware.com/) is an API and graphics engine created by Criterion in 1993.
|
||||
/// It appears that version 4.X was exclusively used by EA internally, with version 3.X being the final public version (https://sigmaco.org/3782-renderware/).
|
||||
/// It was available to use on many different platforms, with it being particularly useful for the PS2 (https://en.wikipedia.org/wiki/RenderWare).
|
||||
///
|
||||
/// Additional resources and documentation:
|
||||
/// RenderWare interview: https://web.archive.org/web/20031208124348/http://www.homelanfed.com/index.php?id=9856
|
||||
/// RenderWare V2.1 API reference: http://www.tnlc.com/rw/api/rwdoc.htm
|
||||
/// RenderWare 2 official docs: https://github.com/electronicarts/RenderWare3Docs
|
||||
/// RenderWare 3.7 SDK: https://github.com/sigmaco/rwsdk-v37-pc
|
||||
/// Wikipedia list of RenderWare games: https://en.wikipedia.org/wiki/Category:RenderWare_games
|
||||
/// </summary>
|
||||
public class RenderWare : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Found in Redump entries 20138, 55823, and 102493.
|
||||
bool rwcsegSection = pex.ContainsSection("_rwcseg", exact: true);
|
||||
// Found in Redump entry 20138.
|
||||
bool rwdsegSection = pex.ContainsSection("_rwdseg", exact: true);
|
||||
|
||||
// TODO: Check if this indicates a specific version, or if these sections are present in multiple.
|
||||
if (rwcsegSection || rwdsegSection)
|
||||
return "RenderWare";
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
BinaryObjectScanner/GameEngine/_DUMMY.cs
Normal file
7
BinaryObjectScanner/GameEngine/_DUMMY.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace BinaryObjectScanner.GameEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// This class exists for reflection purposes and should not be used
|
||||
/// </summary>
|
||||
public sealed class _DUMMY { }
|
||||
}
|
||||
265
BinaryObjectScanner/Handler.cs
Normal file
265
BinaryObjectScanner/Handler.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
using static BinaryObjectScanner.Utilities.Dictionary;
|
||||
|
||||
namespace BinaryObjectScanner
|
||||
{
|
||||
internal static class Handler
|
||||
{
|
||||
#region Public Collections
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static IEnumerable<IPathCheck> PathCheckClasses
|
||||
#else
|
||||
public static IEnumerable<IPathCheck?> PathCheckClasses
|
||||
#endif
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pathCheckClasses == null)
|
||||
pathCheckClasses = InitCheckClasses<IPathCheck>();
|
||||
|
||||
return pathCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Instances
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<IPathCheck> pathCheckClasses;
|
||||
#else
|
||||
private static IEnumerable<IPathCheck?>? pathCheckClasses;
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Multiple Implementation Wrappers
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single path based on all path check implementations
|
||||
/// </summary>
|
||||
/// <param name="path">Path of the file or directory to check</param>
|
||||
/// <param name="scanner">Scanner object to use for options and scanning</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
#if NET48
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePathChecks(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Preprocess the list of files
|
||||
files = files?.Select(f => f.Replace('\\', '/'))?.ToList();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(PathCheckClasses, checkClass =>
|
||||
{
|
||||
var subProtections = checkClass?.PerformCheck(path, files);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, path, subProtections);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Single Implementation Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IDetectable implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">IDetectable class representing the file type</param>
|
||||
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
#if NET48
|
||||
public static ConcurrentQueue<string> HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
|
||||
#else
|
||||
public static ConcurrentQueue<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
var protection = impl.Detect(stream, fileName, includeDebug);
|
||||
return ProcessProtectionString(protection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IExtractable implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">IDetectable class representing the file type</param>
|
||||
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="scanner">Scanner object to use on extractable contents</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
#if NET48
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleExtractable(IExtractable impl, string fileName, Stream stream, Scanner scanner)
|
||||
#else
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
|
||||
#endif
|
||||
{
|
||||
// If the extractable file itself fails
|
||||
try
|
||||
{
|
||||
// Extract and get the output path
|
||||
var tempPath = impl.Extract(stream, fileName, scanner.IncludeDebug);
|
||||
if (tempPath == null)
|
||||
return null;
|
||||
|
||||
// Collect and format all found protections
|
||||
var subProtections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Prepare the returned protections
|
||||
StripFromKeys(subProtections, tempPath);
|
||||
PrependToKeys(subProtections, fileName);
|
||||
return subProtections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IPathCheck implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">IPathCheck class representing the file type</param>
|
||||
/// <param name="path">Path of the file or directory to check</param>
|
||||
/// <returns>Set of protections in path, null on error</returns>
|
||||
#if NET48
|
||||
private static ConcurrentQueue<string> PerformCheck(this IPathCheck impl, string path, IEnumerable<string> files)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// If we have an invalid path
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
// Setup the output dictionary
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// If we have a file path
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var protection = impl.CheckFilePath(path);
|
||||
var subProtections = ProcessProtectionString(protection);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections);
|
||||
}
|
||||
|
||||
// If we have a directory path
|
||||
if (Directory.Exists(path) && files?.Any() == true)
|
||||
{
|
||||
var subProtections = impl.CheckDirectoryPath(path, files);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections);
|
||||
}
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initializers
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<T> InitCheckClasses<T>()
|
||||
#else
|
||||
private static IEnumerable<T?> InitCheckClasses<T>()
|
||||
#endif
|
||||
{
|
||||
return InitCheckClasses<T>(typeof(GameEngine._DUMMY).Assembly)
|
||||
.Concat(InitCheckClasses<T>(typeof(Packer._DUMMY).Assembly))
|
||||
.Concat(InitCheckClasses<T>(typeof(Protection._DUMMY).Assembly));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
#if NET48
|
||||
private static IEnumerable<T> InitCheckClasses<T>(Assembly assembly)
|
||||
#else
|
||||
private static IEnumerable<T?> InitCheckClasses<T>(Assembly assembly)
|
||||
#endif
|
||||
{
|
||||
return assembly.GetTypes()?
|
||||
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)?
|
||||
#if NET48
|
||||
.Select(t => (T)Activator.CreateInstance(t)) ?? Array.Empty<T>();
|
||||
#else
|
||||
.Select(t => (T?)Activator.CreateInstance(t)) ?? Array.Empty<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Process a protection string if it includes multiple protections
|
||||
/// </summary>
|
||||
/// <param name="protection">Protection string to process</param>
|
||||
/// <returns>Set of protections parsed, null on error</returns>
|
||||
#if NET48
|
||||
private static ConcurrentQueue<string> ProcessProtectionString(string protection)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? ProcessProtectionString(string? protection)
|
||||
#endif
|
||||
{
|
||||
// If we have an invalid protection string
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return null;
|
||||
|
||||
// Setup the output queue
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// If we have an indicator of multiple protections
|
||||
if (protection.Contains(";"))
|
||||
{
|
||||
var splitProtections = protection.Split(';');
|
||||
protections.AddRange(splitProtections);
|
||||
}
|
||||
else
|
||||
{
|
||||
protections.Enqueue(protection);
|
||||
}
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BurnOutSharp.Interfaces
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a generic file for protection
|
||||
@@ -12,6 +12,10 @@
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
#if NET48
|
||||
string CheckContents(string file, byte[] fileContent, bool includeDebug);
|
||||
#else
|
||||
string? CheckContents(string file, byte[] fileContent, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
36
BinaryObjectScanner/Interfaces/IDetectable.cs
Normal file
36
BinaryObjectScanner/Interfaces/IDetectable.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.IO;
|
||||
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark a file type as being able to be detected
|
||||
/// </summary>
|
||||
public interface IDetectable
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if a file is detected as this file type
|
||||
/// </summary>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Detected file or protection type, null on error</returns>
|
||||
/// <remarks>Ideally, this should just point to the other detect implementation.</remarks>
|
||||
#if NET48
|
||||
string Detect(string file, bool includeDebug);
|
||||
#else
|
||||
string? Detect(string file, bool includeDebug);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Check if a stream is detected as this file type
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing the input file</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Detected file or protection type, null on error</returns>
|
||||
#if NET48
|
||||
string Detect(Stream stream, string file, bool includeDebug);
|
||||
#else
|
||||
string? Detect(Stream stream, string file, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
38
BinaryObjectScanner/Interfaces/IExtractable.cs
Normal file
38
BinaryObjectScanner/Interfaces/IExtractable.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.IO;
|
||||
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark a file type as being able to be extracted
|
||||
/// </summary>
|
||||
/// TODO: Change to have output directory passed in
|
||||
/// TODO: Change to return a bool
|
||||
public interface IExtractable
|
||||
{
|
||||
/// <summary>
|
||||
/// Extract a file to a temporary path, if possible
|
||||
/// </summary>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Path to extracted files, null on error</returns>
|
||||
/// <remarks>Ideally, this should just point to the other extract implementation.</remarks>
|
||||
#if NET48
|
||||
string Extract(string file, bool includeDebug);
|
||||
#else
|
||||
string? Extract(string file, bool includeDebug);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Extract a stream to a temporary path, if possible
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream representing the input file</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Path to extracted files, null on error</returns>
|
||||
#if NET48
|
||||
string Extract(Stream stream, string file, bool includeDebug);
|
||||
#else
|
||||
string? Extract(Stream? stream, string file, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using BurnOutSharp.Wrappers;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.Interfaces
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a Linear Executable (LE) for protection
|
||||
@@ -14,6 +14,10 @@ namespace BurnOutSharp.Interfaces
|
||||
/// <param name="lex">LinearExecutable representing the read-in file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
string CheckNewExecutable(string file, LinearExecutable lex, bool includeDebug);
|
||||
#if NET48
|
||||
string CheckLinearExecutable(string file, LinearExecutable lex, bool includeDebug);
|
||||
#else
|
||||
string? CheckLinearExecutable(string file, LinearExecutable lex, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
23
BinaryObjectScanner/Interfaces/IMSDOSExecutableCheck.cs
Normal file
23
BinaryObjectScanner/Interfaces/IMSDOSExecutableCheck.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a MS-DOS Executable (MZ) for protection
|
||||
/// </summary>
|
||||
public interface IMSDOSExecutableCheck
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a path for protections based on file contents
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for protection indicators</param>
|
||||
/// <param name="mz">MSDOS representing the read-in file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
#if NET48
|
||||
string CheckMSDOSExecutable(string file, MSDOS mz, bool includeDebug);
|
||||
#else
|
||||
string? CheckMSDOSExecutable(string file, MSDOS mz, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using BurnOutSharp.Wrappers;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.Interfaces
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a New Executable (NE) for protection
|
||||
@@ -14,6 +14,10 @@ namespace BurnOutSharp.Interfaces
|
||||
/// <param name="nex">NewExecutable representing the read-in file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
#if NET48
|
||||
string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug);
|
||||
#else
|
||||
string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BurnOutSharp.Interfaces
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a file or directory path for protection
|
||||
@@ -17,13 +17,21 @@ namespace BurnOutSharp.Interfaces
|
||||
/// <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 a content check instead, if possible</remarks>
|
||||
#if NET48
|
||||
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files);
|
||||
#else
|
||||
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
|
||||
#endif
|
||||
|
||||
/// <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 a content check instead, if possible</remarks>
|
||||
#if NET48
|
||||
string CheckFilePath(string path);
|
||||
#else
|
||||
string? CheckFilePath(string path);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using BurnOutSharp.Wrappers;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.Interfaces
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Check a Portable Executable (PE) for protection
|
||||
@@ -14,6 +14,10 @@ namespace BurnOutSharp.Interfaces
|
||||
/// <param name="pex">PortableExecutable representing the read-in file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>String containing any protections found in the file</returns>
|
||||
#if NET48
|
||||
string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug);
|
||||
#else
|
||||
string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
38
BinaryObjectScanner/Options.cs
Normal file
38
BinaryObjectScanner/Options.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace BinaryObjectScanner
|
||||
{
|
||||
/// <summary>
|
||||
/// Scanning options
|
||||
/// </summary>
|
||||
public class Options
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether archives are decompressed and scanned
|
||||
/// </summary>
|
||||
public bool ScanArchives { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if content matches are used or not
|
||||
/// </summary>
|
||||
public bool ScanContents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if game engines are counted as detected protections or not
|
||||
/// </summary>
|
||||
public bool ScanGameEngines { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if packers are counted as detected protections or not
|
||||
/// </summary>
|
||||
public bool ScanPackers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if path matches are used or not
|
||||
/// </summary>
|
||||
public bool ScanPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if debug information is output or not
|
||||
/// </summary>
|
||||
public bool IncludeDebug { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class ASPack : IPortableExecutableCheck, IScannable
|
||||
public class ASPack : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -29,20 +32,20 @@ namespace BurnOutSharp.PackerType
|
||||
// if (pex.EntryPointRaw != null)
|
||||
// {
|
||||
// var matchers = GenerateMatchers();
|
||||
// string match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
|
||||
// var match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
|
||||
// if (!string.IsNullOrWhiteSpace(match))
|
||||
// return match;
|
||||
// }
|
||||
|
||||
// Get the .adata* section, if it exists
|
||||
var adataSection = pex.GetFirstSection(".adata", exact: false);
|
||||
if (adataSection != null)
|
||||
if (adataSection?.Name != null)
|
||||
{
|
||||
var adataSectionRaw = pex.GetFirstSectionData(Encoding.UTF8.GetString(adataSection.Name));
|
||||
if (adataSectionRaw != null)
|
||||
{
|
||||
var matchers = GenerateMatchers();
|
||||
string match = MatchUtil.GetFirstMatch(file, adataSectionRaw, matchers, includeDebug);
|
||||
var match = MatchUtil.GetFirstMatch(file, adataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
@@ -52,19 +55,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,26 +1,29 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// TODO: Verify that all versions are detected
|
||||
public class AdvancedInstaller : IPortableExecutableCheck, IScannable
|
||||
public class AdvancedInstaller : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .rdata section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".rdata");
|
||||
var strs = pex.GetFirstSectionStrings(".rdata");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("Software\\Caphyon\\Advanced Installer")))
|
||||
@@ -31,19 +34,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
74
BinaryObjectScanner/Packer/Armadillo.cs
Normal file
74
BinaryObjectScanner/Packer/Armadillo.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// TODO: Add version checking, if possible
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class Armadillo : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .nicode section, if it exists
|
||||
bool nicodeSection = pex.ContainsSection(".nicode", exact: true);
|
||||
if (nicodeSection)
|
||||
return "Armadillo";
|
||||
|
||||
// Loop through all "extension" sections -- usually .data1 or .text1
|
||||
if (pex.SectionNames != null)
|
||||
{
|
||||
foreach (var sectionName in pex.SectionNames.Where(s => s != null && s.EndsWith("1")))
|
||||
{
|
||||
// Get the section strings, if they exist
|
||||
var strs = pex.GetFirstSectionStrings(sectionName);
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("ARMDEBUG")))
|
||||
return "Armadillo";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// Created by IndigoRose (creators of Setup Factory), primarily to be used to create autorun menus for various media.
|
||||
// Official website: https://www.autoplay.org/
|
||||
// TODO: Add extraction
|
||||
public class AutoPlayMediaStudio : IPortableExecutableCheck, IScannable
|
||||
public class AutoPlayMediaStudio : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Known to detect versions 5.0.0.3 - 8.1.0.0
|
||||
string name = pex.ProductName;
|
||||
var name = pex.ProductName;
|
||||
if (name?.StartsWith("AutoPlay Media Studio", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return $"AutoPlay Media Studio {GetVersion(pex)}";
|
||||
|
||||
@@ -35,32 +38,40 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private string GetVersion(PortableExecutable pex)
|
||||
{
|
||||
// Check the product version explicitly
|
||||
string version = pex.ProductVersion;
|
||||
var version = pex.ProductVersion;
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
// Check the internal versions
|
||||
version = Tools.Utilities.GetInternalVersion(pex);
|
||||
version = pex.GetInternalVersion();
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
158
BinaryObjectScanner/Packer/CExe.cs
Normal file
158
BinaryObjectScanner/Packer/CExe.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using ICSharpCode.SharpZipLib.Zip.Compression;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// 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
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class CExe : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// If there are exactly 2 resources with type 99
|
||||
if (pex.FindResourceByNamedType("99, ").Count() == 2)
|
||||
return "CExe";
|
||||
|
||||
if (pex.StubExecutableData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
new ContentMatchSet(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
|
||||
}, "CExe")
|
||||
};
|
||||
|
||||
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse into an executable again for easier extraction
|
||||
var pex = PortableExecutable.Create(stream);
|
||||
if (pex == null)
|
||||
return null;
|
||||
|
||||
// Get the first resource of type 99 with index 2
|
||||
var payload = pex.FindResourceByNamedType("99, 2").FirstOrDefault();
|
||||
if (payload == null || payload.Length == 0)
|
||||
return null;
|
||||
|
||||
// Determine which compression was used
|
||||
bool zlib = pex.FindResourceByNamedType("99, 1").Any();
|
||||
|
||||
// Create the output data buffer
|
||||
var data = new byte[0];
|
||||
|
||||
// If we had the decompression DLL included, it's zlib
|
||||
if (zlib)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Inflate the data into the buffer
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.SetInput(payload);
|
||||
data = new byte[payload.Length * 4];
|
||||
int read = inflater.Inflate(data);
|
||||
|
||||
// Trim the buffer to the proper size
|
||||
data = new ReadOnlySpan<byte>(data, 0, read).ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reset the data
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, LZ is used via the Windows API
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
data = SabreTools.Compression.LZ.Decompressor.Decompress(payload);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Reset the data
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no data
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Create the temp filename
|
||||
string tempFile = string.IsNullOrEmpty(file) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(file)}.sxe";
|
||||
tempFile = Path.Combine(tempPath, tempFile);
|
||||
|
||||
// Write the file data to a temp file
|
||||
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
tempStream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,23 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Figure out how to more granularly determine versions like PiD
|
||||
// TODO: Detect 3.15 and up (maybe looking for `Metamorphism`)
|
||||
// TODO: Add extraction
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class EXEStealth : IContentCheck, IPortableExecutableCheck, IScannable
|
||||
public class EXEStealth : IContentCheck, IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#else
|
||||
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
@@ -39,10 +42,14 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -76,19 +83,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
110
BinaryObjectScanner/Packer/EmbeddedExecutable.cs
Normal file
110
BinaryObjectScanner/Packer/EmbeddedExecutable.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
/// <summary>
|
||||
/// Though not technically a packer, this detection is for any executables that include
|
||||
/// others in their resources in some uncompressed manner to be used at runtime.
|
||||
/// </summary>
|
||||
public class EmbeddedExecutable : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the resources that have an executable signature
|
||||
if (pex.ResourceData?.Any(kvp => kvp.Value is byte[] ba && ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) == true)
|
||||
return "Embedded Executable";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse into an executable again for easier extraction
|
||||
var pex = PortableExecutable.Create(stream);
|
||||
if (pex?.ResourceData == null)
|
||||
return null;
|
||||
|
||||
// Get the resources that have an executable signature
|
||||
var resources = pex.ResourceData
|
||||
.Where(kvp => kvp.Value != null && kvp.Value is byte[])
|
||||
.Select(kvp => kvp.Value as byte[])
|
||||
.Where(b => b != null && b.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
|
||||
.ToList();
|
||||
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
for (int i = 0; i < resources.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the resource data
|
||||
var data = resources[i];
|
||||
if (data == null)
|
||||
continue;
|
||||
|
||||
// Create the temp filename
|
||||
string tempFile = $"embedded_resource_{i}.bin";
|
||||
tempFile = Path.Combine(tempPath, tempFile);
|
||||
|
||||
// Write the resource data to a temp file
|
||||
using (var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
if (tempStream != null)
|
||||
tempStream.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,29 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class GenteeInstaller : IPortableExecutableCheck, IScannable
|
||||
public class GenteeInstaller : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("Gentee installer")))
|
||||
@@ -34,19 +37,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,30 +1,33 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// CrackProof is a packer/obfuscator created by Japanese company HyperTech (https://www.hypertech.co.jp/products/windows/).
|
||||
// It is known to be used along with other DRM, such as Shury2 (Redump entry 97135) and BDL.
|
||||
// https://www.reddit.com/r/riseofincarnates/comments/m3vbnm/subreddit_revival_does_anyone_still_have_rise_of/
|
||||
// https://steamcommunity.com/app/310950/discussions/0/4224890554455490819/
|
||||
// https://github.com/horsicq/Detect-It-Easy/blob/63a1aa8bb23ca02d8a7fd5936db8dbc5c5d52dea/db/PE/HyperTech%20Crackproof.2.sg
|
||||
public class HyperTechCrackProof : IPortableExecutableCheck, IScannable
|
||||
public class HyperTechCrackProof : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// This check may be overly limiting, as it excludes the sample provided to DiE (https://github.com/horsicq/Detect-It-Easy/issues/102).
|
||||
// TODO: Find further samples and invesitgate if the "peC" section is only present on specific versions.
|
||||
bool peCSection = pex.ContainsSection("peC", exact: true);
|
||||
bool importTableMatch = (pex.ImportTable?.ImportDirectoryTable?.Any(idte => idte.Name == "KeRnEl32.dLl") ?? false);
|
||||
bool importTableMatch = (pex.Model.ImportTable?.ImportDirectoryTable?.Any(idte => idte?.Name == "KeRnEl32.dLl") ?? false);
|
||||
|
||||
if (peCSection && importTableMatch)
|
||||
return "HyperTech CrackProof";
|
||||
@@ -33,19 +36,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction - https://github.com/dscharrer/InnoExtract
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class InnoSetup : INewExecutableCheck, IPortableExecutableCheck, IScannable
|
||||
public class InnoSetup : IExtractable, INewExecutableCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Check we have a valid executable
|
||||
if (nex == null)
|
||||
return null;
|
||||
|
||||
// Check for "Inno" in the reserved words
|
||||
if (nex.Stub_Reserved2[4] == 0x6E49 && nex.Stub_Reserved2[5] == 0x6F6E)
|
||||
if (nex.Model.Stub?.Header?.Reserved2?[4] == 0x6E49 && nex.Model.Stub?.Header?.Reserved2?[5] == 0x6F6E)
|
||||
{
|
||||
string version = GetOldVersion(file, nex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
@@ -33,18 +32,22 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
string str = strs.FirstOrDefault(s => s.StartsWith("Inno Setup Setup Data"));
|
||||
var str = strs.FirstOrDefault(s => s.StartsWith("Inno Setup Setup Data"));
|
||||
if (str != null)
|
||||
{
|
||||
return str.Replace("Inno Setup Setup Data", "Inno Setup")
|
||||
@@ -59,19 +62,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,24 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction, which may be possible with the current libraries but needs to be investigated further.
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class InstallAnywhere : IPortableExecutableCheck, IScannable
|
||||
public class InstallAnywhere : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.FileDescription;
|
||||
var name= pex.FileDescription;
|
||||
if (name?.StartsWith("InstallAnywhere Self Extractor", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return $"InstallAnywhere {GetVersion(pex)}";
|
||||
|
||||
@@ -30,19 +33,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -50,7 +61,7 @@ namespace BurnOutSharp.PackerType
|
||||
private string GetVersion(PortableExecutable pex)
|
||||
{
|
||||
// Check the internal versions
|
||||
string version = Tools.Utilities.GetInternalVersion(pex);
|
||||
var version = pex.GetInternalVersion();
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction - https://github.com/Bioruebe/UniExtract2
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class InstallerVISE : IPortableExecutableCheck, IScannable
|
||||
public class InstallerVISE : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
//TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds.
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("ViseMain")))
|
||||
@@ -32,19 +35,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,53 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction, seems to primarily use MSZip compression.
|
||||
public class IntelInstallationFramework : IPortableExecutableCheck, IScannable
|
||||
public class IntelInstallationFramework : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.FileDescription;
|
||||
var name= pex.FileDescription;
|
||||
if (name?.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase) == true
|
||||
|| name?.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase) == true)
|
||||
{
|
||||
return $"Intel Installation Framework {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"Intel Installation Framework {pex.GetInternalVersion()}";
|
||||
}
|
||||
|
||||
name = pex.ProductName;
|
||||
if (name?.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase) == true
|
||||
|| name?.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase) == true)
|
||||
{
|
||||
return $"Intel Installation Framework {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"Intel Installation Framework {pex.GetInternalVersion()}";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,26 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction, which should be possible with LibMSPackN, but it refuses to extract due to SFX files lacking the typical CAB identifiers.
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class MicrosoftCABSFX : IPortableExecutableCheck, IScannable
|
||||
public class MicrosoftCABSFX : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.InternalName;
|
||||
var name= pex.InternalName;
|
||||
if (name?.Equals("Wextract", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return $"Microsoft CAB SFX {GetVersion(pex)}";
|
||||
|
||||
@@ -29,7 +31,7 @@ namespace BurnOutSharp.PackerType
|
||||
return $"Microsoft CAB SFX {GetVersion(pex)}";
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("wextract_cleanup")))
|
||||
@@ -50,19 +52,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -70,7 +80,7 @@ namespace BurnOutSharp.PackerType
|
||||
private string GetVersion(PortableExecutable pex)
|
||||
{
|
||||
// Check the internal versions
|
||||
string version = Tools.Utilities.GetInternalVersion(pex);
|
||||
var version = pex.GetInternalVersion();
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"v{version}";
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class NSIS : IPortableExecutableCheck, IScannable
|
||||
public class NSIS : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string description = pex.AssemblyDescription;
|
||||
var description = pex.AssemblyDescription;
|
||||
if (!string.IsNullOrWhiteSpace(description) && description.StartsWith("Nullsoft Install System"))
|
||||
return $"NSIS {description.Substring("Nullsoft Install System".Length).Trim()}";
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("NullsoftInst")))
|
||||
@@ -32,21 +35,29 @@ namespace BurnOutSharp.PackerType
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
70
BinaryObjectScanner/Packer/NeoLite.cs
Normal file
70
BinaryObjectScanner/Packer/NeoLite.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
/// <summary>
|
||||
/// NeoLite (https://web.archive.org/web/20000815214147/http://www.neoworx.com/products/neolite/default.asp) was a packer created by NeoWorx.
|
||||
/// The most common version appears to be 2.0, with earlier versions existing but with no archived copies available.
|
||||
/// NeoWorx was acquired by McAfee in October 2001, who seemingly dropped support for NeoLite (https://web.archive.org/web/20020603224725/http://www.mcafee.com/myapps/neoworx/default.asp).
|
||||
///
|
||||
/// Additional references and documentation:
|
||||
/// NeoLite 2.0 evaluation installer: https://web.archive.org/web/20001012061916/http://www.neoworx.com/download/neolte20.exe
|
||||
/// PEiD scanning definitions that include NeoLite: https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
/// Website listing various packers, including NeoLite: http://protools.narod.ru/packers.htm
|
||||
/// </summary>
|
||||
public class NeoLite : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
// TODO: Find samples of NeoLite 1.X.
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .neolit section, if it exists.
|
||||
// TODO: Check if this section is also present in NeoLite 1.X.
|
||||
bool neolitSection = pex.ContainsSection(".neolit", exact: true);
|
||||
if (neolitSection)
|
||||
return "NeoLite";
|
||||
|
||||
// If more specific or additional checks are needed, "NeoLite Executable File Compressor" should be present
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Add extraction
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,27 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Better version detection - https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
// TODO: Add extraction
|
||||
public class PECompact : IPortableExecutableCheck, IScannable
|
||||
public class PECompact : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// 0x4F434550 is "PECO"
|
||||
if (pex.PointerToSymbolTable == 0x4F434550)
|
||||
if (pex.Model.COFFFileHeader?.PointerToSymbolTable == 0x4F434550)
|
||||
return "PE Compact v1.x";
|
||||
|
||||
// TODO: Get more granular version detection. PiD is somehow able to detect version ranges based
|
||||
@@ -41,21 +44,29 @@ namespace BurnOutSharp.PackerType
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class PEtite : IPortableExecutableCheck, IScannable
|
||||
public class PEtite : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -26,19 +29,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,26 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// 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)
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class SetupFactory : IPortableExecutableCheck, IScannable
|
||||
public class SetupFactory : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Known to detect versions 7.0.5.1 - 9.1.0.0
|
||||
string name = pex.LegalCopyright;
|
||||
var name = pex.LegalCopyright;
|
||||
if (name?.StartsWith("Setup Engine", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return $"Setup Factory {GetVersion(pex)}";
|
||||
|
||||
@@ -40,19 +43,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -60,12 +71,12 @@ namespace BurnOutSharp.PackerType
|
||||
private string GetVersion(PortableExecutable pex)
|
||||
{
|
||||
// Check the product version explicitly
|
||||
string version = pex.ProductVersion;
|
||||
var version = pex.ProductVersion;
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
// Check the internal versions
|
||||
version = Tools.Utilities.GetInternalVersion(pex);
|
||||
version = pex.GetInternalVersion();
|
||||
if (!string.IsNullOrEmpty(version))
|
||||
return version;
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class SevenZipSFX : IPortableExecutableCheck, IScannable
|
||||
public class SevenZipSFX : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -47,19 +50,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class Shrinker : IPortableExecutableCheck, IScannable
|
||||
public class Shrinker : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -27,19 +30,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,35 +1,37 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class UPX : IPortableExecutableCheck, IScannable
|
||||
public class UPX : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
private static readonly Regex _oldUpxVersionMatch = new Regex(@"\$Id: UPX (.*?) Copyright \(C\)", RegexOptions.Compiled);
|
||||
|
||||
private static readonly Regex _upxVersionMatch = new Regex(@"^([0-9]\.[0-9]{2})$", RegexOptions.Compiled);
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Check header padding strings
|
||||
if (pex.HeaderPaddingStrings.Any())
|
||||
if (pex.HeaderPaddingStrings?.Any() == true)
|
||||
{
|
||||
string match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!"));
|
||||
var match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!"));
|
||||
//if (match != null)
|
||||
// return "UPX";
|
||||
|
||||
@@ -44,7 +46,7 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
match = pex.HeaderPaddingStrings.FirstOrDefault(s => _upxVersionMatch.IsMatch(s));
|
||||
if (pex.HeaderPaddingStrings.Any(s => s == "UPX!" && match != null))
|
||||
if (match != null && pex.HeaderPaddingStrings.Any(s => s == "UPX!"))
|
||||
{
|
||||
var regexMatch = _upxVersionMatch.Match(match);
|
||||
if (regexMatch.Success)
|
||||
@@ -52,7 +54,7 @@ namespace BurnOutSharp.PackerType
|
||||
else
|
||||
return "UPX (Unknown Version)";
|
||||
}
|
||||
else if (pex.HeaderPaddingStrings.Any(s => s == "NOS " && match != null))
|
||||
else if (match != null && pex.HeaderPaddingStrings.Any(s => s == "NOS "))
|
||||
{
|
||||
var regexMatch = _upxVersionMatch.Match(match);
|
||||
if (regexMatch.Success)
|
||||
@@ -66,19 +68,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,26 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Rar;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
public class WinRARSFX : IPortableExecutableCheck, IScannable
|
||||
public class WinRARSFX : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.AssemblyDescription;
|
||||
var name = pex.AssemblyDescription;
|
||||
if (name?.Contains("WinRAR archiver") == true)
|
||||
return "WinRAR SFX";
|
||||
|
||||
@@ -31,32 +34,42 @@ namespace BurnOutSharp.PackerType
|
||||
return null;
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// 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}))
|
||||
using (RarArchive zipFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
|
||||
{
|
||||
if (!zipFile.IsComplete)
|
||||
return null;
|
||||
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
foreach (var entry in zipFile.Entries)
|
||||
{
|
||||
// If an individual entry fails
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
@@ -68,35 +81,18 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
900
BinaryObjectScanner/Packer/WinZipSFX.cs
Normal file
900
BinaryObjectScanner/Packer/WinZipSFX.cs
Normal file
@@ -0,0 +1,900 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
public class WinZipSFX : IExtractable, INewExecutableCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the resident-name table doesnt exist
|
||||
if (nex.Model.ResidentNameTable == null)
|
||||
return null;
|
||||
|
||||
// Check for the WinZip name string
|
||||
bool winZipNameFound = nex.Model.ResidentNameTable
|
||||
.Select(rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString))
|
||||
.Any(s => s.Contains("WZ-SE-01"));
|
||||
|
||||
// If we didn't find it
|
||||
if (!winZipNameFound)
|
||||
return null;
|
||||
|
||||
// Try to get a known version
|
||||
var version = GetNEHeaderVersion(nex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
|
||||
return $"WinZip SFX Unknown Version (16-bit)";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Check the export directory table, if it exists
|
||||
if (pex.Model.ExportTable?.ExportDirectoryTable != null)
|
||||
{
|
||||
var version = GetPEExportDirectoryVersion(pex);
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
return $"WinZip SFX {version}";
|
||||
}
|
||||
|
||||
// Get the _winzip_ section, if it exists
|
||||
if (pex.ContainsSection("_winzip_", exact: true))
|
||||
return "WinZip SFX Unknown Version (32-bit)";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Find a way to generically detect 2.X versions and improve exact version detection for SFX PE versions bundled with WinZip 11+
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
if (!zipFile.IsComplete)
|
||||
return null;
|
||||
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
foreach (var entry in zipFile.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
// If we have a directory, skip it
|
||||
if (entry.IsDirectory)
|
||||
continue;
|
||||
|
||||
string tempFile = Path.Combine(tempPath, entry.Key);
|
||||
entry.WriteToFile(tempFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from the NE header value combinations
|
||||
/// </summary>
|
||||
/// TODO: Reduce the checks to only the ones that differ between versions
|
||||
/// TODO: Research to see if the versions are embedded elsewhere in these files
|
||||
#if NET48
|
||||
private string GetNEHeaderVersion(NewExecutable nex)
|
||||
#else
|
||||
private string? GetNEHeaderVersion(NewExecutable nex)
|
||||
#endif
|
||||
{
|
||||
#region 2.0 Variants
|
||||
|
||||
// 2.0 (MS-DOS/16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0086
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00012BE6
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000044B8
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.0 (MS-DOS/16-bit)";
|
||||
|
||||
// 2.0 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0086
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013174
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000198
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.0 (16-bit)";
|
||||
|
||||
// Compact 2.0 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0080
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x000124A0
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Compact 2.0 (16-bit)";
|
||||
|
||||
// Software Installation 2.0 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00CD
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x000136FA
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0005
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0097
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x00A3
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00AD
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001DF
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Software Installation 2.0 (16-bit)";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 2.1 RC2 Variants
|
||||
|
||||
// 2.1 RC2 (MS-DOS/16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0086
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013386
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000043C8
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.1 RC2 (MS-DOS/16-bit)";
|
||||
|
||||
// 2.1 RC2 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00BE
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E56
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.1 RC2 (16-bit)";
|
||||
|
||||
// Compact 2.1 RC2 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0080
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00012B84
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Compact 2.1 RC2 (16-bit)";
|
||||
|
||||
// Software Installation 2.1 RC2 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00BE
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x000143AC
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Software Installation 2.1 RC2 (16-bit)";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 2.1 Variants
|
||||
|
||||
// 2.1 (MS-DOS/16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0086
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013396
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000043C8
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.1 (MS-DOS/16-bit)";
|
||||
|
||||
// 2.1 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00BE
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E7E
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "2.1 (16-bit)";
|
||||
|
||||
// Compact 2.1 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0080
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00012B90
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Compact 2.1 (16-bit)";
|
||||
|
||||
// Software Installation 2.1 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00BE
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00014408
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Software Installation 2.1 (16-bit)";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc. Variants
|
||||
|
||||
// Personal Edition (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x0086
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x4000
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x0001317C
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000198
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Personal Edition (16-bit)";
|
||||
|
||||
// Personal Edition 32-bit (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00BE
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x3C00
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E7C
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Personal Edition 32-bit (16-bit)";
|
||||
|
||||
// Personal Edition 32-bit Build 1260/1285 (16-bit)
|
||||
if (nex.Model.Header?.LinkerVersion == 0x11
|
||||
&& nex.Model.Header?.LinkerRevision == 0x20
|
||||
&& nex.Model.Header?.EntryTableOffset == 0x00C6
|
||||
&& nex.Model.Header?.EntryTableSize == 0x0002
|
||||
&& nex.Model.Header?.CrcChecksum == 0x00000000
|
||||
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
|
||||
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
|
||||
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
|
||||
&& nex.Model.Header?.InitialHeapAlloc == 0x43DC
|
||||
&& nex.Model.Header?.InitialStackAlloc == 0x2708
|
||||
&& nex.Model.Header?.InitialCSIPSetting == 0x00014ADC
|
||||
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
|
||||
&& nex.Model.Header?.FileSegmentCount == 0x0003
|
||||
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0005
|
||||
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
|
||||
&& nex.Model.Header?.SegmentTableOffset == 0x0040
|
||||
&& nex.Model.Header?.ResourceTableOffset == 0x0058
|
||||
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
|
||||
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
|
||||
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A6
|
||||
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D8
|
||||
&& nex.Model.Header?.MovableEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
|
||||
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
|
||||
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
|
||||
&& nex.Model.Header?.AdditionalFlags == 0x00
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
|
||||
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
|
||||
&& nex.Model.Header?.WindowsSDKRevision == 0x00
|
||||
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
|
||||
return "Personal Edition 32-bit Build 1260/1285 (16-bit)";
|
||||
|
||||
#endregion
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version from the PE export directory table value combinations
|
||||
/// </summary>
|
||||
/// TODO: Research to see if the versions are embedded elsewhere in these files
|
||||
#if NET48
|
||||
private string GetPEExportDirectoryVersion(PortableExecutable pex)
|
||||
#else
|
||||
private string? GetPEExportDirectoryVersion(PortableExecutable pex)
|
||||
#endif
|
||||
{
|
||||
string sfxFileName = pex.Model.ExportTable?.ExportDirectoryTable?.Name ?? string.Empty;
|
||||
uint sfxTimeDateStamp = pex.Model.ExportTable?.ExportDirectoryTable?.TimeDateStamp ?? uint.MaxValue;
|
||||
string assemblyVersion = pex.AssemblyVersion ?? "Unknown Version";
|
||||
|
||||
// Standard
|
||||
if (sfxFileName == "VW95SE.SFX" || sfxFileName == "ST32E.SFX"
|
||||
|| sfxFileName == "WZIPSE32.exe" || sfxFileName == "SI32LPG.SFX"
|
||||
|| sfxFileName == "ST32E.WZE")
|
||||
{
|
||||
switch (sfxTimeDateStamp)
|
||||
{
|
||||
case 842636344:
|
||||
return "2.0 (32-bit)";
|
||||
case 865370756:
|
||||
return "2.1 RC2 (32-bit)";
|
||||
case 869059925:
|
||||
return "2.1 (32-bit)";
|
||||
case 979049321:
|
||||
return "2.2.4003";
|
||||
case 1149714685:
|
||||
return "3.0.7158";
|
||||
case 1185211734:
|
||||
return "3.1.7556";
|
||||
case 1185211920:
|
||||
return "3.1.7556";
|
||||
case 1235490556:
|
||||
return "4.0.8421";
|
||||
case 1235490757:
|
||||
return "4.0.8421";
|
||||
case 1235490687:
|
||||
return "4.0.8421"; // 3.1.8421.0, SI32LPG?
|
||||
case 1257193383:
|
||||
return "4.0.8672"; // 3.1.8672.0
|
||||
case 1257193543:
|
||||
return "4.0.8672";
|
||||
case 1470410848:
|
||||
return "4.0.12218"; // 4.0.1221.0
|
||||
default:
|
||||
return $"{assemblyVersion} (32-bit)";
|
||||
}
|
||||
}
|
||||
|
||||
// Personal Edition
|
||||
if (sfxFileName == "VW95LE.SFX" || sfxFileName == "PE32E.SFX"
|
||||
|| sfxFileName == "wzsepe32.exe" || sfxFileName == "SI32PE.SFX"
|
||||
|| sfxFileName == "SI32LPE.SFX")
|
||||
{
|
||||
switch (sfxTimeDateStamp)
|
||||
{
|
||||
case 845061601:
|
||||
return "Personal Edition (32-bit)"; // TODO: Find version
|
||||
case 868303343:
|
||||
return "Personal Edition (32-bit)"; // TODO: Find version
|
||||
case 868304170:
|
||||
return "Personal Edition (32-bit)"; // TODO: Find version
|
||||
case 906039079:
|
||||
return "Personal Edition 2.2.1260 (32-bit)";
|
||||
case 906040543:
|
||||
return "Personal Edition 2.2.1260 (32-bit)";
|
||||
case 908628435:
|
||||
return "Personal Edition 2.2.1285 (32-bit)";
|
||||
case 908628785:
|
||||
return "Personal Edition 2.2.1285 (32-bit)";
|
||||
case 956165981:
|
||||
return "Personal Edition 2.2.3063";
|
||||
case 956166038:
|
||||
return "Personal Edition 2.2.3063";
|
||||
case 1006353695:
|
||||
return "Personal Edition 2.2.4325";
|
||||
case 1006353714:
|
||||
return "Personal Edition 2.2.4325"; // 8.1.0.0
|
||||
case 1076515698:
|
||||
return "Personal Edition 2.2.6028";
|
||||
case 1076515784:
|
||||
return "Personal Edition 2.2.6028"; // 9.0.6028.0
|
||||
case 1092688561:
|
||||
return "Personal Edition 2.2.6224";
|
||||
case 1092688645:
|
||||
return "Personal Edition 2.2.6224"; // 9.0.6224.0
|
||||
case 1125074095:
|
||||
return "Personal Edition 2.2.6604";
|
||||
case 1125074162:
|
||||
return "Personal Edition 2.2.6604"; // 10.0.6604.0
|
||||
case 1130153399:
|
||||
return "Personal Edition 2.2.6663";
|
||||
case 1130153428:
|
||||
return "Personal Edition 2.2.6663"; // 10.0.6663.0
|
||||
case 1149714176:
|
||||
return "Personal Edition 3.0.7158";
|
||||
case 1163137967:
|
||||
return "Personal Edition 3.0.7305";
|
||||
case 1163137994:
|
||||
return "Personal Edition 3.0.7313"; // 11.0.7313.0
|
||||
case 1176345383:
|
||||
return "Personal Edition 3.0.7452";
|
||||
case 1176345423:
|
||||
return "Personal Edition 3.1.7466"; // 11.1.7466.0
|
||||
case 1184106698:
|
||||
return "Personal Edition 3.1.7556";
|
||||
case 1207280880:
|
||||
return "Personal Edition 4.0.8060"; // 2.3.7382.0
|
||||
case 1207280892:
|
||||
return "Personal Edition 4.0.8094"; // 11.2.8094.0
|
||||
case 1220904506:
|
||||
return "Personal Edition 4.0.8213"; // 2.3.7382.0
|
||||
case 1220904518:
|
||||
return "Personal Edition 4.0.8252"; // 12.0.8252.0
|
||||
case 1235490648:
|
||||
return "Personal Edition 4.0.8421"; // 3.1.8421.0
|
||||
case 1242049399:
|
||||
return "Personal Edition 4.0.8497"; // 12.1.8497.0
|
||||
case 1257193469:
|
||||
return "Personal Edition 4.0.8672"; // 3.1.8672.0, SI32LPE?
|
||||
default:
|
||||
return $"Personal Edition {assemblyVersion} (32-bit)";
|
||||
}
|
||||
}
|
||||
|
||||
// Software Installation
|
||||
else if (sfxFileName == "VW95SRE.SFX" || sfxFileName == "SI32E.SFX"
|
||||
|| sfxFileName == "SI32E.WZE")
|
||||
{
|
||||
switch (sfxTimeDateStamp)
|
||||
{
|
||||
case 842636381:
|
||||
return "Software Installation 2.0 (32-bit)";
|
||||
case 865370800:
|
||||
return "Software Installation 2.1 RC2 (32-bit)";
|
||||
case 869059963:
|
||||
return "Software Installation 2.1 (32-bit)";
|
||||
case 893107697:
|
||||
return "Software Installation 2.2.1110 (32-bit)";
|
||||
case 952007369:
|
||||
return "Software Installation 2.2.3063";
|
||||
case 1006352634:
|
||||
return "Software Installation 2.2.4325"; // +Personal Edition?
|
||||
case 979049345:
|
||||
return "Software Installation 2.2.4403";
|
||||
case 1026227373:
|
||||
return "Software Installation 2.2.5196"; // +Personal Edition?
|
||||
case 1090582390:
|
||||
return "Software Installation 2.2.6202"; // +Personal Edition?
|
||||
case 1149714757:
|
||||
return "Software Installation 3.0.7158";
|
||||
case 1154357628:
|
||||
return "Software Installation 3.0.7212";
|
||||
case 1175234637:
|
||||
return "Software Installation 3.0.7454";
|
||||
case 1185211802:
|
||||
return "Software Installation 3.1.7556";
|
||||
case 1470410906:
|
||||
return "Software Installation 4.0.12218"; // 4.0.1221.0
|
||||
default:
|
||||
return $"Software Installation {assemblyVersion} (32-bit)";
|
||||
}
|
||||
}
|
||||
|
||||
switch (sfxFileName)
|
||||
{
|
||||
// Standard
|
||||
case "VW95SE.SFX":
|
||||
return "Unknown Version (32-bit)"; // TODO: Find starting version
|
||||
case "ST32E.SFX":
|
||||
return "Unknown Version (32-bit)"; // TODO: Find starting version
|
||||
case "WZIPSE32.exe":
|
||||
return "Unknown Version (32-bit)"; // TODO: Find starting version
|
||||
case "SI32LPG.SFX":
|
||||
return "Unknown Version (32-bit)"; // TODO: Find starting version
|
||||
case "ST32E.WZE":
|
||||
return "Unknown Version (32-bit)"; // TODO: Find starting version
|
||||
|
||||
// Personal Edition
|
||||
case "VW95LE.SFX":
|
||||
return "Unknown Version before Personal Edition Build 1285 (32-bit)";
|
||||
case "PE32E.SFX":
|
||||
return "Unknown Version after Personal Edition Build 1285 (32-bit)";
|
||||
case "wzsepe32.exe":
|
||||
return "Unknown Version Personal Edition (32-bit)"; // TODO: Find starting version
|
||||
case "SI32PE.SFX":
|
||||
return "Unknown Version Personal Edition (32-bit)"; // TODO: Find starting version
|
||||
case "SI32LPE.SFX":
|
||||
return "Unknown Version Personal Edition (32-bit)"; // TODO: Find starting version
|
||||
|
||||
// Software Installation
|
||||
case "VW95SRE.SFX":
|
||||
return "Unknown Version before Software Installation 2.1 (32-bit)";
|
||||
case "SI32E.SFX":
|
||||
return "Unknown Version after Software Installation 2.1 (32-bit)";
|
||||
case "SI32E.WZE":
|
||||
return "Unknown Version Software Installation (32-bit)"; // TODO: Find starting version
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Utilities;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using static BurnOutSharp.Utilities.Dictionary;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
using Wise = WiseUnpacker.WiseUnpacker;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
public class WiseInstaller : INewExecutableCheck, IPortableExecutableCheck, IScannable
|
||||
public class WiseInstaller : IExtractable, INewExecutableCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
/// Check we have a valid executable
|
||||
if (nex == null)
|
||||
return null;
|
||||
|
||||
// If we match a known header
|
||||
if (MatchesNEVersion(nex) != null)
|
||||
return "Wise Installation Wizard Module";
|
||||
@@ -46,10 +44,14 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -60,7 +62,7 @@ namespace BurnOutSharp.PackerType
|
||||
// TODO: Investigate STUB32.EXE in export directory table
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("WiseMain")))
|
||||
@@ -79,41 +81,47 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the installer file itself fails
|
||||
try
|
||||
{
|
||||
// Try to parse as a New Executable
|
||||
NewExecutable nex = NewExecutable.Create(stream);
|
||||
var nex = NewExecutable.Create(stream);
|
||||
if (nex != null)
|
||||
return ScanNewExecutable(scanner, nex, file);
|
||||
return ExtractNewExecutable(nex, file, includeDebug);
|
||||
|
||||
// Try to parse as a Portable Executable
|
||||
PortableExecutable pex = PortableExecutable.Create(stream);
|
||||
var pex = PortableExecutable.Create(stream);
|
||||
if (pex != null)
|
||||
return ScanPortableExecutable(scanner, pex, file);
|
||||
return ExtractPortableExecutable(pex, file, includeDebug);
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,10 +129,14 @@ namespace BurnOutSharp.PackerType
|
||||
/// </summary>
|
||||
/// <param name="nex">New executable to check</param>
|
||||
/// <returns>True if it matches a known version, false otherwise</returns>
|
||||
#if NET48
|
||||
private FormatProperty MatchesNEVersion(NewExecutable nex)
|
||||
#else
|
||||
private FormatProperty? MatchesNEVersion(NewExecutable nex)
|
||||
#endif
|
||||
{
|
||||
// TODO: Offset is _not_ the EXE header address, rather where the data starts. Fix this.
|
||||
switch (nex.Stub_NewExeHeaderAddr)
|
||||
switch (nex.Model.Stub?.Header?.NewExeHeaderAddr)
|
||||
{
|
||||
case 0x84b0:
|
||||
return new FormatProperty { Dll = false, ArchiveStart = 0x11, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = true };
|
||||
@@ -178,7 +190,11 @@ namespace BurnOutSharp.PackerType
|
||||
/// </summary>
|
||||
/// <param name="pex">Portable executable to check</param>
|
||||
/// <returns>True if it matches a known version, false otherwise</returns>
|
||||
#if NET48
|
||||
private FormatProperty GetPEFormat(PortableExecutable pex)
|
||||
#else
|
||||
private FormatProperty? GetPEFormat(PortableExecutable pex)
|
||||
#endif
|
||||
{
|
||||
if (pex.OverlayAddress == 0x6e00
|
||||
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3cf4
|
||||
@@ -221,63 +237,61 @@ namespace BurnOutSharp.PackerType
|
||||
/// <summary>
|
||||
/// Attempt to extract Wise data from a New Executable
|
||||
/// </summary>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="nex">New executable to check</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>True if it matches a known version, false otherwise</returns>
|
||||
private ConcurrentDictionary<string, ConcurrentQueue<string>> ScanNewExecutable(Scanner scanner, NewExecutable nex, string file)
|
||||
#if NET48
|
||||
private string ExtractNewExecutable(NewExecutable nex, string file, bool includeDebug)
|
||||
#else
|
||||
private string? ExtractNewExecutable(NewExecutable nex, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the installer file itself fails
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
try
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// TODO: Try to find where the file data lives and how to get it
|
||||
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
|
||||
if (!unpacker.ExtractTo(file, tempPath))
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to extract Wise data from a Portable Executable
|
||||
/// </summary>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="pex">Portable executable to check</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>True if it matches a known version, false otherwise</returns>
|
||||
private ConcurrentDictionary<string, ConcurrentQueue<string>> ScanPortableExecutable(Scanner scanner, PortableExecutable pex, string file)
|
||||
#if NET48
|
||||
private string ExtractPortableExecutable(PortableExecutable pex, string file, bool includeDebug)
|
||||
#else
|
||||
private string? ExtractPortableExecutable(PortableExecutable pex, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// If the installer file itself fails
|
||||
try
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// Get the matching PE format
|
||||
var format = GetPEFormat(pex);
|
||||
if (format == null)
|
||||
@@ -285,7 +299,7 @@ namespace BurnOutSharp.PackerType
|
||||
|
||||
// Get the overlay data for easier reading
|
||||
int overlayOffset = 0, dataStart = 0;
|
||||
byte[] overlayData = pex.OverlayData;
|
||||
var overlayData = pex.OverlayData;
|
||||
if (overlayData == null)
|
||||
return null;
|
||||
|
||||
@@ -339,42 +353,19 @@ namespace BurnOutSharp.PackerType
|
||||
int offsetReal = overlayOffset;
|
||||
|
||||
// If the first entry is PKZIP, we assume it's an embedded zipfile
|
||||
byte[] magic = overlayData.ReadBytes(ref overlayOffset, 4); overlayOffset -= 4;
|
||||
bool pkzip = magic.StartsWith(new byte?[] { (byte)'P', (byte)'K' });
|
||||
var magic = overlayData.ReadBytes(ref overlayOffset, 4); overlayOffset -= 4;
|
||||
bool pkzip = magic?.StartsWith(new byte?[] { (byte)'P', (byte)'K' }) ?? false;
|
||||
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
Directory.CreateDirectory(tempPath);
|
||||
|
||||
// If we have PKZIP
|
||||
if (pkzip)
|
||||
{
|
||||
try
|
||||
string tempFile = Path.Combine(tempPath, "WISEDATA.zip");
|
||||
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
string tempFile = Path.Combine(tempPath, "WISEDATA.zip");
|
||||
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
tempStream.Write(overlayData, overlayOffset, overlayData.Length - overlayOffset);
|
||||
}
|
||||
|
||||
// Collect and format all found protections
|
||||
var protections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
tempStream.Write(overlayData, overlayOffset, overlayData.Length - overlayOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,33 +373,28 @@ namespace BurnOutSharp.PackerType
|
||||
else
|
||||
{
|
||||
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
|
||||
if (!unpacker.ExtractTo(file, tempPath))
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Remove temporary path references
|
||||
StripFromKeys(protections, tempPath);
|
||||
|
||||
return protections;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
7
BinaryObjectScanner/Packer/_DUMMY.cs
Normal file
7
BinaryObjectScanner/Packer/_DUMMY.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
/// <summary>
|
||||
/// This class exists for reflection purposes and should not be used
|
||||
/// </summary>
|
||||
public sealed class _DUMMY { }
|
||||
}
|
||||
@@ -1,25 +1,28 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.PackerType
|
||||
namespace BinaryObjectScanner.Packer
|
||||
{
|
||||
// TODO: Add extraction
|
||||
public class dotFuscator : IPortableExecutableCheck, IScannable
|
||||
public class dotFuscator : IExtractable, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .text section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".text");
|
||||
var strs = pex.GetFirstSectionStrings(".text");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("DotfuscatorAttribute")))
|
||||
@@ -30,19 +33,27 @@ namespace BurnOutSharp.PackerType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
#if NET48
|
||||
public string Extract(string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
#if NET48
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
#else
|
||||
public string? Extract(Stream? stream, string file, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
// TODO: Figure out how to get version numbers
|
||||
public class ActiveMARK : IContentCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#else
|
||||
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
@@ -34,10 +38,14 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -50,35 +58,35 @@ namespace BurnOutSharp.ProtectionType
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x89, 0x25, null, null, null, null, 0xEB }))
|
||||
return "ActiveMark -> Trymedia Systems Inc.";
|
||||
return "ActiveMark -> Trymedia Systems Inc. (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x89, 0x25, null, null, null, null, 0x33, 0xED, 0x55, 0x8B, 0xEC, 0xE8, null, null, null, null, 0x8B, 0xD0, 0x81, 0xE2, 0xFF, 0x00, 0x00, 0x00, 0x89, 0x15, null, null, null, null, 0x8B, 0xD0, 0xC1, 0xEA, 0x08, 0x81, 0xE2, 0xFF, 0x00, 0x00, 0x00, 0xA3, null, null, null, null, 0xD1, 0xE0, 0x0F, 0x93, 0xC3, 0x33, 0xC0, 0x8A, 0xC3, 0xA3, null, null, null, null, 0x68, 0xFF, 0x00, 0x00, 0x00, 0xE8, null, null, null, null, 0x6A, 0x00, 0xE8, null, null, null, null, 0xA3, null, null, null, null, 0xBB, null, null, null, null, 0xC7, 0x03, 0x44, 0x00, 0x00, 0x00 }))
|
||||
return "ActiveMark -> Trymedia Systems Inc.";
|
||||
return "ActiveMark -> Trymedia Systems Inc. (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x20, 0x2D, 0x2D, 0x4D, 0x50, 0x52, 0x4D, 0x4D, 0x47, 0x56, 0x41, 0x2D, 0x2D, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6F, 0x78, 0x41, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67 }))
|
||||
return "ActiveMARK 5.x -> Trymedia Systems Inc. (h)";
|
||||
return "ActiveMARK 5.x -> Trymedia Systems Inc. (h) (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x20, 0x2D, 0x2D, 0x4D, 0x50, 0x52, 0x4D, 0x4D, 0x47, 0x56, 0x41, 0x2D, 0x2D, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6F, 0x78, 0x41, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x2E, 0x0D, 0x0A, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x75, 0x6E, 0x6C, 0x6F, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x00, 0x57, 0x61, 0x72, 0x6E, 0x69, 0x6E, 0x67 }))
|
||||
return "ActiveMARK 5.x -> Trymedia Systems,Inc.";
|
||||
return "ActiveMARK 5.x -> Trymedia Systems,Inc. (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x79, 0x11, 0x7F, 0xAB, 0x9A, 0x4A, 0x83, 0xB5, 0xC9, 0x6B, 0x1A, 0x48, 0xF9, 0x27, 0xB4, 0x25 }))
|
||||
return "ActiveMARK[TM]";
|
||||
return "ActiveMARK[TM] (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x79, 0x07, 0x0F, 0xB7, 0x07, 0x47, 0x50, 0x47, 0xB9, 0x57, 0x48, 0xF2, 0xAE, 0x55, 0xFF, 0x96, 0x84, null, 0x00, 0x00, 0x09, 0xC0, 0x74, 0x07, 0x89, 0x03, 0x83, 0xC3, 0x04, 0xEB, 0xD8, 0xFF, 0x96, 0x88, null, 0x00, 0x00, 0x61, 0xE9, null, null, null, 0xFF }))
|
||||
return "ActiveMARK[TM] R5.31.1140 -> Trymedia";
|
||||
return "ActiveMARK[TM] R5.31.1140 -> Trymedia (Unconfirmed - Please report to us on Github)";
|
||||
|
||||
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
|
||||
else if (pex.EntryPointData.StartsWith(new byte?[] { 0xBE, 0x48, 0x01, 0x40, 0x00, 0xAD, 0x8B, 0xF8, 0x95, 0xA5, 0x33, 0xC0, 0x33, 0xC9, 0xAB, 0x48, 0xAB, 0xF7, 0xD8, 0xB1, 0x04, 0xF3, 0xAB, 0xC1, 0xE0, 0x0A, 0xB5, 0x1C, 0xF3, 0xAB, 0xAD, 0x50, 0x97, 0x51, 0xAD, 0x87, 0xF5, 0x58, 0x8D, 0x54, 0x86, 0x5C, 0xFF, 0xD5, 0x72, 0x5A, 0x2C, 0x03, 0x73, 0x02, 0xB0, 0x00, 0x3C, 0x07, 0x72, 0x02, 0x2C, 0x03, 0x50, 0x0F, 0xB6, 0x5F, 0xFF, 0xC1, 0xE3, 0x03, 0xB3, 0x00, 0x8D, 0x1C, 0x5B, 0x8D, 0x9C, 0x9E, 0x0C, 0x10, 0x00, 0x00, 0xB0, 0x01, 0x67, 0xE3, 0x29, 0x8B, 0xD7, 0x2B, 0x56, 0x0C, 0x8A, 0x2A, 0x33, 0xD2, 0x84, 0xE9, 0x0F, 0x95, 0xC6, 0x52, 0xFE, 0xC6, 0x8A, 0xD0, 0x8D, 0x14, 0x93, 0xFF, 0xD5, 0x5A, 0x9F, 0x12, 0xC0, 0xD0, 0xE9, 0x74, 0x0E, 0x9E, 0x1A, 0xF2, 0x74, 0xE4, 0xB4, 0x00, 0x33, 0xC9, 0xB5, 0x01, 0xFF, 0x55, 0xCC, 0x33, 0xC9, 0xE9, 0xDF, 0x00, 0x00, 0x00, 0x8B, 0x5E, 0x0C, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x73, 0x50, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x72, 0x1B, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x72, 0x2B, 0x3C, 0x07, 0xB0, 0x09, 0x72, 0x02, 0xB0, 0x0B, 0x50, 0x8B, 0xC7, 0x2B, 0x46, 0x0C, 0xB1, 0x80, 0x8A, 0x00, 0xEB, 0xCF, 0x83, 0xC2, 0x60, 0xFF, 0xD5, 0x87, 0x5E, 0x10, 0x73, 0x0D, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x87, 0x5E, 0x14, 0x73, 0x03, 0x87, 0x5E, 0x18, 0x3C, 0x07, 0xB0, 0x08, 0x72, 0x02, 0xB0, 0x0B, 0x50, 0x53, 0x8D, 0x96, 0x7C, 0x07, 0x00, 0x00, 0xFF, 0x55, 0xD0, 0x5B, 0x91, 0xEB, 0x77, 0x3C, 0x07, 0xB0, 0x07, 0x72, 0x02, 0xB0, 0x0A, 0x50, 0x87, 0x5E, 0x10, 0x87, 0x5E, 0x14, 0x89, 0x5E, 0x18, 0x8D, 0x96, 0xC4, 0x0B, 0x00, 0x00, 0xFF, 0x55, 0xD0, 0x50, 0x48 }))
|
||||
return "ActiveMARK 5.x -> Trymedia Systems,Inc. (h)";
|
||||
return "ActiveMARK 5.x -> Trymedia Systems,Inc. (h) (Unconfirmed - Please report to us on Github)";
|
||||
}
|
||||
|
||||
// Get the .data section strings, if they exist
|
||||
List<string> strs = pex.GetLastSectionStrings(".data");
|
||||
var strs = pex.GetLastSectionStrings(".data");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("MPRMMGVA"))
|
||||
@@ -92,8 +100,8 @@ namespace BurnOutSharp.ProtectionType
|
||||
var resources = pex.FindResourceByNamedType("REGISTRY, AMINTERNETPROTOCOL");
|
||||
if (resources.Any())
|
||||
{
|
||||
bool match = resources.Where(r => r != null)
|
||||
.Select(r => Encoding.ASCII.GetString(r))
|
||||
bool match = resources
|
||||
.Select(r => r == null ? string.Empty : Encoding.ASCII.GetString(r))
|
||||
.Any(r => r.Contains("ActiveMARK"));
|
||||
if (match)
|
||||
return "ActiveMARK";
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// AegiSoft License Manager was made AegiSoft, which was later bought by Real Networks, the makes of RealArcade (https://www.crunchbase.com/organization/aegisoft).
|
||||
@@ -20,10 +20,14 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class AegiSoft : IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -58,7 +62,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "AegiSoft License Manager"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
|
||||
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
@@ -67,7 +71,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -80,11 +88,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
// These files are "Asc001.dll", "Asc002.dll", "Asc003.dll", "Asc005.dll", and "Asc006.exe" (Found in Redump entry 73521/IA item "Nova_HoyleCasino99USA").
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class AlphaAudio
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Alpha-DVD is a DVD-Video copy protection created by SETTEC.
|
||||
@@ -16,18 +16,26 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class AlphaDVD : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("PlayDVD.exe", useEndsWith: true), "Alpha-DVD (Unconfirmed - Please report to us on Github)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,10 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Alpha-ROM is a form of copy protection created by SETTEC. It is known to make use of twin sectors as well as region locking.
|
||||
@@ -45,18 +44,22 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class AlphaROM : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Add support for detecting Alpha-ROM found in older games made with the RealLive engine.
|
||||
// TODO: Add version detection for Alpha-ROM.
|
||||
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("\\SETTEC")))
|
||||
@@ -1,25 +1,28 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Bitpool is a copy protection found most commonly in German releases.
|
||||
/// It always has errors present on the disc (either between 1-4, or between 1,000-10,000+ depending on generation), and makes use of padded dummy files to prevent copying.
|
||||
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/Bitpool.md"/>
|
||||
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/Bitpool/Bitpool.md"/>
|
||||
/// </summary>
|
||||
public class Bitpool : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("bitpool.rsc", useEndsWith: true), "Bitpool"),
|
||||
new PathMatchSet(new PathMatch($"{Path.DirectorySeparatorChar}CD.IDX", useEndsWith: true), "Bitpool"),
|
||||
new PathMatchSet(new FilePathMatch("CD.IDX"), "Bitpool"),
|
||||
|
||||
// Completely empty file present on multiple discs with Bitpool (Redump entries 52626 and 50229).
|
||||
new PathMatchSet(new PathMatch("LEADOUT.OFS", useEndsWith: true), "Bitpool"),
|
||||
@@ -28,23 +31,27 @@ namespace BurnOutSharp.ProtectionType
|
||||
// Both examples with only having the first letter uppercase and as the whole file name being uppercase have been seen.
|
||||
new PathMatchSet(new List<PathMatch>
|
||||
{
|
||||
new PathMatch($"{Path.DirectorySeparatorChar}Crc_a", useEndsWith: true),
|
||||
new PathMatch($"{Path.DirectorySeparatorChar}Crc_b", useEndsWith: true),
|
||||
new PathMatch($"{Path.DirectorySeparatorChar}Crc_c", useEndsWith: true),
|
||||
new PathMatch($"{Path.DirectorySeparatorChar}Crc_d", useEndsWith: true),
|
||||
new FilePathMatch("Crc_a"),
|
||||
new FilePathMatch("Crc_b"),
|
||||
new FilePathMatch("Crc_c"),
|
||||
new FilePathMatch("Crc_d"),
|
||||
}, "Bitpool"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
new PathMatchSet(new PathMatch("bitpool.rsc", useEndsWith: true), "Bitpool"),
|
||||
new PathMatchSet(new PathMatch($"{Path.DirectorySeparatorChar}CD.IDX", useEndsWith: true), "Bitpool"),
|
||||
new PathMatchSet(new FilePathMatch("CD.IDX"), "Bitpool"),
|
||||
|
||||
// Completely empty file present on multiple discs with Bitpool (Redump entries 52626 and 50229).
|
||||
new PathMatchSet(new PathMatch("LEADOUT.OFS", useEndsWith: true), "Bitpool"),
|
||||
@@ -1,11 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// ByteShield, Inc. (https://web.archive.org/web/20070216191623/http://www.byteshield.net/) was founded in 2004 (https://www.apollo.io/companies/ByteShield--Inc-/54a1357069702d4494ab9b00).
|
||||
@@ -41,42 +41,46 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class ByteShield : IPortableExecutableCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
string name = pex.FileDescription;
|
||||
var name = pex.FileDescription;
|
||||
if (name?.Equals("ByteShield Client") == true)
|
||||
return $"ByteShield Activation Client {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
name = pex.InternalName;
|
||||
if (name?.Equals("ByteShield") == true)
|
||||
return $"ByteShield Activation Client {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
name = pex.OriginalFilename;
|
||||
if (name?.Equals("ByteShield.EXE") == true)
|
||||
return $"ByteShield Activation Client {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
name = pex.ProductName;
|
||||
if (name?.Equals("ByteShield Client") == true)
|
||||
return $"ByteShield Activation Client {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
|
||||
|
||||
// Found in "ByteShield.dll" in Redump entry 6236
|
||||
name = pex.ExportTable?.ExportDirectoryTable?.Name;
|
||||
name = pex.Model.ExportTable?.ExportDirectoryTable?.Name;
|
||||
if (name?.Equals("ByteShield Client") == true)
|
||||
return "ByteShield Component Module";
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
var stMatch = pex.FindStringTableByEntry("ByteShield");
|
||||
if (stMatch.Any())
|
||||
return $"ByteShield Activation Client {Tools.Utilities.GetInternalVersion(pex)}";
|
||||
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
|
||||
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
var dbMatch = pex.FindDialogByTitle("About ByteShield");
|
||||
@@ -91,7 +95,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
return "ByteShield";
|
||||
|
||||
// Get the .data/DATA section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
|
||||
if (strs != null)
|
||||
{
|
||||
// Found in "LineRider2.exe" in Redump entry 6236
|
||||
@@ -128,9 +132,13 @@ namespace BurnOutSharp.ProtectionType
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// TODO: Investigate reference to "bbz650.tmp" in "Byteshield.dll" (Redump entry 6236)
|
||||
// Files with the ".bbz" extension are associated with ByteShield, but the extenstion is known to be used in other places as well.
|
||||
@@ -140,11 +148,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("Byteshield.ini", useEndsWith: true), "ByteShield"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
// TODO: Investigate reference to "bbz650.tmp" in "Byteshield.dll" (Redump entry 6236)
|
||||
// Files with the ".bbz" extension are associated with ByteShield, but the extenstion is known to be used in other places as well.
|
||||
@@ -1,19 +1,23 @@
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CDCheck : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.Comments;
|
||||
var name = pex.Comments;
|
||||
if (name?.Contains("CDCheck utlity for Microsoft Game Studios") == true)
|
||||
return "Microsoft Game Studios CD Check";
|
||||
|
||||
262
BinaryObjectScanner/Protection/CDDVDCops.cs
Normal file
262
BinaryObjectScanner/Protection/CDDVDCops.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Models.PortableExecutable;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO: Investigate "Cops Copylock II" (https://www.cbmstuff.com/forum/showthread.php?tid=488).
|
||||
/// TODO: Investigate additional products mentioned on the Link Data Security website (https://www.linkdatasecurity.com/index.htm#/protection-products/overview).
|
||||
/// `AgentHugo.exe`
|
||||
/// Embedded PE executable in one of the NE sections
|
||||
/// `AgentHugo.exe` / `NE.EXE` (1.46) / `NETINST.EXE` (1.48) / `NETINST.QZ_`
|
||||
/// Embedded PKZIP archive that may contain the CD-Cops files
|
||||
/// `CDCOPS.DLL` (1.46) / `CDCOPS.DLL` (1.48)
|
||||
/// `WINCOPS.INI`
|
||||
///
|
||||
/// TODO: Investigate if "DVD-Cops" is a separate product, or simply what CD-Cops is referred to when used on a DVD.
|
||||
///
|
||||
/// Known versions of CD-Cops:
|
||||
/// * 1.08 (Unconfirmed) (Redump entry 84517).
|
||||
/// * 1,13[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20040307124358/http://www.caprino.no:80/download/fgpgold_upd4.exe).
|
||||
/// * 1.21 (Unconfirmed) (Redump entry 91713).
|
||||
/// * 1,22[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20030430194917/http://www.caprino.no:80/download/fgpgold_upd2.exe).
|
||||
/// * 1,28[sic] (Confirmed) ("RunMenu.exe" in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes").
|
||||
/// * 1,31[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168).
|
||||
/// * 1.31 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with Patch 11).
|
||||
/// * 1.46 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20210103064517/http://www.caprino.no/download/FGPGOLD_UPD12.exe)
|
||||
/// * 1,63[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20060926082522/http://www.caprino.no:80/download/fgpgold_upd7.exe).
|
||||
/// * 1.72 (Confirmed) ("h3blade.exe" in Redump entry 85077).
|
||||
/// * 1.73 (Confirmed) ("WETFLIPPER.EXE" in IA item "LULA_Erotic_Pinball_-_Windows95_Eng).
|
||||
/// * 1,81[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20030308040529/http://www.caprino.no:80/download/fgpgold_upd1.exe).
|
||||
/// * 2.03 (Confirmed) ("HyperBowl.exe" in IA item "hyperbowl_20190626").
|
||||
///
|
||||
/// Known versions of DVD-Cops:
|
||||
/// * 1.69 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169).
|
||||
///
|
||||
/// Known samples of CD-Cops include:
|
||||
/// * IA item "der-brockhaus-multimedial-2002-premium".
|
||||
/// * IA item "der-brockhaus-multimedial-2003-premium".
|
||||
/// * IA item "SCIENCESENCYCLOPEDIAV2.0ARISSCD1".
|
||||
/// * IA item "SCIENCESENCYCLOPEDIAV2.0ARISSCD2".
|
||||
/// * IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
|
||||
/// * IA item "LULA_Erotic_Pinball_-_Windows95_Eng".
|
||||
/// * IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168.
|
||||
/// * Patches for "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168, found at https://web.archive.org/web/*/http://www.caprino.no/download/* (FGPGOLD_UPD files).
|
||||
/// * IA item "hyperbowl_20190626"/"hyperbowl-arcade-edition".
|
||||
/// * Redump entries 51403(?), 84517, and 85077.
|
||||
///
|
||||
/// Known samples of DVD-Cops include:
|
||||
/// * IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
|
||||
///
|
||||
/// Known samples of WEB-Cops include:
|
||||
/// * https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe
|
||||
///
|
||||
/// A sample of CD-Cops that makes use of encrypted PDFs (LDSCRYPT) can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
|
||||
///
|
||||
/// List of applications that have CD/DVD/WEB-Cops relating to a Windows update: https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/924867
|
||||
/// </summary>
|
||||
|
||||
public class CDDVDCops : IContentCheck, INewExecutableCheck, IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
// TODO: Investigate reference to "CD32COPS.DLL" in "WETFLIPP.QZ_" in IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#else
|
||||
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// TODO: Remove from here once it's confirmed that no PE executables contain this string
|
||||
// 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 (Unconfirmed - Please report to us on Github)"),
|
||||
|
||||
// // DVD-Cops, ver.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
|
||||
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
|
||||
}, GetVersion, "DVD-Cops (Unconfirmed - Please report to us on Github)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Don't read entire file
|
||||
var data = nex.ReadArbitraryRange();
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
// TODO: Figure out what NE section this lives in
|
||||
var neMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// CD-Cops, ver.
|
||||
// Found in "h3blade.exe" in Redump entry 85077.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
|
||||
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
|
||||
}, GetVersion, "CD-Cops"),
|
||||
};
|
||||
|
||||
var match = MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
|
||||
if (!string.IsNullOrEmpty(match))
|
||||
return match;
|
||||
|
||||
// Check the imported-name table
|
||||
// Found in "h3blade.exe" in Redump entry 85077.
|
||||
bool importedNameTableEntries = nex.Model.ImportedNameTable?
|
||||
.Select(kvp => kvp.Value)
|
||||
.Select(inte => inte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(inte.NameString))
|
||||
.Any(s => s.Contains("CDCOPS")) ?? false;
|
||||
if (importedNameTableEntries)
|
||||
return "CD-Cops";
|
||||
|
||||
// Check the nonresident-name table
|
||||
// Found in "CDCOPS.DLL" in Redump entry 85077.
|
||||
bool nonresidentNameTableEntries = nex.Model.NonResidentNameTable?
|
||||
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
|
||||
.Any(s => s.Contains("CDcops assembly-language DLL")) ?? false;
|
||||
if (nonresidentNameTableEntries)
|
||||
return "CD-Cops";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the stub executable data, if it exists
|
||||
if (pex.StubExecutableData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// WEBCOPS
|
||||
// Found in "HyperBowl.C_S" in https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe.
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
|
||||
}, "WEB-Cops")
|
||||
};
|
||||
|
||||
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
|
||||
// Get the .grand section, if it exists
|
||||
// Found in "AGENTHUG.QZ_" in Redump entry 84517 and "h3blade.QZ_" in Redump entry 85077.
|
||||
bool grandSection = pex.ContainsSection(".grand", exact: true);
|
||||
if (grandSection)
|
||||
return "CD/DVD/WEB-Cops";
|
||||
|
||||
// Get the UNICops section, if it exists
|
||||
// Found in "FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
|
||||
bool UNICopsSection = pex.ContainsSection("UNICops", exact: true);
|
||||
if (UNICopsSection)
|
||||
return "UNI-Cops";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// TODO: Original had "CDCOPS.DLL" required and all the rest in a combined OR
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
// A 400+ MB file called "WASTE.DAT" that is fully 00 padded can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
|
||||
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
|
||||
|
||||
// Found in Redump entry 84517.
|
||||
new PathMatchSet(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
|
||||
new PathMatchSet(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
|
||||
new PathMatchSet(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
|
||||
|
||||
new PathMatchSet(new PathMatch(".GZ_", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
|
||||
new PathMatchSet(new PathMatch(".Qz", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
// A 400+ MB file called "WASTE.DAT" that is fully 00 padded can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
|
||||
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
|
||||
|
||||
// Found in Redump entry 84517.
|
||||
new PathMatchSet(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
|
||||
new PathMatchSet(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
|
||||
new PathMatchSet(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
|
||||
|
||||
new PathMatchSet(new PathMatch(".GZ_", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
|
||||
new PathMatchSet(new PathMatch(".Qz", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
||||
}
|
||||
|
||||
#if NET48
|
||||
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
|
||||
#else
|
||||
public static string? GetVersion(string file, byte[]? fileContent, List<int> positions)
|
||||
#endif
|
||||
{
|
||||
// If we have no content
|
||||
if (fileContent == null)
|
||||
return null;
|
||||
|
||||
char[] version = new ArraySegment<byte>(fileContent, positions[0] + 15, 4).Select(b => (char)b).ToArray();
|
||||
if (version[0] == 0x00)
|
||||
return string.Empty;
|
||||
|
||||
return new string(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// CD-Guard is a DRM from Russia that's similar to CD-Cops and may be related to StarForce, meaning it likely needs DPM.
|
||||
@@ -24,29 +24,33 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class CDGuard : IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// TODO: Investigate the numerous ".guard" sections present in "Randevu.exe" in Redump entry 97142.
|
||||
|
||||
// Get the export directory table
|
||||
if (pex.ExportTable?.ExportDirectoryTable != null)
|
||||
if (pex.Model.ExportTable?.ExportDirectoryTable != null)
|
||||
{
|
||||
// Found in "cdguard.dll" in Redump entry 97142 and IA item "pahgeby-he3hakomkou".
|
||||
bool match = pex.ExportTable.ExportDirectoryTable.Name?.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase) == true;
|
||||
bool match = pex.Model.ExportTable.ExportDirectoryTable.Name?.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase) == true;
|
||||
if (match)
|
||||
return "CD-Guard Copy Protection System";
|
||||
}
|
||||
|
||||
// Get the import directory table
|
||||
if (pex.ImportTable?.ImportDirectoryTable != null)
|
||||
if (pex.Model.ImportTable?.ImportDirectoryTable != null)
|
||||
{
|
||||
// Found in "Randevu.exe" in Redump entry 97142.
|
||||
bool match = pex.ImportTable.ImportDirectoryTable.Any(idte => idte.Name?.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase) == true);
|
||||
bool match = pex.Model.ImportTable.ImportDirectoryTable.Any(idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
|
||||
if (match)
|
||||
return "CD-Guard Copy Protection System";
|
||||
}
|
||||
@@ -55,7 +59,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -63,11 +71,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("cdguard.dll", useEndsWith: true), "CD-Guard Copy Protection System"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,20 +1,24 @@
|
||||
using System;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CDKey : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
string name = pex.InternalName;
|
||||
var name = pex.InternalName;
|
||||
if (name?.Equals("CDKey", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return "CD-Key / Serial";
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// CD-Lock (https://www.cdmediaworld.com/hardware/cdrom/cd_protections_dummy_files.shtml) is a copy protection most commonly used in Europe and active from 1998-2001 that seems to have a resemblance to Bitpool in a few ways.
|
||||
@@ -27,10 +27,14 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class CDLock : IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -52,7 +56,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "CD-Lock"),
|
||||
};
|
||||
|
||||
string match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
|
||||
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
return match;
|
||||
}
|
||||
@@ -61,7 +65,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -73,11 +81,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
// There is also a "$$$$$$$$.$$$" file present on some discs, but it isn't known if this is directly related to CD-Lock (Redump entries 37788 and 43221).
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// CD-Protector is a form of DRM that allows users to create their own copy protected discs.
|
||||
@@ -17,7 +17,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class CDProtector : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -35,11 +39,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("Track#1 - Track#2 Cd-Protector.wav", useEndsWith: true), "CD-Protector"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,31 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CDSHiELDSE : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// TODO: Indicates Hypertech Crack Proof as well?
|
||||
//// Get the import directory table
|
||||
//if (pex.ImportTable?.ImportDirectoryTable != null)
|
||||
//if (pex.Model.ImportTable?.ImportDirectoryTable != null)
|
||||
//{
|
||||
// bool match = pex.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
|
||||
// bool match = pex.Model.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
|
||||
// if (match)
|
||||
// return "CDSHiELD SE";
|
||||
//}
|
||||
|
||||
// Get the code/CODE section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
|
||||
var strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("~0017.tmp")))
|
||||
@@ -1,14 +1,18 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CDX : IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// TODO: Verify if these are OR or AND
|
||||
var matchers = new List<PathMatchSet>
|
||||
@@ -18,11 +22,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("CHKCDXNT.DLL", useEndsWith: true), "CD-X (Unconfirmed - Please report to us on Github)"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
37
BinaryObjectScanner/Protection/CactusDataShield.cs
Normal file
37
BinaryObjectScanner/Protection/CactusDataShield.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CactusDataShield : IContentCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#else
|
||||
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Limit these checks to Mac binaries
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
{
|
||||
var contentMatchSets = new List<ContentMatchSet>
|
||||
{
|
||||
// CDSPlayer
|
||||
new ContentMatchSet(new byte?[] { 0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72 }, "Cactus Data Shield 200"),
|
||||
|
||||
// yucca.cds
|
||||
new ContentMatchSet(new byte?[] { 0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73 }, "Cactus Data Shield 200"),
|
||||
};
|
||||
|
||||
if (contentMatchSets != null && contentMatchSets.Any())
|
||||
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Cenega ProtectDVD is a protection seemingly created by the publisher Cenega for use with their games.
|
||||
/// Games using this protection aren't able to be run from an ISO file, and presumably use DMI as a protection feature.
|
||||
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/Cenega_ProtectDVD.md"/>
|
||||
/// Games using this protection aren't able to be run from an ISO file, and presumably use DPM as a protection feature.
|
||||
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/Cenega_ProtectDVD/Cenega_ProtectDVD.md"/>
|
||||
/// </summary>
|
||||
public class CengaProtectDVD : IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the export directory table
|
||||
if (pex.ExportTable?.ExportDirectoryTable != null)
|
||||
if (pex.Model.ExportTable?.ExportDirectoryTable != null)
|
||||
{
|
||||
// Found in "cenega.dll" in IA item "speed-pack".
|
||||
bool match = pex.ExportTable.ExportDirectoryTable.Name?.Equals("ProtectDVD.dll", StringComparison.OrdinalIgnoreCase) == true;
|
||||
bool match = pex.Model.ExportTable.ExportDirectoryTable.Name?.Equals("ProtectDVD.dll", StringComparison.OrdinalIgnoreCase) == true;
|
||||
if (match)
|
||||
return "Cenega ProtectDVD";
|
||||
}
|
||||
@@ -53,7 +57,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -62,11 +70,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("cenega.dll", useEndsWith: true), "Cenega ProtectDVD"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -2,11 +2,11 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// Code-Lock by ChosenBytes (https://web.archive.org/web/20040225072021/http://chosenbytes.com/) is a form of DRM that protects Visual Basic and .NET programs.
|
||||
@@ -23,21 +23,25 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class ChosenBytesCodeLock : IPathCheck, IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Found in "Code-Lock.ocx" in Code-Lock version 2.35.
|
||||
// Also worth noting is the File Description for this file, which is "A future for you, a challenge for the rest.".
|
||||
string name = pex.ProductName;
|
||||
var name = pex.ProductName;
|
||||
if (name?.StartsWith("Code-Lock", StringComparison.OrdinalIgnoreCase) == true)
|
||||
return $"ChosenBytes Code-Lock {pex.ProductVersion}";
|
||||
|
||||
// Get the .text section strings, if they exist
|
||||
List<string> strs = pex.GetFirstSectionStrings(".text");
|
||||
var strs = pex.GetFirstSectionStrings(".text");
|
||||
if (strs != null)
|
||||
{
|
||||
if (strs.Any(s => s.Contains("CODE-LOCK.OCX")))
|
||||
@@ -54,7 +58,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -65,11 +73,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
new PathMatchSet(new PathMatch("Code-Lock Wizard.exe", useEndsWith: true), "ChosenBytes Code-Lock"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
var matchers = new List<PathMatchSet>
|
||||
{
|
||||
@@ -1,14 +1,18 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class CopyKiller : IContentCheck, IPathCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#else
|
||||
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// TODO: Obtain a sample to find where this string is in a typical executable
|
||||
if (includeDebug)
|
||||
@@ -30,7 +34,11 @@ namespace BurnOutSharp.ProtectionType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
||||
#else
|
||||
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
|
||||
#endif
|
||||
{
|
||||
// TODO: The following checks are overly broad and should be refined
|
||||
// TODO: Look into .PFF files as an indicator. At least one disc has those oversized files
|
||||
@@ -39,11 +47,15 @@ namespace BurnOutSharp.ProtectionType
|
||||
//new PathMatchSet(new PathMatch("Autorun.dat", useEndsWith: true), "CopyKiller"),
|
||||
};
|
||||
|
||||
return MatchUtil.GetAllMatches(files, matchers, any: true);
|
||||
return MatchUtil.GetAllMatches(files ?? System.Array.Empty<string>(), matchers, any: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckFilePath(string path)
|
||||
#else
|
||||
public string? CheckFilePath(string path)
|
||||
#endif
|
||||
{
|
||||
// TODO: The following checks are overly broad and should be refined
|
||||
// TODO: Look into .PFF files as an indicator. At least one disc has those oversized files
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Linq;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
/// <summary>
|
||||
/// CopyLok (AKA CodeLok) is a DRM created by PAN Technology (https://web.archive.org/web/19991117100625/http://www.pantechnology.com/).
|
||||
@@ -23,17 +23,21 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class CopyLok : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// If there are more than 2 icd-prefixed sections, then we have a match
|
||||
// Though this is the same name that SafeDisc uses for protected executables, this seems to be a coincidence.
|
||||
// Found in Redump entries 31557, 31674, 31675, 31708, 38239, 44210, and 53929.
|
||||
int icdSectionCount = pex.SectionNames.Count(s => s.StartsWith("icd"));
|
||||
int icdSectionCount = pex.SectionNames?.Count(s => s.StartsWith("icd")) ?? 0;
|
||||
if (icdSectionCount >= 2)
|
||||
return "CopyLok / CodeLok";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Wrappers;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
// http://www.crypkey.com/products/cdlock/cdmain.html
|
||||
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/CrypKey%20Installer.1.sg
|
||||
@@ -10,10 +10,14 @@ namespace BurnOutSharp.ProtectionType
|
||||
public class CrypKey : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex?.SectionTable;
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
@@ -21,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
string version = pex.GetVersionInfoString("CrypKey Version") ?? string.Empty;
|
||||
|
||||
// Found in 'cki32k.dll'
|
||||
string name = pex.CompanyName;
|
||||
var name = pex.CompanyName;
|
||||
if (name?.StartsWith("CrypKey") == true)
|
||||
return $"CrypKey {version}".TrimEnd();
|
||||
|
||||
51
BinaryObjectScanner/Protection/Cucko.cs
Normal file
51
BinaryObjectScanner/Protection/Cucko.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using SabreTools.Matching;
|
||||
using SabreTools.Serialization.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
// TODO: Do more research into the Cucko protection:
|
||||
// - Reference to `EASTL` and `EAStdC` are standard for EA products and does not indicate Cucko by itself
|
||||
// - There's little information outside of PiD detection that actually knows about Cucko
|
||||
// - Cucko is confirmed to, at least, use DMI checks.
|
||||
public class Cucko : IPortableExecutableCheck
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
#if NET48
|
||||
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#else
|
||||
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
|
||||
#endif
|
||||
{
|
||||
// Get the sections from the executable, if possible
|
||||
var sections = pex.Model.SectionTable;
|
||||
if (sections == null)
|
||||
return null;
|
||||
|
||||
// Get the .text section, if it exists
|
||||
if (pex.ContainsSection(".text"))
|
||||
{
|
||||
var textData = pex.GetFirstSectionData(".text");
|
||||
if (textData != null)
|
||||
{
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
// Confirmed to detect most examples known of Cucko. The only known exception is the version of "TSLHost.dll" included on Redump entry 36119.
|
||||
// ŠU‰8...…™...ŠUŠ8T...
|
||||
new ContentMatchSet(new byte?[]
|
||||
{
|
||||
0x8A, 0x55, 0x89, 0x38, 0x14, 0x1E, 0x0F, 0x85,
|
||||
0x99, 0x00, 0x00, 0x00, 0x8A, 0x55, 0x8A, 0x38,
|
||||
0x54, 0x1E, 0x01, 0x0F
|
||||
}, "Cucko (EA Custom)")
|
||||
};
|
||||
|
||||
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace BurnOutSharp.ProtectionType
|
||||
namespace BinaryObjectScanner.Protection
|
||||
{
|
||||
public class DBB
|
||||
{
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user