Compare commits

..

144 Commits

Author SHA1 Message Date
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
Matt Nadareski
e5dc66b140 Bump version 2024-11-03 20:01:41 -05:00
HeroponRikiBestest
41e10a4150 Add aditional light directory checks (#335)
Compensate for some additional variance in directory names found from new samples, in lieu of a more "advanced" check
2024-11-02 19:42:00 -04:00
Matt Nadareski
3c4381049b Minor leftover cleanup 2024-10-31 23:11:11 -04:00
Matt Nadareski
3188c6e922 Further reduce awkward framework gating 2024-10-31 23:08:05 -04:00
Matt Nadareski
1bfb6cda08 Use CheckDictionary helper type 2024-10-31 22:52:20 -04:00
Matt Nadareski
86feb930a8 Add CheckDictionary (unused) 2024-10-31 22:49:57 -04:00
Matt Nadareski
5587c79ac5 Reduce use of generic PathMatch 2024-10-31 22:42:20 -04:00
Matt Nadareski
dc2a2e10de Add summary to ProtectionDictionary 2024-10-31 22:25:11 -04:00
Matt Nadareski
a2fdcb4f6f Remove remaining unncessary Concurrent usings 2024-10-31 22:22:52 -04:00
Matt Nadareski
a355670af9 Use semantic versioning for var names 2024-10-31 22:16:51 -04:00
Matt Nadareski
3489c67e2b Make CheckDirectoryPath signature easier 2024-10-31 22:15:30 -04:00
Matt Nadareski
99a64942ea Reduce per-framework complexity 2024-10-31 21:46:40 -04:00
Matt Nadareski
5eab12946f Fix accidental change 2024-10-31 21:13:09 -04:00
Matt Nadareski
683cfb6306 Start using ProtectionDictionary 2024-10-31 21:10:06 -04:00
Matt Nadareski
9a3fde0518 Add ProtectionDictionary type (unused) 2024-10-31 20:54:36 -04:00
Matt Nadareski
26d19aab37 Fix very strange formatting 2024-10-31 20:38:15 -04:00
Matt Nadareski
08564ed607 Remove end-of-program pauses 2024-10-31 20:36:40 -04:00
Matt Nadareski
0f6378cd2c Update packages 2024-10-31 16:05:11 -04:00
TheRogueArchivist
34a78fc4b9 Minor SafeCast additions (#333)
Adds a text check for SafeCast, along with adding a new confirmed version. Also add notes for a few known programs that used SafeCast, a few TODOs, and a semi-related note about stxt sections.
2024-10-30 07:28:21 -04:00
Matt Nadareski
c9ee45c1d2 Count not Count() 2024-10-27 20:24:24 -04:00
HeroponRikiBestest
13f5b4f79b Improve Copy-X Light detection with additional folder check. (#332)
* Improve Copy-X Light detection with additional folder check.

* Add requested changes to additional copy-X light folder check.

* Cleaned up changes.

* One final comment cleanup.
2024-10-27 20:20:19 -04:00
HeroponRikiBestest
e5d0c5bdc4 Replace tivola with copy-x. (#331) 2024-10-27 00:19:41 -04:00
Matt Nadareski
6220382531 Clarify switch expression use 2024-10-27 00:12:21 -04:00
Matt Nadareski
165896e335 Add note about first-person comments 2024-10-27 00:04:11 -04:00
Matt Nadareski
284d0ea108 Clear out old info from the coding guide 2024-10-27 00:01:22 -04:00
Matt Nadareski
b04feab5da Minor cleanup 2024-10-26 23:54:54 -04:00
HeroponRikiBestest
4e0442d526 Add preliminary copy-X protection checking (#328)
* Add preliminary copy-X protection checking

* Fixed formatting.

* Removed some unecessary lines of code.

* Added debatably sufficient documentation.

* Fixed formatting, hopefully

* Finalize formatting and PR.

* Fleshes out checks after more samples. Fixes some but not all of the change requests.

* Fix ordering.

* Fixes pex check, fixes redump id formatting.

* Added copy-X info to readme.

* Revert "Added copy-X info to readme."

This reverts commit 77349aa8de.

* Add copy-X info to readme, for real this time.

* Replaced some code in byte check with BoS helper function.

* Remove first person.

* Source is no longer just trust me (to some degree)

* Fix typo

* WIP figuring out enumerable (fails to build)

* WIP 2 figuring out getfirstmatch (compiles, but breaks detection)

* Pass 1 of suggested changes.

* Removed debug match.

* Pass 2 of suggested changes.

* Added line.

* Added line for real.

* Added todo

* Improved comments.

* Finished todo.

* Redid change.

* Fixes more comments.

* double double and make it trouble
2024-10-26 23:53:17 -04:00
TheRogueArchivist
d8aa4d230d Fix WTM false positive (#327)
"imp.dat" isn't exactly a very distinctive file name.
2024-10-26 20:31:25 -04:00
TheRogueArchivist
07a7fd05d2 Add new SafeCast version (#329) 2024-10-26 20:30:07 -04:00
Matt Nadareski
671e1ee2b6 Update Matching to 1.3.3 2024-10-26 19:46:34 -04:00
Matt Nadareski
d627e8a4c9 Be consistent with naming 2024-10-25 12:01:08 -04:00
Matt Nadareski
6ee90b28cd Be consistent with naming 2024-10-25 11:57:51 -04:00
Matt Nadareski
8dc2b019b6 Update packages 2024-10-24 17:32:26 -04:00
TheRogueArchivist
f151563e28 Move Armadillo to Protection and add notes (#326)
Armadillo has packer and protection features, meaning it should be move to be a protection. Also add additional notes, including about an alternate later name, "SoftwarePassport".
2024-10-23 00:38:53 -04:00
Matt Nadareski
edbbbb011d Renmae MediaMax CD-3 to be more accurate 2024-10-21 21:59:15 -04:00
TheRogueArchivist
e3fd44134b Add initial .NET Reactor support (#325)
* Add initial .NET Reactor support

It's minimal, but is much better than nothing. A few notes on how it can be realistically improved have been added as well.

* Fix missing using

* 7-zip SFX is extractable now
2024-10-04 23:56:52 -04:00
Matt Nadareski
71fb7318e3 Better handling of Windows libraries 2024-10-03 14:57:14 -04:00
Matt Nadareski
aba4395139 Enable Windows libraries on .NET Framework 4.0 2024-10-03 14:46:35 -04:00
Matt Nadareski
1fd69f101f Remove last two this qualifiers 2024-10-03 13:02:23 -04:00
Matt Nadareski
aa4c72fb90 Old .NET really doesn't like readonly 2024-10-03 12:55:38 -04:00
Matt Nadareski
150b9a0d67 Remove more this qualifiers 2024-10-03 12:53:43 -04:00
Matt Nadareski
b08921a94a Use readonly instead of private set 2024-10-03 12:52:27 -04:00
Matt Nadareski
3406f3c4b3 Remove this qualifiers 2024-10-03 12:51:49 -04:00
Matt Nadareski
ffca156209 Remove init variants :( 2024-10-03 12:51:30 -04:00
Matt Nadareski
b842599006 Update packages 2024-10-03 12:01:08 -04:00
TheRogueArchivist
86b639b04f Add Kalypso Launcher support (#324)
* Add Kalypso Launcher support

* Small changes to Kalypso Launcher

* More minor Kalypso Launcher changes
2024-10-03 10:42:39 -04:00
Matt Nadareski
570602aac6 Remove unused package 2024-10-01 10:45:12 -04:00
Matt Nadareski
4989956a91 Bump version 2024-09-28 13:13:06 -04:00
Matt Nadareski
14849f45da Remove redundant reports in Macrovision code 2024-09-27 13:24:19 -04:00
TheRogueArchivist
28ebc14fe1 Fix various archive formats not extracting folders (#323)
Fixes folder extraction for 7z, RAR, and WinRAR SFX. Applied same fix to tar, but more is needed for it to work properly.
2024-09-26 01:15:38 -04:00
TheRogueArchivist
54cb996fce [WIP] Add 7-Zip SFX extraction (#321)
* Add 7-Zip SFX extraction

Newest SharpCompress added support for extracting 7-Zip SFX files, so we can add support for them here too.

* Clean up 7z SFX extraction method

* Remove unneeded import

* Use file instead of stream for 7z SFX

* Update 7z SFX to be more consistent with other packers
2024-09-26 00:30:25 -04:00
Matt Nadareski
8df58fa4d4 This doesn't inherit from anything 2024-09-25 11:25:52 -04:00
TheRogueArchivist
422add9827 Update SharpCompress to 0.38.0 (#320) 2024-09-25 11:01:16 -04:00
TheRogueArchivist
59435903eb Small update to nProtect comments (#319)
Add new confirmed game to use GameGuard, and start a known version list.
2024-09-12 02:33:17 -04:00
TheRogueArchivist
95ee417e00 Small update to SafeWrap comments (#318)
* Small update to SafeWrap comments

* Further additions to SafeWrap comments
2024-09-05 01:22:11 -04:00
Matt Nadareski
df913372bf Add more SecuROM PA checks (fixes #313) 2024-08-08 08:55:46 -04:00
TheRogueArchivist
2f1c76b7f9 Add EA Anti Cheat detection (#314)
* Add EA Anti Cheat detection

* Make a check more exact
2024-08-02 12:34:43 -04:00
Matt Nadareski
18e57c8182 Fix minor formatting issue 2024-08-02 12:23:05 -04:00
TheRogueArchivist
b4e2117c4b Confirm one SafeCast version (#309) 2024-08-02 00:07:12 -04:00
Matt Nadareski
1bb5ff9e18 Fix README a bit 2024-07-20 21:54:55 -04:00
TheRogueArchivist
a46cae469d Fix scans that use directory name in Windows (#312)
Removes ``.Replace("\\", "/")``, as it was messing with folder paths on Windows.
2024-07-13 01:29:45 -04:00
TheRogueArchivist
b564ff214d Add initial Channelware detection (#311) 2024-07-12 12:35:26 -04:00
TheRogueArchivist
0744a10de0 Improve phenoProtect detection (#307) 2024-07-04 22:16:11 -04:00
HeroponRikiBestest
343ca9497e Fix #.##.xx version number writing second x digit to first digit (#310) 2024-07-04 22:13:49 -04:00
Matt Nadareski
861958527d Fix under-matched runtimes 2024-06-26 12:44:32 -04:00
Matt Nadareski
a6b9dca291 Only copy DLLs for win-x86 2024-06-26 11:53:10 -04:00
Matt Nadareski
18c05cb49d Update workflow runtimes 2024-06-26 11:34:31 -04:00
Matt Nadareski
ed3e58af6c Update publishing to cooler version 2024-06-26 11:32:20 -04:00
Matt Nadareski
e3eed76826 Make debug table reading safer, kinda 2024-06-20 11:26:20 -04:00
Matt Nadareski
7eb86b223f Fix build script 2024-06-17 16:16:11 -04:00
Matt Nadareski
a4ee4529ca Bump version 2024-06-17 16:15:04 -04:00
Matt Nadareski
abc68d8503 Update Serialization to 1.6.7 2024-06-13 11:20:33 -04:00
TheRogueArchivist
aaff4bad1b Add new Alpha-ROM checks (#306) 2024-06-07 13:11:24 -04:00
TheRogueArchivist
d5c81857c3 Update Roxxe detections (#305) 2024-06-05 09:37:37 -04:00
TheRogueArchivist
c2594cdd2d Add checks for Macrovision SecDrv Update Installer (#304) 2024-06-02 19:43:15 -04:00
Matt Nadareski
2412042cef Update Serialization to 1.6.6 2024-06-02 19:42:49 -04:00
Matt Nadareski
1f5c1a8100 Bump version 2024-05-18 22:12:35 -04:00
Matt Nadareski
78cc67f30e Update UnshieldSharp 2024-05-18 22:05:32 -04:00
Matt Nadareski
5b78ba5621 Bump version 2024-05-15 20:30:43 -04:00
Matt Nadareski
c4734cfc3d Update packages 2024-05-15 15:16:41 -04:00
Matt Nadareski
dd45384226 Add secondary check for WinZipSFX NE 2024-05-15 15:15:09 -04:00
Matt Nadareski
3e75d9fa3b Add safety around executable wrapper creation 2024-05-15 13:09:40 -04:00
Matt Nadareski
aa690ab602 Update packages 2024-05-15 12:24:40 -04:00
Matt Nadareski
7432100139 Bump version 2024-05-07 08:57:17 -04:00
Matt Nadareski
29fabb44eb Update IO and Serialization 2024-05-07 05:31:42 -04:00
Matt Nadareski
ad776d4189 Add explicit compatibility notes section 2024-05-06 22:40:39 -04:00
Matt Nadareski
4cf12c76a8 Update IO and Serialization 2024-05-06 22:30:58 -04:00
Matt Nadareski
39185f5ddd Remove now-irrelevant note 2024-05-06 21:59:37 -04:00
Matt Nadareski
03477327c4 Clearer in another place 2024-05-06 21:59:10 -04:00
Matt Nadareski
29fa0d1ac7 Clarify support 2024-05-06 21:54:45 -04:00
Matt Nadareski
7eca23a7f3 Bump version 2024-04-28 19:51:22 -04:00
Matt Nadareski
f0c90bb332 Update packages for critical issues 2024-04-28 19:50:53 -04:00
Matt Nadareski
0af67e5802 Fix build 2024-04-26 22:13:27 -04:00
Matt Nadareski
6ab9f730f9 Bump version 2024-04-26 22:10:27 -04:00
Matt Nadareski
258238bcc0 Update packages 2024-04-26 22:09:05 -04:00
Matt Nadareski
3936a15ef7 Bump version 2024-04-24 17:08:16 -04:00
Matt Nadareski
f6dbb349c4 Update packages 2024-04-24 17:06:51 -04:00
Matt Nadareski
3c69e02cfc Update SabreTools.Serialization 2024-04-24 16:29:58 -04:00
Matt Nadareski
531e634e62 Version-gate a using statement 2024-04-24 14:43:28 -04:00
Matt Nadareski
f9c0c42b26 One Nuget packing error 2024-04-24 12:13:56 -04:00
Matt Nadareski
83aebbbfbd Maybe the last one? 2024-04-24 12:11:05 -04:00
Matt Nadareski
3847e5e9dc Even more warnings 2024-04-24 11:55:27 -04:00
Matt Nadareski
a72bb7e332 Yet more, plus an XML comment 2024-04-24 11:45:20 -04:00
Matt Nadareski
839791f467 Add a couple more for external 2024-04-24 11:43:09 -04:00
Matt Nadareski
469356e8c1 Suppress some "necessary" warnings 2024-04-24 11:35:09 -04:00
198 changed files with 4185 additions and 6601 deletions

View File

@@ -1,4 +1,4 @@
name: Build Test
name: Build Programs
on:
push:
@@ -10,10 +10,10 @@ jobs:
strategy:
matrix:
project: [Test]
runtime: [win-x86, win-x64, linux-x64, osx-x64] #[win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
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]
conf: [Debug] #[Release, Debug]
steps:
- uses: actions/checkout@v4

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/net8.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/net8.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,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
@@ -10,8 +10,10 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors> --> <!-- Can't be enabled because of external code -->
<Version>3.1.6</Version>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.1.16</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>
@@ -29,7 +31,7 @@
<DefineConstants>$(DefineConstants);WIN</DefineConstants>
</PropertyGroup>
<!-- Exclude certain parts of external modules for .NET Framework 4.5.2 and above -->
<!-- Exclude certain parts of external modules for by default -->
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
@@ -42,8 +44,16 @@
</DefaultItemExcludes>
</PropertyGroup>
<!-- Exclude all external modules for .NET Framework 2.0, .NET Framework 3.5, .NET Framework 4.0 or non-Windows builds -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`)) OR !$(RuntimeIdentifier.StartsWith(`win-`))">
<!-- Exclude all StormLibSharp for .NET Framework 4.0 -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net40`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\stormlibsharp\src\**
</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\**
@@ -51,7 +61,7 @@
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))">
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND $(RuntimeIdentifier.StartsWith(`win-x86`))">
<Content Include="*.dll">
<Pack>true</Pack>
<PackagePath>contentFiles;content</PackagePath>
@@ -67,13 +77,12 @@
<!-- 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" />
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.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.37.0" />
<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`))">
@@ -81,14 +90,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Compression" Version="0.5.0" />
<PackageReference Include="SabreTools.Hashing" Version="1.2.0" />
<PackageReference Include="SabreTools.IO" Version="1.4.0" />
<PackageReference Include="SabreTools.Matching" Version="1.3.1" />
<PackageReference Include="SabreTools.Models" Version="1.4.5" />
<PackageReference Include="SabreTools.Serialization" Version="1.5.5" />
<PackageReference Include="UnshieldSharp" Version="1.8.0" />
<PackageReference Include="WiseUnpacker" Version="1.4.0" />
<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>
</Project>

View File

@@ -0,0 +1,26 @@
namespace BinaryObjectScanner
{
/// <summary>
/// Represents a mapping from checker to detected protection
/// </summary>
#if NET20 || NET35
public class CheckDictionary<T> : System.Collections.Generic.Dictionary<T, string> where T : notnull
#else
public class CheckDictionary<T> : System.Collections.Concurrent.ConcurrentDictionary<T, string> where T : notnull
#endif
{
/// <inheritdoc cref="System.Collections.Generic.Dictionary{TKey, TValue}.Add(TKey, TValue)"/>
/// <remarks>Handles the proper Add implementation</remarks>
public void Append(T key, string? value)
{
if (value == null)
return;
#if NET20 || NET35
this[key] = value;
#else
TryAdd(key, value);
#endif
}
}
}

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
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
List<Type> assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
}
// Get information from the type param
string interfaceName = typeof(T)!.FullName!;
// Loop through all types
foreach (Type type in assemblyTypes)
{
// 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,27 @@
using System;
using System.Collections.Generic;
namespace BinaryObjectScanner
{
internal static class EnumerableExtensions
{
/// <summary>
/// Wrap iterating through an enumerable with an action
/// </summary>
/// <remarks>
/// .NET Frameworks 2.0 and 3.5 process in series.
/// .NET Frameworks 4.0 onward process in parallel.
/// </remarks>
public static void IterateWithAction<T>(this IEnumerable<T> source, Action<T> action)
{
#if NET20 || NET35
foreach (var item in source)
{
action(item);
}
#else
System.Threading.Tasks.Parallel.ForEach(source, action);
#endif
}
}
}

View File

@@ -1,5 +1,5 @@
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner
{
@@ -8,65 +8,65 @@ namespace BinaryObjectScanner
/// <summary>
/// Create an instance of a detectable based on file type
/// </summary>
public static IDetectable? CreateDetectable(SupportedFileType fileType)
public static IDetectable? CreateDetectable(WrapperType fileType)
{
switch (fileType)
return fileType switch
{
case SupportedFileType.AACSMediaKeyBlock: return new FileType.AACSMediaKeyBlock();
case SupportedFileType.BDPlusSVM: return new FileType.BDPlusSVM();
//case SupportedFileType.CIA: return new FileType.CIA();
case SupportedFileType.Executable: return new FileType.Executable();
case SupportedFileType.LDSCRYPT: return new FileType.LDSCRYPT();
//case SupportedFileType.N3DS: return new FileType.N3DS();
//case SupportedFileType.Nitro: return new FileType.Nitro();
case SupportedFileType.PLJ: return new FileType.PLJ();
case SupportedFileType.RealArcadeInstaller: return new FileType.RealArcadeInstaller();
case SupportedFileType.RealArcadeMezzanine: return new FileType.RealArcadeMezzanine();
case SupportedFileType.SFFS: return new FileType.SFFS();
case SupportedFileType.Textfile: return new FileType.Textfile();
default: return null;
}
WrapperType.AACSMediaKeyBlock => new FileType.AACSMediaKeyBlock(),
WrapperType.BDPlusSVM => new FileType.BDPlusSVM(),
//WrapperType.CIA => new FileType.CIA(),
WrapperType.Executable => new FileType.Executable(),
WrapperType.LDSCRYPT => new FileType.LDSCRYPT(),
//WrapperType.N3DS => new FileType.N3DS(),
//WrapperType.Nitro => new FileType.Nitro(),
WrapperType.PlayJAudioFile => new FileType.PLJ(),
WrapperType.RealArcadeInstaller => new FileType.RealArcadeInstaller(),
WrapperType.RealArcadeMezzanine => new FileType.RealArcadeMezzanine(),
WrapperType.SFFS => new FileType.SFFS(),
WrapperType.Textfile => new FileType.Textfile(),
_ => null,
};
}
/// <summary>
/// Create an instance of an extractable based on file type
/// </summary>
public static IExtractable? CreateExtractable(SupportedFileType fileType)
public static IExtractable? CreateExtractable(WrapperType fileType)
{
switch (fileType)
return fileType switch
{
case SupportedFileType.BFPK: return new FileType.BFPK();
case SupportedFileType.BSP: return new FileType.BSP();
case SupportedFileType.BZip2: return new FileType.BZip2();
case SupportedFileType.CFB: return new FileType.CFB();
//case SupportedFileType.CIA: return new FileType.CIA();
case SupportedFileType.GCF: return new FileType.GCF();
case SupportedFileType.GZIP: return new FileType.GZIP();
case SupportedFileType.InstallShieldArchiveV3: return new FileType.InstallShieldArchiveV3();
case SupportedFileType.InstallShieldCAB: return new FileType.InstallShieldCAB();
case SupportedFileType.MicrosoftCAB: return new FileType.MicrosoftCAB();
case SupportedFileType.MicrosoftLZ: return new FileType.MicrosoftLZ();
case SupportedFileType.MPQ: return new FileType.MPQ();
//case SupportedFileType.N3DS: return new FileType.N3DS();
//case SupportedFileType.NCF: return new FileType.NCF();
//case SupportedFileType.Nitro: return new FileType.Nitro();
case SupportedFileType.PAK: return new FileType.PAK();
case SupportedFileType.PFF: return new FileType.PFF();
case SupportedFileType.PKZIP: return new FileType.PKZIP();
//case SupportedFileType.PLJ: return new FileType.PLJ();
//case SupportedFileType.Quantum: return new FileType.Quantum();
case SupportedFileType.RAR: return new FileType.RAR();
case SupportedFileType.SevenZip: return new FileType.SevenZip();
case SupportedFileType.SFFS: return new FileType.SFFS();
case SupportedFileType.SGA: return new FileType.SGA();
case SupportedFileType.TapeArchive: return new FileType.TapeArchive();
case SupportedFileType.VBSP: return new FileType.VBSP();
case SupportedFileType.VPK: return new FileType.VPK();
case SupportedFileType.WAD: return new FileType.WAD();
case SupportedFileType.XZ: return new FileType.XZ();
case SupportedFileType.XZP: return new FileType.XZP();
default: return null;
}
WrapperType.BFPK => new FileType.BFPK(),
WrapperType.BSP => new FileType.BSP(),
WrapperType.BZip2 => new FileType.BZip2(),
WrapperType.CFB => new FileType.CFB(),
//WrapperType.CIA => new FileType.CIA(),
WrapperType.GCF => new FileType.GCF(),
WrapperType.GZIP => new FileType.GZIP(),
WrapperType.InstallShieldArchiveV3 => new FileType.InstallShieldArchiveV3(),
WrapperType.InstallShieldCAB => new FileType.InstallShieldCAB(),
WrapperType.MicrosoftCAB => new FileType.MicrosoftCAB(),
WrapperType.MicrosoftLZ => new FileType.MicrosoftLZ(),
WrapperType.MoPaQ => new FileType.MPQ(),
//WrapperType.N3DS => new FileType.N3DS(),
//WrapperType.NCF => new FileType.NCF(),
//WrapperType.Nitro => new FileType.Nitro(),
WrapperType.PAK => new FileType.PAK(),
WrapperType.PFF => new FileType.PFF(),
WrapperType.PKZIP => new FileType.PKZIP(),
//WrapperType.PlayJAudioFile => new FileType.PLJ(),
//WrapperType.Quantum => new FileType.Quantum(),
WrapperType.RAR => new FileType.RAR(),
WrapperType.SevenZip => new FileType.SevenZip(),
WrapperType.SFFS => new FileType.SFFS(),
WrapperType.SGA => new FileType.SGA(),
WrapperType.TapeArchive => new FileType.TapeArchive(),
WrapperType.VBSP => new FileType.VBSP(),
WrapperType.VPK => new FileType.VPK(),
WrapperType.WAD => new FileType.WAD(),
WrapperType.XZ => new FileType.XZ(),
WrapperType.XZP => new FileType.XZP(),
_ => null,
};
}
}
}

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/>

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

@@ -11,41 +11,36 @@ 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;
// 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(bsp, tempPath);
ExtractAllTextures(bsp, tempPath);
Directory.CreateDirectory(outDir);
ExtractAllLumps(bsp, outDir);
ExtractAllTextures(bsp, outDir);
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}

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

@@ -1,15 +1,11 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using BinaryObjectScanner.Data;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.IO.Extensions;
using SabreTools.Serialization.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.FileType
@@ -17,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
@@ -35,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/>
@@ -139,52 +42,97 @@ 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 queue
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// Create the internal list
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.ToArray());
protections.Append(file, subProtections.Values);
}
if (wrapper is MSDOS mz)
{
var subProtections = RunMSDOSExecutableChecks(file, stream, mz, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
// 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.ToArray());
// 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.ToArray());
// 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.ToArray());
// 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
@@ -195,382 +143,182 @@ 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>
#if NET20 || NET35
public Dictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
#else
public ConcurrentDictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
#endif
/// <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;
// Read the file contents
byte[] fileContent = [];
try
{
#if NET20 || NET35 || NET40
using var br = new BinaryReader(stream, Encoding.Default);
#else
using var br = new BinaryReader(stream, Encoding.Default, true);
#endif
fileContent = br.ReadBytes((int)stream.Length);
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
#if NET20 || NET35
var protections = new Dictionary<IContentCheck, string>();
#else
var protections = new ConcurrentDictionary<IContentCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in ContentCheckClasses)
#else
Parallel.ForEach(ContentCheckClasses, checkClass =>
#endif
StaticChecks.ContentCheckClasses.IterateWithAction(checkClass =>
{
// Get the protection for the class, if possible
var protection = checkClass.CheckContents(file!, fileContent, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
protections.Append(checkClass, protection);
});
#endif
return protections;
}
/// <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>
#if NET20 || NET35
public Dictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
#else
public ConcurrentDictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
#endif
/// <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
#if NET20 || NET35
var protections = new Dictionary<ILinearExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<ILinearExecutableCheck, string>();
#endif
var protections = new CheckDictionary<U>();
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in LinearExecutableCheckClasses)
#else
Parallel.ForEach(LinearExecutableCheckClasses, checkClass =>
#endif
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))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
protections.Append(checkClass, protection);
});
#endif
return protections;
}
/// <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>
#if NET20 || NET35
public Dictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
#else
public ConcurrentDictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
#endif
/// <returns>Set of protections found from extraction, empty on error</returns>
private static ProtectionDictionary HandleExtractableProtections<T, U>(string file,
T exe,
IEnumerable<U> checks,
Func<string, ProtectionDictionary>? getProtections,
bool includeDebug)
where T : WrapperBase
where U : IExecutableCheck<T>
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<IMSDOSExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<IMSDOSExecutableCheck, string>();
#endif
var protections = new ProtectionDictionary();
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in MSDOSExecutableCheckClasses)
#else
Parallel.ForEach(MSDOSExecutableCheckClasses, checkClass =>
#endif
// If we have an invalid set of classes
if (checks == null || !checks.Any())
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))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
var subProtections = PerformExtractableCheck(extractable!, file, exe, getProtections, includeDebug);
protections.Append(subProtections);
});
#endif
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>
#if NET20 || NET35
public Dictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
#else
public ConcurrentDictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
#endif
/// <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
#if NET20 || NET35
var protections = new Dictionary<INewExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<INewExecutableCheck, string>();
#endif
// If we have an invalid extractable somehow
if (impl == null)
return [];
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in NewExecutableCheckClasses)
#else
Parallel.ForEach(NewExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
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>
#if NET20 || NET35
public Dictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
#else
public ConcurrentDictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<IPortableExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<IPortableExecutableCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in PortableExecutableCheckClasses)
#else
Parallel.ForEach(PortableExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
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
@@ -583,7 +331,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>
@@ -592,7 +340,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;
}
}

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,35 +11,31 @@ 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);
(byte[]? fileContents, string? error) = archive.Extract(cfile.Key);
byte[]? fileContents = archive.Extract(cfile.Key, out string? error);
if (fileContents == null || !string.IsNullOrEmpty(error))
continue;
@@ -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/>

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
#if (NET452_OR_GREATER || NETCOREAPP) && WIN
using StormLibSharp;
#endif
@@ -13,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
// 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(), 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 (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
if (includeDebug) System.Console.WriteLine(ex);
}
}
return tempPath;
return true;
}
catch (Exception ex)
catch (System.Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
if (includeDebug) System.Console.WriteLine(ex);
return false;
}
#endif
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
#if (NET40_OR_GREATER || NETCOREAPP) && WIN
using LibMSPackN;
#endif
@@ -16,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 || 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(), 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 (Exception ex)
{
if (includeDebug) 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 (Exception ex)
catch (System.Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
if (includeDebug) System.Console.WriteLine(ex);
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;
}
}

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/>

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,61 +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;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
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/>

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/>

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/>
@@ -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

@@ -13,38 +13,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;
}
}

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,61 +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;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
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,61 +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;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
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

@@ -54,6 +54,14 @@ namespace BinaryObjectScanner.FileType
else if (fileContent.Contains("Please enter a valid registration number"))
protections.Add("CD-Key / Serial");
// Channelware
// Found in "README.TXT" in Redump entry 116358.
if (fileContent.Contains("This application is a Channelware-activated product."))
protections.Add("Channelware");
// Found in "Swr.dat" in the "TOYSTORY" installation folder from Redump entry 12354.
if (fileContent.Contains("cwsw.com/authts"))
protections.Add("Channelware");
// CopyKiller
// Found in "autorun.dat" in CopyKiller versions 3.62 and 3.64.
if (fileContent.Contains("CopyKiller CD-Protection V3.6x"))
@@ -100,8 +108,14 @@ namespace BinaryObjectScanner.FileType
protections.Add("MediaMax CD-3");
// phenoProtect
// Found in Redump entry 84082.
if (fileContent.Contains("phenoProtect"))
protections.Add("phenoProtect");
// Additional check to minimize overmatching.
if (fileContent.Contains("InstallSHIELD Software Coporation"))
// Found in Redump entry 102493.
if (fileContent.Contains("COPYPROTECTION_FAILEDR"))
protections.Add("phenoProtect");
// Rainbow Sentinel
// Found in "SENTW95.HLP" and "SENTINEL.HLP" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".
@@ -117,6 +131,11 @@ namespace BinaryObjectScanner.FileType
if (fileContent.Contains("Sentinel Driver Disk"))
protections.Add("Rainbow Sentinel");
// SafeCast
// Found in "AdlmLog.xml" in IA item game-programming-in-c-start-to-finish-2006 after installing "3dsMax8_Demo.zip".
if (fileContent.Contains("<NAME>SAFECAST</NAME>"))
protections.Add("SafeCast");
// SafeDisc
// TODO: Add better version parsing.
// Found in "Info.plist" in Redump entries 23983, 42762, 72713, 73070, and 89603.

View File

@@ -10,40 +10,35 @@ 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;
// 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(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;
}
}

View File

@@ -12,40 +12,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;
}
}

View File

@@ -10,40 +10,35 @@ namespace BinaryObjectScanner.FileType
public class WAD : 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);
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;
}
}

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

@@ -11,40 +11,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;
}
}

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,478 +0,0 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Dictionary;
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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
// Preprocess the list of files
files = files?.Select(f => f.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))?.ToList();
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in PathCheckClasses)
#else
Parallel.ForEach(PathCheckClasses, checkClass =>
#endif
{
var subProtections = checkClass?.PerformCheck(path, files);
if (subProtections != null)
AppendToDictionary(protections, path, subProtections);
#if NET20 || NET35
}
#else
});
#endif
return protections;
}
#endregion
#region Single Implementation Handlers
/// <summary>
/// Handle files based on an IDetectable implementation
/// </summary>
/// <param name="impl">IDetectable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="stream">Stream to scan the contents of</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Queue<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
#else
public static ConcurrentQueue<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
#endif
{
var protection = impl.Detect(stream, fileName, includeDebug);
return ProcessProtectionString(protection);
}
/// <summary>
/// Handle files based on an IExtractable implementation
/// </summary>
/// <param name="impl">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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(stream, fileName, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#endif
{
// 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
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#endif
{
// 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
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#endif
{
// 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
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#endif
{
// 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
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IPathCheck implementation
/// </summary>
/// <param name="impl">IPathCheck class representing the file type</param>
/// <param name="path">Path of the file or directory to check</param>
/// <returns>Set of protections in path, null on error</returns>
#if NET20 || NET35
private static Queue<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
#else
private static ConcurrentQueue<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
#endif
{
// If we have an invalid path
if (string.IsNullOrEmpty(path))
return null;
// Setup the output dictionary
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// 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>
#if NET20 || NET35
private static Queue<string>? ProcessProtectionString(string? protection)
#else
private static ConcurrentQueue<string>? ProcessProtectionString(string? protection)
#endif
{
// If we have an invalid protection string
if (string.IsNullOrEmpty(protection))
return null;
// Setup the output queue
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// If we have an indicator of multiple protections
if (protection!.Contains(";"))
{
var splitProtections = protection.Split(';');
protections.AddRange(splitProtections);
}
else
{
protections.Enqueue(protection);
}
return protections;
}
#endregion
}
}

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

@@ -1,7 +1,4 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
namespace BinaryObjectScanner.Interfaces
{
@@ -19,11 +16,7 @@ namespace BinaryObjectScanner.Interfaces
/// <param name="path">Path to check for protection indicators</param>
/// <param name="files">Enumerable of strings representing files in a directory</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use a content check instead, if possible</remarks>
#if NET20 || NET35
Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#else
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#endif
IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<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

@@ -2,15 +2,16 @@ using System.Collections.Generic;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
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;
@@ -50,9 +51,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;
}
/// <summary>

View File

@@ -6,10 +6,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;
@@ -28,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

@@ -1,49 +0,0 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// TODO: Add version checking, if possible
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Armadillo : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(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 .nicode section, if it exists
bool nicodeSection = pex.ContainsSection(".nicode", exact: true);
if (nicodeSection)
return "Armadillo";
// Loop through all "extension" sections -- usually .data1 or .text1
if (pex.SectionNames != null)
{
foreach (var sectionName in pex.SectionNames.Where(s => s != null && s.EndsWith("1")))
{
// Get the section strings, if they exist
var strs = pex.GetFirstSectionStrings(sectionName);
if (strs != null)
{
if (strs.Any(s => s.Contains("ARMDEBUG")))
return "Armadillo";
}
}
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

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;
@@ -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;
}
private string GetVersion(PortableExecutable pex)

View File

@@ -5,6 +5,7 @@ using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.zlib;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
@@ -12,10 +13,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;
@@ -50,14 +51,14 @@ 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;
return false;
// Determine which compression was used
bool zlib = pex.FindResourceByNamedType("99, 1").Any();
@@ -124,27 +125,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

@@ -5,10 +5,10 @@ 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;
@@ -27,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

@@ -0,0 +1,106 @@
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
using System.Collections.Generic;
using SabreTools.Matching;
using SabreTools.Matching.Content;
namespace BinaryObjectScanner.Packer
{
/// <summary>
/// .NET Reactor is a .NET obfuscator that was original released in 2004. https://web.archive.org/web/20040828162124/http://eziriz.com:80/
/// It is currently still being updated and supported. https://www.eziriz.com/dotnet_reactor.htm
/// While ProtectionID does detect .NET Reactor, it's currently unknown exactly how.
/// It seems to simply check for the string "<PrivateImplementationDetails>" in specific, and currently unknown, conditions but appears to be prone to false positives.
/// A "Demo/Nag Screen" version is available for free, and may be able to be used to make samples to improve detections. https://www.eziriz.com/reactor_download.htm
///
/// Resource that could be useful for extraction: https://github.com/SychicBoy/NETReactorSlayer
/// </summary>
public class DotNetReactor : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
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
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .text section, if it exists
if (pex.ContainsSection(".text"))
{
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
{
var matchers = new List<ContentMatchSet>
{
// 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"),
// 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)")
};
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
}
return null;
}
/// <inheritdoc/>
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
// TODO: Add extraction
return false;
}
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
@@ -9,7 +10,7 @@ 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)
@@ -37,7 +38,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;
@@ -74,9 +75,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

@@ -11,10 +11,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;
@@ -29,13 +29,13 @@ 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
{
// 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
@@ -44,9 +44,6 @@ namespace BinaryObjectScanner.Packer
.Where(b => b != null && b.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
.ToList();
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
for (int i = 0; i < resources.Count; i++)
{
try
@@ -58,7 +55,10 @@ namespace BinaryObjectScanner.Packer
// Create the temp filename
string tempFile = $"embedded_resource_{i}.bin";
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 resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
@@ -70,12 +70,12 @@ namespace BinaryObjectScanner.Packer
}
}
return tempPath;
return true;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
return false;
}
}
}

View File

@@ -6,10 +6,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;
@@ -31,9 +31,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

@@ -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;
@@ -31,9 +31,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

@@ -2,16 +2,18 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Serialization.Wrappers;
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)
@@ -27,7 +29,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;
@@ -53,9 +55,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)

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,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;
}
private string GetVersion(PortableExecutable pex)

View File

@@ -6,11 +6,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;
@@ -29,9 +29,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

@@ -7,10 +7,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;
@@ -47,9 +47,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 string GetVersion(PortableExecutable pex)

View File

@@ -5,10 +5,10 @@ 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;
@@ -31,9 +31,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.IO;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
@@ -14,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;
@@ -37,9 +36,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;
@@ -41,9 +41,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;
@@ -24,9 +24,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
// 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,9 +38,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 string GetVersion(PortableExecutable pex)

View File

@@ -4,11 +4,10 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
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;
@@ -18,7 +17,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";
@@ -45,9 +44,10 @@ 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;
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;
@@ -25,9 +25,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

@@ -9,14 +9,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;
@@ -63,9 +63,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)

View File

@@ -1,20 +1,13 @@
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;
@@ -33,52 +26,10 @@ namespace BinaryObjectScanner.Packer
}
/// <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 zipFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
if (!zipFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
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);
}
}
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,29 +1,26 @@
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;
// Check for the WinZip name string
// 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;
// If we didn't find it
if (!winZipNameFound)
@@ -38,7 +35,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;
@@ -63,67 +60,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>
/// <inheritdoc/>
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>
@@ -794,14 +744,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

@@ -5,6 +5,7 @@ using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Serialization.Wrappers;
using WiseUnpacker;
using WiseUnpacker.EWISE;
@@ -12,10 +13,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)
@@ -41,7 +42,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;
@@ -74,52 +75,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)
@@ -174,43 +159,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;
}
}

View File

@@ -23,7 +23,7 @@ namespace System
public class Progress<T> : IProgress<T> where T : EventArgs
{
/// <summary>The synchronization context captured upon construction. This will never be null.</summary>
private readonly SynchronizationContext _synchronizationContext;
private readonly SynchronizationContext? _synchronizationContext;
/// <summary>The handler specified to the constructor. This may be null.</summary>
private readonly Action<T>? _handler;
/// <summary>A cached delegate used to post invocation to the synchronization context.</summary>
@@ -73,7 +73,7 @@ namespace System
{
// Post the processing to the sync context.
// (If T is a value type, it will get boxed here.)
_synchronizationContext.Post(_invokeHandlers, value);
_synchronizationContext?.Post(_invokeHandlers, value);
}
}

View File

@@ -3,12 +3,13 @@ using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
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)
@@ -34,7 +35,7 @@ namespace BinaryObjectScanner.Protection
}
/// <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,10 +1,9 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -19,10 +18,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;
@@ -69,11 +68,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,9 +1,7 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
namespace BinaryObjectScanner.Protection
{
@@ -18,11 +16,7 @@ namespace BinaryObjectScanner.Protection
public class AlphaDVD : IPathCheck
{
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -41,10 +40,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.
@@ -71,6 +70,12 @@ namespace BinaryObjectScanner.Protection
{
if (strs.Any(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")))
return "Alpha-ROM";
// Found in "Uninstall.exe" in Redump entry 115358.
if (strs.Any(s => s.Contains("AlphaCheck.dat")))
return "Alpha-ROM";
}
// Get the overlay data, if it exists

View File

@@ -0,0 +1,60 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Armadillo was a license manager, packer, and DRM by "The Silicon Realm Toolworks": https://web.archive.org/web/20030203101931/http://www.siliconrealms.com/armadillo.shtml
/// They were later bought by Digital River, and updated their website: https://web.archive.org/web/20031203021152/http://www.siliconrealms.com/armadillo.shtml
/// A new updated version named "SoftwarePassport" was released: https://web.archive.org/web/20040423044529/http://siliconrealms.com/softwarepassport/popup.shtml
/// Later copy of the website, with SoftwarePassport being named instead of Armadillo: https://web.archive.org/web/20040804032608/http://www.siliconrealms.com/armadillo.shtml
/// It appears as though both Armadillo and SoftwarePassport were being released at the same time, possibly with Armadillo acting as the core component and SoftwarePassport being supplementary: https://web.archive.org/web/20050619013312/http://siliconrealms.com/srt-news.shtml
/// Digital River itself also advertised Armadillo at first: https://web.archive.org/web/20040116043029/http://www.digitalriver.com:80/corporate/solutions06.shtml
/// But then only advertised SoftwarePassport once it was released: https://web.archive.org/web/20040604065907/http://www.digitalriver.com/corporate/solutions06.shtml
/// </summary>
// TODO: Add extraction
// TODO: Add version checking, if possible
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Armadillo : 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 .nicode section, if it exists
bool nicodeSection = pex.ContainsSection(".nicode", exact: true);
if (nicodeSection)
return "Armadillo";
// Loop through all "extension" sections -- usually .data1 or .text1
if (pex.SectionNames != null)
{
foreach (var sectionName in pex.SectionNames.Where(s => s != null && s.EndsWith("1")))
{
// Get the section strings, if they exist
var strs = pex.GetFirstSectionStrings(sectionName);
if (strs != null)
{
if (strs.Any(s => s.Contains("ARMDEBUG")))
return "Armadillo";
}
}
}
return null;
}
/// <inheritdoc/>
public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug)
{
return false;
}
}
}

View File

@@ -1,9 +1,7 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
namespace BinaryObjectScanner.Protection
{
@@ -15,11 +13,7 @@ namespace BinaryObjectScanner.Protection
public class Bitpool : IPathCheck
{
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -31,13 +25,13 @@ namespace BinaryObjectScanner.Protection
// A set of 4 identically sized (within the same game, not between games), corrupted/padded files present in several games (Redump entries 31782 and 35476).
// Both examples with only having the first letter uppercase and as the whole file name being uppercase have been seen.
new(new List<PathMatch>
{
new(
[
new FilePathMatch("Crc_a"),
new FilePathMatch("Crc_b"),
new FilePathMatch("Crc_c"),
new FilePathMatch("Crc_d"),
}, "Bitpool"),
], "Bitpool"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);

View File

@@ -1,10 +1,8 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -40,10 +38,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;
@@ -132,11 +130,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<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

@@ -1,13 +1,11 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Models.PortableExecutable;
using SabreTools.Matching.Content;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -65,7 +63,7 @@ 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/>
@@ -99,7 +97,7 @@ namespace BinaryObjectScanner.Protection
}
/// <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();
@@ -143,7 +141,7 @@ namespace BinaryObjectScanner.Protection
}
/// <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;
@@ -184,11 +182,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
// TODO: Original had "CDCOPS.DLL" required and all the rest in a combined OR
var matchers = new List<PathMatchSet>
@@ -197,7 +191,7 @@ namespace BinaryObjectScanner.Protection
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
// Found in Redump entry 84517.
new(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new(new FilePathMatch("CDCOPS.DLL"), "CD-Cops"),
new(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
@@ -217,7 +211,7 @@ namespace BinaryObjectScanner.Protection
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
// Found in Redump entry 84517.
new(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new(new FilePathMatch("CDCOPS.DLL"), "CD-Cops"),
new(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),

View File

@@ -1,11 +1,9 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -23,10 +21,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;
@@ -57,11 +55,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<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

@@ -1,9 +1,8 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -26,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;
@@ -63,18 +62,14 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{
// TODO: Determine if there's any consistency in the naming of the additional AFP files.
// Found in every confirmed sample of CD-Lock, generally (but not always) appears to include markers relating to the additional AFP files present (Redump entries 24287 and 31615).
new(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
new(new FilePathMatch("CONFIG.AFP"), "CD-Lock"),
// There is also a "$$$$$$$$.$$$" file present on some discs, but it isn't known if this is directly related to CD-Lock (Redump entries 37788 and 43221).
};
@@ -90,7 +85,7 @@ namespace BinaryObjectScanner.Protection
// TODO: Determine if there's any consistency in the naming of the additional AFP files.
// Found in every confirmed sample of CD-Lock, generally (but not always) appears to include markers relating to the additional AFP files present (Redump entries 24287 and 31615).
new(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
new(new FilePathMatch("CONFIG.AFP"), "CD-Lock"),
// There is also a "$$$$$$$$.$$$" file present on some discs, but it isn't known if this is directly related to CD-Lock (Redump entries 37788 and 43221).
};

View File

@@ -1,9 +1,7 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
namespace BinaryObjectScanner.Protection
{
@@ -19,11 +17,7 @@ namespace BinaryObjectScanner.Protection
public class CDProtector : IPathCheck
{
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -1,14 +1,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Linq;
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;

View File

@@ -1,9 +1,7 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
namespace BinaryObjectScanner.Protection
{
@@ -14,11 +12,7 @@ namespace BinaryObjectScanner.Protection
public class CDX : IPathCheck
{
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
// TODO: Verify if these are OR or AND
var matchers = new List<PathMatchSet>

View File

@@ -2,6 +2,7 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
namespace BinaryObjectScanner.Protection
{

View File

@@ -1,10 +1,8 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -14,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;
@@ -55,11 +53,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -0,0 +1,115 @@
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Channelware was an online activation DRM.
///
/// Official websites:
///
/// https://web.archive.org/web/19980212121046/http://www.channelware.com/index.html
/// https://web.archive.org/web/20021002225705/http://cwsw.com/Home/default.asp
/// https://web.archive.org/web/20040101180929/http://www.netactive.com/Home/
///
/// TODO:
/// 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 : IExecutableCheck<PortableExecutable>, IPathCheck
{
/// <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;
// Found in "AbeWincw.dll" in Redump entry 116358 and in "TOYSGMcw.dll" in the "TOYSTORY" installation folder from Redump entry 12354.
var name = pex.ProductName;
if (name?.Equals("ChannelWare Utilities") == true)
return "Channelware";
// Found in "cwbrowse.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Browser Launcher") == true)
return "Channelware";
// Found in "cwuninst.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Launcher Uninstall Application") == true)
return "Channelware";
// Found in "cwbrowse.exe" in the "Channelware\CWBrowse" folder installed from Redump entry 116358.
if (name?.Equals("Channelware Authorization Server Browser Launcher") == true)
return "Channelware";
name = pex.FileDescription;
// Found in "cwuninst.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Launcher Uninstall") == true)
return "Channelware";
name = pex.LegalTrademarks;
// Found in "CWAuto.dll" and "Upgrader.exe" in the "TOYSTORY" installation folder from Redump entry 12354.
if (name?.Equals("Channelware") == true)
return "Channelware";
return null;
}
/// <inheritdoc/>
public IEnumerable<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entries 12354 and 116358.
new(new FilePathMatch("cwlaunch.hlp"), "Channelware"),
// Found in the "Channelware\CWBrowse" folder installed from Redump entry 116358, and in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwbrowse.exe"), "Channelware"),
// Found in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwuninst.exe"), "Channelware"),
new(new FilePathMatch("chanwr.ini"), "Channelware"),
new(new FilePathMatch("CWAuto.dll"), "Channelware"),
// Found in Redump entry 116358.
new(Path.Combine("CWare", "install.exe"), "Channelware"),
// Found in Redump entry 12354.
new(Path.Combine("cware", "Install.exe"), "Channelware"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entries 12354 and 116358.
new(new FilePathMatch("cwlaunch.hlp"), "Channelware"),
// Found in the "Channelware\CWBrowse" folder installed from Redump entry 116358, and in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwbrowse.exe"), "Channelware"),
// Found in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwuninst.exe"), "Channelware"),
new(new FilePathMatch("chanwr.ini"), "Channelware"),
new(new FilePathMatch("CWAuto.dll"), "Channelware"),
// Found in Redump entry 116358.
new(Path.Combine("CWare", "install.exe"), "Channelware"),
// Found in Redump entry 12354.
new(Path.Combine("cware", "Install.exe"), "Channelware"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

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