Compare commits

...

72 Commits

Author SHA1 Message Date
Matt Nadareski
eb03470625 Bump version 2024-11-21 11:20:19 -05:00
Matt Nadareski
b1aa2fc73a Enable MPQ on .NET Framework 4.0 2024-11-21 10:40:10 -05:00
Matt Nadareski
cd21c76c97 Add versions to executables 2024-11-21 10:35:15 -05:00
Matt Nadareski
9e205ddf2a More incidental cleanup 2024-11-21 01:32:30 -05:00
Matt Nadareski
07a183955b Reduce framework gating in SecuROM 2024-11-20 23:41:09 -05:00
Matt Nadareski
b49c6e96fd Add guards around previous commit 2024-11-20 21:48:37 -05:00
Matt Nadareski
148cfed141 Add executable extraction to tool 2024-11-20 21:45:15 -05:00
Matt Nadareski
cebbe6a1e8 Check overlay for embedded data as well 2024-11-20 21:33:56 -05:00
Matt Nadareski
558e23a9cd Clean up after last few commits 2024-11-20 21:18:12 -05:00
Matt Nadareski
d7c37f6e0a Lists lead to less Linq 2024-11-20 20:58:39 -05:00
Matt Nadareski
c05090db8c Update packages 2024-11-20 20:23:05 -05:00
Matt Nadareski
fa19304a6d Remove some framework gating 2024-11-20 20:10:18 -05:00
Matt Nadareski
ec4962a3c9 Use List where possible, Macrovision edition 2024-11-20 17:13:47 -05:00
Matt Nadareski
7122aa44a1 Use List where possible 2024-11-20 17:10:03 -05:00
Matt Nadareski
cf62be365c Use List where possible 2024-11-20 17:05:40 -05:00
Matt Nadareski
9cc2f99334 Quick package sync 2024-11-20 16:51:06 -05:00
Matt Nadareski
d9d9f23af9 Read entire file for content checks 2024-11-20 15:53:09 -05:00
Matt Nadareski
c29354f054 Add embedded archive scanning 2024-11-20 15:19:39 -05:00
Matt Nadareski
7738630952 Bump version 2024-11-16 00:00:00 -05:00
Matt Nadareski
c945ca4fe3 Make BOS compatible with RedumpLib 2024-11-15 23:59:23 -05:00
Matt Nadareski
6acf5ccc09 Bump version 2024-11-15 23:11:00 -05:00
Matt Nadareski
a5f9006ef1 One last Linq place (not all of them) 2024-11-15 23:09:58 -05:00
Matt Nadareski
ae7111e201 Update package versions 2024-11-15 23:06:47 -05:00
Matt Nadareski
5a94cd3b66 Framework only matters for executable 2024-11-15 23:00:37 -05:00
Matt Nadareski
3de58ff05e Fix linux publish script 2024-11-13 13:03:13 -05:00
Matt Nadareski
6e409988a5 Bump version 2024-11-13 13:01:48 -05:00
Matt Nadareski
864fa8d3f8 Add .NET 9 to target frameworks 2024-11-13 04:26:26 -05:00
Matt Nadareski
622f36b056 Add .NET 9 to target frameworks 2024-11-13 04:26:24 -05:00
Matt Nadareski
efe144313b Fix build 2024-11-12 23:29:53 -05:00
Matt Nadareski
1e3aac6748 Linq is friend, not food 2024-11-12 23:17:48 -05:00
Matt Nadareski
984ad1f642 Remove minimally-used System.Memory package 2024-11-05 16:58:13 -05:00
Matt Nadareski
b379e1781b Remove unused MinThreadingBridge library 2024-11-05 16:53:52 -05:00
Matt Nadareski
e244d6939c Attempt to reduce nesting in GHA builds 2024-11-05 13:50:04 -05:00
Matt Nadareski
b4a781acc7 Bump version 2024-11-05 13:10:09 -05:00
Matt Nadareski
eb7bbdde52 Remove now-incorrect remark 2024-11-05 11:06:30 -05:00
Matt Nadareski
f470263196 Func not obj 2024-11-05 01:45:35 -05:00
Matt Nadareski
3822cc41f2 Extract loop into new method; fix build 2024-11-05 01:24:14 -05:00
Matt Nadareski
f04cf25fa9 Move all executable handling to Executable 2024-11-05 01:12:18 -05:00
Matt Nadareski
eb8b9daea8 Reduce unncessary nulls 2024-11-05 00:42:45 -05:00
Matt Nadareski
33ecc246dc Reorganize yet again around check sets 2024-11-05 00:32:42 -05:00
Matt Nadareski
7d55c8224a Move Factory to Data namespace 2024-11-05 00:28:39 -05:00
Matt Nadareski
0ccae4e4b7 Move static check collections to separate class 2024-11-05 00:25:22 -05:00
Matt Nadareski
1798371513 Add better info to coding and dev guides 2024-11-05 00:10:40 -05:00
Matt Nadareski
0858437196 Undo launch changes 2024-11-04 23:59:46 -05:00
Matt Nadareski
ece758bf03 IExtractableExecutable extends IExecutableCheck 2024-11-04 23:59:10 -05:00
Matt Nadareski
d9661cd03d Fix access level 2024-11-04 23:52:40 -05:00
Matt Nadareski
682529d7ba Consolidate more typed methods 2024-11-04 23:49:13 -05:00
Matt Nadareski
27ef24636c Use typed check methods as well 2024-11-04 23:37:23 -05:00
Matt Nadareski
f5f3d3d29a Fun with typed interfaces 2024-11-04 23:21:12 -05:00
Matt Nadareski
550fb70952 Use typed interface for extractable executables 2024-11-04 22:02:10 -05:00
Matt Nadareski
7d6248a3bf Re-merge some code from Handler to Scanner 2024-11-04 21:53:59 -05:00
Matt Nadareski
4575da77bd Use private field when possible 2024-11-04 21:40:56 -05:00
Matt Nadareski
a85aa08117 Reduce publicly visible fields in Scanner 2024-11-04 21:37:03 -05:00
Matt Nadareski
667207761c Reduce SFX code duplication 2024-11-04 21:25:30 -05:00
Matt Nadareski
92097222b0 Sync IExtractable*Executable implementations 2024-11-04 21:14:06 -05:00
Matt Nadareski
5ec90b290a Steam any false 2024-11-04 20:06:47 -05:00
Matt Nadareski
5de78ef552 Make GitHub action Debug-only 2024-11-04 15:02:11 -05:00
Matt Nadareski
57a5531fbd Remove old Test executable; update docs 2024-11-04 14:58:21 -05:00
Matt Nadareski
f7a4b6b43c Add separate ExtractionTool executable 2024-11-04 14:48:29 -05:00
Matt Nadareski
3de56083d8 Add separate ProtectionScan executable 2024-11-04 14:38:23 -05:00
Matt Nadareski
f998a578cc Make Extractor static like Protector 2024-11-04 14:14:50 -05:00
Matt Nadareski
0fc7ce2e07 Simplify code in Extractor 2024-11-04 14:10:16 -05:00
Matt Nadareski
156df10e37 Remove Printer 2024-11-04 14:05:20 -05:00
Matt Nadareski
9490d06509 Remove Utilities namespace references 2024-11-04 11:54:41 -05:00
Matt Nadareski
b8b70a3848 Ensure all files matched in RainbowSentinel (fixes #336) 2024-11-04 11:42:24 -05:00
Matt Nadareski
42df482ffa Fix MPQ compilation 2024-11-04 11:29:36 -05:00
Matt Nadareski
058dfaeb37 Fix missed outDir location 2024-11-04 11:25:42 -05:00
Matt Nadareski
1622bcbe60 Replace now-duplicate code 2024-11-04 11:17:09 -05:00
Matt Nadareski
72629ea3a4 Update IExtractable interface 2024-11-04 11:00:59 -05:00
Matt Nadareski
4ba3c3e3ad Normalize extraction 2024-11-04 10:20:46 -05:00
Matt Nadareski
56c1fd31d4 Add Steam extension matching (fixes #234) 2024-11-04 09:51:20 -05:00
Matt Nadareski
9c27da72bb Add VOB-PCD.KEY detection 2024-11-04 09:38:25 -05:00
190 changed files with 3915 additions and 5441 deletions

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore

View File

@@ -1,4 +1,4 @@
name: Build Test
name: Build Programs
on:
push:
@@ -10,10 +10,10 @@ jobs:
strategy:
matrix:
project: [Test]
project: [ExtractionTool, ProtectionScan]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
framework: [net8.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0]
conf: [Release, Debug]
framework: [net9.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0, net9.0]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4
@@ -23,16 +23,18 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8') || startsWith(matrix.framework, 'net9')) && '-p:PublishSingleFile=true' || ''}}
- name: Archive build
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ${{ matrix.project }}/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
run: |
cd ${{ matrix.project }}/bin/Debug/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
zip -r ${{ github.workspace }}/${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ./
- name: Upload build
uses: actions/upload-artifact@v4

View File

@@ -11,7 +11,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Build
run: dotnet build

19
.vscode/launch.json vendored
View File

@@ -5,14 +5,27 @@
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (Test)",
"name": ".NET Core Launch (ProtectionScan)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Test/bin/Debug/net8.0/Test.dll",
"program": "${workspaceFolder}/ProtectionScan/bin/Debug/net9.0/ProtectionScan.dll",
"args": [],
"cwd": "${workspaceFolder}/Test",
"cwd": "${workspaceFolder}/ProtectionScan",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Launch (ExtractionTool)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/ExtractionTool/bin/Debug/net9.0/ExtractionTool.dll",
"args": [],
"cwd": "${workspaceFolder}/ExtractionTool",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false

View File

@@ -3,8 +3,6 @@ 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
@@ -18,20 +16,28 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner", "BinaryObjectScanner\BinaryObjectScanner.csproj", "{341EA3F5-847C-4739-B86F-2B051FFE4EF2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtectionScan", "ProtectionScan\ProtectionScan.csproj", "{14CC56E0-7D56-497C-BF3D-4C06FA169831}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtractionTool", "ExtractionTool\ExtractionTool.csproj", "{89767A19-043F-4251-805B-B2CBC48E2B79}"
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
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.Build.0 = Release|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,103 +1,97 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.1.15</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS0162;CS0612;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Protection scanning library</Description>
<Copyright>Copyright (c)2018-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/BinaryObjectScanner</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>protection copy-protection scanning packer</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<NoWarn>CS0162;CS0612</NoWarn>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.2.3</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<DefineConstants>$(DefineConstants);WIN</DefineConstants>
</PropertyGroup>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Protection scanning library</Description>
<Copyright>Copyright (c)2018-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/BinaryObjectScanner</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>protection copy-protection scanning packer</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<!-- Exclude certain parts of external modules for by default -->
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
**\AssemblyInfo.cs;
_EXTERNAL\LessIO\src\LessIO.Tests\**;
_EXTERNAL\libmspack4n\lib\**;
_EXTERNAL\libmspack4n\libmspack4ntest\**;
_EXTERNAL\stormlibsharp\lib\**;
_EXTERNAL\stormlibsharp\src\TestConsole\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<DefineConstants>$(DefineConstants);WIN</DefineConstants>
</PropertyGroup>
<!-- Exclude all StormLibSharp for .NET Framework 4.0 -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net40`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\stormlibsharp\src\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- Exclude certain parts of external modules for by default -->
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
**\AssemblyInfo.cs;
_EXTERNAL\LessIO\src\LessIO.Tests\**;
_EXTERNAL\libmspack4n\lib\**;
_EXTERNAL\libmspack4n\libmspack4ntest\**;
_EXTERNAL\stormlibsharp\lib\**;
_EXTERNAL\stormlibsharp\src\TestConsole\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- Exclude all external modules for .NET Framework 2.0, .NET Framework 3.5, or non-Windows builds -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR !$(RuntimeIdentifier.StartsWith(`win-x86`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- Exclude all external modules for .NET Framework 2.0, .NET Framework 3.5, or non-Windows
builds -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR !$(RuntimeIdentifier.StartsWith(`win-x86`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND $(RuntimeIdentifier.StartsWith(`win-x86`))">
<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>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND $(RuntimeIdentifier.StartsWith(`win-x86`))">
<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>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="MinThreadingBridge" Version="0.11.4" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`))">
<PackageReference Include="OpenMcdf" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
<PackageReference Include="SharpCompress" Version="0.38.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`))">
<PackageReference Include="Net30.LinqBridge" Version="1.3.0" />
<PackageReference Include="Net35.Actions" Version="1.1.0" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`))">
<PackageReference Include="OpenMcdf" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="MinAsyncBridge" Version="0.12.4" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
<PackageReference Include="SharpCompress" Version="0.38.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Compression" Version="0.5.2" />
<PackageReference Include="SabreTools.Hashing" Version="1.2.2" />
<PackageReference Include="SabreTools.IO" Version="1.4.13" />
<PackageReference Include="SabreTools.Matching" Version="1.3.3" />
<PackageReference Include="SabreTools.Models" Version="1.4.11" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.9" />
<PackageReference Include="UnshieldSharp" Version="1.8.5" />
<PackageReference Include="WiseUnpacker" Version="1.4.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Compression" Version="0.6.1" />
<PackageReference Include="SabreTools.Hashing" Version="1.4.0" />
<PackageReference Include="SabreTools.IO" Version="1.5.1" />
<PackageReference Include="SabreTools.Matching" Version="1.4.1" />
<PackageReference Include="SabreTools.Models" Version="1.5.3" />
<PackageReference Include="SabreTools.Serialization" Version="1.7.6" />
<PackageReference Include="UnshieldSharp" Version="1.9.1" />
<PackageReference Include="WiseUnpacker" Version="1.5.1" />
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Data
{
internal static class StaticChecks
{
#region Public Collections
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
public static List<IContentCheck> ContentCheckClasses
{
get
{
contentCheckClasses ??= InitCheckClasses<IContentCheck>();
return contentCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<LinearExecutable> types
/// </summary>
public static List<IExecutableCheck<LinearExecutable>> LinearExecutableCheckClasses
{
get
{
linearExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<LinearExecutable>>();
return linearExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<MSDOS> types
/// </summary>
public static List<IExecutableCheck<MSDOS>> MSDOSExecutableCheckClasses
{
get
{
msdosExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<MSDOS>>();
return msdosExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<NewExecutable> types
/// </summary>
public static List<IExecutableCheck<NewExecutable>> NewExecutableCheckClasses
{
get
{
newExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<NewExecutable>>();
return newExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
public static List<IPathCheck> PathCheckClasses
{
get
{
pathCheckClasses ??= InitCheckClasses<IPathCheck>();
return pathCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<PortableExecutable> types
/// </summary>
public static List<IExecutableCheck<PortableExecutable>> PortableExecutableCheckClasses
{
get
{
portableExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<PortableExecutable>>();
return portableExecutableCheckClasses ?? [];
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
private static List<IContentCheck>? contentCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<LinearExecutable> types
/// </summary>
private static List<IExecutableCheck<LinearExecutable>>? linearExecutableCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<MSDOS> types
/// </summary>
private static List<IExecutableCheck<MSDOS>>? msdosExecutableCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<NewExecutable> types
/// </summary>
private static List<IExecutableCheck<NewExecutable>>? newExecutableCheckClasses;
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
private static List<IPathCheck>? pathCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<PortableExecutable> types
/// </summary>
private static List<IExecutableCheck<PortableExecutable>>? portableExecutableCheckClasses;
#endregion
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static List<T>? InitCheckClasses<T>() =>
InitCheckClasses<T>(Assembly.GetExecutingAssembly()) ?? [];
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static List<T>? InitCheckClasses<T>(Assembly assembly)
{
List<T> classTypes = [];
// If not all types can be loaded, use the ones that could be
Type?[] assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = [.. rtle.Types];
}
// Get information from the type param
string interfaceName = typeof(T)!.FullName!;
// Loop through all types
foreach (Type? type in assemblyTypes)
{
// Skip invalid types
if (type == null)
continue;
// If the type isn't a class
if (!type.IsClass)
continue;
// If the type isn't a class or doesn't implement the interface
bool interfaceFound = false;
foreach (var ii in type.GetInterfaces())
{
if (ii.FullName != interfaceName)
continue;
interfaceFound = true;
break;
}
if (!interfaceFound)
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
}
}

View File

@@ -0,0 +1,9 @@
#if NET20
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
internal sealed class ExtensionAttribute : Attribute {}
}
#endif

View File

@@ -62,7 +62,7 @@ namespace BinaryObjectScanner
WrapperType.TapeArchive => new FileType.TapeArchive(),
WrapperType.VBSP => new FileType.VBSP(),
WrapperType.VPK => new FileType.VPK(),
WrapperType.WAD => new FileType.WAD(),
WrapperType.WAD => new FileType.WAD3(),
WrapperType.XZ => new FileType.XZ(),
WrapperType.XZP => new FileType.XZP(),
_ => null,

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
@@ -16,10 +15,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -34,7 +31,7 @@ namespace BinaryObjectScanner.FileType
return null;
// Derive the version, if possible
var typeAndVersion = mkb.Model.Records?.FirstOrDefault(r => r?.RecordType == SabreTools.Models.AACS.RecordType.TypeAndVersion);
var typeAndVersion = Array.Find(mkb.Model.Records ?? [], r => r?.RecordType == SabreTools.Models.AACS.RecordType.TypeAndVersion);
if (typeAndVersion == null)
return "AACS (Unknown Version)";
else

View File

@@ -15,10 +15,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>

View File

@@ -14,38 +14,35 @@ namespace BinaryObjectScanner.FileType
public class BFPK : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Extract all files
ExtractAll(bfpk, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(bfpk, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Models.BSP;
namespace BinaryObjectScanner.FileType
{
@@ -11,41 +11,37 @@ namespace BinaryObjectScanner.FileType
public class BSP : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
try
{
// Create the wrapper
var bsp = SabreTools.Serialization.Wrappers.BSP.Create(stream);
if (bsp == null)
return null;
return false;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// TODO: Introduce helper methods for all specialty lump types
// Loop through and extract all files
ExtractAllLumps(bsp, tempPath);
ExtractAllTextures(bsp, tempPath);
Directory.CreateDirectory(outDir);
ExtractAllLumps(bsp, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -57,12 +53,12 @@ namespace BinaryObjectScanner.FileType
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.BSP item, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
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.Lumps.Length; i++)
for (int i = 0; i < item.Model.Header.Lumps.Length; i++)
{
allExtracted &= ExtractLump(item, i, outputDirectory);
}
@@ -79,15 +75,15 @@ namespace BinaryObjectScanner.FileType
public static bool ExtractLump(SabreTools.Serialization.Wrappers.BSP item, int index, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
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.Lumps.Length)
if (index < 0 || index >= item.Model.Header.Lumps.Length)
return false;
// Get the lump
var lump = item.Model.Lumps[index];
var lump = item.Model.Header.Lumps[index];
if (lump == null)
return false;
@@ -98,12 +94,12 @@ namespace BinaryObjectScanner.FileType
// Create the filename
string filename = $"lump_{index}.bin";
switch (index)
switch ((LumpType)index)
{
case SabreTools.Models.BSP.Constants.HL_BSP_LUMP_ENTITIES:
case LumpType.LUMP_ENTITIES:
filename = "entities.ent";
break;
case SabreTools.Models.BSP.Constants.HL_BSP_LUMP_TEXTUREDATA:
case LumpType.LUMP_TEXTURES:
filename = "texture_data.bin";
break;
}
@@ -124,10 +120,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{
@@ -136,172 +130,5 @@ namespace BinaryObjectScanner.FileType
return true;
}
/// <summary>
/// Extract all textures from the BSP to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all textures extracted, false otherwise</returns>
public static bool ExtractAllTextures(SabreTools.Serialization.Wrappers.BSP item, string outputDirectory)
{
// If we have no textures
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 < item.Model.TextureHeader.Offsets.Length; i++)
{
allExtracted &= ExtractTexture(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a texture from the BSP 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 texture extracted, false otherwise</returns>
public static bool ExtractTexture(SabreTools.Serialization.Wrappers.BSP item, int index, string outputDirectory)
{
// If we have no textures
if (item.Model.Textures == null || item.Model.Textures.Length == 0)
return false;
// If the texture index is invalid
if (index < 0 || index >= item.Model.Textures.Length)
return false;
// Get the texture
var texture = item.Model.Textures[index];
if (texture == null)
return false;
// Read the data
var data = CreateTextureData(texture);
if (data == null)
return false;
// Create the filename
string filename = $"{texture.Name}.bmp";
// If we have an invalid output directory
if (string.IsNullOrEmpty(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;
}
/// <summary>
/// Create a bitmap from the texture and palette data
/// </summary>
/// <param name="texture">Texture object to format</param>
/// <returns>Byte array representing the texture as a bitmap</returns>
private static byte[]? CreateTextureData(SabreTools.Models.BSP.Texture texture)
{
// 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 SabreTools.Models.BMP.BITMAPFILEHEADER()
{
Type = ('M' << 8) | 'B',
Size = 14 + 40 + (texture.PaletteSize * 4) + (texture.Width * texture.Height),
OffBits = 14 + 40 + (texture.PaletteSize * 4),
};
// Create the bitmap info header
var infoHeader = new SabreTools.Models.BMP.BITMAPINFOHEADER
{
Size = 40,
Width = (int)texture.Width,
Height = (int)texture.Height,
Planes = 1,
BitCount = 8,
SizeImage = 0,
ClrUsed = texture.PaletteSize,
ClrImportant = texture.PaletteSize,
};
// Reformat the palette data
byte[] paletteData = new byte[texture.PaletteSize * 4];
for (uint i = 0; i < texture.PaletteSize; i++)
{
paletteData[i * 4 + 0] = texture.PaletteData[i * 3 + 2];
paletteData[i * 4 + 1] = texture.PaletteData[i * 3 + 1];
paletteData[i * 4 + 2] = texture.PaletteData[i * 3 + 0];
paletteData[i * 4 + 3] = 0;
}
// Reformat the pixel data
byte[] pixelData = new byte[texture.Width * texture.Height];
for (uint i = 0; i < texture.Width; i++)
{
for (uint j = 0; j < texture.Height; j++)
{
pixelData[i + ((texture.Height - 1 - j) * texture.Width)] = texture.TextureData[i + j * texture.Width];
}
}
// Build the file data
List<byte> buffer = new List<byte>();
// Bitmap file header
buffer.AddRange(BitConverter.GetBytes(fileHeader.Type));
buffer.AddRange(BitConverter.GetBytes(fileHeader.Size));
buffer.AddRange(BitConverter.GetBytes(fileHeader.Reserved1));
buffer.AddRange(BitConverter.GetBytes(fileHeader.Reserved2));
buffer.AddRange(BitConverter.GetBytes(fileHeader.OffBits));
// Bitmap info header
buffer.AddRange(BitConverter.GetBytes(infoHeader.Size));
buffer.AddRange(BitConverter.GetBytes(infoHeader.Width));
buffer.AddRange(BitConverter.GetBytes(infoHeader.Height));
buffer.AddRange(BitConverter.GetBytes(infoHeader.Planes));
buffer.AddRange(BitConverter.GetBytes(infoHeader.BitCount));
buffer.AddRange(BitConverter.GetBytes(infoHeader.Compression));
buffer.AddRange(BitConverter.GetBytes(infoHeader.SizeImage));
buffer.AddRange(BitConverter.GetBytes(infoHeader.XPelsPerMeter));
buffer.AddRange(BitConverter.GetBytes(infoHeader.YPelsPerMeter));
buffer.AddRange(BitConverter.GetBytes(infoHeader.ClrUsed));
buffer.AddRange(BitConverter.GetBytes(infoHeader.ClrImportant));
// Palette data
buffer.AddRange(paletteData);
// Pixel data
buffer.AddRange(pixelData);
return buffer.ToArray();
}
}
}

View File

@@ -14,46 +14,44 @@ namespace BinaryObjectScanner.FileType
public class BZip2 : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Try opening the stream
using var bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true);
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);
}
}
// Create the output file path
Directory.CreateDirectory(outDir);
string tempFile = Path.Combine(outDir, Guid.NewGuid().ToString());
return tempPath;
// Extract the file
using FileStream fs = File.OpenWrite(tempFile);
bz2File.CopyTo(fs);
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -14,79 +14,75 @@ namespace BinaryObjectScanner.FileType
public class CFB : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
#if NET20 || NET35
// Not supported for .NET Framework 2.0 or .NET Framework 3.5 due to library support
return null;
return false;
#else
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (CompoundFile msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default))
using var msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default);
msi.RootStorage.VisitEntries((e) =>
{
msi.RootStorage.VisitEntries((e) =>
try
{
try
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())
{
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);
}
decoded = decoded.Replace(c, '_');
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}, recursive: true);
}
return tempPath;
string tempFile = Path.Combine(outDir, decoded);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
using Stream fs = File.OpenWrite(tempFile);
fs.Write(strData, 0, strData.Length);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}, recursive: true);
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#endif
}

View File

@@ -2,9 +2,10 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BinaryObjectScanner.Data;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
using SabreTools.Serialization.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.FileType
@@ -12,10 +13,6 @@ 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
@@ -30,95 +27,6 @@ namespace BinaryObjectScanner.FileType
/// </summary>
public bool IncludePackers { get; set; }
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
public static IEnumerable<IContentCheck> ContentCheckClasses
{
get
{
contentCheckClasses ??= InitCheckClasses<IContentCheck>();
return contentCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all ILinearExecutableCheck types
/// </summary>
public static IEnumerable<ILinearExecutableCheck> LinearExecutableCheckClasses
{
get
{
linearExecutableCheckClasses ??= InitCheckClasses<ILinearExecutableCheck>();
return linearExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IMSDOSExecutableCheck types
/// </summary>
public static IEnumerable<IMSDOSExecutableCheck> MSDOSExecutableCheckClasses
{
get
{
msdosExecutableCheckClasses ??= InitCheckClasses<IMSDOSExecutableCheck>();
return msdosExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all INewExecutableCheck types
/// </summary>
public static IEnumerable<INewExecutableCheck> NewExecutableCheckClasses
{
get
{
newExecutableCheckClasses ??= InitCheckClasses<INewExecutableCheck>();
return newExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IPortableExecutableCheck types
/// </summary>
public static IEnumerable<IPortableExecutableCheck> PortableExecutableCheckClasses
{
get
{
portableExecutableCheckClasses ??= InitCheckClasses<IPortableExecutableCheck>();
return portableExecutableCheckClasses ?? [];
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
private static IEnumerable<IContentCheck>? contentCheckClasses;
/// <summary>
/// Cache for all ILinearExecutableCheck types
/// </summary>
private static IEnumerable<ILinearExecutableCheck>? linearExecutableCheckClasses;
/// <summary>
/// Cache for all IMSDOSExecutableCheck types
/// </summary>
private static IEnumerable<IMSDOSExecutableCheck>? msdosExecutableCheckClasses;
/// <summary>
/// Cache for all INewExecutableCheck types
/// </summary>
private static IEnumerable<INewExecutableCheck>? newExecutableCheckClasses;
/// <summary>
/// Cache for all IPortableExecutableCheck types
/// </summary>
private static IEnumerable<IPortableExecutableCheck>? portableExecutableCheckClasses;
#endregion
/// <inheritdoc/>
@@ -134,48 +42,105 @@ namespace BinaryObjectScanner.FileType
/// <inheritdoc/>
public string? Detect(Stream stream, string file, bool includeDebug)
{
// Try to create a wrapper for the proper executable type
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
if (wrapper == null)
// Get all non-nested protections
var protections = DetectDict(stream, file, getProtections: null, includeDebug);
if (protections.Count == 0)
return null;
// Create the internal list
var protections = new List<string>();
var protectionList = new List<string>();
foreach (string key in protections.Keys)
{
protectionList.AddRange(protections[key]);
}
return string.Join(";", [.. protectionList]);
}
/// <inheritdoc cref="IDetectable.Detect(Stream, string, bool)"/>
/// <remarks>
/// Ideally, we wouldn't need to circumvent the proper handling of file types just for Executable,
/// but due to the complexity of scanning, this is not currently possible.
/// </remarks>
public ProtectionDictionary DetectDict(Stream stream,
string file,
Func<string, ProtectionDictionary>? getProtections,
bool includeDebug)
{
// Create the output dictionary
var protections = new ProtectionDictionary();
// Try to create a wrapper for the proper executable type
IWrapper? wrapper;
try
{
wrapper = WrapperFactory.CreateExecutableWrapper(stream);
if (wrapper == null)
return protections;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return protections;
}
// 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);
protections.Append(file, subProtections.Values);
}
if (wrapper is MSDOS mz)
{
var subProtections = RunMSDOSExecutableChecks(file, stream, mz, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values);
// Standard checks
var subProtections
= RunExecutableChecks(file, mz, StaticChecks.MSDOSExecutableCheckClasses, includeDebug);
protections.Append(file, subProtections.Values);
// Extractable checks
var extractedProtections
= HandleExtractableProtections(file, mz, subProtections.Keys, getProtections, includeDebug);
protections.Append(extractedProtections);
}
else if (wrapper is LinearExecutable lex)
{
var subProtections = RunLinearExecutableChecks(file, stream, lex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values);
// Standard checks
var subProtections
= RunExecutableChecks(file, lex, StaticChecks.LinearExecutableCheckClasses, includeDebug);
protections.Append(file, subProtections.Values);
// Extractable checks
var extractedProtections
= HandleExtractableProtections(file, lex, subProtections.Keys, getProtections, includeDebug);
protections.Append(extractedProtections);
}
else if (wrapper is NewExecutable nex)
{
var subProtections = RunNewExecutableChecks(file, stream, nex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values);
// Standard checks
var subProtections
= RunExecutableChecks(file, nex, StaticChecks.NewExecutableCheckClasses, includeDebug);
protections.Append(file, subProtections.Values);
// Extractable checks
var extractedProtections
= HandleExtractableProtections(file, nex, subProtections.Keys, getProtections, includeDebug);
protections.Append(extractedProtections);
}
else if (wrapper is PortableExecutable pex)
{
var subProtections = RunPortableExecutableChecks(file, stream, pex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values);
// Standard checks
var subProtections
= RunExecutableChecks(file, pex, StaticChecks.PortableExecutableCheckClasses, includeDebug);
protections.Append(file, subProtections.Values);
// Extractable checks
var extractedProtections
= HandleExtractableProtections(file, pex, subProtections.Keys, getProtections, includeDebug);
protections.Append(extractedProtections);
}
return string.Join(";", [.. protections]);
return protections;
}
#region Check Runners
@@ -186,34 +151,39 @@ namespace BinaryObjectScanner.FileType
/// <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>
public IDictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
/// <returns>Set of protections in file, empty on error</returns>
public IDictionary<IContentCheck, string> RunContentChecks(string? file, Stream stream, bool includeDebug)
{
// Create the output dictionary
var protections = new CheckDictionary<IContentCheck>();
// If we have an invalid file
if (string.IsNullOrEmpty(file))
return null;
return protections;
else if (!File.Exists(file))
return null;
return protections;
// If the stream isn't seekable
if (!stream.CanSeek)
return protections;
// Read the file contents
byte[] fileContent = [];
try
{
stream.Seek(0, SeekOrigin.Begin);
fileContent = stream.ReadBytes((int)stream.Length);
if (fileContent == null)
return null;
return protections;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return protections;
}
// Create the output dictionary
var protections = new CheckDictionary<IContentCheck>();
// Iterate through all checks
ContentCheckClasses.IterateWithAction(checkClass =>
StaticChecks.ContentCheckClasses.IterateWithAction(checkClass =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckContents(file!, fileContent, includeDebug);
@@ -235,22 +205,26 @@ namespace BinaryObjectScanner.FileType
}
/// <summary>
/// Handle a single file based on all linear executable check implementations
/// Handle a single file based on all 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="exe">Executable to scan</param>
/// <param name="checks">Set of checks to use</param>
/// <param name="scanner">Scanner for handling recursive protections</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
public IDictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
/// <returns>Set of protections in file, empty on error</returns>
public IDictionary<U, string> RunExecutableChecks<T, U>(string file, T exe, List<U> checks, bool includeDebug)
where T : WrapperBase
where U : IExecutableCheck<T>
{
// Create the output dictionary
var protections = new CheckDictionary<ILinearExecutableCheck>();
var protections = new CheckDictionary<U>();
// Iterate through all checks
LinearExecutableCheckClasses.IterateWithAction(checkClass =>
checks.IterateWithAction(checkClass =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckLinearExecutable(file, lex, includeDebug);
var protection = checkClass.CheckExecutable(file, exe, includeDebug);
if (string.IsNullOrEmpty(protection))
return;
@@ -269,149 +243,95 @@ namespace BinaryObjectScanner.FileType
}
/// <summary>
/// Handle a single file based on all MS-DOS executable check implementations
/// Handle extractable protections, such as executable packers
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="mz">Executable to scan</param>
/// <param name="file">Name of the source file of the stream, for tracking</param>
/// <param name="exe">Executable to scan the contents of</param>
/// <param name="checks">Set of classes returned from Exectuable scans</param>
/// <param name="getProtections">Optional function for handling recursive protections</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
public IDictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
/// <returns>Set of protections found from extraction, empty on error</returns>
private static ProtectionDictionary HandleExtractableProtections<T, U>(string file,
T exe,
ICollection<U> checks,
Func<string, ProtectionDictionary>? getProtections,
bool includeDebug)
where T : WrapperBase
where U : IExecutableCheck<T>
{
// Create the output dictionary
var protections = new CheckDictionary<IMSDOSExecutableCheck>();
var protections = new ProtectionDictionary();
// Iterate through all checks
MSDOSExecutableCheckClasses.IterateWithAction(checkClass =>
// If we have an invalid set of classes
if (checks == null)
return protections;
// If we have any extractable packers
var extractables = checks
.Where(c => c is IExtractableExecutable<T>)
.Select(c => c as IExtractableExecutable<T>);
extractables.IterateWithAction(extractable =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckMSDOSExecutable(file, mz, includeDebug);
if (string.IsNullOrEmpty(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.Append(checkClass, protection);
var subProtections = PerformExtractableCheck(extractable!, file, exe, getProtections, includeDebug);
protections.Append(subProtections);
});
return protections;
}
/// <summary>
/// Handle a single file based on all new executable check implementations
/// Handle files based on an IExtractableExecutable implementation
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="nex">Executable to scan</param>
/// <param name="file">Name of the source file of the stream, for tracking</param>
/// <param name="exe">Executable to scan the contents of</param>
/// <param name="impl">IExtractableExecutable class representing the file type</param>
/// <param name="getProtections">Optional function for handling recursive protections</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
public IDictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
/// <returns>Set of protections in path, empty on error</returns>
private static ProtectionDictionary PerformExtractableCheck<T>(IExtractableExecutable<T> impl,
string file,
T exe,
Func<string, ProtectionDictionary>? getProtections,
bool includeDebug)
where T : WrapperBase
{
// Create the output dictionary
var protections = new CheckDictionary<INewExecutableCheck>();
// If we have an invalid extractable somehow
if (impl == null)
return [];
// Iterate through all checks
NewExecutableCheckClasses.IterateWithAction(checkClass =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
if (string.IsNullOrEmpty(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.Append(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 IDictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
{
// Create the output dictionary
var protections = new CheckDictionary<IPortableExecutableCheck>();
// Iterate through all checks
PortableExecutableCheckClasses.IterateWithAction(checkClass =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
if (string.IsNullOrEmpty(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.Append(checkClass, protection);
});
return protections;
}
#endregion
#region Initializers
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>() =>
InitCheckClasses<T>(Assembly.GetExecutingAssembly()) ?? [];
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>(Assembly assembly)
{
List<T> classTypes = [];
// If not all types can be loaded, use the ones that could be
List<Type> assemblyTypes = [];
// If the extractable file itself fails
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
// Extract and get the output path
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
bool extracted = impl.Extract(file, exe, tempPath, includeDebug);
// Collect and format all found protections
ProtectionDictionary? subProtections = null;
if (extracted && getProtections != null)
subProtections = getProtections(tempPath);
// If temp directory cleanup fails
try
{
if (Directory.Exists(tempPath))
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(file);
return subProtections ?? [];
}
catch (ReflectionTypeLoadException rtle)
catch (Exception ex)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
if (includeDebug) Console.WriteLine(ex);
return [];
}
// Loop through all types
foreach (Type type in assemblyTypes)
{
// If the type isn't a class or doesn't implement the interface
if (!type.IsClass || type.GetInterface(typeof(T).Name) == null)
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
#endregion
@@ -424,7 +344,7 @@ namespace BinaryObjectScanner.FileType
/// <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;
return impl.GetType().Namespace?.ToLowerInvariant()?.Contains("gameengine") ?? false;
}
/// <summary>
@@ -433,7 +353,7 @@ namespace BinaryObjectScanner.FileType
/// <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;
return impl.GetType().Namespace?.ToLowerInvariant()?.Contains("packer") ?? false;
}
#endregion

View File

@@ -11,40 +11,35 @@ namespace BinaryObjectScanner.FileType
public class GCF : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Loop through and extract all files
ExtractAll(gcf, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(gcf, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -131,19 +126,18 @@ namespace BinaryObjectScanner.FileType
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;
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
// 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

View File

@@ -14,61 +14,59 @@ namespace BinaryObjectScanner.FileType
public class GZIP : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (GZipArchive zipFile = GZipArchive.Open(stream))
using var zipFile = GZipArchive.Open(stream);
foreach (var entry in zipFile.Entries)
{
foreach (var entry in zipFile.Entries)
try
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using ISv3 = UnshieldSharp.Archive.InstallShieldArchiveV3;
namespace BinaryObjectScanner.FileType
{
@@ -10,30 +11,26 @@ namespace BinaryObjectScanner.FileType
public class InstallShieldArchiveV3 : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
var archive = new ISv3(file);
foreach (var cfile in archive.Files)
{
try
{
string tempFile = Path.Combine(tempPath, cfile.Key);
string tempFile = Path.Combine(outDir, cfile.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
@@ -53,12 +50,12 @@ namespace BinaryObjectScanner.FileType
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -12,17 +12,17 @@ namespace BinaryObjectScanner.FileType
public class InstallShieldCAB : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
// Get the name of the first cabinet file or header
var directory = Path.GetDirectoryName(file);
@@ -50,17 +50,13 @@ namespace BinaryObjectScanner.FileType
// If we have anything but the first file
if (!shouldScanCabinet)
return null;
return false;
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
var cabfile = InstallShieldCabinet.Open(file);
if (cabfile?.HeaderList == null)
return null;
return false;
for (int i = 0; i < cabfile.HeaderList.FileCount; i++)
{
@@ -74,11 +70,11 @@ namespace BinaryObjectScanner.FileType
try
{
string? filename = cabfile.HeaderList.GetFileName(i);
tempFile = Path.Combine(tempPath, filename ?? string.Empty);
tempFile = Path.Combine(outDir, filename ?? string.Empty);
}
catch
{
tempFile = Path.Combine(tempPath, $"BAD_FILENAME{i}");
tempFile = Path.Combine(outDir, $"BAD_FILENAME{i}");
}
cabfile.FileSave(i, tempFile);
@@ -89,12 +85,12 @@ namespace BinaryObjectScanner.FileType
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -16,10 +16,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -28,7 +26,7 @@ namespace BinaryObjectScanner.FileType
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
int read = stream.Read(magic, 0, 16);
if (magic.StartsWith(new byte?[] { 0x4C, 0x44, 0x53, 0x43, 0x52, 0x59, 0x50, 0x54 }))
return "Link Data Security encrypted file";

View File

@@ -12,71 +12,68 @@ namespace BinaryObjectScanner.FileType
public class MPQ : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
// TODO: Add stream opening support
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
#if NET20 || NET35 || NET40 || !WIN
#if NET20 || NET35 || !WIN
// Not supported for old .NET due to feature requirements
// Not supported in non-Windows builds due to DLL requirements
return null;
return false;
#else
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), System.Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Try to open the archive and listfile
var mpqArchive = new MpqArchive(file, FileAccess.Read);
string? listfile = null;
MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
using (var mpqArchive = new MpqArchive(file, FileAccess.Read))
// If we can't read the listfile, we just return
if (!listStream.CanRead)
return false;
// Read the listfile in for processing
using (var sr = new StreamReader(listStream))
{
// Try to open the listfile
string? listfile = null;
MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
listfile = sr.ReadToEnd();
}
// If we can't read the listfile, we just return
if (!listStream.CanRead)
return null;
// Split the listfile by newlines
string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n');
// Read the listfile in for processing
using (var sr = new StreamReader(listStream))
// Loop over each entry
foreach (string sub in listfileLines)
{
try
{
listfile = sr.ReadToEnd();
string tempFile = Path.Combine(outDir, sub);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
mpqArchive.ExtractFile(sub, tempFile);
}
// Split the listfile by newlines
string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n');
// Loop over each entry
foreach (string sub in listfileLines)
catch (System.Exception ex)
{
try
{
string tempFile = Path.Combine(tempPath, sub);
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
mpqArchive.ExtractFile(sub, tempFile);
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.WriteLine(ex);
}
if (includeDebug) System.Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.WriteLine(ex);
return null;
return false;
}
#endif
}

View File

@@ -14,53 +14,50 @@ namespace BinaryObjectScanner.FileType
public class MicrosoftCAB : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
#if NET20 || NET35 || !WIN
// Not supported for old .NET due to feature requirements
// Not supported in non-Windows builds due to DLL requirements
return null;
return false;
#else
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), System.Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (var cabArchive = new MSCabinet(file))
// Loop over each entry
var cabArchive = new MSCabinet(file);
foreach (var compressedFile in cabArchive.GetFiles())
{
// Loop over each entry
foreach (var compressedFile in cabArchive.GetFiles())
try
{
try
{
string tempFile = Path.Combine(tempPath, compressedFile.Filename);
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
compressedFile.ExtractTo(tempFile);
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, compressedFile.Filename);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
compressedFile.ExtractTo(tempFile);
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (System.Exception ex)
{
if (includeDebug) System.Console.WriteLine(ex);
return null;
return false;
}
#endif
}

View File

@@ -12,29 +12,23 @@ namespace BinaryObjectScanner.FileType
public class MicrosoftLZ : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
var data = Decompressor.Decompress(stream);
if (data == null)
return null;
return false;
// Create the temp filename
string tempFile = "temp.bin";
@@ -49,20 +43,20 @@ namespace BinaryObjectScanner.FileType
tempFile += "l";
}
tempFile = Path.Combine(tempPath, tempFile);
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// 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);
}
using Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(data, 0, data.Length);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -10,40 +10,35 @@ namespace BinaryObjectScanner.FileType
public class PAK : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Loop through and extract all files
ExtractAll(pak, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(pak, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -113,10 +108,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{

View File

@@ -10,40 +10,35 @@ namespace BinaryObjectScanner.FileType
public class PFF : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Extract all files
ExtractAll(pff, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(pff, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.Message);
return null;
return false;
}
}

View File

@@ -4,6 +4,7 @@ using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.FileType
@@ -14,68 +15,72 @@ namespace BinaryObjectScanner.FileType
public class PKZIP : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
=> Extract(file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(string, string, bool)"/>
public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, lookForHeader, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
=> Extract(stream, file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(Stream?, string, string, bool)"/>
public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (ZipArchive zipFile = ZipArchive.Open(stream))
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using var zipFile = ZipArchive.Open(stream, readerOptions);
foreach (var entry in zipFile.Entries)
{
foreach (var entry in zipFile.Entries)
try
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry is partial due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// If the entry is partial due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -16,10 +16,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -28,7 +26,7 @@ namespace BinaryObjectScanner.FileType
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
int read = stream.Read(magic, 0, 16);
if (magic.StartsWith(new byte?[] { 0xFF, 0x9D, 0x53, 0x4B }))
return "PlayJ Audio File";

View File

@@ -10,40 +10,35 @@ namespace BinaryObjectScanner.FileType
public class Quantum : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Extract all files
ExtractAll(quantum, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(quantum, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.Message);
return null;
return false;
}
}

View File

@@ -4,6 +4,7 @@ using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.FileType
@@ -14,68 +15,75 @@ namespace BinaryObjectScanner.FileType
public class RAR : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
=> Extract(file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(string, string, bool)"/>
public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, lookForHeader, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
=> Extract(stream, file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(Stream?, string, string, bool)"/>
public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using RarArchive rarFile = RarArchive.Open(stream, readerOptions);
if (!rarFile.IsComplete)
return false;
using (RarArchive rarFile = RarArchive.Open(stream))
foreach (var entry in rarFile.Entries)
{
foreach (var entry in rarFile.Entries)
try
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -18,10 +18,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -30,7 +28,7 @@ namespace BinaryObjectScanner.FileType
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
int read = stream.Read(magic, 0, 16);
// RASGI2.0
// Found in the ".rgs" files in IA item "Nova_RealArcadeCD_USA".

View File

@@ -18,10 +18,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -30,7 +28,7 @@ namespace BinaryObjectScanner.FileType
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
int read = stream.Read(magic, 0, 16);
// XZip2.0
// Found in the ".mez" files in IA item "Nova_RealArcadeCD_USA".

View File

@@ -17,10 +17,8 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
/// <inheritdoc/>
@@ -29,7 +27,7 @@ namespace BinaryObjectScanner.FileType
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
int read = stream.Read(magic, 0, 16);
if (magic.StartsWith(new byte?[] { 0x53, 0x46, 0x46, 0x53 }))
return "StarForce Filesystem Container";
@@ -43,21 +41,19 @@ namespace BinaryObjectScanner.FileType
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.zlib;
@@ -13,38 +12,35 @@ namespace BinaryObjectScanner.FileType
public class SGA : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Loop through and extract all files
ExtractAll(sga, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(sga, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -55,16 +51,15 @@ namespace BinaryObjectScanner.FileType
/// <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)
// Get the file count
int filesLength = item.Model.Directory switch
{
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;
}
SabreTools.Models.SGA.Directory4 d4 => filesLength = d4.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory5 d5 => filesLength = d5.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory6 d6 => filesLength = d6.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory7 d7 => filesLength = d7.Files?.Length ?? 0,
_ => 0,
};
// If we have no files
if (filesLength == 0)
@@ -88,16 +83,15 @@ namespace BinaryObjectScanner.FileType
/// <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)
// Get the file count
int filesLength = item.Model.Directory switch
{
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;
}
SabreTools.Models.SGA.Directory4 d4 => filesLength = d4.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory5 d5 => filesLength = d5.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory6 d6 => filesLength = d6.Files?.Length ?? 0,
SabreTools.Models.SGA.Directory7 d7 => filesLength = d7.Files?.Length ?? 0,
_ => 0,
};
// If we have no files
if (filesLength == 0)
@@ -108,55 +102,53 @@ namespace BinaryObjectScanner.FileType
return false;
// Get the files
object? file;
switch (item.Model.Header?.MajorVersion)
object? file = item.Model.Directory switch
{
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;
}
SabreTools.Models.SGA.Directory4 d4 => d4.Files![index],
SabreTools.Models.SGA.Directory5 d5 => d5.Files![index],
SabreTools.Models.SGA.Directory6 d6 => d6.Files![index],
SabreTools.Models.SGA.Directory7 d7 => d7.Files![index],
_ => null,
};
// If the file is invalid
if (file == null)
return false;
// Create the filename
var filename = string.Empty;
switch (item.Model.Header?.MajorVersion)
var filename = file switch
{
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;
}
SabreTools.Models.SGA.File4 f4 => f4.Name,
_ => null,
};
// If the filename is invalid
if (filename == null)
return false;
// Loop through and get all parent directories
var parentNames = new List<string?> { filename };
var parentNames = new List<string> { filename };
// Get the parent directory
var folder = default(object);
switch (item.Model.Header?.MajorVersion)
var folder = item.Model.Directory switch
{
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;
default: return false;
}
SabreTools.Models.SGA.Directory4 d4 => Array.Find(d4.Folders ?? [], f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex),
SabreTools.Models.SGA.Directory5 d5 => Array.Find(d5.Folders ?? [], f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex),
SabreTools.Models.SGA.Directory6 d6 => Array.Find(d6.Folders ?? [], f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex),
SabreTools.Models.SGA.Directory7 d7 => Array.Find(d7.Folders ?? [], f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex),
_ => default(object),
};
// If we have a parent folder
if (folder != null)
{
switch (item.Model.Header?.MajorVersion)
string folderName = folder switch
{
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;
}
SabreTools.Models.SGA.Folder4 f4 => f4.Name ?? string.Empty,
SabreTools.Models.SGA.Folder5 f5 => f5.Name ?? string.Empty,
_ => string.Empty,
};
parentNames.Add(folderName);
}
// TODO: Should the section name/alias be used in the path as well?
@@ -164,55 +156,45 @@ namespace BinaryObjectScanner.FileType
// Reverse and assemble the filename
parentNames.Reverse();
#if NET20 || NET35
var parentNamesArray = parentNames.Cast<string>().ToArray();
filename = parentNamesArray[0];
for (int i = 1; i < parentNamesArray.Length; i++)
filename = parentNames[0];
for (int i = 1; i < parentNames.Count; i++)
{
filename = Path.Combine(filename, parentNamesArray[i]);
filename = Path.Combine(filename, parentNames[i]);
}
#else
filename = Path.Combine(parentNames.Cast<string>().ToArray());
filename = Path.Combine([.. parentNames]);
#endif
// Get the file offset
long fileOffset;
switch (item.Model.Header?.MajorVersion)
long fileOffset = file switch
{
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;
}
SabreTools.Models.SGA.File4 f4 => f4.Offset,
_ => -1,
};
// Adjust the file offset
switch (item.Model.Header?.MajorVersion)
fileOffset += item.Model.Header switch
{
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;
SabreTools.Models.SGA.Header4 h4 => h4.FileDataOffset,
SabreTools.Models.SGA.Header6 h6 => h6.FileDataOffset,
_ => -1,
};
// If the offset is invalid
if (fileOffset < 0)
return false;
// Get the file sizes
long fileSize, outputFileSize;
switch (item.Model.Header?.MajorVersion)
switch (file)
{
case 4:
case 5:
fileSize = (file as SabreTools.Models.SGA.File4)?.SizeOnDisk ?? 0;
outputFileSize = (file as SabreTools.Models.SGA.File4)?.Size ?? 0;
case SabreTools.Models.SGA.File4 f4:
fileSize = f4.SizeOnDisk;
outputFileSize = f4.Size;
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;
default:
return false;
}
// Read the compressed data directly

View File

@@ -4,6 +4,7 @@ using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.FileType
@@ -14,68 +15,72 @@ namespace BinaryObjectScanner.FileType
public class SevenZip : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
=> Extract(file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(string, string, bool)"/>
public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, lookForHeader, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
=> Extract(stream, file, outDir, lookForHeader: false, includeDebug);
/// <inheritdoc cref="IExtractable.Extract(Stream?, string, string, bool)"/>
public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(stream))
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using var sevenZip = SevenZipArchive.Open(stream, readerOptions);
foreach (var entry in sevenZip.Entries)
{
foreach (var entry in sevenZipFile.Entries)
try
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -14,69 +14,63 @@ namespace BinaryObjectScanner.FileType
public class TapeArchive : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
if (stream == null)
return null;
if (stream == null || !stream.CanRead)
return false;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (TarArchive tarFile = TarArchive.Open(stream))
using var tarFile = TarArchive.Open(stream);
foreach (var entry in tarFile.Entries)
{
foreach (var entry in tarFile.Entries)
try
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// TODO: Fix bug with extracting folders from tar.
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
string tempFile = Path.Combine(outDir, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Models.BSP;
namespace BinaryObjectScanner.FileType
{
@@ -10,40 +11,37 @@ namespace BinaryObjectScanner.FileType
public class VBSP : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
try
{
// Create the wrapper
var vbsp = SabreTools.Serialization.Wrappers.VBSP.Create(stream);
if (vbsp == null)
return null;
return false;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// TODO: Introduce helper methods for all specialty lump types
// Loop through and extract all files
ExtractAllLumps(vbsp, tempPath);
Directory.CreateDirectory(outDir);
ExtractAllLumps(vbsp, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.ToString());
return null;
return false;
}
}
@@ -96,12 +94,12 @@ namespace BinaryObjectScanner.FileType
// Create the filename
string filename = $"lump_{index}.bin";
switch (index)
switch ((LumpType)index)
{
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_ENTITIES:
case LumpType.LUMP_ENTITIES:
filename = "entities.ent";
break;
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_PAKFILE:
case LumpType.LUMP_PAKFILE:
filename = "pakfile.zip";
break;
}
@@ -122,10 +120,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
@@ -12,40 +11,35 @@ namespace BinaryObjectScanner.FileType
public class VPK : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Loop through and extract all files
ExtractAll(vpk, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(vpk, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -143,7 +137,7 @@ namespace BinaryObjectScanner.FileType
// If we have preload data, prepend it
if (data != null && directoryItem.PreloadData != null)
data = directoryItem.PreloadData.Concat(data).ToArray();
data = [.. directoryItem.PreloadData, .. data];
}
// If there is nothing to write out
@@ -171,10 +165,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{

View File

@@ -7,60 +7,55 @@ namespace BinaryObjectScanner.FileType
/// <summary>
/// Half-Life Texture Package File
/// </summary>
public class WAD : IExtractable
public class WAD3 : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
try
{
// Create the wrapper
var wad = SabreTools.Serialization.Wrappers.WAD.Create(stream);
var wad = SabreTools.Serialization.Wrappers.WAD3.Create(stream);
if (wad == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
return false;
// Loop through and extract all files
ExtractAllLumps(wad, tempPath);
Directory.CreateDirectory(outDir);
ExtractAllLumps(wad, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
/// <summary>
/// Extract all lumps from the WAD to an output directory
/// Extract all lumps from the WAD3 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)
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.WAD3 item, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
if (item.Model.DirEntries == null || item.Model.DirEntries.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++)
for (int i = 0; i < item.Model.DirEntries.Length; i++)
{
allExtracted &= ExtractLump(item, i, outputDirectory);
}
@@ -69,23 +64,23 @@ namespace BinaryObjectScanner.FileType
}
/// <summary>
/// Extract a lump from the WAD to an output directory by index
/// Extract a lump from the WAD3 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)
public static bool ExtractLump(SabreTools.Serialization.Wrappers.WAD3 item, int index, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
if (item.Model.DirEntries == null || item.Model.DirEntries.Length == 0)
return false;
// If the lumps index is invalid
if (index < 0 || index >= item.Model.Lumps.Length)
if (index < 0 || index >= item.Model.DirEntries.Length)
return false;
// Get the lump
var lump = item.Model.Lumps[index];
var lump = item.Model.DirEntries[index];
if (lump == null)
return false;
@@ -113,10 +108,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{

View File

@@ -13,43 +13,41 @@ namespace BinaryObjectScanner.FileType
public class XZ : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Try opening the stream
using var xzFile = new XZStream(stream);
using (XZStream xzFile = new XZStream(stream))
{
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempFile))
{
xzFile.CopyTo(fs);
}
}
// Create the output file path
Directory.CreateDirectory(outDir);
string tempFile = Path.Combine(outDir, Guid.NewGuid().ToString());
return tempPath;
// Extract the file
using FileStream fs = File.OpenWrite(tempFile);
xzFile.CopyTo(fs);
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
#else
return null;
return false;
#endif
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
@@ -11,40 +10,35 @@ namespace BinaryObjectScanner.FileType
public class XZP : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public bool Extract(string file, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
return false;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, outDir, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
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);
return false;
// Loop through and extract all files
ExtractAll(xzp, tempPath);
Directory.CreateDirectory(outDir);
ExtractAll(xzp, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -95,7 +89,7 @@ namespace BinaryObjectScanner.FileType
return false;
// Get the associated directory item
var directoryItem = item.Model.DirectoryItems.Where(di => di?.FileNameCRC == directoryEntry.FileNameCRC).FirstOrDefault();
var directoryItem = Array.Find(item.Model.DirectoryItems, di => di?.FileNameCRC == directoryEntry.FileNameCRC);
if (directoryItem == null)
return false;
@@ -123,10 +117,8 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{

View File

@@ -15,10 +15,10 @@ namespace BinaryObjectScanner.GameEngine
/// 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
public class RenderWare : IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;

View File

@@ -1,416 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner
{
internal static class Handler
{
#region Public Collections
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
public static IEnumerable<IPathCheck?> PathCheckClasses
{
get
{
pathCheckClasses ??= InitCheckClasses<IPathCheck>();
return pathCheckClasses;
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
private static IEnumerable<IPathCheck?>? pathCheckClasses;
#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>
public static ProtectionDictionary HandlePathChecks(string path, IEnumerable<string>? files)
{
// Create the output dictionary
var protections = new ProtectionDictionary();
// Preprocess the list of files
files = files?.Select(f => f.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))?.ToList();
// Iterate through all checks
PathCheckClasses.IterateWithAction(checkClass =>
{
var subProtections = checkClass?.PerformCheck(path, files);
if (subProtections != null)
protections.Append(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>
public static List<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
{
var protection = impl.Detect(stream, fileName, includeDebug);
return ProcessProtectionString(protection);
}
/// <summary>
/// Handle files based on an IExtractable implementation
/// </summary>
/// <param name="impl">IExtractable 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>
public static ProtectionDictionary? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
{
// 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
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableMSDOSExecutable implementation
/// </summary>
/// <param name="impl">IExtractableMSDOSExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="mz">MSDOS 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>
public static ProtectionDictionary? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, mz, 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
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableLinearExecutable implementation
/// </summary>
/// <param name="impl">IExtractableLinearExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="lex">LinearExecutable 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>
public static ProtectionDictionary? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, lex, 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
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableNewExecutable implementation
/// </summary>
/// <param name="impl">IExtractableNewExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="nex">NewExecutable 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>
public static ProtectionDictionary? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, nex, 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
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractablePortableExecutable implementation
/// </summary>
/// <param name="impl">IExtractablePortableExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="pex">PortableExecutable 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>
public static ProtectionDictionary? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, pex, 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
subProtections?.StripFromKeys(tempPath);
subProtections?.PrependToKeys(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>
private static List<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
{
// If we have an invalid path
if (string.IsNullOrEmpty(path))
return null;
// Setup the list
var protections = new List<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>
private static IEnumerable<T?> InitCheckClasses<T>() =>
InitCheckClasses<T>(Assembly.GetExecutingAssembly());
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T?> InitCheckClasses<T>(Assembly assembly)
{
List<T?> classTypes = [];
// If not all types can be loaded, use the ones that could be
List<Type> assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
}
// Loop through all types
foreach (Type type in assemblyTypes)
{
// If the type isn't a class or doesn't implement the interface
if (!type.IsClass || type.GetInterface(typeof(T).Name) == null)
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
#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>
private static List<string>? ProcessProtectionString(string? protection)
{
// If we have an invalid protection string
if (string.IsNullOrEmpty(protection))
return null;
// Setup the output queue
var protections = new List<string>();
// If we have an indicator of multiple protections
if (protection!.Contains(";"))
{
var splitProtections = protection.Split(';');
protections.AddRange(splitProtections);
}
else
{
protections.Add(protection);
}
return protections;
}
#endregion
}
}

View File

@@ -1,19 +1,19 @@
using SabreTools.Serialization.Wrappers;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a MS-DOS Executable (MZ) for protection
/// Check an executable for protection
/// </summary>
public interface IMSDOSExecutableCheck
public interface IExecutableCheck<T> where T : WrapperBase
{
/// <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="exe">Executable 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? CheckMSDOSExecutable(string file, MSDOS mz, bool includeDebug);
string? CheckExecutable(string file, T exe, bool includeDebug);
}
}

View File

@@ -5,26 +5,26 @@ 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="outDir">Path to the output directory</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
/// <returns>Indicates if the extractable was successfully extracted</returns>
/// <remarks>Ideally, this should just point to the other extract implementation.</remarks>
string? Extract(string file, bool includeDebug);
bool Extract(string file, string outDir, bool includeDebug);
/// <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="outDir">Path to the output directory</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(Stream? stream, string file, bool includeDebug);
/// <returns>Indicates if the extractable was successfully extracted</returns>
bool Extract(Stream? stream, string file, string outDir, bool includeDebug);
}
}

View File

@@ -0,0 +1,20 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark an executable type as being able to be extracted
/// </summary>
public interface IExtractableExecutable<T> : IExecutableCheck<T> where T : WrapperBase
{
/// <summary>
/// Extract an Executable to a path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="exe">Executable representing the read-in file</param>
/// <param name="outDir">Path to the output directory</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
bool Extract(string file, T exe, string outDir, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a LinearExecutable type as being able to be extracted
/// </summary>
public interface IExtractableLinearExecutable
{
/// <summary>
/// Extract a LinearExecutable to a temporary path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="lex">LinearExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(string file, LinearExecutable lex, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a MSDOS type as being able to be extracted
/// </summary>
public interface IExtractableMSDOSExecutable
{
/// <summary>
/// Extract a MSDOS to a temporary path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="mz">MSDOS representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(string file, MSDOS mz, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a NewExecutable type as being able to be extracted
/// </summary>
public interface IExtractableNewExecutable
{
/// <summary>
/// Extract a NewExecutable to a temporary path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="nex">NewExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(string file, NewExecutable nex, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a PortableExecutable type as being able to be extracted
/// </summary>
public interface IExtractablePortableExecutable
{
/// <summary>
/// Extract a PortableExecutable to a temporary path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="pex">PortableExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(string file, PortableExecutable pex, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a Linear Executable (LE) for protection
/// </summary>
public interface ILinearExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
/// </summary>
/// <param name="file">File to check for protection indicators</param>
/// <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? CheckLinearExecutable(string file, LinearExecutable lex, bool includeDebug);
}
}

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a New Executable (NE) for protection
/// </summary>
public interface INewExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
/// </summary>
/// <param name="file">File to check for protection indicators</param>
/// <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>
string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug);
}
}

View File

@@ -14,9 +14,9 @@ namespace BinaryObjectScanner.Interfaces
/// Check a file path for protections based on path name
/// </summary>
/// <param name="path">Path to check for protection indicators</param>
/// <param name="files">Enumerable of strings representing files in a directory</param>
/// <param name="files">List 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>
IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
List<string> CheckDirectoryPath(string path, List<string>? files);
/// <summary>
/// Check a file path for protections based on path name

View File

@@ -1,19 +0,0 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a Portable Executable (PE) for protection
/// </summary>
public interface IPortableExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
/// </summary>
/// <param name="file">File to check for protection indicators</param>
/// <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>
string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug);
}
}

View File

@@ -8,10 +8,10 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class ASPack : IExtractablePortableExecutable, IPortableExecutableCheck
public class ASPack : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -19,8 +19,7 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .aspack section, if it exists
bool aspackSection = pex.ContainsSection(".aspack", exact: true);
if (aspackSection)
if (pex.ContainsSection(".aspack", exact: true))
return "ASPack 2.29";
// TODO: Re-enable all Entry Point checks after implementing
@@ -51,19 +50,19 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
/// <summary>
/// Generate the set of matchers used for each section
/// </summary>
/// <returns></returns>
private List<ContentMatchSet> GenerateMatchers()
private static List<ContentMatchSet> GenerateMatchers()
{
return new List<ContentMatchSet>
{
return
[
#region No Wildcards (Long)
new(new byte?[]
@@ -641,7 +640,7 @@ namespace BinaryObjectScanner.Packer
new(new byte?[] { 0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81, 0xED }, "ASPack 1.02b/1.08.03"),
#endregion
};
];
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -6,10 +5,10 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// TODO: Verify that all versions are detected
public class AdvancedInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
public class AdvancedInstaller : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -20,7 +19,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
if (strs.Any(s => s.Contains("Software\\Caphyon\\Advanced Installer")))
if (strs.Exists(s => s.Contains("Software\\Caphyon\\Advanced Installer")))
return "Caphyon Advanced Installer";
}
@@ -28,9 +27,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -7,10 +7,10 @@ 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class AutoPlayMediaStudio : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -27,18 +27,18 @@ namespace BinaryObjectScanner.Packer
name = Utilities.GetLegalCopyright(pex);
if (name?.StartsWith("Runtime Engine", StringComparison.OrdinalIgnoreCase) == true)
return $"AutoPlay Media Studio {GetVersion(pex)}";
*/
*/
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
var version = pex.ProductVersion;

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.zlib;
using SabreTools.Matching;
@@ -13,10 +12,10 @@ 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class CExe : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -24,23 +23,23 @@ namespace BinaryObjectScanner.Packer
return null;
// If there are exactly 2 resources with type 99
if (pex.FindResourceByNamedType("99, ").Count() == 2)
if (pex.FindResourceByNamedType("99, ").Count == 2)
return "CExe";
if (pex.StubExecutableData != null)
{
var matchers = new List<ContentMatchSet>
{
new(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")
};
new(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.IsNullOrEmpty(match))
@@ -51,23 +50,25 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// 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;
// Get all resources of type 99 with index 2
var resources = pex.FindResourceByNamedType("99, 2");
if (resources == null || resources.Count == 0)
return false;
// Determine which compression was used
bool zlib = pex.FindResourceByNamedType("99, 1").Any();
// Get the first resource of type 99 with index 2
var payload = resources[0];
if (payload == null || payload.Length == 0)
return false;
// Create the output data buffer
var data = new byte[0];
byte[]? data = [];
// If we had the decompression DLL included, it's zlib
if (zlib)
if (pex.FindResourceByNamedType("99, 1").Count > 0)
{
try
{
@@ -94,12 +95,12 @@ namespace BinaryObjectScanner.Packer
// Trim the buffer to the proper size
uint read = zstream.total_out;
#if NET462_OR_GREATER || NETCOREAPP
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
#else
#if NETFRAMEWORK
var temp = new byte[read];
Array.Copy(data, 0, temp, 0, read);
data = temp;
#else
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
#endif
}
catch
@@ -125,27 +126,25 @@ namespace BinaryObjectScanner.Packer
// If we have no data
if (data == null)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
return false;
// Create the temp filename
string tempFile = string.IsNullOrEmpty(file) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(file)}.sxe";
tempFile = Path.Combine(tempPath, tempFile);
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// 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);
}
var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(data, 0, data.Length);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -1,14 +1,13 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class DotFuscator : IExtractablePortableExecutable, IPortableExecutableCheck
public class DotFuscator : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -19,7 +18,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".text");
if (strs != null)
{
if (strs.Any(s => s.Contains("DotfuscatorAttribute")))
if (strs.Exists(s => s.Contains("DotfuscatorAttribute")))
return "dotFuscator";
}
@@ -27,9 +26,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -15,10 +15,10 @@ namespace BinaryObjectScanner.Packer
///
/// Resource that could be useful for extraction: https://github.com/SychicBoy/NETReactorSlayer
/// </summary>
public class DotNetReactor : IExtractablePortableExecutable, IPortableExecutableCheck
public class DotNetReactor : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// TODO: Detect version
// TODO: Further refine checks using https://github.com/horsicq/Detect-It-Easy/blob/075a70b1484d1d84d1dc37c86aac16188d5a84e7/db/PE/NetReactor.2.sg and https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar
@@ -28,79 +28,75 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .text section, if it exists
if (pex.ContainsSection(".text"))
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
{
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
var matchers = new List<ContentMatchSet>
{
var matchers = new List<ContentMatchSet>
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <PrivateImplementationDetails>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <PrivateImplementationDetails>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x7B, null,
null, null, null, null, null, null, null, 0x2D,
null, null, null, null, 0x2D, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, null, null, null, null, null,
null, null, null, 0x7D
}, ".NET Reactor"),
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x7B, null,
null, null, null, null, null, null, null, 0x2D,
null, null, null, null, 0x2D, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, null, null, null, null, null,
null, null, null, 0x7D
}, ".NET Reactor"),
// Modified from the previous detection to detect a presumably newer version of .NET Reactor found in "KalypsoLauncher.dll" version 2.0.4.2.
// TODO: Check if this can/should be made more specific.
// <PrivateImplementationDetails>.RSA
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x00, 0x52,
0x53, 0x41
}, ".NET Reactor"),
// Modified from the previous detection to detect a presumably newer version of .NET Reactor found in "KalypsoLauncher.dll" version 2.0.4.2.
// TODO: Check if this can/should be made more specific.
// <PrivateImplementationDetails>.RSA
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x00, 0x52,
0x53, 0x41
}, ".NET Reactor"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// 3{.[9].-.[9].-.[9].}
new(new byte?[]
{
0x33, 0x7B, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x2D, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x7D, 0x00
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <Module>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x3E,
0x7B, null, null, null, null, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, 0x2D, null, null, null, null,
0x2D, null, null, null, null, null, null, null,
null, null, null, null, null, 0x7D
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)")
};
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// 3{.[9].-.[9].-.[9].}
new(new byte?[]
{
0x33, 0x7B, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x2D, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x7D, 0x00
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <Module>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x3E,
0x7B, null, null, null, null, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, 0x2D, null, null, null, null,
0x2D, null, null, null, null, null, null, null,
null, null, null, null, null, 0x7D
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)")
};
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
// TODO: Add extraction
return null;
return false;
}
}
}

View File

@@ -10,35 +10,34 @@ namespace BinaryObjectScanner.Packer
// 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, IExtractablePortableExecutable, IPortableExecutableCheck
public class EXEStealth : IContentCheck, IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
{
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
0x3F
}, "EXE Stealth"),
};
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
0x3F
}, "EXE Stealth"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -57,27 +56,26 @@ namespace BinaryObjectScanner.Packer
// `ExeStealth V2 Shareware not for public - This text not in registered version - www.webtoolmaster.com`
// Get the ExeS/EXES section, if it exists
bool exesSection = pex.ContainsSection("ExeS", exact: true) || pex.ContainsSection("EXES", exact: true);
if (exesSection)
if (pex.ContainsSection("ExeS", exact: true))
return "EXE Stealth 2.41-2.75";
if (pex.ContainsSection("EXES", exact: true))
return "EXE Stealth 2.41-2.75";
// Get the mtw section, if it exists
bool mtwSection = pex.ContainsSection("mtw", exact: true);
if (mtwSection)
if (pex.ContainsSection("mtw", exact: true))
return "EXE Stealth 1.1";
// Get the rsrr section, if it exists
bool rsrrSection = pex.ContainsSection("rsrr", exact: true);
if (rsrrSection)
if (pex.ContainsSection("rsrr", exact: true))
return "EXE Stealth 2.76";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.IO;
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
/// archives in their resources in some uncompressed manner to be used at runtime.
/// </summary>
public class EmbeddedArchive : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the resources that have a PKZIP signature
if (pex.ResourceData != null)
{
foreach (var value in pex.ResourceData.Values)
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
continue;
return "Embedded Archive";
}
}
// Check the overlay, if it exists
if (pex.OverlayData != null && pex.OverlayData.Length > 0)
{
if (pex.OverlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
return "Embedded Archive";
}
return null;
}
/// <inheritdoc/>
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
bool overlay = ExtractFromOverlay(pex, outDir, includeDebug);
bool resources = ExtractFromResources(pex, outDir, includeDebug);
return overlay || resources;
}
/// <summary>
/// Extract archive data from the overlay
/// </summary>
private static bool ExtractFromOverlay(PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// Get the overlay data for easier reading
var overlayData = pex.OverlayData;
if (overlayData == null)
return false;
// Only process the overlay if it has an archive signature
if (!overlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
return false;
// Create the temp filename
string tempFile = $"embedded_overlay.zip";
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(overlayData, 0, overlayData.Length);
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return false;
}
}
/// <summary>
/// Extract archive data from the resources
/// </summary>
private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// If there are no resources
if (pex.ResourceData == null)
return false;
// Get the resources that have an archive signature
int i = 0;
foreach (var value in pex.ResourceData.Values)
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
continue;
try
{
// Create the temp filename
string tempFile = $"embedded_resource_{i++}.zip";
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(ba, 0, ba.Length);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return false;
}
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
@@ -11,10 +10,10 @@ namespace BinaryObjectScanner.Packer
/// 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class EmbeddedExecutable : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -22,47 +21,105 @@ namespace BinaryObjectScanner.Packer
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";
if (pex.ResourceData != null)
{
foreach (var value in pex.ResourceData.Values)
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
continue;
return "Embedded Executable";
}
}
// Check the overlay, if it exists
if (pex.OverlayData != null && pex.OverlayData.Length > 0)
{
if (pex.OverlayData.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
return "Embedded Executable";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
bool overlay = ExtractFromOverlay(pex, outDir, includeDebug);
bool resources = ExtractFromResources(pex, outDir, includeDebug);
return overlay || resources;
}
/// <summary>
/// Extract executable data from the overlay
/// </summary>
private static bool ExtractFromOverlay(PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// Get the overlay data for easier reading
var overlayData = pex.OverlayData;
if (overlayData == null)
return false;
// Only process the overlay if it has an executable signature
if (!overlayData.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
return false;
// Create the temp filename
string tempFile = $"embedded_overlay.bin"; // exe/dll
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(overlayData, 0, overlayData.Length);
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return false;
}
}
/// <summary>
/// Extract executable data from the resources
/// </summary>
private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// If there are no resources
if (pex.ResourceData == null)
return null;
return false;
// 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++)
int i = 0;
foreach (var value in pex.ResourceData.Values)
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
continue;
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);
string tempFile = $"embedded_resource_{i++}.bin"; // exe/dll
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(data, 0, data.Length);
tempStream?.Write(ba, 0, ba.Length);
}
catch (Exception ex)
{
@@ -70,12 +127,12 @@ namespace BinaryObjectScanner.Packer
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -6,10 +5,10 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class GenteeInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
public class GenteeInstaller : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -20,10 +19,10 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("Gentee installer")))
if (strs.Exists(s => s.Contains("Gentee installer")))
return "Gentee Installer";
if (strs.Any(s => s.Contains("ginstall.dll")))
if (strs.Exists(s => s.Contains("ginstall.dll")))
return "Gentee Installer";
}
@@ -31,9 +30,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -9,10 +9,10 @@ namespace BinaryObjectScanner.Packer
// 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class HyperTechCrackProof : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -21,19 +21,19 @@ namespace BinaryObjectScanner.Packer
// 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.Model.ImportTable?.ImportDirectoryTable?.Any(idte => idte?.Name == "KeRnEl32.dLl") ?? false);
bool importTableMatch = Array.Exists(pex.Model.ImportTable?.ImportDirectoryTable ?? [],
idte => idte?.Name == "KeRnEl32.dLl");
if (peCSection && importTableMatch)
if (pex.ContainsSection("peC", exact: true) && importTableMatch)
return "HyperTech CrackProof";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
@@ -9,26 +8,31 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction - https://github.com/dscharrer/InnoExtract
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InnoSetup : IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
public class InnoSetup : IExecutableCheck<NewExecutable>,
IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// Check for "Inno" in the reserved words
if (nex.Model.Stub?.Header?.Reserved2?[4] == 0x6E49 && nex.Model.Stub?.Header?.Reserved2?[5] == 0x6F6E)
var reserved2 = nex.Model.Stub?.Header?.Reserved2;
if (reserved2 != null && reserved2.Length > 5)
{
string version = GetOldVersion(file, nex);
if (!string.IsNullOrEmpty(version))
return $"Inno Setup {version}";
return "Inno Setup (Unknown Version)";
if (reserved2[4] == 0x6E49 && reserved2[5] == 0x6F6E)
{
string version = GetOldVersion(file, nex);
if (!string.IsNullOrEmpty(version))
return $"Inno Setup {version}";
return "Inno Setup (Unknown Version)";
}
}
return null;
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -39,7 +43,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
var str = strs.FirstOrDefault(s => s.StartsWith("Inno Setup Setup Data"));
var str = strs.Find(s => s.StartsWith("Inno Setup Setup Data"));
if (str != null)
{
return str.Replace("Inno Setup Setup Data", "Inno Setup")
@@ -54,9 +58,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
private static string GetOldVersion(string file, NewExecutable nex)
@@ -78,8 +82,8 @@ namespace BinaryObjectScanner.Packer
return MatchUtil.GetFirstMatch(file, data, matchers, false) ?? "Unknown 1.X";
}
return "Unknown 1.X";
return "Unknown 1.X";
}
}
}

View File

@@ -6,10 +6,10 @@ 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class InstallAnywhere : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -28,12 +28,12 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the internal versions
var version = pex.GetInternalVersion();

View File

@@ -1,4 +1,3 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -6,11 +5,11 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction - https://github.com/Bioruebe/UniExtract2
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InstallerVISE : IExtractablePortableExecutable, IPortableExecutableCheck
public class InstallerVISE : IExtractableExecutable<PortableExecutable>
{
//TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds.
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -21,7 +20,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("ViseMain")))
if (strs.Exists(s => s.Contains("ViseMain")))
return "Installer VISE";
}
@@ -29,9 +28,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -5,10 +5,10 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, seems to primarily use MSZip compression.
public class IntelInstallationFramework : IExtractablePortableExecutable, IPortableExecutableCheck
public class IntelInstallationFramework : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -33,9 +33,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -7,10 +6,10 @@ 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class MicrosoftCABSFX : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -29,7 +28,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("wextract_cleanup")))
if (strs.Exists(s => s.Contains("wextract_cleanup")))
return $"Microsoft CAB SFX {GetVersion(pex)}";
}
@@ -39,7 +38,7 @@ namespace BinaryObjectScanner.Packer
{
// This detects a different but similar type of SFX that uses Microsoft CAB files.
// Further research is needed to see if it's just a different version or entirely separate.
if (strs.Any(s => s.Contains("MSCFu")))
if (strs.Exists(s => s.Contains("MSCFu")))
return $"Microsoft CAB SFX {GetVersion(pex)}";
}
@@ -47,12 +46,12 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the internal versions
var version = pex.GetInternalVersion();

View File

@@ -1,29 +1,28 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class NSIS : IExtractablePortableExecutable, IPortableExecutableCheck
public class NSIS : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
var description = pex.AssemblyDescription;
if (!string.IsNullOrEmpty(description) && description!.StartsWith("Nullsoft Install System"))
return $"NSIS {description.Substring("Nullsoft Install System".Length).Trim()}";
var name = pex.AssemblyDescription;
if (name?.StartsWith("Nullsoft Install System") == true)
return $"NSIS {name.Substring("Nullsoft Install System".Length).Trim()}";
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("NullsoftInst")))
if (strs.Exists(s => s.Contains("NullsoftInst")))
return "NSIS";
}
@@ -31,9 +30,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -13,11 +13,11 @@ namespace BinaryObjectScanner.Packer
/// 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class NeoLite : IExtractableExecutable<PortableExecutable>
{
// TODO: Find samples of NeoLite 1.X.
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -26,8 +26,7 @@ namespace BinaryObjectScanner.Packer
// 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)
if (pex.ContainsSection(".neolit", exact: true))
return "NeoLite";
// If more specific or additional checks are needed, "NeoLite Executable File Compressor" should be present
@@ -36,9 +35,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -5,10 +5,10 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Better version detection - https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
// TODO: Add extraction
public class PECompact : IExtractablePortableExecutable, IPortableExecutableCheck
public class PECompact : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -23,13 +23,12 @@ namespace BinaryObjectScanner.Packer
// on the data in the file. This may be related to information in other fields
// Get the pec1 section, if it exists
bool pec1Section = pex.ContainsSection("pec1", exact: true);
if (pec1Section)
if (pex.ContainsSection("pec1", exact: true))
return "PE Compact v1.x";
// Get the PEC2 section, if it exists -- TODO: Verify this comment since it's pulling the .text section
var textSection = pex.GetFirstSection(".text", exact: true);
if (textSection != null && textSection.PointerToRelocations == 0x32434550)
if (textSection?.PointerToRelocations == 0x32434550)
{
if (textSection.PointerToLinenumbers != 0)
return $"PE Compact v{textSection.PointerToLinenumbers} (internal version)";
@@ -41,9 +40,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -5,10 +5,10 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class PEtite : IExtractablePortableExecutable, IPortableExecutableCheck
public class PEtite : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -16,17 +16,16 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .petite section, if it exists -- TODO: Is there a version number that can be found?
bool petiteSection = pex.ContainsSection(".petite", exact: true);
if (petiteSection)
if (pex.ContainsSection(".petite", exact: true))
return "PEtite";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -7,10 +7,10 @@ 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 : IExtractablePortableExecutable, IPortableExecutableCheck
public class SetupFactory : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -38,12 +38,12 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
var version = pex.ProductVersion;

View File

@@ -1,20 +1,12 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.Packer
{
public class SevenZipSFX : IExtractablePortableExecutable, IPortableExecutableCheck
public class SevenZipSFX : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -24,7 +16,7 @@ namespace BinaryObjectScanner.Packer
// Get the assembly description, if possible
if (pex.AssemblyDescription?.StartsWith("7-Zip Self-extracting Archive") == true)
return $"7-Zip SFX {pex.AssemblyDescription.Substring("7-Zip Self-extracting Archive ".Length)}";
// Get the file description, if it exists
if (pex.FileDescription?.Equals("7z SFX") == true)
return "7-Zip SFX";
@@ -44,66 +36,17 @@ namespace BinaryObjectScanner.Packer
return "7-Zip SFX";
// If any dialog boxes match
if (pex.FindDialogByTitle("7-Zip self-extracting archive").Any())
if (pex.FindDialogByTitle("7-Zip self-extracting archive").Count > 0)
return "7-Zip SFX";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
if (!File.Exists(file))
return null;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
foreach (var entry in sevenZipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
var sevenZip = new FileType.SevenZip();
return sevenZip.Extract(file, outDir, lookForHeader: true, includeDebug);
}
}
}

View File

@@ -5,10 +5,10 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Shrinker : IExtractablePortableExecutable, IPortableExecutableCheck
public class Shrinker : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -16,18 +16,16 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .shrink0 and .shrink2 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
bool shrink0Section = pex.ContainsSection(".shrink0", true);
bool shrink2Section = pex.ContainsSection(".shrink2", true);
if (shrink0Section || shrink2Section)
if (pex.ContainsSection(".shrink0", true) || pex.ContainsSection(".shrink2", true))
return "Shrinker";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using BinaryObjectScanner.Interfaces;
@@ -9,14 +8,14 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class UPX : IExtractablePortableExecutable, IPortableExecutableCheck
public class UPX : IExtractableExecutable<PortableExecutable>
{
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/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -24,13 +23,13 @@ namespace BinaryObjectScanner.Packer
return null;
// Check header padding strings
if (pex.HeaderPaddingStrings?.Any() == true)
if (pex.HeaderPaddingStrings != null && pex.HeaderPaddingStrings.Count > 0)
{
var match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!"));
var match = pex.HeaderPaddingStrings.Find(s => s.Contains("UPX!"));
//if (match != null)
// return "UPX";
match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.StartsWith("$Id: UPX"));
match = pex.HeaderPaddingStrings.Find(s => s.StartsWith("$Id: UPX"));
if (match != null)
{
var regexMatch = _oldUpxVersionMatch.Match(match);
@@ -40,8 +39,8 @@ namespace BinaryObjectScanner.Packer
return "UPX (Unknown Version)";
}
match = pex.HeaderPaddingStrings.FirstOrDefault(s => _upxVersionMatch.IsMatch(s));
if (match != null && pex.HeaderPaddingStrings.Any(s => s == "UPX!"))
match = pex.HeaderPaddingStrings.Find(s => _upxVersionMatch.IsMatch(s));
if (match != null && pex.HeaderPaddingStrings.Exists(s => s == "UPX!"))
{
var regexMatch = _upxVersionMatch.Match(match);
if (regexMatch.Success)
@@ -49,7 +48,7 @@ namespace BinaryObjectScanner.Packer
else
return "UPX (Unknown Version)";
}
else if (match != null && pex.HeaderPaddingStrings.Any(s => s == "NOS "))
else if (match != null && pex.HeaderPaddingStrings.Exists(s => s == "NOS "))
{
var regexMatch = _upxVersionMatch.Match(match);
if (regexMatch.Success)
@@ -63,9 +62,9 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
@@ -74,10 +73,13 @@ namespace BinaryObjectScanner.Packer
{
// Check the normal version location first
int index = positions[0] - 5;
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
if (index >= 0 && index < fileContent.Length - 4)
{
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
}
// Check for the old-style string
//
// Example:
@@ -85,9 +87,12 @@ namespace BinaryObjectScanner.Packer
// $Id: UPX 1.02 Copyright (C) 1996-2000 the UPX Team. All Rights Reserved. $
// UPX!
index = positions[0] - 67;
versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
if (index >= 0 && index < fileContent.Length - 4)
{
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
}
return "(Unknown Version)";
}

View File

@@ -1,20 +1,12 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.Packer
{
public class WinRARSFX : IExtractablePortableExecutable, IPortableExecutableCheck
public class WinRARSFX : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -25,67 +17,17 @@ namespace BinaryObjectScanner.Packer
if (name?.Contains("WinRAR archiver") == true)
return "WinRAR SFX";
var resources = pex.FindDialogByTitle("WinRAR self-extracting archive");
if (resources.Any())
if (pex.FindDialogByTitle("WinRAR self-extracting archive").Count > 0)
return "WinRAR SFX";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
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 (RarArchive rarFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
if (!rarFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in rarFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
var rar = new FileType.RAR();
return rar.Extract(file, outDir, lookForHeader: true, includeDebug);
}
}
}

View File

@@ -1,32 +1,28 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
#endif
namespace BinaryObjectScanner.Packer
{
public class WinZipSFX : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
public class WinZipSFX : IExtractableExecutable<NewExecutable>, IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// If the resident-name table doesnt exist
if (nex.Model.ResidentNameTable == null)
return null;
// Get the resident and non-resident name table strings
var rntStrs = Array.ConvertAll(nex.Model.ResidentNameTable,
rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString));
var nrntStrs = Array.ConvertAll(nex.Model.NonResidentNameTable ?? [],
nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString));
// Check for the WinZip name strings
bool winZipNameFound = nex.Model.ResidentNameTable
.Select(rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString))
.Any(s => s.Contains("WZ-SE-01"));
winZipNameFound |= nex.Model.NonResidentNameTable?
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
.Any(s => s.Contains("WinZip(R) Self-Extractor")) ?? false;
bool winZipNameFound = Array.Exists(rntStrs, s => s.Contains("WZ-SE-01"));
winZipNameFound |= Array.Exists(nrntStrs, s => s.Contains("WinZip(R) Self-Extractor"));
// If we didn't find it
if (!winZipNameFound)
@@ -41,7 +37,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -66,66 +62,20 @@ namespace BinaryObjectScanner.Packer
// TODO: Find a way to generically detect 2.X versions and improve exact version detection for SFX PE versions bundled with WinZip 11+
/// <inheritdoc/>
public string? Extract(string file, NewExecutable nex, bool includeDebug)
=> Extract(file, includeDebug);
public bool Extract(string file, NewExecutable nex, string outDir, bool includeDebug)
=> Extract(file, outDir, includeDebug);
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
=> Extract(file, includeDebug);
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
=> Extract(file, outDir, includeDebug);
/// <summary>
/// Handle common extraction between executable types
/// </summary>
public static string? Extract(string file, bool includeDebug)
public static bool Extract(string file, string outDir, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (ZipArchive zipFile = ZipArchive.Open(file))
{
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
var pkzip = new FileType.PKZIP();
return pkzip.Extract(file, outDir, lookForHeader: true, includeDebug);
}
/// <summary>
@@ -698,8 +648,10 @@ namespace BinaryObjectScanner.Packer
string assemblyVersion = pex.AssemblyVersion ?? "Unknown Version";
// Standard
if (sfxFileName == "VW95SE.SFX" || sfxFileName == "ST32E.SFX"
|| sfxFileName == "WZIPSE32.exe" || sfxFileName == "SI32LPG.SFX"
if (sfxFileName == "VW95SE.SFX"
|| sfxFileName == "ST32E.SFX"
|| sfxFileName == "WZIPSE32.exe"
|| sfxFileName == "SI32LPG.SFX"
|| sfxFileName == "ST32E.WZE")
{
return sfxTimeDateStamp switch
@@ -722,8 +674,10 @@ namespace BinaryObjectScanner.Packer
}
// Personal Edition
if (sfxFileName == "VW95LE.SFX" || sfxFileName == "PE32E.SFX"
|| sfxFileName == "wzsepe32.exe" || sfxFileName == "SI32PE.SFX"
if (sfxFileName == "VW95LE.SFX"
|| sfxFileName == "PE32E.SFX"
|| sfxFileName == "wzsepe32.exe"
|| sfxFileName == "SI32PE.SFX"
|| sfxFileName == "SI32LPE.SFX")
{
return sfxTimeDateStamp switch
@@ -765,7 +719,8 @@ namespace BinaryObjectScanner.Packer
}
// Software Installation
else if (sfxFileName == "VW95SRE.SFX" || sfxFileName == "SI32E.SFX"
else if (sfxFileName == "VW95SRE.SFX"
|| sfxFileName == "SI32E.SFX"
|| sfxFileName == "SI32E.WZE")
{
return sfxTimeDateStamp switch
@@ -796,14 +751,14 @@ namespace BinaryObjectScanner.Packer
"WZIPSE32.exe" => "Unknown Version (32-bit)",// TODO: Find starting version
"SI32LPG.SFX" => "Unknown Version (32-bit)",// TODO: Find starting version
"ST32E.WZE" => "Unknown Version (32-bit)",// TODO: Find starting version
// Personal Edition
"VW95LE.SFX" => "Unknown Version before Personal Edition Build 1285 (32-bit)",
"PE32E.SFX" => "Unknown Version after Personal Edition Build 1285 (32-bit)",
"wzsepe32.exe" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
"SI32PE.SFX" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
"SI32LPE.SFX" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
// Software Installation
"VW95SRE.SFX" => "Unknown Version before Software Installation 2.1 (32-bit)",
"SI32E.SFX" => "Unknown Version after Software Installation 2.1 (32-bit)",

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
@@ -13,10 +12,10 @@ using WiseUnpacker.EWISE;
namespace BinaryObjectScanner.Packer
{
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class WiseInstaller : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
public class WiseInstaller : IExtractableExecutable<NewExecutable>, IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// If we match a known header
if (MatchesNEVersion(nex) != null)
@@ -42,7 +41,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -59,7 +58,7 @@ namespace BinaryObjectScanner.Packer
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("WiseMain")))
if (strs.Exists(s => s.Contains("WiseMain")))
return "Wise Installation Wizard Module";
}
@@ -67,7 +66,7 @@ namespace BinaryObjectScanner.Packer
strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
if (strs.Any(s => s.Contains("WiseMain")))
if (strs.Exists(s => s.Contains("WiseMain")))
return "Wise Installation Wizard Module";
}
@@ -75,52 +74,36 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, NewExecutable nex, bool includeDebug)
public bool Extract(string file, NewExecutable nex, string outDir, bool includeDebug)
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
Directory.CreateDirectory(outDir);
try
{
// TODO: Try to find where the file data lives and how to get it
if (!Extractor.ExtractTo(file, tempPath))
{
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
return Extractor.ExtractTo(file, outDir);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
return tempPath;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
try
{
// Get the matching PE format
var format = GetPEFormat(pex);
if (format == null)
return null;
return false;
// Get the overlay data for easier reading
int overlayOffset = 0, dataStart = 0;
var overlayData = pex.OverlayData;
if (overlayData == null)
return null;
return false;
// Skip over the additional DLL name, if we expect it
if (format.Dll)
@@ -175,43 +158,28 @@ namespace BinaryObjectScanner.Packer
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);
// Create the output directory
Directory.CreateDirectory(outDir);
// If we have PKZIP
if (pkzip)
{
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);
}
string tempFile = Path.Combine(outDir, "WISEDATA.zip");
using Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(overlayData, overlayOffset, overlayData.Length - overlayOffset);
return true;
}
// If we have DEFLATE -- TODO: Port implementation here or use DeflateStream
else
{
if (!Extractor.ExtractTo(file, tempPath))
{
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
return Extractor.ExtractTo(file, outDir);
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
@@ -220,7 +188,7 @@ namespace BinaryObjectScanner.Packer
/// </summary>
/// <param name="nex">New executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? MatchesNEVersion(NewExecutable nex)
private static FormatProperty? MatchesNEVersion(NewExecutable nex)
{
// TODO: Offset is _not_ the EXE header address, rather where the data starts. Fix this.
switch (nex.Model.Stub?.Header?.NewExeHeaderAddr)
@@ -277,7 +245,7 @@ namespace BinaryObjectScanner.Packer
/// </summary>
/// <param name="pex">Portable executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? GetPEFormat(PortableExecutable pex)
private static FormatProperty? GetPEFormat(PortableExecutable pex)
{
if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3cf4

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
@@ -9,33 +8,32 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
// TODO: Figure out how to get version numbers
public class ActiveMARK : IContentCheck, IPortableExecutableCheck
public class ActiveMARK : IContentCheck, IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new(new byte?[]
{
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new(new byte?[]
{
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5 (Unconfirmed - Please report to us on Github)"),
};
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5 (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -52,28 +50,16 @@ namespace BinaryObjectScanner.Protection
// 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. (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. (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) (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. (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] (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 (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) (Unconfirmed - Please report to us on Github)";
}
@@ -82,8 +68,8 @@ namespace BinaryObjectScanner.Protection
var strs = pex.GetLastSectionStrings(".data");
if (strs != null)
{
if (strs.Any(s => s.Contains("MPRMMGVA"))
&& strs.Any(s => s.Contains("This application cannot run with an active debugger in memory.")))
if (strs.Exists(s => s.Contains("MPRMMGVA"))
&& strs.Exists(s => s.Contains("This application cannot run with an active debugger in memory.")))
{
return "ActiveMARK 6.x";
}
@@ -91,11 +77,11 @@ namespace BinaryObjectScanner.Protection
// Get "REGISTRY, AMINTERNETPROTOCOL" resource items
var resources = pex.FindResourceByNamedType("REGISTRY, AMINTERNETPROTOCOL");
if (resources.Any())
if (resources.Count > 0)
{
bool match = resources
.Select(r => r == null ? string.Empty : Encoding.ASCII.GetString(r))
.Any(r => r.Contains("ActiveMARK"));
.ConvertAll(r => r == null ? string.Empty : Encoding.ASCII.GetString(r))
.FindIndex(r => r.Contains("ActiveMARK")) > -1;
if (match)
return "ActiveMARK";
}
@@ -103,7 +89,7 @@ namespace BinaryObjectScanner.Protection
// Get the overlay data, if it exists
if (pex.OverlayStrings != null)
{
if (pex.OverlayStrings.Any(s => s.Contains("TMSAMVOH")))
if (pex.OverlayStrings.Exists(s => s.Contains("TMSAMVOH")))
return "ActiveMARK";
}
@@ -111,7 +97,7 @@ namespace BinaryObjectScanner.Protection
strs = pex.GetLastSectionStrings(".bss");
if (strs != null)
{
if (strs.Any(s => s.Contains("TMSAMVOF")))
if (strs.Exists(s => s.Contains("TMSAMVOF")))
return "ActiveMARK";
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
@@ -18,10 +17,10 @@ namespace BinaryObjectScanner.Protection
/// https://pitchbook.com/profiles/company/118805-59
/// https://web.archive.org/web/19990417191351/http://www.aegisoft.com:80/
/// </summary>
public class AegiSoft : IPathCheck, IPortableExecutableCheck
public class AegiSoft : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -41,7 +40,7 @@ namespace BinaryObjectScanner.Protection
// Get string table resources
var resource = pex.FindStringTableByEntry("AegiSoft License Manager");
if (resource.Any())
if (resource.Count > 0)
return "AegiSoft License Manager";
// Get the .data/DATA section, if it exists
@@ -68,7 +67,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.Protection
public class AlphaDVD : IPathCheck
{
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,5 +1,4 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -40,10 +39,10 @@ namespace BinaryObjectScanner.Protection
// - SETTEC0000SETTEC1111
// - SOFTWARE\SETTEC
// TODO: Are there version numbers?
public class AlphaROM : IPortableExecutableCheck
public class AlphaROM : IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// TODO: Add support for detecting Alpha-ROM found in older games made with the RealLive engine.
// TODO: Add version detection for Alpha-ROM.
@@ -57,10 +56,10 @@ namespace BinaryObjectScanner.Protection
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("\\SETTEC")))
if (strs.Exists(s => s.Contains("\\SETTEC")))
return "Alpha-ROM";
if (strs.Any(s => s.Contains("SETTEC0000")))
if (strs.Exists(s => s.Contains("SETTEC0000")))
return "Alpha-ROM";
}
@@ -68,13 +67,15 @@ namespace BinaryObjectScanner.Protection
strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
if (strs.Any(s => s.Contains("This Game is Japan Only")))
if (strs.Exists(s => s.Contains("This Game is Japan Only")))
return "Alpha-ROM";
// Found in "Filechk.exe" in Redump entry 115358.
if (strs.Any(s => s.Contains("AlphaCheck.exe")))
if (strs.Exists(s => s.Contains("AlphaCheck.exe")))
return "Alpha-ROM";
// Found in "Uninstall.exe" in Redump entry 115358.
if (strs.Any(s => s.Contains("AlphaCheck.dat")))
if (strs.Exists(s => s.Contains("AlphaCheck.dat")))
return "Alpha-ROM";
}
@@ -82,7 +83,7 @@ namespace BinaryObjectScanner.Protection
if (pex.OverlayStrings != null)
{
// Found in Redump entry 84122.
if (pex.OverlayStrings.Any(s => s.Contains("SETTEC0000")))
if (pex.OverlayStrings.Exists(s => s.Contains("SETTEC0000")))
return "Alpha-ROM";
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -18,10 +18,10 @@ namespace BinaryObjectScanner.Protection
// TODO: Add version checking, if possible
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Armadillo : IExtractablePortableExecutable, IPortableExecutableCheck
public class Armadillo : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -29,20 +29,19 @@ namespace BinaryObjectScanner.Protection
return null;
// Get the .nicode section, if it exists
bool nicodeSection = pex.ContainsSection(".nicode", exact: true);
if (nicodeSection)
if (pex.ContainsSection(".nicode", exact: true))
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")))
foreach (var sectionName in Array.FindAll(pex.SectionNames ?? [], 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")))
if (strs.Exists(s => s.Contains("ARMDEBUG")))
return "Armadillo";
}
}
@@ -52,9 +51,9 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return null;
return false;
}
}
}

View File

@@ -13,7 +13,7 @@ namespace BinaryObjectScanner.Protection
public class Bitpool : IPathCheck
{
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
@@ -38,10 +37,10 @@ namespace BinaryObjectScanner.Protection
/// https://www.ftc.gov/sites/default/files/documents/public_comments/ftc-town-hall-address-digital-rights-management-technologies-event-takes-place-wednesday-march-25/539814-00707.pdf
/// https://www.gamesindustry.biz/byteshield-drm-system-now-protecting-over-200-games
/// </summary>
public class ByteShield : IPortableExecutableCheck, IPathCheck
public class ByteShield : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -74,20 +73,17 @@ namespace BinaryObjectScanner.Protection
return "ByteShield Component Module";
// Found in "LineRider2.exe" in Redump entry 6236
var stMatch = pex.FindStringTableByEntry("ByteShield");
if (stMatch.Any())
if (pex.FindStringTableByEntry("ByteShield").Count > 0)
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "LineRider2.exe" in Redump entry 6236
var dbMatch = pex.FindDialogByTitle("About ByteShield");
if (dbMatch.Any())
if (pex.FindDialogByTitle("About ByteShield").Count > 0)
return "ByteShield";
// TODO: See if the version number is anywhere else
// TODO: Parse the version number out of the dialog box item
// Found in "LineRider2.exe" in Redump entry 6236
dbMatch = pex.FindDialogBoxByItemTitle("ByteShield Version 1.0");
if (dbMatch.Any())
if (pex.FindDialogBoxByItemTitle("ByteShield Version 1.0").Count > 0)
return "ByteShield";
// Get the .data/DATA section strings, if they exist
@@ -95,7 +91,7 @@ namespace BinaryObjectScanner.Protection
if (strs != null)
{
// Found in "LineRider2.exe" in Redump entry 6236
if (strs.Any(s => s?.Contains("ByteShield") == true))
if (strs.Exists(s => s?.Contains("ByteShield") == true))
return "ByteShield";
}
@@ -104,15 +100,15 @@ namespace BinaryObjectScanner.Protection
if (strs != null)
{
// Found in "ByteShield.dll" in Redump entry 6236
if (strs.Any(s => s?.Contains("Byte|Shield") == true))
if (strs.Exists(s => s?.Contains("Byte|Shield") == true))
return "ByteShield Component Module";
// Found in "ByteShield.dll" in Redump entry 6236
else if (strs.Any(s => s?.Contains("Byteshield0") == true))
else if (strs.Exists(s => s?.Contains("Byteshield0") == true))
return "ByteShield Component Module";
// Found in "ByteShield.dll" in Redump entry 6236
else if (strs.Any(s => s?.Contains("ByteShieldLoader") == true))
else if (strs.Exists(s => s?.Contains("ByteShieldLoader") == true))
return "ByteShield Component Module";
}
@@ -122,7 +118,7 @@ namespace BinaryObjectScanner.Protection
{
// TODO: Figure out if this specifically indicates if the file is encrypted
// Found in "LineRider2.bbz" in Redump entry 6236
if (strs.Any(s => s?.Contains("ByteShield") == true))
if (strs.Exists(s => s?.Contains("ByteShield") == true))
return "ByteShield";
}
@@ -130,7 +126,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
// 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.

View File

@@ -3,10 +3,10 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
public class CDCheck : IPortableExecutableCheck
public class CDCheck : IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;

View File

@@ -63,41 +63,40 @@ namespace BinaryObjectScanner.Protection
/// 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
public class CDDVDCops : IContentCheck, IExecutableCheck<NewExecutable>, IExecutableCheck<PortableExecutable>, IPathCheck
{
// TODO: Investigate reference to "CD32COPS.DLL" in "WETFLIPP.QZ_" in IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(new byte?[]
{
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(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)"),
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(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)"),
};
// // DVD-Cops, ver.
new(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;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// TODO: Don't read entire file
var data = nex.ReadArbitraryRange();
@@ -120,28 +119,28 @@ namespace BinaryObjectScanner.Protection
if (!string.IsNullOrEmpty(match))
return match;
// Get the resident and non-resident name table strings
var nrntStrs = Array.ConvertAll(nex.Model.NonResidentNameTable ?? [],
nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString));
// Check the imported-name table
// Found in "h3blade.exe" in Redump entry 85077.
bool importedNameTableEntries = nex.Model.ImportedNameTable?
.Select(kvp => kvp.Value)
bool intMatch = nex.Model.ImportedNameTable?.Values?
.Select(inte => inte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(inte.NameString))
.Any(s => s.Contains("CDCOPS")) ?? false;
if (importedNameTableEntries)
if (intMatch)
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)
if (Array.Exists(nrntStrs, s => s.Contains("CDcops assembly-language DLL")))
return "CD-Cops";
return null;
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -152,14 +151,14 @@ namespace BinaryObjectScanner.Protection
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(new byte?[]
{
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
}, "WEB-Cops")
};
// WEBCOPS
// Found in "HyperBowl.C_S" in https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe.
new(new byte?[]
{
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
}, "WEB-Cops")
};
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
@@ -168,21 +167,19 @@ namespace BinaryObjectScanner.Protection
// 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)
if (pex.ContainsSection(".grand", exact: true))
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)
if (pex.ContainsSection("UNICops", exact: true))
return "UNI-Cops";
return null;
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
// TODO: Original had "CDCOPS.DLL" required and all the rest in a combined OR
var matchers = new List<PathMatchSet>
@@ -228,17 +225,11 @@ namespace BinaryObjectScanner.Protection
if (fileContent == null)
return null;
#if NET20 || NET35 || NET40
byte[] versionBytes = new byte[4];
Array.Copy(fileContent, positions[0] + 15, versionBytes, 0, 4);
char[] version = versionBytes.Select(b => (char)b).ToArray();
#else
char[] version = new ArraySegment<byte>(fileContent, positions[0] + 15, 4).Select(b => (char)b).ToArray();
#endif
string version = Encoding.ASCII.GetString(fileContent, positions[0] + 15, 4);
if (version[0] == 0x00)
return string.Empty;
return new string(version);
return version;
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
@@ -21,10 +20,10 @@ namespace BinaryObjectScanner.Protection
/// https://gamecopyworld.com/games/pc_omikron.shtml
/// https://forum.ixbt.com/topic.cgi?id=31:3985
/// </summary>
public class CDGuard : IPathCheck, IPortableExecutableCheck
public class CDGuard : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -46,7 +45,7 @@ namespace BinaryObjectScanner.Protection
if (pex.Model.ImportTable?.ImportDirectoryTable != null)
{
// Found in "Randevu.exe" in Redump entry 97142.
bool match = pex.Model.ImportTable.ImportDirectoryTable.Any(idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
bool match = Array.Exists(pex.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
if (match)
return "CD-Guard Copy Protection System";
}
@@ -55,7 +54,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -4,10 +4,10 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
public class CDKey : IPortableExecutableCheck
public class CDKey : IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;

View File

@@ -25,10 +25,10 @@ namespace BinaryObjectScanner.Protection
/// Possible false positives include Redump entries 51241, 51373, 54397, 76437.
/// Confirmed to be present on Redump entries 24287, 31615, 34448, 35967, 36627, 37700, 37788, 43221, 55788, and 66749.
/// </summary>
public class CDLock : IPathCheck, IPortableExecutableCheck
public class CDLock : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -62,7 +62,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.Protection
public class CDProtector : IPathCheck
{
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,13 +1,12 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
public class CDSHiELDSE : IPortableExecutableCheck
public class CDSHiELDSE : IExecutableCheck<PortableExecutable>
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -27,7 +26,7 @@ namespace BinaryObjectScanner.Protection
var strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
if (strs != null)
{
if (strs.Any(s => s.Contains("~0017.tmp")))
if (strs.Exists(s => s.Contains("~0017.tmp")))
return "CDSHiELD SE";
}

View File

@@ -12,7 +12,7 @@ namespace BinaryObjectScanner.Protection
public class CDX : IPathCheck
{
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
// TODO: Verify if these are OR or AND
var matchers = new List<PathMatchSet>

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
@@ -11,24 +10,22 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// 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>
{
var contentMatchSets = new List<ContentMatchSet>
{
// CDSPlayer
new(new byte?[] { 0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72 }, "Cactus Data Shield 200"),
// CDSPlayer
new([0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72], "Cactus Data Shield 200"),
// yucca.cds
new(new byte?[] { 0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73 }, "Cactus Data Shield 200"),
};
// yucca.cds
new([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;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
}
}

View File

@@ -12,10 +12,10 @@ namespace BinaryObjectScanner.Protection
/// 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
public class CengaProtectDVD : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -32,28 +32,22 @@ namespace BinaryObjectScanner.Protection
}
// Get the .cenega section, if it exists. Seems to be found in the protected game executable ("game.exe" in Redump entry 31422 and "Classic Car Racing.exe" in IA item "speed-pack").
bool cenegaSection = pex.ContainsSection(".cenega", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega", exact: true))
return "Cenega ProtectDVD";
// Get the .cenega0 through .cenega2 sections, if they exists. Found in "cenega.dll" in Redump entry 31422 and IA item "speed-pack".
cenegaSection = pex.ContainsSection(".cenega0", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega0", exact: true))
return "Cenega ProtectDVD";
cenegaSection = pex.ContainsSection(".cenega1", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega1", exact: true))
return "Cenega ProtectDVD";
cenegaSection = pex.ContainsSection(".cenega2", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega2", exact: true))
return "Cenega ProtectDVD";
return null;
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -20,10 +20,10 @@ namespace BinaryObjectScanner.Protection
/// Add version detection. Redump entry 116358 is version 1.x and Redump entry 12354 is 2.x, but the file versions are inconsistent.
/// Investigate "NetActive Reach", which is is either a newer version of this DRM, or a new DRM created by the same company. (https://web.archive.org/web/20040101162921/http://www.netactive.com/Products/)
/// </summary>
public class Channelware : IPathCheck, IPortableExecutableCheck
public class Channelware : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -61,7 +61,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
@@ -20,10 +19,10 @@ namespace BinaryObjectScanner.Protection
/// Code-Lock FAQ: https://web.archive.org/web/20041205165232/http://www.chosenbytes.com/codefaq.php
/// Download (Version 2.35 trial): https://web.archive.org/web/20060220121200/http://www.chosenbytes.com:80/Code-Lock_cnet.zip
/// </summary>
public class ChosenBytesCodeLock : IPathCheck, IPortableExecutableCheck
public class ChosenBytesCodeLock : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -40,13 +39,13 @@ namespace BinaryObjectScanner.Protection
var strs = pex.GetFirstSectionStrings(".text");
if (strs != null)
{
if (strs.Any(s => s.Contains("CODE-LOCK.OCX")))
if (strs.Exists(s => s.Contains("CODE-LOCK.OCX")))
return "ChosenBytes Code-Lock";
if (strs.Any(s => s.Contains("Code-Lock.ocx")))
if (strs.Exists(s => s.Contains("Code-Lock.ocx")))
return "ChosenBytes Code-Lock";
if (strs.Any(s => s.Contains("CodeLock.Secure")))
if (strs.Exists(s => s.Contains("CodeLock.Secure")))
return "ChosenBytes Code-Lock";
}
@@ -54,7 +53,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{

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