Compare commits

...

165 Commits

Author SHA1 Message Date
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
Matt Nadareski
66e8eb985c Bump version 2024-04-24 11:23:33 -04:00
Matt Nadareski
90223e6c94 Handle some warnings and messages 2024-04-24 11:16:03 -04:00
Matt Nadareski
2f2cf76d7b Update SabreTools.Printing 2024-04-24 11:15:51 -04:00
Matt Nadareski
558fee2200 Clean up using statements 2024-04-24 11:03:09 -04:00
Matt Nadareski
a82abc05ec Update packages 2024-04-24 11:01:10 -04:00
Matt Nadareski
74df37597a Slight cleanup to Scanner 2024-04-22 11:34:04 -04:00
Matt Nadareski
1581023c01 Update WiseUnpacker 2024-04-18 13:04:49 -04:00
Matt Nadareski
c0d1260656 Update UnshieldSharp 2024-04-18 12:58:32 -04:00
Matt Nadareski
969d103c2c Update packages 2024-04-18 12:48:44 -04:00
TheRogueArchivist
e5e3f3e3ef Add check for StarForce driver removal tool (#301) 2024-04-17 19:30:57 -04:00
Matt Nadareski
c1ee399262 Usings cleanup 2024-04-17 13:46:38 -04:00
Matt Nadareski
74ee9932a7 Update WrapperFactory a bit 2024-04-17 13:44:33 -04:00
Matt Nadareski
e70f8d7220 Reduce unncessary printing code 2024-04-17 13:41:00 -04:00
Matt Nadareski
ceba351372 Update packages 2024-04-17 13:38:14 -04:00
Matt Nadareski
ad4082c531 Forgot the name for playlist 2024-04-17 12:16:57 -04:00
Matt Nadareski
115ea02822 Update libraries 2024-04-17 12:12:01 -04:00
TheRogueArchivist
f876a4e4a6 Add RealArcade detection (#300) 2024-04-16 19:30:48 -04:00
TheRogueArchivist
be114f60d3 Fix WinZip SFX folders not being scanned (#299)
* Fix WinZip SFX folders not being scanned

Use PKZIP extraction to fix WinZip SFX extraction not extracting folders.

* Remove unneeded null check

* Add checks for incomplete zip entries
2024-04-15 00:18:00 -04:00
Matt Nadareski
b2594f8148 Update WiseUnpacker 2024-04-11 12:33:00 -04:00
TheRogueArchivist
f58ada3dde Fix Steam overmatch (#298) 2024-04-11 12:23:46 -04:00
TheRogueArchivist
bc4f07970d Minor Rainbow Sentinel improvements (#295) 2024-04-07 19:15:30 -04:00
Matt Nadareski
25d6822283 Bump version 2024-04-05 15:42:43 -04:00
Silent
3b22262c21 Update SecuROM v7 detection to correctly handle a partly stripped header (#297) 2024-04-04 15:00:09 -04:00
Matt Nadareski
314fc1e3fc Update SabreTools.Printing 2024-04-04 13:48:00 -04:00
Matt Nadareski
5742749dec Update packages 2024-04-04 12:12:52 -04:00
Silent
c55fffeb7b Fix a crash when a sharing violation occurs during --info (#296)
Prints an exception the same way GetInternalProtections
does.
2024-04-03 12:52:12 -07:00
TheRogueArchivist
e469dc38bf Fix Roxxe false positive (#294) 2024-04-02 21:57:23 -07:00
Matt Nadareski
553703c30e Bump version 2024-04-02 17:03:49 -04:00
Matt Nadareski
3fd093f9b4 Update packages 2024-04-02 16:37:02 -04:00
TheRogueArchivist
4946d4e7ff Add Roxxe detection (#293)
* Add Roxxe detection

* Fix Roxxe PR review comments
2024-04-01 09:14:13 -07:00
Matt Nadareski
491fc0f71c Bump version 2024-03-27 12:01:40 -04:00
Matt Nadareski
fe6627f1ba Update to WiseUnpacker 1.3.1 2024-03-25 22:43:34 -04:00
Matt Nadareski
edffa3c7cc Default to using net8.0 target for launch 2024-03-25 22:32:29 -04:00
Matt Nadareski
a66d62bfbc Remove version gate from UnshieldSharp in Test 2024-03-25 21:56:08 -04:00
Matt Nadareski
9321b8f221 Update to UnshieldSharp 1.7.3 2024-03-25 21:53:33 -04:00
Matt Nadareski
cd0863ac56 Ensure zlib inflateEnd is called 2024-03-25 21:34:38 -04:00
Matt Nadareski
24a73e8bfd Update README 2024-03-25 20:08:51 -04:00
Matt Nadareski
46eaa7db1e Fix errant formatting issues 2024-03-25 19:58:37 -04:00
TheRogueArchivist
0eab7fd555 Significantly update Rainbow Sentinel detections and notes (#290) 2024-03-25 16:57:29 -07:00
Matt Nadareski
dba476d8bb Create new extractable interfaces for each executable type 2024-03-25 19:55:16 -04:00
Matt Nadareski
b10b4d6658 Seek to beginning for Embedded Executable 2024-03-25 17:14:10 -04:00
Matt Nadareski
2959fdbe9a Fix zlib with init 2024-03-25 17:10:24 -04:00
Matt Nadareski
9c0d100c2a Set zlib totals (nw) 2024-03-25 17:06:17 -04:00
Matt Nadareski
03ca0faf2e Start fixing zlib implementation 2024-03-25 16:58:11 -04:00
Matt Nadareski
cbaf004e25 Seek to beginning of stream for CExe 2024-03-25 16:37:53 -04:00
Matt Nadareski
bbe4fb610c Correct assumption about directory separators 2024-03-25 16:16:55 -04:00
Matt Nadareski
650115f722 Replace SharpZipLib with ST.Compression 2024-03-25 15:00:42 -04:00
Matt Nadareski
1afcbe3182 Update packages 2024-03-25 14:41:20 -04:00
TheRogueArchivist
8aa90dbc49 Add FlexLM detection (#289) 2024-03-24 19:08:09 -07:00
Matt Nadareski
0781524669 Bump version 2024-03-16 11:16:00 -04:00
Matt Nadareski
3b3cb7a862 Case-insensitive hash comparisons 2024-03-15 21:22:48 -04:00
Matt Nadareski
810d20d95c Bump version 2024-03-14 13:20:30 -04:00
Matt Nadareski
de578511bf Fix type retrieval for all build types 2024-03-13 23:26:16 -04:00
Matt Nadareski
f1ec025950 Fix nulability warning 2024-03-12 16:54:49 -04:00
Matt Nadareski
0c58ecc548 Update packages 2024-03-12 16:53:12 -04:00
Matt Nadareski
d2a73a153b Unroll Linq statements to fix exceptions (fixes #287) 2024-03-10 22:27:18 -04:00
TheRogueArchivist
eae2e3366b Remove DBB Skeleton (#286)
DBB is now documented in DRML.
2024-03-06 08:15:06 -08:00
Matt Nadareski
afb04c99c0 Update packages 2024-03-06 11:08:22 -05:00
Matt Nadareski
1d3bd2f8b1 Use SabreTools.Hashing 2024-03-04 21:27:36 -05:00
TheRogueArchivist
3f52c24713 Move CopyKiller comments to DRML (#285) 2024-02-28 07:36:23 -08:00
Matt Nadareski
ae1417a343 Remove unnecessary commit setting 2024-02-27 17:17:04 -05:00
Matt Nadareski
871a3e6366 Add PR check workflow 2024-02-27 11:21:01 -05:00
Matt Nadareski
3457b807cb Remove GHA on pull request builds 2024-02-27 11:17:41 -05:00
Matt Nadareski
027f295d21 Remove unnecessary newline 2024-02-26 12:46:26 -05:00
Matt Nadareski
63e6d1e285 Add badges to README 2024-02-26 12:43:49 -05:00
Matt Nadareski
2193095f70 Change nupkg location 2024-02-26 12:42:55 -05:00
Matt Nadareski
074694298f Typo typo 2024-02-26 12:37:43 -05:00
Matt Nadareski
ce4d32b053 Forgot to add recursive here 2024-02-26 12:37:11 -05:00
Matt Nadareski
a25af3940c Add recursive checkout 2024-02-26 12:36:47 -05:00
Matt Nadareski
9d1a2db45a Migrate to GitHub Actions 2024-02-26 12:29:12 -05:00
Matt Nadareski
5cdf269a3e Bump version 2024-02-26 12:14:30 -05:00
TheRogueArchivist
b9d90ec35d Remove GetVersionFromSHA1Hash from SafeDisc (#284)
* Remove GetVersionFromSHA1Hash from SafeDisc.
* Minor SafeDisc comment cleanup.
2024-02-23 10:58:58 -08:00
Matt Nadareski
5fc1d3254d Remove outdated comments in build scripts 2024-02-21 19:24:33 -05:00
Matt Nadareski
d61bae8e61 Don't use the auto git hash 2024-02-21 00:04:16 -05:00
Matt Nadareski
f8f53869ae Fix build scripts, again 2024-02-20 23:22:10 -05:00
Matt Nadareski
f5146a6e35 osx-arm64 is such a pain 2024-02-20 22:48:12 -05:00
Matt Nadareski
faf96b9375 Wrong array 2024-02-20 22:10:51 -05:00
Matt Nadareski
2228e344f6 Or, not And 2024-02-20 21:53:52 -05:00
Matt Nadareski
9955bdcab1 Not all DLLs, oops 2024-02-20 21:47:59 -05:00
Matt Nadareski
4586d49a3f Use DLL filtering in publish scripts 2024-02-20 21:45:18 -05:00
Matt Nadareski
1f4e24452a Add non-DLL lists, not hooked up 2024-02-20 21:33:14 -05:00
Matt Nadareski
090bac4d59 Remove unbuildable runtime 2024-02-20 21:12:21 -05:00
Matt Nadareski
59bedf5fce Fix DLL bundling 2024-02-20 21:07:29 -05:00
Matt Nadareski
1bbc541957 Limit packing to just BOS library 2024-02-20 21:04:39 -05:00
Matt Nadareski
1bb0107ceb Remove net6.0 from AppVeyor, add win-x86 2024-02-20 21:03:28 -05:00
Matt Nadareski
10dad356cd Expand default and extended publish targets 2024-02-20 20:59:28 -05:00
Matt Nadareski
22b6971e51 Tabs lose this battle 2024-02-20 20:54:28 -05:00
Matt Nadareski
3203b56ef6 Update publish scripts 2024-02-20 20:51:59 -05:00
Matt Nadareski
d6db84152f Limit to MS-CAB to x86 until IntPtr issue resolved 2024-02-20 20:14:38 -05:00
Matt Nadareski
b7afad5a4a Enable MS-CAB extraction on at least x86 2024-02-20 19:59:43 -05:00
Matt Nadareski
9d6c53f631 Update build after submodule update 2024-02-20 18:45:37 -05:00
Matt Nadareski
aa7b02dfc3 Add libmspack4n and LessIO as submodlues 2024-02-20 18:44:51 -05:00
TheRogueArchivist
379ffaf61a Add more empty file checks for SafeDisc (#283) 2024-02-20 06:47:20 -08:00
TheRogueArchivist
1bdfccddbc Fix Hexalock false positive (#281) 2024-02-08 10:09:11 -08:00
Matt Nadareski
c83cdd590c Update libraries 2024-02-06 10:48:59 -05:00
Matt Nadareski
f4770374a7 Update copyright date 2024-02-06 10:44:36 -05:00
TheRogueArchivist
72880e93bc Add new Denuvo Anti-Cheat detections (#279) 2024-02-01 20:27:49 -08:00
TheRogueArchivist
6c9cd72948 Add CD-X notes (#278)
* Add CD-X notes

* Add additional note
2024-01-26 06:40:09 -08:00
TheRogueArchivist
2e71ef4635 Update CopyKiller detection and notes (WIP) (#277)
* Update CopyKiller detection and notes

* Cleanup Copykiller
2024-01-25 21:19:16 -08:00
TheRogueArchivist
04cd1098ea Improve CrypKey detection (#275)
* Improve CrypKey detection

* Add CrypKey file detections.
* Add new CrypKey executable detections.

* Fix CrypKey version parsing

* Address PR reviews

* Check for both "code" and "CODE" sections
2023-12-28 20:35:57 -08:00
TheRogueArchivist
e76ce64568 Update known versions for the first SafeDisc splash-screen (#274) 2023-12-25 17:31:09 -08:00
Matt Nadareski
8fe84abef3 Use more lenient file reading 2023-12-13 15:52:03 -05:00
TheRogueArchivist
1b1fa53547 Add small note about ProtectDISC using CSS (#272) 2023-12-01 21:28:21 -08:00
TheRogueArchivist
5019407f35 Add additional SafeDisc for Mac detections and notes (#271)
* Add additional SafeDisc for Mac detections and notes

* Slightly update notes

* Minor additions

* Update earliest known SafeDisc splash-screen version
2023-12-01 17:42:03 -08:00
Matt Nadareski
83ba19eccb Fix ancient .NET dictionary extensions 2023-11-29 13:13:27 -05:00
Matt Nadareski
936bf38521 Slight cleanup 2023-11-25 22:25:44 -05:00
TheRogueArchivist
f54b0d2bbb Add SafeDisc Splash-Screen detection and notes (#269)
* Add initial SafeDisc splash-screen scanning and notes

So far only SafeDisc 1 has been added.

* Further update SafeDisc splash screen notes

This gets part of the way through SafeDisc 2 at least

* Update SafeDisc splash-screen notes and detection up through SafeDisc 2

* Update splash-screen notes through SafeDisc 3

* Starting adding SafeDisc 4 splash-screen notes

* Finish adding SafeDisc 4 splash-screen support

* Update SafeDisc splash-screen notes

* oops

* oops again
2023-11-25 19:21:59 -08:00
122 changed files with 3330 additions and 2774 deletions

43
.github/workflows/build_nupkg.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Nuget Pack
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Pack
run: dotnet pack
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: 'Nuget Package'
path: 'BinaryObjectScanner/bin/Release/*.nupkg'
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: 'BinaryObjectScanner/bin/Release/*.nupkg'
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

53
.github/workflows/build_test.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Build Test
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
project: [Test]
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]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet publish ${{ matrix.project }}/${{ matrix.project }}.csproj -f ${{ matrix.framework }} -r ${{ matrix.runtime }} -c ${{ matrix.conf == 'Release' && 'Release -p:DebugType=None -p:DebugSymbols=false' || 'Debug'}} --self-contained true --version-suffix ${{ github.sha }} ${{ (startsWith(matrix.framework, 'net5') || startsWith(matrix.framework, 'net6') || startsWith(matrix.framework, 'net7') || startsWith(matrix.framework, 'net8')) && '-p:PublishSingleFile=true' || ''}}
- name: Archive build
run: zip -r ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip ${{ matrix.project }}/bin/${{ matrix.conf }}/${{ matrix.framework }}/${{ matrix.runtime }}/publish/
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}
path: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: ${{ matrix.project }}_${{ matrix.framework }}_${{ matrix.runtime }}_${{ matrix.conf }}.zip
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

17
.github/workflows/check_pr.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Build PR
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Build
run: dotnet build

6
.gitmodules vendored
View File

@@ -1,3 +1,9 @@
[submodule "BinaryObjectScanner/_EXTERNAL/stormlibsharp"]
path = BinaryObjectScanner/_EXTERNAL/stormlibsharp
url = https://github.com/robpaveza/stormlibsharp.git
[submodule "BinaryObjectScanner/_EXTERNAL/libmspack4n"]
path = BinaryObjectScanner/_EXTERNAL/libmspack4n
url = https://github.com/activescott/libmspack4n.git
[submodule "BinaryObjectScanner/_EXTERNAL/LessIO"]
path = BinaryObjectScanner/_EXTERNAL/LessIO
url = https://github.com/activescott/LessIO.git

2
.vscode/launch.json vendored
View File

@@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Test/bin/Debug/net6.0/Test.dll",
"program": "${workspaceFolder}/Test/bin/Debug/net8.0/Test.dll",
"args": [],
"cwd": "${workspaceFolder}/Test",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console

View File

@@ -12,7 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Developer Guide.md = Developer Guide.md
LICENSE = LICENSE
publish-nix.sh = publish-nix.sh
publish-win.bat = publish-win.bat
publish-win.ps1 = publish-win.ps1
README.md = README.md
EndProjectSection
EndProject

View File

@@ -3,19 +3,22 @@
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors> --> <!-- Can't be enabled because of external code -->
<Version>3.0.2</Version>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.1.14</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS0162;CS0612;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Protection scanning library</Description>
<Copyright>Copyright (c)2018-2023 Matt Nadareski</Copyright>
<Copyright>Copyright (c)2018-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/BinaryObjectScanner</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -23,26 +26,34 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<DefineConstants>$(DefineConstants);WIN</DefineConstants>
</PropertyGroup>
<!-- Exclude certain parts of external modules for .NET Framework 4.5.2 and above -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
**\AssemblyInfo.cs;
_EXTERNAL\LessIO\src\LessIO.Tests\**;
_EXTERNAL\libmspack4n\lib\**;
_EXTERNAL\libmspack4n\libmspack4ntest\**;
_EXTERNAL\stormlibsharp\lib\**;
_EXTERNAL\stormlibsharp\src\TestConsole\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- Exclude all external modules for .NET Framework 2.0, .NET Framework 3.5, .NET Framework 4.0, .NET Core and modern .NET -->
<PropertyGroup Condition="!$(TargetFramework.StartsWith(`net4`)) OR $(TargetFramework.StartsWith(`net40`))">
<!-- 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-`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\**;
_EXTERNAL\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND $(RuntimeIdentifier.StartsWith(`win-x86`))">
<Content Include="*.dll">
<Pack>true</Pack>
<PackagePath>contentFiles;content</PackagePath>
@@ -57,16 +68,14 @@
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="MinThreadingBridge" Version="0.11.2" />
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.2" />
<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.0" />
<PackageReference Include="UnshieldSharp" Version="1.7.1" />
<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.34.2" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<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`))">
@@ -74,12 +83,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Compression" Version="0.3.0" />
<PackageReference Include="SabreTools.IO" Version="1.3.0" />
<PackageReference Include="SabreTools.Matching" Version="1.3.0" />
<PackageReference Include="SabreTools.Models" Version="1.3.0" />
<PackageReference Include="SabreTools.Serialization" Version="1.3.0" />
<PackageReference Include="WiseUnpacker" Version="1.3.0" />
<PackageReference Include="SabreTools.Compression" Version="0.5.1" />
<PackageReference Include="SabreTools.Hashing" Version="1.2.0" />
<PackageReference Include="SabreTools.IO" Version="1.4.11" />
<PackageReference Include="SabreTools.Matching" Version="1.3.1" />
<PackageReference Include="SabreTools.Models" Version="1.4.8" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.7" />
<PackageReference Include="UnshieldSharp" Version="1.8.3" />
<PackageReference Include="WiseUnpacker" Version="1.4.2" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,5 @@
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner
{
@@ -8,20 +8,22 @@ 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)
{
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.SFFS: return new FileType.SFFS();
case SupportedFileType.Textfile: return new FileType.Textfile();
case WrapperType.AACSMediaKeyBlock: return new FileType.AACSMediaKeyBlock();
case WrapperType.BDPlusSVM: return new FileType.BDPlusSVM();
//case WrapperType.CIA: return new FileType.CIA();
case WrapperType.Executable: return new FileType.Executable();
case WrapperType.LDSCRYPT: return new FileType.LDSCRYPT();
//case WrapperType.N3DS: return new FileType.N3DS();
//case WrapperType.Nitro: return new FileType.Nitro();
case WrapperType.PlayJAudioFile: return new FileType.PLJ();
case WrapperType.RealArcadeInstaller: return new FileType.RealArcadeInstaller();
case WrapperType.RealArcadeMezzanine: return new FileType.RealArcadeMezzanine();
case WrapperType.SFFS: return new FileType.SFFS();
case WrapperType.Textfile: return new FileType.Textfile();
default: return null;
}
}
@@ -29,40 +31,40 @@ namespace BinaryObjectScanner
/// <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)
{
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();
case WrapperType.BFPK: return new FileType.BFPK();
case WrapperType.BSP: return new FileType.BSP();
case WrapperType.BZip2: return new FileType.BZip2();
case WrapperType.CFB: return new FileType.CFB();
//case WrapperType.CIA: return new FileType.CIA();
case WrapperType.GCF: return new FileType.GCF();
case WrapperType.GZIP: return new FileType.GZIP();
case WrapperType.InstallShieldArchiveV3: return new FileType.InstallShieldArchiveV3();
case WrapperType.InstallShieldCAB: return new FileType.InstallShieldCAB();
case WrapperType.MicrosoftCAB: return new FileType.MicrosoftCAB();
case WrapperType.MicrosoftLZ: return new FileType.MicrosoftLZ();
case WrapperType.MoPaQ: return new FileType.MPQ();
//case WrapperType.N3DS: return new FileType.N3DS();
//case WrapperType.NCF: return new FileType.NCF();
//case WrapperType.Nitro: return new FileType.Nitro();
case WrapperType.PAK: return new FileType.PAK();
case WrapperType.PFF: return new FileType.PFF();
case WrapperType.PKZIP: return new FileType.PKZIP();
//case WrapperType.PlayJAudioFile: return new FileType.PLJ();
//case WrapperType.Quantum: return new FileType.Quantum();
case WrapperType.RAR: return new FileType.RAR();
case WrapperType.SevenZip: return new FileType.SevenZip();
case WrapperType.SFFS: return new FileType.SFFS();
case WrapperType.SGA: return new FileType.SGA();
case WrapperType.TapeArchive: return new FileType.TapeArchive();
case WrapperType.VBSP: return new FileType.VBSP();
case WrapperType.VPK: return new FileType.VPK();
case WrapperType.WAD: return new FileType.WAD();
case WrapperType.XZ: return new FileType.XZ();
case WrapperType.XZP: return new FileType.XZP();
default: return null;
}
}

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}

View File

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

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}

View File

@@ -7,7 +7,9 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
#if NET40_OR_GREATER || NETCOREAPP
using System.Threading.Tasks;
#endif
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
@@ -43,7 +45,7 @@ namespace BinaryObjectScanner.FileType
get
{
contentCheckClasses ??= InitCheckClasses<IContentCheck>();
return contentCheckClasses ?? Enumerable.Empty<IContentCheck>();
return contentCheckClasses ?? [];
}
}
@@ -55,7 +57,7 @@ namespace BinaryObjectScanner.FileType
get
{
linearExecutableCheckClasses ??= InitCheckClasses<ILinearExecutableCheck>();
return linearExecutableCheckClasses ?? Enumerable.Empty<ILinearExecutableCheck>();
return linearExecutableCheckClasses ?? [];
}
}
@@ -67,7 +69,7 @@ namespace BinaryObjectScanner.FileType
get
{
msdosExecutableCheckClasses ??= InitCheckClasses<IMSDOSExecutableCheck>();
return msdosExecutableCheckClasses ?? Enumerable.Empty<IMSDOSExecutableCheck>();
return msdosExecutableCheckClasses ?? [];
}
}
@@ -79,7 +81,7 @@ namespace BinaryObjectScanner.FileType
get
{
newExecutableCheckClasses ??= InitCheckClasses<INewExecutableCheck>();
return newExecutableCheckClasses ?? Enumerable.Empty<INewExecutableCheck>();
return newExecutableCheckClasses ?? [];
}
}
@@ -91,7 +93,7 @@ namespace BinaryObjectScanner.FileType
get
{
portableExecutableCheckClasses ??= InitCheckClasses<IPortableExecutableCheck>();
return portableExecutableCheckClasses ?? Enumerable.Empty<IPortableExecutableCheck>();
return portableExecutableCheckClasses ?? [];
}
}
@@ -132,7 +134,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
@@ -529,7 +531,7 @@ namespace BinaryObjectScanner.FileType
return protections;
}
#endregion
#endregion
#region Initializers
@@ -537,17 +539,40 @@ namespace BinaryObjectScanner.FileType
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>() =>
InitCheckClasses<T>(typeof(Handler).Assembly) ?? Enumerable.Empty<T>();
InitCheckClasses<T>(Assembly.GetExecutingAssembly()) ?? [];
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>(Assembly assembly)
{
return assembly.GetTypes()?
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)?
.Select(t => (T?)Activator.CreateInstance(t))
.Cast<T>() ?? [];
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

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -42,10 +42,14 @@ namespace BinaryObjectScanner.FileType
{
try
{
// If we have a directory, skip it
// 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);
}

View File

@@ -1,10 +1,6 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
#if NET40_OR_GREATER || NETCOREAPP
using UnshieldSharp.Archive;
#endif
namespace BinaryObjectScanner.FileType
{
@@ -19,17 +15,13 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
#if NET20 || NET35
// Not supported for .NET Framework 2.0 or .NET Framework 3.5 due to library support
return null;
#else
try
{
// Create a temp output directory
@@ -37,16 +29,16 @@ namespace BinaryObjectScanner.FileType
Directory.CreateDirectory(tempPath);
UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file);
foreach (CompressedFile cfile in archive.Files.Select(kvp => kvp.Value))
foreach (var cfile in archive.Files)
{
try
{
string tempFile = Path.Combine(tempPath, cfile.FullPath!);
string tempFile = Path.Combine(tempPath, cfile.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
(byte[]? fileContents, string? error) = archive.Extract(cfile.FullPath!);
(byte[]? fileContents, string? error) = archive.Extract(cfile.Key);
if (fileContents == null || !string.IsNullOrEmpty(error))
continue;
@@ -68,7 +60,6 @@ namespace BinaryObjectScanner.FileType
if (includeDebug) Console.WriteLine(ex);
return null;
}
#endif
}
}
}

View File

@@ -2,9 +2,7 @@
using System.IO;
using System.Text.RegularExpressions;
using BinaryObjectScanner.Interfaces;
#if NET40_OR_GREATER || NETCOREAPP
using UnshieldSharp.Cabinet;
#endif
namespace BinaryObjectScanner.FileType
{
@@ -19,17 +17,13 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
#if NET20 || NET35
// Not supported for .NET Framework 2.0 or .NET Framework 3.5 due to library support
return null;
#else
// Get the name of the first cabinet file or header
var directory = Path.GetDirectoryName(file);
string noExtension = Path.GetFileNameWithoutExtension(file);
@@ -65,21 +59,21 @@ namespace BinaryObjectScanner.FileType
Directory.CreateDirectory(tempPath);
var cabfile = InstallShieldCabinet.Open(file);
if (cabfile == null)
if (cabfile?.HeaderList == null)
return null;
for (int i = 0; i < cabfile.FileCount; i++)
for (int i = 0; i < cabfile.HeaderList.FileCount; i++)
{
try
{
// Check if the file is valid first
if (!cabfile.FileIsValid(i))
if (!cabfile.HeaderList.FileIsValid(i))
continue;
string tempFile;
try
{
string? filename = cabfile.FileName(i);
string? filename = cabfile.HeaderList.GetFileName(i);
tempFile = Path.Combine(tempPath, filename ?? string.Empty);
}
catch
@@ -102,7 +96,6 @@ namespace BinaryObjectScanner.FileType
if (includeDebug) Console.WriteLine(ex);
return null;
}
#endif
}
}
}

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NETFRAMEWORK && !NET20 && !NET35 && !NET40
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
using StormLibSharp;
#endif
@@ -18,7 +18,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -26,8 +26,9 @@ namespace BinaryObjectScanner.FileType
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
#if NET20 || NET35 || NET40 || NETCOREAPP || NET5_0_OR_GREATER
// Not supported for .NET Core and modern .NET due to Windows DLL requirements
#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;
#else
try

View File

@@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
using LibMSPackN;
#endif
namespace BinaryObjectScanner.FileType
{
@@ -18,16 +21,50 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, 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;
#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
foreach (var compressedFile in cabArchive.GetFiles())
{
try
{
string tempFile = Path.Combine(tempPath, compressedFile.Filename);
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
compressedFile.ExtractTo(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#endif
}
}
}

View File

@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -42,10 +42,18 @@ namespace BinaryObjectScanner.FileType
{
try
{
// If we have a directory, skip it
// 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 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))

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -42,11 +42,22 @@ namespace BinaryObjectScanner.FileType
{
try
{
// If we have a directory, skip it
// 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)

View File

@@ -0,0 +1,48 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// RealArcade Installer. Known to use the ".rgs" file extension.
///
/// TODO: Add further parsing, game ID and name should be possible to parse.
/// </summary>
public class RealArcadeInstaller : IDetectable
{
/// <inheritdoc/>
public string? Detect(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Detect(Stream stream, string file, bool includeDebug)
{
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
// RASGI2.0
// Found in the ".rgs" files in IA item "Nova_RealArcadeCD_USA".
if (magic.StartsWith(new byte?[] { 0x52, 0x41, 0x53, 0x47, 0x49, 0x32, 0x2E, 0x30 }))
return "RealArcade Installer";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// RealArcade Mezzanine files, which contain metadata. Known to use the ".mez" file extension.
///
/// TODO: Add further parsing, game ID should be possible to parse.
/// </summary>
public class RealArcadeMezzanine : IDetectable
{
/// <inheritdoc/>
public string? Detect(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Detect(Stream stream, string file, bool includeDebug)
{
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
// XZip2.0
// Found in the ".mez" files in IA item "Nova_RealArcadeCD_USA".
if (magic.StartsWith(new byte?[] { 0x58, 0x5A, 0x69, 0x70, 0x32, 0x2E, 0x30 }))
return "RealArcade Mezzanine";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Detect(fs, file, includeDebug);
}
@@ -48,7 +48,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -3,9 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using ICSharpCode.SharpZipLib.Zip.Compression;
#endif
using SabreTools.Compression.zlib;
namespace BinaryObjectScanner.FileType
{
@@ -20,7 +18,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -230,15 +228,26 @@ namespace BinaryObjectScanner.FileType
}
else
{
// Decompress the data
#if NET462_OR_GREATER || NETCOREAPP
// Inflate the data into the buffer
var zstream = new ZLib.z_stream_s();
data = new byte[outputFileSize];
Inflater inflater = new Inflater();
inflater.SetInput(compressedData);
inflater.Inflate(data);
#else
data = new byte[outputFileSize];
#endif
unsafe
{
fixed (byte* payloadPtr = compressedData)
fixed (byte* dataPtr = data)
{
zstream.next_in = payloadPtr;
zstream.avail_in = (uint)compressedData.Length;
zstream.total_in = (uint)compressedData.Length;
zstream.next_out = dataPtr;
zstream.avail_out = (uint)data.Length;
zstream.total_out = 0;
ZLib.inflateInit_(zstream, ZLib.zlibVersion(), compressedData.Length);
int zret = ZLib.inflate(zstream, 1);
ZLib.inflateEnd(zstream);
}
}
}
// If we have an invalid output directory

View File

@@ -19,13 +19,16 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
if (stream == null)
return null;
#if NET462_OR_GREATER || NETCOREAPP
try
{
@@ -39,11 +42,22 @@ namespace BinaryObjectScanner.FileType
{
try
{
// If we have a directory, skip it
// 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)

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
@@ -42,11 +42,23 @@ namespace BinaryObjectScanner.FileType
{
try
{
// If we have a directory, skip it
// 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;
// TODO: Fix bug with extracting folders from tar.
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)

View File

@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Detect(fs, file, includeDebug);
}
@@ -54,6 +54,28 @@ 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"))
protections.Add("CopyKiller V3.62-V3.64");
// Found in "autorun.dat" in CopyKiller versions 3.99 and 3.99a.
else if (fileContent.Contains("CopyKiller V4 CD / DVD-Protection"))
protections.Add("CopyKiller V3.99+");
// Found in "engine.wzc" in CopyKiller versions 3.62 and 3.64.
else if (fileContent.Contains("CopyKiller V3.6x Protection Engine"))
protections.Add("CopyKiller V3.62-V3.64");
// Found in "engine.wzc" in CopyKiller versions 3.99 and 3.99a.
else if (fileContent.Contains("CopyKiller V3.99x Protection Engine"))
protections.Add("CopyKiller V3.99+");
// Freelock
// Found in "FILE_ID.DIZ" distributed with Freelock.
if (fileContent.Contains("FREELOCK 1.0"))
@@ -86,18 +108,51 @@ 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]".
if (fileContent.Contains("Rainbow Sentinel Driver Help"))
protections.Add("Rainbow Sentinel");
// Found in "\disc4\cad\sdcc_200.zip\DISK1\_USER1.HDR\Language_Independent_Intel_32_Files\SNTNLUSB.INF" in "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
if (fileContent.Contains("SNTNLUSB.SvcDesc=\"Rainbow Security Device\""))
protections.Add("Rainbow Sentinel USB Driver");
if (fileContent.Contains("SntUsb95.SvcDesc=\"Rainbow Security Device\""))
protections.Add("Rainbow Sentinel USB Driver");
// Found in "OEMSETUP.INF" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".
if (fileContent.Contains("Sentinel Driver Disk"))
protections.Add("Rainbow Sentinel");
// SafeDisc
// TODO: Add better version parsing.
// Found in "Info.plist" in Redump entries 23983, 42762, 72713, 73070, and 89603.
if (fileContent.Contains("<string>com.europevisionmacro.SafeDiscDVD</string>"))
{
if (fileContent.Contains("<string>2.90.032</string>"))
protections.Add("SafeDiscDVD for Macintosh 2.90.032");
else
protections.Add("SafeDiscDVD for Macintosh (Unknown Version - Please report to us on GitHub)");
}
// Found in "Info.plist" in Redump entry 89649.
if (fileContent.Contains("<string>com.macrovisioneurope.SafeDiscLT</string>"))
{
// TODO: Investigate why "CFBundleGetInfoString" and "CFBundleShortVersionString" say version 2.70.020, but "CFBundleVersion" says version 2.70.010.
if (fileContent.Contains("<string>2.70.020</string"))
protections.Add("SafeDiscLT for Macintosh 2.70.020");
else
protections.Add("SafeDiscLT for Macintosh (Unknown Version - Please report to us on GitHub)");
}
// The full line from a sample is as follows:
//
// The files securom_v7_01.dat and securom_v7_01.bak have been created during the installation of a SecuROM protected application.

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO;
using SabreTools.IO.Extensions;
namespace BinaryObjectScanner.FileType
{
@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
@@ -124,7 +124,7 @@ namespace BinaryObjectScanner.FileType
try
{
// Open the archive
archiveStream = File.OpenRead(archiveFileName);
archiveStream = File.Open(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Seek to the data
archiveStream.Seek(directoryItem.DirectoryEntry.EntryOffset, SeekOrigin.Begin);

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -18,7 +18,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}

View File

@@ -16,7 +16,7 @@ namespace BinaryObjectScanner.FileType
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return Extract(fs, file, includeDebug);
}

View File

@@ -9,6 +9,7 @@ using System.Reflection;
using System.Threading.Tasks;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Dictionary;
namespace BinaryObjectScanner
@@ -62,7 +63,7 @@ namespace BinaryObjectScanner
#endif
// Preprocess the list of files
files = files?.Select(f => f.Replace('\\', '/'))?.ToList();
files = files?.Select(f => f.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))?.ToList();
// Iterate through all checks
#if NET20 || NET35
@@ -108,7 +109,7 @@ namespace BinaryObjectScanner
/// <summary>
/// Handle files based on an IExtractable implementation
/// </summary>
/// <param name="impl">IDetectable class representing the file type</param>
/// <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>
@@ -153,6 +154,198 @@ namespace BinaryObjectScanner
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>
@@ -204,16 +397,40 @@ namespace BinaryObjectScanner
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T?> InitCheckClasses<T>() =>
InitCheckClasses<T>(typeof(Handler).Assembly);
InitCheckClasses<T>(Assembly.GetExecutingAssembly());
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T?> InitCheckClasses<T>(Assembly assembly)
{
return assembly.GetTypes()?
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)?
.Select(t => (T?)Activator.CreateInstance(t)) ?? [];
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

View File

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,19 @@
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,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
@@ -8,7 +7,7 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class ASPack : IExtractable, IPortableExecutableCheck
public class ASPack : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -51,19 +50,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +6,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// TODO: Verify that all versions are detected
public class AdvancedInstaller : IExtractable, IPortableExecutableCheck
public class AdvancedInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -30,19 +28,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +7,7 @@ namespace BinaryObjectScanner.Packer
// TODO: Add extraction
// TODO: Add version checking, if possible
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Armadillo : IExtractable, IPortableExecutableCheck
public class Armadillo : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -42,19 +41,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +7,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class AutoPlayMediaStudio : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -34,19 +33,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -3,9 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using ICSharpCode.SharpZipLib.Zip.Compression;
#endif
using SabreTools.Compression.zlib;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
@@ -14,7 +12,7 @@ namespace BinaryObjectScanner.Packer
// The official website for CExe also includes the source code (which does have to be retrieved by the Wayback Machine)
// http://www.scottlu.com/Content/CExe.html
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class CExe : IExtractable, IPortableExecutableCheck
public class CExe : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -52,25 +50,10 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
try
{
// Parse into an executable again for easier extraction
var pex = PortableExecutable.Create(stream);
if (pex == null)
return null;
// Get the first resource of type 99 with index 2
var payload = pex.FindResourceByNamedType("99, 2").FirstOrDefault();
if (payload == null || payload.Length == 0)
@@ -88,16 +71,34 @@ namespace BinaryObjectScanner.Packer
try
{
// Inflate the data into the buffer
#if NET462_OR_GREATER || NETCOREAPP
Inflater inflater = new Inflater();
inflater.SetInput(payload);
var zstream = new ZLib.z_stream_s();
data = new byte[payload.Length * 4];
int read = inflater.Inflate(data);
unsafe
{
fixed (byte* payloadPtr = payload)
fixed (byte* dataPtr = data)
{
zstream.next_in = payloadPtr;
zstream.avail_in = (uint)payload.Length;
zstream.total_in = (uint)payload.Length;
zstream.next_out = dataPtr;
zstream.avail_out = (uint)data.Length;
zstream.total_out = 0;
ZLib.inflateInit_(zstream, ZLib.zlibVersion(), payload.Length);
int zret = ZLib.inflate(zstream, 1);
ZLib.inflateEnd(zstream);
}
}
// Trim the buffer to the proper size
data = new ReadOnlySpan<byte>(data, 0, read).ToArray();
uint read = zstream.total_out;
#if NET462_OR_GREATER || NETCOREAPP
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
#else
data = null;
var temp = new byte[read];
Array.Copy(data, 0, temp, 0, read);
data = temp;
#endif
}
catch
@@ -107,7 +108,7 @@ namespace BinaryObjectScanner.Packer
}
}
// Otherwise, LZ is used via the Windows API
// Otherwise, LZ is used
else
{
try

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
@@ -10,7 +9,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, IExtractable, IPortableExecutableCheck
public class EXEStealth : IContentCheck, IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
@@ -75,19 +74,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -11,7 +11,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class EmbeddedExecutable : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -29,25 +29,12 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
try
{
// Parse into an executable again for easier extraction
var pex = PortableExecutable.Create(stream);
if (pex?.ResourceData == null)
// If there are no resources
if (pex.ResourceData == null)
return null;
// Get the resources that have an executable signature
@@ -74,11 +61,8 @@ namespace BinaryObjectScanner.Packer
tempFile = Path.Combine(tempPath, tempFile);
// Write the resource data to a temp file
using (var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
if (tempStream != null)
tempStream.Write(data, 0, data.Length);
}
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(data, 0, data.Length);
}
catch (Exception ex)
{

View File

@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +6,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class GenteeInstaller : IExtractable, IPortableExecutableCheck
public class GenteeInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -33,19 +31,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -10,7 +9,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class HyperTechCrackProof : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -32,19 +31,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
@@ -9,7 +8,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction - https://github.com/dscharrer/InnoExtract
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InnoSetup : IExtractable, INewExecutableCheck, IPortableExecutableCheck
public class InnoSetup : IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
@@ -54,19 +53,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -7,7 +6,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class InstallAnywhere : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -29,19 +28,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +6,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction - https://github.com/Bioruebe/UniExtract2
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InstallerVISE : IExtractable, IPortableExecutableCheck
public class InstallerVISE : IExtractablePortableExecutable, IPortableExecutableCheck
{
//TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds.
/// <inheritdoc/>
@@ -31,19 +29,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,12 +1,11 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, seems to primarily use MSZip compression.
public class IntelInstallationFramework : IExtractable, IPortableExecutableCheck
public class IntelInstallationFramework : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -34,19 +33,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +7,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class MicrosoftCABSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -48,23 +47,11 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
private string GetVersion(PortableExecutable pex)
{
// Check the internal versions

View File

@@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -7,7 +5,7 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class NSIS : IExtractable, IPortableExecutableCheck
public class NSIS : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -33,19 +31,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -14,7 +14,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class NeoLite : IExtractablePortableExecutable, IPortableExecutableCheck
{
// TODO: Find samples of NeoLite 1.X.
/// <inheritdoc/>
@@ -37,20 +37,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
// TODO: Add extraction
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,12 +1,11 @@
using System.IO;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Better version detection - https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
// TODO: Add extraction
public class PECompact : IExtractable, IPortableExecutableCheck
public class PECompact : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -42,19 +41,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,12 +1,11 @@
using System.IO;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class PEtite : IExtractable, IPortableExecutableCheck
public class PEtite : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -25,19 +24,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -8,7 +7,7 @@ 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 : IExtractable, IPortableExecutableCheck
public class SetupFactory : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -39,23 +38,11 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
private string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly

View File

@@ -1,12 +1,17 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class SevenZipSFX : IExtractable, IPortableExecutableCheck
public class SevenZipSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -46,21 +51,59 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
#if NET462_OR_GREATER || NETCOREAPP
try
{
return Extract(fs, file, includeDebug);
}
}
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
foreach (var entry in sevenZipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -1,4 +1,3 @@
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
@@ -6,7 +5,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class Shrinker : IExtractable, IPortableExecutableCheck
public class Shrinker : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -26,19 +25,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
@@ -10,7 +9,7 @@ namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class UPX : IExtractable, IPortableExecutableCheck
public class UPX : IExtractablePortableExecutable, IPortableExecutableCheck
{
private static readonly Regex _oldUpxVersionMatch = new Regex(@"\$Id: UPX (.*?) Copyright \(C\)", RegexOptions.Compiled);
@@ -64,19 +63,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -11,7 +11,7 @@ using SharpCompress.Readers;
namespace BinaryObjectScanner.Packer
{
public class WinRARSFX : IExtractable, IPortableExecutableCheck
public class WinRARSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -33,39 +33,40 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, 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 }))
using (RarArchive rarFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
if (!zipFile.IsComplete)
if (!rarFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in zipFile.Entries)
foreach (var entry in rarFile.Entries)
{
try
{
// If we have a directory, skip it
// 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)

View File

@@ -11,7 +11,7 @@ using SharpCompress.Archives.Zip;
namespace BinaryObjectScanner.Packer
{
public class WinZipSFX : IExtractable, INewExecutableCheck, IPortableExecutableCheck
public class WinZipSFX : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
@@ -20,10 +20,13 @@ namespace BinaryObjectScanner.Packer
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)
@@ -63,39 +66,47 @@ 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, bool includeDebug)
{
if (!File.Exists(file))
return null;
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
return Extract(fs, file, includeDebug);
}
public string? Extract(string file, NewExecutable nex, bool includeDebug)
=> Extract(file, includeDebug);
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
=> Extract(file, includeDebug);
/// <summary>
/// Handle common extraction between executable types
/// </summary>
public static string? Extract(string file, 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.
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (ZipArchive zipFile = ZipArchive.Open(file))
{
if (!zipFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in zipFile.Entries)
{
try
{
// If we have a directory, skip it
// If 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)
@@ -103,9 +114,9 @@ namespace BinaryObjectScanner.Packer
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
return tempPath;
}
catch (Exception ex)
{
@@ -122,7 +133,7 @@ namespace BinaryObjectScanner.Packer
/// </summary>
/// TODO: Reduce the checks to only the ones that differ between versions
/// TODO: Research to see if the versions are embedded elsewhere in these files
private string? GetNEHeaderVersion(NewExecutable nex)
private static string? GetNEHeaderVersion(NewExecutable nex)
{
#region 2.0 Variants
@@ -680,7 +691,7 @@ namespace BinaryObjectScanner.Packer
/// Get the version from the PE export directory table value combinations
/// </summary>
/// TODO: Research to see if the versions are embedded elsewhere in these files
private string? GetPEExportDirectoryVersion(PortableExecutable pex)
private static string? GetPEExportDirectoryVersion(PortableExecutable pex)
{
string sfxFileName = pex.Model.ExportTable?.ExportDirectoryTable?.Name ?? string.Empty;
uint sfxTimeDateStamp = pex.Model.ExportTable?.ExportDirectoryTable?.TimeDateStamp ?? uint.MaxValue;

View File

@@ -3,15 +3,16 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
using Wise = WiseUnpacker.WiseUnpacker;
using WiseUnpacker;
using WiseUnpacker.EWISE;
namespace BinaryObjectScanner.Packer
{
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class WiseInstaller : IExtractable, INewExecutableCheck, IPortableExecutableCheck
public class WiseInstaller : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
@@ -73,33 +74,138 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
public string? Extract(string file, NewExecutable nex, bool includeDebug)
{
if (!File.Exists(file))
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
try
{
return Extract(fs, file, includeDebug);
// 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;
}
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
return tempPath;
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
try
{
// Try to parse as a New Executable
var nex = NewExecutable.Create(stream);
if (nex != null)
return ExtractNewExecutable(nex, file, includeDebug);
// Get the matching PE format
var format = GetPEFormat(pex);
if (format == null)
return null;
// Try to parse as a Portable Executable
var pex = PortableExecutable.Create(stream);
if (pex != null)
return ExtractPortableExecutable(pex, file, includeDebug);
// Get the overlay data for easier reading
int overlayOffset = 0, dataStart = 0;
var overlayData = pex.OverlayData;
if (overlayData == null)
return null;
return null;
// Skip over the additional DLL name, if we expect it
if (format.Dll)
{
// Read the name length
byte dllNameLength = overlayData.ReadByte(ref overlayOffset);
dataStart++;
// Read the name, if it exists
if (dllNameLength != 0)
{
// Ignore the name for now
_ = overlayData.ReadBytes(ref overlayOffset, dllNameLength);
dataStart += dllNameLength;
// Named DLLs also have a DLL length that we ignore
_ = overlayData.ReadUInt32(ref overlayOffset);
dataStart += 4;
}
}
// Check if flags are consistent
if (!format.NoCrc)
{
// Unlike WiseUnpacker, we ignore the flag value here
_ = overlayData.ReadUInt32(ref overlayOffset);
}
// Ensure that we have an archive end
if (format.ArchiveEnd > 0)
{
overlayOffset = (int)(dataStart + format.ArchiveEnd);
int archiveEndLoaded = overlayData.ReadInt32(ref overlayOffset);
if (archiveEndLoaded != 0)
format.ArchiveEnd = archiveEndLoaded;
}
// Skip to the start of the archive
overlayOffset = (int)(dataStart + format.ArchiveStart);
// Skip over the initialization text, if we expect it
if (format.InitText)
{
int initTextLength = overlayData.ReadByte(ref overlayOffset);
_ = overlayData.ReadBytes(ref overlayOffset, initTextLength);
}
// Cache the current offset in the overlay as the "start of data"
int offsetReal = overlayOffset;
// If the first entry is PKZIP, we assume it's an embedded zipfile
var magic = overlayData.ReadBytes(ref overlayOffset, 4); overlayOffset -= 4;
bool pkzip = magic?.StartsWith(new byte?[] { (byte)'P', (byte)'K' }) ?? false;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// If we have PKZIP
if (pkzip)
{
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);
}
}
// 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 tempPath;
}
catch (Exception ex)
{
@@ -209,202 +315,5 @@ namespace BinaryObjectScanner.Packer
return null;
}
/// <summary>
/// Attempt to extract Wise data from a New Executable
/// </summary>
/// <param name="nex">New executable to check</param>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private string? ExtractNewExecutable(NewExecutable nex, string file, bool includeDebug)
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
try
{
// TODO: Try to find where the file data lives and how to get it
Wise unpacker = new Wise();
if (!unpacker.ExtractTo(file, tempPath))
{
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
return tempPath;
}
/// <summary>
/// Attempt to extract Wise data from a Portable Executable
/// </summary>
/// <param name="pex">Portable executable to check</param>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private string? ExtractPortableExecutable(PortableExecutable pex, string file, bool includeDebug)
{
try
{
// Get the matching PE format
var format = GetPEFormat(pex);
if (format == null)
return null;
// Get the overlay data for easier reading
int overlayOffset = 0, dataStart = 0;
var overlayData = pex.OverlayData;
if (overlayData == null)
return null;
// Skip over the additional DLL name, if we expect it
if (format.Dll)
{
// Read the name length
byte dllNameLength = overlayData.ReadByte(ref overlayOffset);
dataStart++;
// Read the name, if it exists
if (dllNameLength != 0)
{
// Ignore the name for now
_ = overlayData.ReadBytes(ref overlayOffset, dllNameLength);
dataStart += dllNameLength;
// Named DLLs also have a DLL length that we ignore
_ = overlayData.ReadUInt32(ref overlayOffset);
dataStart += 4;
}
}
// Check if flags are consistent
if (!format.NoCrc)
{
// Unlike WiseUnpacker, we ignore the flag value here
_ = overlayData.ReadUInt32(ref overlayOffset);
}
// Ensure that we have an archive end
if (format.ArchiveEnd > 0)
{
overlayOffset = dataStart + format.ArchiveEnd;
int archiveEndLoaded = overlayData.ReadInt32(ref overlayOffset);
if (archiveEndLoaded != 0)
format.ArchiveEnd = archiveEndLoaded;
}
// Skip to the start of the archive
overlayOffset = dataStart + format.ArchiveStart;
// Skip over the initialization text, if we expect it
if (format.InitText)
{
int initTextLength = overlayData.ReadByte(ref overlayOffset);
_ = overlayData.ReadBytes(ref overlayOffset, initTextLength);
}
// Cache the current offset in the overlay as the "start of data"
int offsetReal = overlayOffset;
// If the first entry is PKZIP, we assume it's an embedded zipfile
var magic = overlayData.ReadBytes(ref overlayOffset, 4); overlayOffset -= 4;
bool pkzip = magic?.StartsWith(new byte?[] { (byte)'P', (byte)'K' }) ?? false;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// If we have PKZIP
if (pkzip)
{
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);
}
}
// If we have DEFLATE -- TODO: Port implementation here or use DeflateStream
else
{
Wise unpacker = new Wise();
if (!unpacker.ExtractTo(file, tempPath))
{
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Class representing the properties of each recognized Wise installer format
/// </summary>
/// <see href="https://github.com/mnadareski/WiseUnpacker/blob/master/WiseUnpacker/FormatProperty.cs"/>
private class FormatProperty
{
/// <summary>
/// Offset to the executable data
/// </summary>
public int ExecutableOffset { get; set; }
/// <summary>
/// Indicates if this format includes a DLL at the start or not
/// </summary>
public bool Dll { get; set; }
/// <summary>
/// Offset within the data where the archive starts
/// </summary>
public int ArchiveStart { get; set; }
/// <summary>
/// Position in the archive head of the archive end
/// </summary>
public int ArchiveEnd { get; set; }
/// <summary>
/// Format includes initialization text
/// </summary>
public bool InitText { get; set; }
/// <summary>
/// Position of the filename within the data
/// </summary>
public int FilenamePosition { get; set; }
/// <summary>
/// Format does not include a CRC
/// </summary>
public bool NoCrc { get; set; }
}
}
}

View File

@@ -1,13 +1,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class dotFuscator : IExtractable, IPortableExecutableCheck
public class dotFuscator : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -29,19 +27,7 @@ namespace BinaryObjectScanner.Packer
}
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

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

@@ -71,6 +71,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

@@ -7,6 +7,10 @@ using SabreTools.Matching;
namespace BinaryObjectScanner.Protection
{
// Nothing is currently known about this DRM. One program may possibly have included it, as it has been listed as including these files in the installion directory (https://www.advanceduninstaller.com/Visit-Gallery-2-90896afd3151ed9660dddc23b892863f-application.htm).
// Unfortunately, this program and developer are so obscure, I'm not able to find any relevant further information on them whatsoever.
// The only source of valuable information currently known is a forum post about a user attempting to crack this DRM (https://forum.p30world.com/showthread.php?t=413264).
// Every attachment, upload, or photo from the forum thread are offline and unarchived.
public class CDX : IPathCheck
{
/// <inheritdoc/>

View File

@@ -0,0 +1,121 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
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 : IPathCheck, 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;
// 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/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
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);
}
}
}

View File

@@ -1,32 +1,38 @@
#if NET40_OR_GREATER || NETCOREAPP
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
public class CopyKiller : IContentCheck, IPathCheck
/// <summary>
/// CopyKiller was a program made by WebStylerZone that allowed users to copy-protect their burned discs.
/// It worked by having users copy files with byte patterns that would create weak sectors to their discs to burn, and relied on drives with buggy firmwares to create bad burns of the discs.
/// This would result in discs having intentional bad sectors, making them harder to copy. There was also an optional autorun available that would check for the original CopyKiller files on the disc.
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/CopyKiller/CopyKiller.md"/>
/// TODO: Add support for the developer's EXE obfuscator, "EXEShield Deluxe". Most, if not all, EXEShield protected files are currently detected as "EXE Stealth" by BOS.
/// Samples include CopyKiller (Versions 3.64 & 3.99a) and SafeDiscScanner (Version 0.16) (https://archive.org/details/safediscscanner-0.16-webstylerzone-from-unofficial-source).
/// </summary>
public class CopyKiller : IPathCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
{
var contentMatchSets = new List<ContentMatchSet>
{
// Tom Commander
new(new byte?[]
{
0x54, 0x6F, 0x6D, 0x20, 0x43, 0x6F, 0x6D, 0x6D,
0x61, 0x6E, 0x64, 0x65, 0x72
}, "CopyKiller"),
};
// TODO: Figure out how to differentiate between V3.99 and V3.99a.
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
// TODO: Figure out why this check doesn't work.
// Found in "autorun.exe" in CopyKiller V3.64, V3.99, and V3.99a.
var name = pex.ProductName;
if (name?.StartsWith("CopyKiller", StringComparison.OrdinalIgnoreCase) == true)
return "CopyKiller V3.64+";
return null;
}
@@ -38,11 +44,43 @@ namespace BinaryObjectScanner.Protection
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
// TODO: The following checks are overly broad and should be refined
// TODO: Look into .PFF files as an indicator. At least one disc has those oversized files
// Previous versions of BOS noted to look at ".PFF" files as possible indicators of CopyKiller, but those files seem unrelated.
// TODO: Figure out why this doesn't work.
var matchers = new List<PathMatchSet>
{
//new(new PathMatch("Autorun.dat", useEndsWith: true), "CopyKiller"),
new(new FilePathMatch("CopyKillerV3"), "CopyKiller V3.62-3.64"),
new(new FilePathMatch("CopyKillerV4"), "CopyKiller V3.99-3.99a"),
new(new List<PathMatch>
{
new FilePathMatch("ACK3900.ckt"),
new FilePathMatch("ACK3999.ckt"),
new FilePathMatch("CK100.wzc"),
new FilePathMatch("CK2500.ck"),
new FilePathMatch("CK3600.tcwz"),
new FilePathMatch("Engine.wzc"),
new FilePathMatch("P261XP.tcck"),
new FilePathMatch("WZ200.rwzc"),
new FilePathMatch("XCK3900.ck2"),
}, "CopyKiller V3.99+"),
new(new List<PathMatch>
{
new FilePathMatch("ACK3900.ckt"),
new FilePathMatch("CK100.wzc"),
new FilePathMatch("CK2500.ck"),
new FilePathMatch("CK3600.tcwz"),
new FilePathMatch("Engine.wzc"),
new FilePathMatch("P261XP.tcck"),
new FilePathMatch("WZ200.rwzc"),
new FilePathMatch("XCK3900.ck2"),
}, "CopyKiller V3.64+"),
new(new List<PathMatch>
{
new FilePathMatch("CK100.wzc"),
new FilePathMatch("Engine.wzc"),
}, "CopyKiller V3.62+"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
@@ -51,11 +89,12 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
// TODO: The following checks are overly broad and should be refined
// TODO: Look into .PFF files as an indicator. At least one disc has those oversized files
// Previous versions of BOS noted to look at ".PFF" files as possible indicators of CopyKiller, but those files seem unrelated.
// TODO: Figure out why this doesn't work.
var matchers = new List<PathMatchSet>
{
//new(new PathMatch("Autorun.dat", useEndsWith: true), "CopyKiller"),
new(new FilePathMatch("CopyKillerV3"), "CopyKiller V3.62-3.64"),
new(new FilePathMatch("CopyKillerV4"), "CopyKiller V3.99-3.99a"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -1,4 +1,10 @@
using BinaryObjectScanner.Interfaces;
#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.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -7,7 +13,7 @@ namespace BinaryObjectScanner.Protection
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/CrypKey%20Installer.1.sg
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/CrypKey.2.sg
// https://github.com/wolfram77web/app-peid/blob/master/userdb.txt
public class CrypKey : IPortableExecutableCheck
public class CrypKey : IPathCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
@@ -17,6 +23,26 @@ namespace BinaryObjectScanner.Protection
if (sections == null)
return null;
// Get the code/CODE section strings, if they exist
var strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
if (strs != null)
{
// Found in "NECRO95.EXE" in IA item "NBECRORV11".
// Full string:
// *CrypKey Instant 2.0 security i(32 - bit) *
// *Copyright(c) 1996 Kenonic Controls Ltd. *
if (strs.Any(s => s.Contains("CrypKey Instant 2.0 security")))
return "CrypKey Instant 2.0";
// Generic check to catch unknown CrypKey Instant versions.
if (strs.Any(s => s.Contains("CrypKey Instant")))
return "CrypKey Instant (Unknown version - Please report to us on GitHub)";
// Generic check to catch unknown CrypKey products.
if (strs.Any(s => s.Contains("CrypKey")))
return "CrypKey (Unknown version - Please report to us on GitHub)";
}
// Get the CrypKey version from the VersionInfo, if it exists
string version = pex.GetVersionInfoString("CrypKey Version") ?? string.Empty;
@@ -24,9 +50,14 @@ namespace BinaryObjectScanner.Protection
var name = pex.CompanyName;
if (name?.StartsWith("CrypKey") == true)
return $"CrypKey {version}".TrimEnd();
name = pex.FileDescription;
// Found in "CKSEC_32.DLL" in IA item "NBECRORV11".
if (name?.StartsWith("CrypKey Instant security library") == true)
return $"CrypKey Instant {pex.GetInternalVersion()}";
// Found in 'cki32k.dll'
name = pex.FileDescription;
if (name?.StartsWith("CrypKey") == true)
return $"CrypKey {version}".TrimEnd();
@@ -43,5 +74,41 @@ namespace BinaryObjectScanner.Protection
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Found in IA item "NBECRORV11".
new(new FilePathMatch("CKLICENS.HLP"), "CrypKey"),
new(new FilePathMatch("CKSEC_32.DLL"), "CrypKey"),
new(new FilePathMatch("CRYP95.DLL"), "CrypKey"),
new(new FilePathMatch("CRYP9516.DLL"), "CrypKey"),
new(new FilePathMatch("CRYPKEY.HLP"), "CrypKey"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in IA item "NBECRORV11".
new(new FilePathMatch("CKLICENS.HLP"), "CrypKey"),
new(new FilePathMatch("CKSEC_32.DLL"), "CrypKey"),
new(new FilePathMatch("CRYP95.DLL"), "CrypKey"),
new(new FilePathMatch("CRYP9516.DLL"), "CrypKey"),
new(new FilePathMatch("CRYPKEY.HLP"), "CrypKey"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,7 +0,0 @@
namespace BinaryObjectScanner.Protection
{
public class DBB
{
// TODO: Implement - http://web.archive.org/web/20040604233815/www.wkit.com/sites/wkit/setup/eng/index.asp
}
}

View File

@@ -51,10 +51,18 @@ namespace BinaryObjectScanner.Protection
if (name?.Equals("Denuvo Anti-Cheat Update Service", StringComparison.OrdinalIgnoreCase) == true)
return $"Denuvo Anti-Cheat";
// Found in "denuvo-anti-cheat-update-service-launcher.dll".
if (name?.Equals("Denuvo Anti-Cheat Update Service Launcher", StringComparison.OrdinalIgnoreCase) == true)
return $"Denuvo Anti-Cheat";
// Found in "denuvo-anti-cheat-runtime.dll".
if (name?.Equals("Denuvo Anti-Cheat Runtime", StringComparison.OrdinalIgnoreCase) == true)
return $"Denuvo Anti-Cheat";
// Found in "denuvo-anti-cheat-crash-report.exe".
if (name?.Equals("Denuvo Anti-Cheat Crash Report Tool", StringComparison.OrdinalIgnoreCase) == true)
return $"Denuvo Anti-Cheat";
// Data sourced from:
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/Denuvo%20protector.2.sg
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/_denuvoComplete.2.sg
@@ -274,6 +282,15 @@ namespace BinaryObjectScanner.Protection
// This file is a renamed copy of "denuvo-anti-cheat-update-service.exe" which is only seen in the folder of the main game executable after it has been run, but before Denuvo Anti-Cheat is finished installing.
new(new PathMatch("Denuvo Anti-Cheat Installer.exe", useEndsWith: true), "Denuvo Anti-Cheat"),
// Found in the Denuvo Anti-Cheat installer on their support website. (https://web.archive.org/web/20240130142033/https://support.codefusion.technology/anti-cheat/?l=ja&s=ac&e=2009)
new(new PathMatch("denuvo-anti-cheat-installer.zip", useEndsWith: true), "Denuvo Anti-Cheat"),
// Found in "denuvo-anti-cheat-installer.zip".
new(new PathMatch("Denuvo-Anti-Cheat_install_run_as_Admin.bat", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-crash-report.exe", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-crash-report.exe.config", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-update-service-launcher.dll", useEndsWith: true), "Denuvo Anti-Cheat"),
};
return MatchUtil.GetAllMatches(files, matchers, any: false);
@@ -293,6 +310,15 @@ namespace BinaryObjectScanner.Protection
// This file is a renamed copy of "denuvo-anti-cheat-update-service.exe" which is only seen in the folder of the main game executable after it has been run, but before Denuvo Anti-Cheat is finished installing.
new(new PathMatch("Denuvo Anti-Cheat Installer.exe", useEndsWith: true), "Denuvo Anti-Cheat"),
// Found in the Denuvo Anti-Cheat installer on their support website. (https://web.archive.org/web/20240130142033/https://support.codefusion.technology/anti-cheat/?l=ja&s=ac&e=2009)
new(new PathMatch("denuvo-anti-cheat-installer.zip", useEndsWith: true), "Denuvo Anti-Cheat"),
// Found in "denuvo-anti-cheat-installer.zip".
new(new PathMatch("Denuvo-Anti-Cheat_install_run_as_Admin.bat", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-crash-report.exe", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-crash-report.exe.config", useEndsWith: true), "Denuvo Anti-Cheat"),
new(new PathMatch("denuvo-anti-cheat-update-service-launcher.dll", useEndsWith: true), "Denuvo Anti-Cheat"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -0,0 +1,88 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// EA Anti Cheat is a kernel-level anti-cheat developed and used by EA. (https://www.ea.com/security/news/eaac-deep-dive).
/// List of games that contain EA Anti Cheat on Steam: https://steamdb.info/tech/AntiCheat/EA_AntiCheat/
///
/// An EasyAntiCheat installer is present in the file "EAAntiCheat.Installer.Tool.exe" found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
/// This could indicate that EasyAntiCheat is directly integrated into EA Anti Cheat.
///
/// The internal name appears to be "skyfall", as this is the Internal Name set to several EA Anti Cheat files, and the string "C:\dev\gitlab-runner\builds\r5uPUG7E\0\anticheat\skyfall\Build\Retail\EAAntiCheat.Installer.pdb" is present in "EAAntiCheat.Installer.Tool.exe".
/// </summary>
public class EAAntiCheat : IPathCheck, IPortableExecutableCheck
{
// TODO: Add support for detecting older versions, especially versions made before Easy Anti-Cheat was purchased by Epic Games.
/// <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;
var name = pex.FileDescription;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Contains("EA Anticheat"))
return "EA Anti Cheat";
name = pex.ProductName;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Contains("EA Anticheat"))
return "EA Anti Cheat";
name = pex.InternalName;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Equals("skyfall"))
return "EA Anti Cheat";
// TODO: Add check for "EA SPEAR AntiCheat Engineering" in ASN.1 certificate data. Found in files "EAAntiCheat.GameServiceLauncher.dll", "EAAntiCheat.GameServiceLauncher.exe", "EAAntiCheat.Installer.exe", and "preloader_l.dll".
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
new(new FilePathMatch("EAAntiCheat.cfg"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.dll"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.splash.png"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.Tool.exe"), "EA Anti Cheat"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
new(new FilePathMatch("EAAntiCheat.cfg"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.dll"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.splash.png"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.Tool.exe"), "EA Anti Cheat"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -113,9 +113,6 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
// Found to be the default name used in HexaLock AutoLock 4.5.
new(new FilePathMatch("Start_Here.exe"), "HexaLock AutoLock 4.5"),
// Found to be contained in HexaLock AutoLock 4.5 and 4.7.
new(new FilePathMatch("MFINT.DLL"), "HexaLock AutoLock"),
new(new FilePathMatch("MFIMP.DLL"), "HexaLock AutoLock"),

View File

@@ -63,20 +63,20 @@ namespace BinaryObjectScanner.Protection
new(new List<PathMatch>
{
#if NET20 || NET35
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQ2SETUP.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQSTART.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQ2SETUP.EXE")),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQSTART.EXE")),
#else
new(Path.Combine("BIN", "WIN32", "MQ2SETUP.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("BIN", "WIN32", "MQSTART.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("BIN", "WIN32", "MQ2SETUP.EXE")),
new(Path.Combine("BIN", "WIN32", "MQSTART.EXE")),
#endif
}, "LabelGate CD2 Media Player"),
// All of these are also found present on all known LabelGate CD2 releases, though an additional file "RESERVED.DAT" is found in the same directory in at least one release (Product ID SVWC-7185)
new(new List<PathMatch>
{
new(Path.Combine("MQDISC", "LICENSE.TXT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "MQDISC.INI").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "START.INI").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "LICENSE.TXT")),
new(Path.Combine("MQDISC", "MQDISC.INI")),
new(Path.Combine("MQDISC", "START.INI")),
}, "LabelGate CD2"),
};

View File

@@ -1,4 +1,11 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -16,12 +23,96 @@ namespace BinaryObjectScanner.Protection
if (sections == null)
return null;
// Found in "IsSvcInstDanceEJay7.dll" in IA item "computer200709dvd" (Dance eJay 7).
var name = pex.ProductName;
// Found in "IsSvcInstDanceEJay7.dll" in IA item "computer200709dvd" (Dance eJay 7).
if (name?.Equals("FLEXnet Activation Toolkit", StringComparison.OrdinalIgnoreCase) == true)
return $"FLEXnet";
return "FLEXnet";
// Found in "INSTALLS.EXE", "LMGR326B.DLL", "LMGRD.EXE", and "TAKEFIVE.EXE" in IA item "prog-17_202403".
if (name?.Equals("Globetrotter Software Inc lmgr326b Flexlm", StringComparison.OrdinalIgnoreCase) == true)
return $"FlexLM {pex.ProductVersion}";
// Generic case to catch unknown versions.
if (name?.Contains("Flexlm") == true)
return "FlexLM (Unknown Version - Please report to us on GitHub)";
name = pex.FileDescription;
// Found in "INSTALLS.EXE", "LMGR326B.DLL", "LMGRD.EXE", and "TAKEFIVE.EXE" in IA item "prog-17_202403".
if (name?.Equals("lmgr326b", StringComparison.OrdinalIgnoreCase) == true)
return $"FlexLM {pex.ProductVersion}";
name = pex.LegalTrademarks;
// Found in "INSTALLS.EXE", "LMGR326B.DLL", "LMGRD.EXE", and "TAKEFIVE.EXE" in IA item "prog-17_202403".
if (name?.Equals("Flexible License Manager,FLEXlm,Globetrotter,FLEXID", StringComparison.OrdinalIgnoreCase) == true)
return $"FlexLM {pex.ProductVersion}";
if (name?.Contains("FLEXlm") == true)
return $"FlexLM {pex.ProductVersion}";
name = pex.OriginalFilename;
// Found in "INSTALLS.EXE", "LMGR326B.DLL", "LMGRD.EXE", and "TAKEFIVE.EXE" in IA item "prog-17_202403".
// It isn't known why these various executables have the same original filename.
if (name?.Equals("lmgr326b.dll", StringComparison.OrdinalIgnoreCase) == true)
return $"FlexLM {pex.ProductVersion}";
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
// Found in "FLEXLM.CPL", "INSTALLS.EXE", "LMGR326B.DLL", "LMGRD.EXE", and "TAKEFIVE.EXE" in IA item "prog-17_202403".
if (strs.Any(s => s.Contains("FLEXlm License Manager")))
return "FlexLM";
}
return null;
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, IEnumerable{string})"/>
#if NET20 || NET35
internal Queue<string> FLEXNetCheckDirectoryPath(string path, IEnumerable<string>? files)
#else
internal ConcurrentQueue<string> FLEXNetDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Found in IA item "prog-17_202403".
new(new PathMatch("FlexLM-6.1F", useEndsWith: true), "FlexLM 6.1f"),
new(new PathMatch("FlexLM", useEndsWith: true), "FlexLM"),
new(new PathMatch("FLexLM_Licensing.wri", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGR326B.DLL", useEndsWith: true), "FlexLM"),
new(new PathMatch("FLEXLM.CPL", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGRD.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGRD95.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMUTIL.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("READFLEX.WRI", useEndsWith: true), "FlexLM"),
};
return MatchUtil.GetAllMatches(files, matchers, any: false);
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? FLEXNetCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in IA item "prog-17_202403".
new(new PathMatch("FlexLM-6.1F", useEndsWith: true), "FlexLM 6.1f"),
new(new PathMatch("FlexLM", useEndsWith: true), "FlexLM"),
new(new PathMatch("FLexLM_Licensing.wri", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGR326B.DLL", useEndsWith: true), "FlexLM"),
new(new PathMatch("FLEXLM.CPL", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGRD.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMGRD95.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("LMUTIL.EXE", useEndsWith: true), "FlexLM"),
new(new PathMatch("READFLEX.WRI", useEndsWith: true), "FlexLM"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -4,9 +4,9 @@ using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using SabreTools.Hashing;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Hashing;
namespace BinaryObjectScanner.Protection
{
@@ -47,8 +47,8 @@ namespace BinaryObjectScanner.Protection
// So far, every seemingly-randomly named EXE on RipGuard discs have a consistent hash.
if (fi.Length == 49_152)
{
var sha1 = GetFileSHA1(file);
if (sha1 == "6A7B8545800E0AB252773A8CD0A2185CA2497938")
var sha1 = HashTool.GetFileHash(file, HashType.SHA1);
if (string.Equals(sha1, "6A7B8545800E0AB252773A8CD0A2185CA2497938", StringComparison.OrdinalIgnoreCase))
return "RipGuard";
}
}

View File

@@ -5,9 +5,9 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.Hashing;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Hashing;
namespace BinaryObjectScanner.Protection
{
@@ -72,6 +72,10 @@ namespace BinaryObjectScanner.Protection
return "SafeDisc Lite";
if (strs.Any(s => s.Contains("LTDLL_Unwrap")))
return "SafeDisc Lite";
// Present in "Setup.exe" from the earlier "safedisc.exe" driver update provided by Macrovision.
if (strs.Any(s => s.Contains("Failed to get the DRVMGT.DLL Setup API address")))
return "Macrovision SecDrv Update Installer";
}
var name = pex.FileDescription;
@@ -79,14 +83,23 @@ namespace BinaryObjectScanner.Protection
if (name?.Equals("SafeDisc SRV Tool APP", StringComparison.OrdinalIgnoreCase) == true)
return $"SafeDisc SRV Tool APP {GetSafeDiscDiagExecutableVersion(pex)}";
// Present in "Setup.exe" from the later "safedisc.exe" driver update provided by Macrovision.
if (name?.Equals("Macrovision SecDrv Update", StringComparison.OrdinalIgnoreCase) == true)
return "Macrovision SecDrv Update Installer";
// Present on all "CLOKSPL.DLL" versions before SafeDisc 1.06.000. Found on Redump entries 61731 and 66004.
name = pex.ProductName;
if (name?.Equals("SafeDisc CDROM Protection System", StringComparison.OrdinalIgnoreCase) == true)
return "SafeDisc 1.00.025-1.01.044";
// Present in "Diag.exe" files from SafeDisc 4.50.000+.
else if (name?.Equals("SafeDisc SRV Tool APP", StringComparison.OrdinalIgnoreCase) == true)
return $"SafeDisc SRV Tool APP {GetSafeDiscDiagExecutableVersion(pex)}";
// Present in "Setup.exe" from the later "safedisc.exe" driver update provided by Macrovision.
if (name?.Equals("Macrovision SecDrv Update", StringComparison.OrdinalIgnoreCase) == true)
return "Macrovision SecDrv Update Installer";
// Present on all "CLOKSPL.EXE" versions before SafeDisc 1.06.000. Found on Redump entries 61731 and 66004.
// Only found so far on SafeDisc 1.00.025-1.01.044, but the report is currently left generic due to the generic nature of the check.
name = pex.FileDescription;
@@ -95,8 +108,12 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entries 20729 and 65569.
// Get the debug data
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Any() || pex.FindCodeViewDebugTableByPath("Safedisk").Any())
return "SafeDisc";
try
{
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Any() || pex.FindCodeViewDebugTableByPath("Safedisk").Any())
return "SafeDisc";
}
catch { }
// TODO: Investigate various section names:
// "STLPORT_" - Found in Redump entry 11638.
@@ -128,6 +145,14 @@ namespace BinaryObjectScanner.Protection
new(".icd", useEndsWith: true),
}, "SafeDisc 1/Lite"),
// Check for the original filename used for the SafeDisc splash-screens, new file names are used in later versions.
new(new List<PathMatch>
{
new FilePathMatch("00000001.TMP"),
new FilePathMatch("SPLSH16.BMP"),
new FilePathMatch("SPLSH256.BMP"),
}, "SafeDisc 1.00.025-1.01.044"),
new(new List<PathMatch>
{
new FilePathMatch("00000001.TMP"),
@@ -154,10 +179,21 @@ namespace BinaryObjectScanner.Protection
new FilePathMatch("secdrv.sys"),
}, "SafeDisc 1.45.011-1.50.020"),
// TODO: Research "splash16.bmp" and "splash256.bmp".
// Search for the splash screen files known to sometimes contain a generic SafeDisc splash-screen.
new(new FilePathMatch("00000000.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000000.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("0000040c.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("0000040c.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000407.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000407.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000409.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000409.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000809.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000809.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00001009.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00001009.256"), GetSafeDiscSplshVersion, "SafeDisc"),
// Found to be present in every version of SafeDisc, possibly every single release.
//new(new FilePathMatch("00000001.TMP"), GetSafeDisc00000001TMPVersion, "SafeDisc"),
// The file "00000001.TMP" is found in most, if not all, SafeDisc protected programs and is detected within the general Macrovision checks due to being used in other Macrovision DRM.
// Found in many versions of SafeDisc, beginning in 2.05.030 and being used all the way until the final version 4.90.010. It is not always present, even in versions it has been used in. Found in Redump entries 56319 and 72195.
new(new FilePathMatch("00000002.TMP"), "SafeDisc 2+"),
@@ -215,8 +251,20 @@ namespace BinaryObjectScanner.Protection
new(new FilePathMatch("00000001.LT1"), "SafeDisc Lite"),
new(new FilePathMatch("LTDLL.DLL"), "SafeDisc Lite"),
// Found on Redump entry 42762.
new(".SafeDiscDVD.bundle", "SafeDisc for Macintosh"),
// Found in Redump entries 23983, 42762, 72713, 73070, and 89603.
new(new FilePathMatch(".SafeDiscDVD.bundle"), "SafeDiscDVD for Macintosh"),
new(new FilePathMatch("SafeDiscDVD"), "SafeDiscDVD for Macintosh"),
// Found in Redump entries 42762 and 73070.
// These files, along with "00000001.TMP" as found in the same version of SafeDiscDVD, appear to be likely encrypted game executables and are multiple GB in size.
new(new FilePathMatch("00000001I.TMP"), "SafeDiscDVD for Macintosh"),
new(new FilePathMatch("00000001P.TMP"), "SafeDiscDVD for Macintosh"),
// Found in Redump entry 89649.
new(new FilePathMatch("SafeDiscLT.bundle"), "SafeDiscLT for Macintosh"),
new(new FilePathMatch("SafeDiscLT"), "SafeDiscLT for Macintosh"),
// TODO: Add SafeDisc detection for Redump entry 63769 once Mac executables are supported for scanning. It appears to contain the same "BoG_" string and version detection logic.
};
return MatchUtil.GetAllMatches(files, matchers, any: false);
@@ -231,10 +279,25 @@ namespace BinaryObjectScanner.Protection
new(new FilePathMatch("CLCD32.DLL"), GetSafeDiscCLCD32Version, "SafeDisc"),
new(new FilePathMatch("CLOKSPL.EXE"), GetSafeDiscCLOKSPLVersion, "SafeDisc"),
//new(new FilePathMatch("00000001.TMP"), GetSafeDisc00000001TMPVersion, "SafeDisc"),
// The file "00000001.TMP" is found in most, if not all, SafeDisc protected programs and is detected within the general Macrovision checks due to being used in other Macrovision DRM.
// Found in many versions of SafeDisc, beginning in 2.05.030 and being used all the way until the final version 4.90.010. It is not always present, even in versions it has been used in. Found in Redump entries 56319 and 72195.
new(new FilePathMatch("00000002.TMP"), "SafeDisc 2+"),
// TODO: Research "splash16.bmp" and "splash256.bmp".
// Search for the splash screen files known to sometimes contain a generic SafeDisc splash-screen.
new(new FilePathMatch("00000000.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000000.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("0000040c.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("0000040c.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000407.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000407.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000409.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000409.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000809.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00000809.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00001009.016"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("00001009.256"), GetSafeDiscSplshVersion, "SafeDisc"),
new(new FilePathMatch("DPLAYERX.DLL"), GetSafeDiscDPlayerXVersion, "SafeDisc"),
new(new FilePathMatch("drvmgt.dll"), GetSafeDiscDrvmgtVersion, "SafeDisc"),
@@ -292,8 +355,20 @@ namespace BinaryObjectScanner.Protection
new(new FilePathMatch("00000001.LT1"), "SafeDisc Lite"),
new(new FilePathMatch("LTDLL.DLL"), "SafeDisc Lite"),
// Found in Redump entry 42762.
new(".SafeDiscDVD.bundle", "SafeDisc for Macintosh"),
// Found in Redump entries 23983, 42762, 72713, 73070, and 89603.
new(new FilePathMatch(".SafeDiscDVD.bundle"), "SafeDiscDVD for Macintosh"),
new(new FilePathMatch("SafeDiscDVD"), "SafeDiscDVD for Macintosh"),
// Found in Redump entries 42762 and 73070.
// These files, along with "00000001.TMP" as found in the same version of SafeDiscDVD, appear to be likely encrypted game executables and are multiple GB in size.
new(new FilePathMatch("00000001I.TMP"), "SafeDiscDVD for Macintosh"),
new(new FilePathMatch("00000001P.TMP"), "SafeDiscDVD for Macintosh"),
// Found in Redump entry 89649.
new(new FilePathMatch("SafeDiscLT.bundle"), "SafeDiscLT for Macintosh"),
new(new FilePathMatch("SafeDiscLT"), "SafeDiscLT for Macintosh"),
// TODO: Add SafeDisc detection for Redump entry 63769 once Mac executables are supported for scanning. It appears to contain the same "BoG_" string and version detection logic.
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
@@ -305,8 +380,8 @@ namespace BinaryObjectScanner.Protection
return string.Empty;
// The hash of the file CLCD16.dll is able to provide a broad version range that appears to be consistent, but it seems it was rarely updated so these checks are quite broad.
var sha1 = GetFileSHA1(firstMatchedString);
return sha1 switch
var sha1 = HashTool.GetFileHash(firstMatchedString, HashType.SHA1);
return sha1?.ToUpperInvariant() switch
{
// Found in Redump entries 61731 and 66005.
"C13493AB753891B8BEE9E4E014896B026C01AC92" => "1.00.025-1.01.044",
@@ -328,8 +403,8 @@ namespace BinaryObjectScanner.Protection
return string.Empty;
// The hash of the file CLCD32.dll so far appears to be a solid indicator of version for versions it was used with. It appears to have been updated with every release, unlike its counterpart, CLCD16.dll.
var sha1 = GetFileSHA1(firstMatchedString);
return sha1 switch
var sha1 = HashTool.GetFileHash(firstMatchedString, HashType.SHA1);
return sha1?.ToUpperInvariant() switch
{
// Found in Redump entry 66005.
"BAD49BA0DEA041E85EF1CABAA9F0ECD822CE1376" => "1.00.025",
@@ -427,8 +502,8 @@ namespace BinaryObjectScanner.Protection
// The hash of every "CLOKSPL.EXE" correlates directly to a specific SafeDisc version.
var sha1 = GetFileSHA1(firstMatchedString);
return sha1 switch
var sha1 = HashTool.GetFileHash(firstMatchedString, HashType.SHA1);
return sha1?.ToUpperInvariant() switch
{
// Found in Redump entry 66005.
"DD131A7B988065764E2A0F20B66C89049B20A7DE" => "1.00.025",
@@ -542,7 +617,7 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entries 9718, 12885, and 37523.
156_160 => "1.07.000-1.11.000",
// File size checks for versions 1.2X+ are superceded by executable string checks, which are more accurate. For reference, the previously used file sizes are kept as comments.
// File size checks for versions 1.2X+ are superseded by executable string checks, which are more accurate. For reference, the previously used file sizes are kept as comments.
// 157,184 bytes corresponds to SafeDisc 1.20.000-1.20.001 (Redump entries 21154 and 37920).
// 163,382 bytes corresponds to SafeDisc 1.30.010 (Redump entries 31526 and 55080).
// 165,888 bytes corresponds to SafeDisc 1.35.000 (Redump entries 9617 and 49552).
@@ -552,6 +627,16 @@ namespace BinaryObjectScanner.Protection
// 138,752 bytes corresponds to SafeDisc 1.50.020 (Redump entries 28810 and 62935).
_ => "1",
// Hashes have not been found to be a reliable indicator for these files, and likely differ on a game-to-game basis. Some hashes were previously collected and are collected below:
// Found in Redump entry 41923.
// F7A57F83BDC29040E20FD37CD0C6D7E6B2984180" => "1.00.030",
// Found in Redump entries 3569 and 3570.
// "A8ED1613D47D1B5064300FF070484528EBB20A3B" => "1.11.000",
// It is not known which games these files are from.
// "ED680E9A13F593E7A80A69EE1035D956AB62212B" => "1.3x",
// "66D8589343E00FA3E11BBF462E38C6F502515BEA" => "1.30.010",
// "5751AE2EE805D31227CFE7680F3C8BE4AB8945A3" => "1.40",
};
}
@@ -564,12 +649,15 @@ namespace BinaryObjectScanner.Protection
// There are occasionaly inconsistencies, even within the well detected version range. This seems to me to mostly happen with later (3.20+) games, and seems to me to be an example of the SafeDisc distribution becoming more disorganized with time.
// Particularly interesting inconsistencies will be noted below:
// Redump entry 73786 has an EXE with a scrubbed version, a DIAG.exe with a version of 4.60.000, and a copy of drvmgt.dll belonging to version 3.10.020. This seems like an accidental(?) distribution of older drivers, as this game was released 3 years after the use of 3.10.020.
var sha1 = GetFileSHA1(firstMatchedString);
return sha1 switch
var sha1 = HashTool.GetFileHash(firstMatchedString, HashType.SHA1);
return sha1?.ToUpperInvariant() switch
{
// Found in Redump entry 102979.
"B858CB282617FB0956D960215C8E84D1CCF909C6" => "(Empty File)",
// Found in Redump entry 63488.
"DA39A3EE5E6B4B0D3255BFEF95601890AFD80709" => "(Empty File)",
// Found in Redump entries 29073 and 31149.
"33434590D7DE4EEE2C35FCC98B0BF141F422B26D" => "1.06.000",
@@ -655,7 +743,8 @@ namespace BinaryObjectScanner.Protection
"B824ED257946EEE93F438B25C855E9DDE7A3671A" => "2.90.010-2.90.040",
// Found in Redump entries 13230 and 68204.
"CDA56FD150C9E9A19D7AF484621352122431F029" => "3.10.020",
// SafeDisc 4+ is known to sometimes use old versions of drivers, such as in Redump entry 101261.
"CDA56FD150C9E9A19D7AF484621352122431F029" => "3.10.020/4+",
// Found in Redump entries 36511 and 74338.
"E5504C4C31561D38C1F626C851A8D06212EA13E0" => "3.15.010",
@@ -701,33 +790,148 @@ namespace BinaryObjectScanner.Protection
};
}
private string? GetVersionFromSHA1Hash(string sha1Hash)
internal static string? GetSafeDiscSplshVersion(string firstMatchedString, IEnumerable<string>? files)
{
return sha1Hash.ToLowerInvariant() switch
// Special thanks to TheMechasaur for combing through known SafeDisc games and cataloging the splash-screens used in them, making these detections possible.
if (string.IsNullOrEmpty(firstMatchedString) || !File.Exists(firstMatchedString))
return string.Empty;
var sha1 = HashTool.GetFileHash(firstMatchedString, HashType.SHA1);
switch (sha1?.ToUpperInvariant())
{
// dplayerx.dll
"f7a57f83bdc29040e20fd37cd0c6d7e6b2984180" => "1.00.030",
"a8ed1613d47d1b5064300ff070484528ebb20a3b" => "1.11.000",
"ed680e9a13f593e7a80a69ee1035d956ab62212b" => "1.3x",
"66d8589343e00fa3e11bbf462e38c6f502515bea" => "1.30.010",
"5751ae2ee805d31227cfe7680f3c8be4ab8945a3" => "1.40",
// Found in Redump entry 63488.
case "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709":
return "(Empty File)";
// secdrv.sys
"b64ad3ec82f2eb9fb854512cb59c25a771322181" => "1.11.000",
"ebf69b0a96adfc903b7e486708474dc864cc0c7c" => "1.40.004",
"f68a1370660f8b94f896bbba8dc6e47644d19092" => "2.30",
"60bc8c3222081bf76466c521474d63714afd43cd" => "2.40",
"08ceca66432278d8c4e0f448436b77583c3c61c8" => "2.50",
"10080eb46bf76ac9cf9ea74372cfa4313727f0ca" => "2.51",
"832d359a6de191c788b0e61e33f3d01f8d793d3c" => "2.70",
"afcfaac945a5b47712719a5e6a7eb69e36a5a6e0" or "cb24fbe8aa23a49e95f3c83fb15123ffb01f43f4" => "2.80",
"0383b69f98d0a9c0383c8130d52d6b431c79ac48" => "2.90",
"d7c9213cc78ff57f2f655b050c4d5ac065661aa9" => "3.20",
"fc6fedacc21a7244975b8f410ff8673285374cc2" => "4.00.002",// Also 4.60.000, might be a fluke
"2d9f54f35f5bacb8959ef3affdc3e4209a4629cb" => "1-4",
// First known generic SafeDisc splash-screen.
// 4-bit (16 color) version, found in Redump entries 43321, 45040, 45202, 66586, 68206, 75501, 79272, and 110603.
case "D8A8CF761DD7C04F635385E4C4589E5F26C6171E":
return "1.11.000-2.40.011";
// 8-bit (256 color) version, found in Redump entries 43321, 45040, 45202, 66586, 68206, 75501, 79272, and 110603.
case "0C9E45BF3EBE1382A3593994328C22BCB9A55456":
return "1.11.000-2.40.011";
_ => null,
};
// Second known generic SafeDisc splash-screen.
// 4-bit (16 color), found in Redump entries 46339 and 75897.
case "9B80F524D45041ED8CE1613AD5BDE94BFDBB2814":
return "2.70.030-2.80.010";
// 8-bit (256 color) version, found in Redump entries 46339 and 75897.
case "827AE9A32906CBE9098C9101184E0BE74CEA2744":
return "2.70.030-2.80.010";
// Third known generic SafeDisc splash-screen.
// 4-bit (16 color), found in Redump entries 74338, 75782, 84985, and 91552.
case "814ED63FD619655650E271D1B8B46BBE39C3655A":
return "3.15.010-3.20.022";
// 8-bit (256 color) version, found in Redump entries 31824, 74338, 75782, 84985, 91552, and 104053.
case "40C7ACEDB6C41AB067285090373E886EFB4F4AC4":
return "3.15.010-4.60.000";
default:
return null;
}
// There appear to be a few distinct generations of file names used for SafeDisc splash-screens.
// The first are the files named "SPLSH16.BMP"/"SPLSH256.BMP", which were typically used in SafeDisc versions 1.00.025-1.01.044.
// The next are the files named "000004XX", "000008XX", "00000cXX", and "00001XXX". When one of these is present, they seemingly always come in pairs of 2 with the extensions ".016" and ".256". They're typically present in SafeDisc versions 1.06.000-2.51.021.
// Next come the files simply named "0000000X", which still come in pairs with the extensions ".016" and ".256", starting in SafeDisc version 2.60.052 up until version 4.85.000. After this point, there doesn't seem to be any consistent SafeDisc splash-screen used at all.
// Starting SafeDisc version 4.00.000, the files with the ".016" extension seem to mostly disappear, with the ".256" files still being present.
// Exceptions:
// The files "00000409.016" and "00000409.256" are present in Redump entry 39273, despite it being SafeDisc 2.80.011. This may be because this disc contains some form of SafeDisc Lite as well, which tends to more closely resemble SafeDisc 1.
// Redump entry 51597 contains "00000000.016" and "00000000.256", breaking the trend of SafeDisc 4 not having any files with the ".016" extension. This may be due to this being a rerelease, so the splash-screen may have already been present in the original game files and carried over.
// TODO: Investigate "/409/splash.bmp" and "/0x0409.ini" files in Redump entry 45469.
// Known SafeDisc splash-screen file names (case-insensitive):
// "00000000.016": Found in SafeDisc version 2.60.052-4.00.003 (Redump entries 2064, 9621, 11639, 13230, 32783, 35385, 35512, 39273, 52606, 51597, 63813, 74338, 76775, and 84586).
// "00000000.256": Found in SafeDisc version 2.60.052-4.85.000 (Redump entries 2064, 9621, 11639, 13230, 32783, 34783, 35382, 35385, 35512, 39273, 46765, 52606, 51597, 63813, 68551, 71646, 74338, 74366, 76775, 76813, 79113, 83017, 84586, and 98589).
// "00000001.016": Found in SafeDisc version 2.72.000-3.20.024 (Redump entries 9621, 76775, and 86177).
// "00000001.256": Found in SafeDisc version 2.72.000-4.50.000 (Redump entries 9621, 71646, 76775, 76813, and 86177).
// "00000002.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000002.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000003.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000003.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000004.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000004.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000005.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000005.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000006.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000006.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000007.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000007.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000008.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000008.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000009.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000009.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000010.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000010.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000011.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000011.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000a.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000a.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000b.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000b.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000c.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000c.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000d.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000d.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000e.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000e.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000f.016": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "0000000f.256": Found in SafeDisc version 2.72.000 (Redump entry 9621).
// "00000404.016": Found in SafeDisc versions 1.40.004-1.50.020 (IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000404.256": Found in SafeDisc versions 1.40.004-1.50.020 (IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000406.016": Found in SafeDisc versions 1.41.000-2.51.021 (Redump entries 61047 and 66852).
// "00000406.256": Found in SafeDisc versions 1.41.000-2.51.021 (Redump entries 61047 and 66852).
// "00000407.016": Found in SafeDisc versions 1.07.000-2.51.021 (Redump entries 43321, 44350, 46756, 48863, 49552, 66586, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000407.256": Found in SafeDisc versions 1.07.000-2.51.021 (Redump entries 43321, 44350, 46756, 48863, 49552, 66586, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000408.016": Found in SafeDisc version 2.51.021 (Redump entry 38589).
// "00000408.256": Found in SafeDisc version 2.51.021 (Redump entry 38589).
// "00000409.016": Found in SafeDisc versions 1.06.000-2.80.011 (Redump entries 2022, 2595, 9718, 9819, 9846, 12885, 23786, 29073, 30022, 30555, 31526, 31666, 37832, 37920, 37982, 39273, 48863, 49552, 59462, 62935, and 63323).
// "00000409.256": Found in SafeDisc versions 1.06.000-2.80.011 (Redump entries 2022, 2595, 9718, 9819, 9846, 12885, 23786, 29073, 30022, 30555, 31526, 31666, 37982, 37920, 37832, 39273, 48863, 49552, 59462, 62935, and 63323).
// "0000040A.016": Found in SafeDisc versions 1.06.000-2.51.021 (Redump entries 29073, 43321, 49552, and 66852).
// "0000040A.256": Found in SafeDisc versions 1.06.000-2.51.021 (Redump entries 29073, 43321, 49552 and 66852).
// "0000040c.016": Found in SafeDisc versions 1.30.010-2.51.021 (Redump entries 43321, 48863, 49552, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "0000040c.256": Found in SafeDisc versions 1.30.010-2.51.021 (Redump entries 43321, 48863, 49552, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "0000040d.016": Found in SafeDisc version 2.51.021 (Redump entry 38589).
// "0000040d.256": Found in SafeDisc version 2.51.021 (Redump entry 38589).
// "0000040f.016": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "0000040f.256": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000410.016": Found in SafeDisc versions 1.35.000-2.51.021 (Redump entries 9617, 48863, 49552, 66852, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000410.256": Found in SafeDisc versions 1.35.000-2.51.021 (Redump entries 9617, 48863, 49552, 66852, and 79476, IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000411.016": Found in SafeDisc versions 1.40.004-2.51.031 (Redump entries 38589, 53659 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000411.256": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entries 38589, 53659 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000412.016": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entry 38589 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000412.256": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entry 38589 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000413.016": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entries 66852 and 72195 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000413.256": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entries 66852 and 72195 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000415.016": Found in SafeDisc versions 1.40.004-2.10.030 (Redump entry 38541 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000415.256": Found in SafeDisc versions 1.40.004-2.10.030 (Redump entry 38541 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000416.016": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entry 38589 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000416.256": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entry 38589 and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000419.016": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000419.256": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "0000041d.016": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entries 55823, 66852, and 72195, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "0000041d.256": Found in SafeDisc versions 1.40.004-2.51.021 (Redump entries 55823, 66852, and 72195, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "0000041e.016": Found in SafeDisc version 1.40.004 (IA item the-sims-thai-english-electronic-arts-2000).
// "0000041e.256": Found in SafeDisc version 1.40.004 (IA item the-sims-thai-english-electronic-arts-2000).
// "00000429.016": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000429.256": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000804.016": Found in SafeDisc versions 1.40.004-1.50.020 (IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000804.256": Found in SafeDisc versions 1.40.004-1.50.020 (IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000809.016": Found in SafeDisc versions 1.06.000-2.51.021 (Redump entries 9617, 31149, 37478, 37523, 37832, 43321, 48863, 53659, 59462, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000, the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000, and "primal-3d-interactive-series-professional-edition-2002-english" items "Interactive Hand CD", "Interactive Hip CD", and "Interactive Spine CD").
// "00000809.256": Found in SafeDisc versions 1.06.000-2.51.021 (Redump entries 9617, 31149, 37478, 37523, 37832, 43321, 48863, 53659, 59462, 66852, 72195, and 79476, and IA items the-sims-thai-english-electronic-arts-2000, the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000, and "primal-3d-interactive-series-professional-edition-2002-english" items "Interactive Hand CD", "Interactive Hip CD", and "Interactive Spine CD").
// "00000814.016": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000814.256": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000816.016": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000816.256": Found in SafeDisc version 1.41.000 (Redump entry 61047).
// "00000c0a.016": Found in SafeDisc versions 1.11.000-2.30.031 (Redump entry 3569, 48863, 55078, 55080, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00000c0a.256": Found in SafeDisc versions 1.11.000-2.30.031 (Redump entry 3569, 48863, 55078, 55080, and 79476, and IA items the-sims-thai-english-electronic-arts-2000 and the-sims-livin-large-expansion-pack-thai-english-electronic-arts-2000).
// "00001009.016": Found in SafeDisc version 2.30.030 (Redump entry 45040).
// "00001009.256": Found in SafeDisc version 2.30.030 (Redump entry 45040).
// "SPLSH16.BMP": Found in SafeDisc versions 1.00.025-1.01.044 (Redump entries 66005 and 81619).
// "SPLSH256.BMP": Found in SafeDisc versions 1.00.025-1.01.044 (Redump entries 66005 and 81619).
}
private string GetSafeDiscDiagExecutableVersion(PortableExecutable pex)

View File

@@ -7,7 +7,7 @@ namespace BinaryObjectScanner.Protection
/// It's used (to an unknown extent) within SafeCast and SafeDisc (https://web.archive.org/web/20030829044647/http://www.macrovision.com:80/solutions/software/SafeWrap_FAQ_July2003.pdf Section #3).
/// It can be used separately from any other Macrovision product, such as (supposedly) for RioPort (https://www.cdrinfo.com/d7/content/macrovision-invests-next-generation-security-and-transport-technologies-internet-delivery).
/// No direct SafeWrap only sample has currently been found, nor is it exactly clear what parts of SafeCast/SafeDisc are SafeWrap.
/// It's claimed that SafeWrap uses one DLL and one .SYS "security driver" (https://www.cdrinfo.com/d7/content/macrovision-invests-next-generation-security-and-transport-technologies-internet-delivery Section #30).
/// It's claimed that SafeWrap uses one DLL and one .SYS "security driver" (https://web.archive.org/web/20030829044647/http://www.macrovision.com:80/solutions/software/SafeWrap_FAQ_July2003.pdf Section #30).
/// This would appear to be referring to the "drvmgt.dll" and "secdrv.sys" files, the latter of which is officially referred to as the "Macrovision SECURITY Driver" in some SafeDisc versions.
/// This may not be fully accurate, as not all of these files are known to always be used with SafeCast, though this does need further investigation.
/// The .stxt* sections found in various Macrovision products may indicate SafeWrap, as they started being used around the time that SafeWrap was made public.
@@ -18,13 +18,17 @@ namespace BinaryObjectScanner.Protection
///
/// Further information and resources:
/// Macrovision press release that mentions SafeWrap: https://www.sec.gov/Archives/edgar/data/1027443/000100547701501658/ex99-1.txt
/// Macrionvision "Tamper-proof" blurb advertising SafeWrap: https://web.archive.org/web/20030412093353/http://www.macrovision.com/solutions/software/tamper.php3
/// SafeAudio news that mentions SafeWrap: https://www.cdmediaworld.com/hardware/cdrom/news/0201/safeaudio_3.shtml
/// The titles for a few audio DRM FAQ's include the text "SafeWrap™ Frequently Asked Questions" in the page title, but this may be a copy-paste error:
/// https://web.archive.org/web/20030324080804/http://www.macrovision.com:80/solutions/audio/images/SafeAudio_FAQ_Public_5-02.pdf + https://web.archive.org/web/20030403050432/http://www.macrovision.com:80/solutions/audio/Audio_protection_FAQ_Public_March2003.pdf
/// Eclipse SafeAudio news that mentions SafeWrap: http://www.eclipsedata.com/PDFs/21.pdf
/// Report to congress that mentions SafeWrap: https://www.uspto.gov/sites/default/files/web/offices/dcom/olia/teachreport.pdf
/// Patent that mentions possibly using SafeWrap: https://patents.google.com/patent/US7493289B2/en
/// MacroSafe presentation that mentions current customer of SafeWrap/SafeCast/SafeDisc: https://slideplayer.com/slide/6840826/
/// List of DRM companies and products: https://www1.villanova.edu/villanova/generalcounsel/copyright/digitized/companies.html
/// Forum post that briefly mentions SafeWrap: https://www.ttlg.com/forums/showthread.php?t=70035
/// Forum post (with no replies) that asks for information about SafeWrap: https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/9167-macrovision-anti-code-tampering-tool
/// Document that mentions SafeWrap as third-party security tool: https://www.cs.clemson.edu/course/cpsc420/material/Papers/Guide_AppSecurity.pdf
/// Japanese PDF that mentions SafeWrap: https://ipsj.ixsq.nii.ac.jp/ej/index.php?action=pages_view_main&active_action=repository_action_common_download&item_id=64743&item_no=1&attribute_id=1&file_no=1&page_id=13&block_id=8
/// Korean PDF that mentions SafeWrap: http://contents.kocw.or.kr/contents4/document/lec/2012/KonKuk_glocal/Nohyounghee1/9.pdf

View File

@@ -7,7 +7,7 @@ using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.IO;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
@@ -275,6 +275,8 @@ namespace BinaryObjectScanner.Protection
if (!string.IsNullOrEmpty(safeDisc))
resultsList.Add(safeDisc!);
// Clean the result list
resultsList = CleanResultList(resultsList);
if (resultsList != null && resultsList.Count > 0)
return string.Join(", ", [.. resultsList]);
@@ -342,6 +344,9 @@ namespace BinaryObjectScanner.Protection
var fi = new FileInfo(firstMatchedString);
return fi.Length switch
{
// Found in Redump entry 63488.
0 => "(Empty File)",
// Found in Redump entry 102979.
1 => "(Empty File)",
@@ -388,7 +393,8 @@ namespace BinaryObjectScanner.Protection
12_400 => "3.18.000 / SafeDisc 2.90.010-2.90.040",
// Found in Redump entries 13230, 15383, and 36511.
12_528 => "3.19.000 / SafeDisc 3.10.020-3.15.011",
// SafeDisc 4+ is known to sometimes use old versions of drivers, such as in Redump entry 101261.
12_528 => "3.19.000 / SafeDisc 3.10.020-3.15.011/4+",
// Found in Redump entries 58625 and 84586.
11_973 => "3.22.000 / SafeDisc 3.20.020-3.20.022",
@@ -396,8 +402,8 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entries 15614, 42034, 45686, 56320, 60021, 79729, and 80776.
163_644 => "4.00.060 / SafeDisc 4.00.000-4.70.000",
// Found distributed online, but so far not in a game release. TODO: Discover original source.
// Can be found at https://github.com/ericwj/PsSecDrv/blob/master/tools/SECDRV/SECDRV.sys, and the file is confirmed to be distributed officialy by Microsoft: https://www.virustotal.com/gui/file/34bbb0459c96b3de94ccb0d73461562935c583d7bf93828da4e20a6bc9b7301d/.
// Found distributed online, but so far not in a game release. May be a final driver version never released with a game. TODO: Discover original source.
// Can be found at https://github.com/ericwj/PsSecDrv/blob/master/tools/SECDRV/SECDRV.sys, and the file is confirmed to be distributed officially by Microsoft: https://www.virustotal.com/gui/file/34bbb0459c96b3de94ccb0d73461562935c583d7bf93828da4e20a6bc9b7301d/.
23_040 => "4.03.086 / Product Unknown",
// Found in https://web.archive.org/web/20010417215205/http://www.macrovision.com:80/demos/Trialware.exe.
@@ -405,6 +411,22 @@ namespace BinaryObjectScanner.Protection
// This file is not currently known to be used in versions past 4.70.000.
_ => "/ Product Unknown (Report this to us on GitHub)",
// Hashes have not been found to be a reliable indicator for these files, and likely differ on a game-to-game basis. Some hashes were previously collected and are collected below:
// Found in Redump entries 3569 and 3570.
// "B64AD3EC82F2EB9FB854512CB59C25A771322181" => "1.11.000",
// It is not known which games these files are from.
// "EBF69B0A96ADFC903B7E486708474DC864CC0C7C" => "1.40.004",
// "F68A1370660F8B94F896BBBA8DC6E47644D19092" => "2.30",
// "60BC8C3222081BF76466C521474D63714AFD43CD" => "2.40",
// "08CECA66432278D8C4E0F448436B77583C3C61C8" => "2.50",
// "10080EB46BF76AC9CF9EA74372CFA4313727F0CA" => "2.51",
// "832D359A6DE191C788B0E61E33F3D01F8D793D3C" => "2.70",
// "AFCFAAC945A5B47712719A5E6A7EB69E36A5A6E0" or "CB24FBE8AA23A49E95F3C83FB15123FFB01F43F4" => "2.80",
// "0383B69F98D0A9C0383C8130D52D6B431C79AC48" => "2.90",
// "D7C9213CC78FF57F2F655B050C4D5AC065661AA9" => "3.20",
// "FC6FEDACC21A7244975B8F410FF8673285374CC2" => "4.00.002",// Also 4.60.000, might be a fluke
// "2D9F54F35F5BACB8959EF3AFFDC3E4209A4629CB" => "1-4",
};
}
@@ -427,8 +449,9 @@ namespace BinaryObjectScanner.Protection
"3.18.000" => "3.18.000 / SafeDisc 2.90.010-2.90.040",
// Found in Redump entries 13230, 15383, and 36511.
// SafeDisc 4+ is known to sometimes use old versions of drivers, such as in Redump entry 101261.
// The product version is "3.19.000 Windows NT/2K/XP 2003/03/19".
"3.19.000" => "3.19.000 / SafeDisc 3.10.020-3.15.011",
"3.19.000" => "3.19.000 / SafeDisc 3.10.020-3.15.011/4+",
// Found in Redump entries 58625 and 84586.
// The product version is "SECURITY Driver 3.22.000 2004/01/16".
@@ -530,16 +553,26 @@ namespace BinaryObjectScanner.Protection
// Version 1.04.000/1.4.0.0 can be found in "cdac01aa.dll" and "cdac01ba.dll" from IA item "ejay_nestle_trial", but needs further research.
// Found in Redump entry 83145.
"2.11.010"
// Found in IA item microsoft-software-jukebox-for-toshiba-1.0.
or "2.11.020"
// Source not documented.
or "2.11.060"
or "2.16.050"
// Found in Redump entry 90157 / IA item microsoft-software-jukebox-usa-hp-oem.
or "2.41.000"
// Source not documented.
or "2.60.030"
or "2.67.010" => "SafeCast",
// SafeCast (Unconfirmed)
// Found in Adobe Photoshop according to http://www.reversing.be/article.php?story=2006102413541932
"2.41.000"
or "2.42.000"
"2.42.000"
// Source not documented.
or "2.50.030"
or "2.51.000" => "SafeCast (Unconfirmed - Please report to us on GitHub)",
@@ -550,6 +583,8 @@ namespace BinaryObjectScanner.Protection
// SafeDisc (Confirmed)
// Found in Redump entry 66005.
"1.00.025"
// Source not documented.
or "1.00.026"
or "1.00.030"
or "1.00.032"
@@ -617,12 +652,25 @@ namespace BinaryObjectScanner.Protection
};
}
private List<string>? CleanResultList(List<string>? resultsList)
private static List<string>? CleanResultList(List<string>? resultsList)
{
// If we have an invalid result list
if (resultsList == null || resultsList.Count == 0)
return resultsList;
// Remove duplicates
if (resultsList.Contains("Macrovision Protected Application"))
{
if (resultsList.Contains("Macrovision Protected Application [Version Expunged]"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Entry point not present in the stxt371 section. Executable is either unprotected or nonfunctional)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Generic detection - Report to us on GitHub)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Report this to us on GitHub)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
}
// Get distinct and order
return [.. resultsList.Distinct().OrderBy(s => s)];
}

View File

@@ -79,10 +79,10 @@ namespace BinaryObjectScanner.Protection
// TODO: Investigate the consistency of "\OMGEXTRA\INDX0000.XML" and "\OMGEXTRA\INDX0001.XML", they seem to only appear when bonus content is present ("Touch" by Amerie).
new(new List<PathMatch>
{
new(Path.Combine("OMGAUDIO", "00AUDTOC.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "01AUDSTR.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "05SRPCDS.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGEXTRA", "OMGSVC.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "00AUDTOC.DAT")),
new(Path.Combine("OMGAUDIO", "01AUDSTR.DAT")),
new(Path.Combine("OMGAUDIO", "05SRPCDS.DAT")),
new(Path.Combine("OMGEXTRA", "OMGSVC.DAT")),
}, "OpenMG"),
// Always found together on OpenMG releases ("Touch" by Amerie, Redump entry 95010, and product ID SVWC-7185).

View File

@@ -4,6 +4,8 @@
{
// Currently implemented as a text file check, more checks are likely possible but currently unknown.
// Current checks based off Redump entry 84082 are found in the InstallShield setup.inx file, but the game also checks if the original disc is present in the drive after installation as well, so it seems unlikely for the InstallShield check to be relevant at that stage.
// A later version of it can be found in Redump entry 102493, which is found in the InstallShield setup.ins file, and also has a disc check when the game is run. On top of this, there is also a serial number check present. It is currently unknown how to uniquely detect either of them.
// The disc checks may be completely generic and undetectable, as these checks seem to be more lax than the installer checks.
// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/phenoProtect/phenoProtect.md"/>
}
}

View File

@@ -8,6 +8,7 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
// This protection was called VOB ProtectCD / ProtectDVD in versions prior to 6
// ProtectDISC 9/10 checks for the presence of CSS on the disc to run, but don't encrypt any sectors or check for keys. Confirmed in Redump entries 78367 and 110095.
public class ProtectDISC : IPortableExecutableCheck
{
/// <inheritdoc/>

View File

@@ -4,6 +4,7 @@ using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
@@ -15,16 +16,123 @@ namespace BinaryObjectScanner.Protection
/// Rainbow Sentinel SuperPro: https://www.rainbow.com.my/superpro.php
/// TODO: Investigate other versions/products.
/// TODO: See if this is at all related to https://cpl.thalesgroup.com/software-monetization/all-products/sentinel-hl.
/// TODO: Investigate the possible integration between FlexLM and Rainbow Sentinel in IA item "prog-17_202403".
/// TODO: Investigate the "NetSentinel Protection System" found in "NSRVOM.EXE" and "NSRVGX.EXE" in IA item "czchip199707cd".
/// TODO: Investigate "sntnlusb.sys" (https://www.rainbow.com.my/document/endusertroubleshooting.pdf).
///
/// Versions:
/// Rainbow Sentinel PD-15: IA items "ASMEsMechanicalEngineeringToolkit1997December" and "aplicaciones-windows".
/// Rainbow Sentinel PD-5.1: IA items "pcwkcd-1296, "CHIPTRMart97", and "bugcd199801".
/// Rainbow Sentinel PD-5.1e (Beta): IA item "CHIPTRMart97".
/// Rainbow Sentinel PD-5.37: File "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
/// Rainbow Sentinel PD-5.39: IA item "chip-cds-2001-08".
/// Rainbow Sentinel PD-15: IA items "ASMEsMechanicalEngineeringToolkit1997December", "aplicaciones-windows", and "ASMEsMechanicalEngineeringToolkit1997December".
/// Rainbow Sentinel PD-17: IA item "czchip199707cd".
/// Rainbow Sentinel PD-30: BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]" and IA item "auto-cad-r14-cdrom".
/// Rainbow Sentinel PD-31: BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]" and IA item "auto-cad-r14-cdrom".
///
/// Rainbow Sentinel SuperPro 5.0: IA items "chip-cds-2001-08".
/// Rainbow Sentinel SuperPro 5.1: IA items "ASMEsMechanicalEngineeringToolkit1997December" and "aplicaciones-windows".
///
/// Rainbow SentinelPro 5.1: IA item "pcwkcd-1296".
///
/// Rainbow NetSentinel: IA item "czchip199707cd".
/// </summary>
public class RainbowSentinel : IPathCheck, IPortableExecutableCheck
public class RainbowSentinel : IPathCheck, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
{
// TODO: Don't read entire file
var data = nex.ReadArbitraryRange();
if (data == null)
return null;
// TODO: Figure out what NE section this lives in
var neMatchSets = new List<ContentMatchSet>
{
// SentinelPro Windows Driver DLL
// Found in "SSWIN.dll" in IA item "pcwkcd-1296".
new(new byte?[]
{
0x53, 0x65, 0x6E, 0x74, 0x69, 0x6E, 0x65, 0x6C,
0x50, 0x72, 0x6F, 0x20, 0x57, 0x69, 0x6E, 0x64,
0x6F, 0x77, 0x73, 0x20, 0x44, 0x72, 0x69, 0x76,
0x65, 0x72, 0x20, 0x44, 0x4C, 0x4C
}, "Rainbow SentinelPro"),
// Sentinel Device Driver Version <20>PD-5.17
// Found in "SENTINEL.SYS" in IA item "czchip199707cd".
new(new byte?[]
{
0x53, 0x65, 0x6E, 0x74, 0x69, 0x6E, 0x65, 0x6C,
0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20,
0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x20, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x00,
0x50, 0x44, 0x2D, 0x35, 0x2E, 0x31, 0x37
}, "Rainbow Sentinel PD-5.17"),
// NetSentinel OS/2 security server
// Found in "NSRVOM.EXE" in IA item "czchip199707cd".
new(new byte?[]
{
0x4E, 0x65, 0x74, 0x53, 0x65, 0x6E, 0x74, 0x69,
0x6E, 0x65, 0x6C, 0x20, 0x4F, 0x53, 0x2F, 0x32,
0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72
}, "Rainbow NetSentinel Server for OS/2"),
// NetSentinel Monitor
// Found in "OS2MON.EXE" in IA item "czchip199707cd".
new(new byte?[]
{
0x4E, 0x65, 0x74, 0x53, 0x65, 0x6E, 0x74, 0x69,
0x6E, 0x65, 0x6C, 0x20, 0x20, 0x4D, 0x6F, 0x6E,
0x69, 0x74, 0x6F, 0x72
}, "Rainbow NetSentinel Monitor"),
// Sentinel Device Driver
// Generic case to catch unknown versions.
// TODO: Add version parsing for this check.
new (new byte?[]
{
0x53, 0x65, 0x6E, 0x74, 0x69, 0x6E, 0x65, 0x6C,
0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20,
0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x20, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x00,
0x50, 0x44, 0x2D, 0x35, 0x2E, 0x31, 0x37
}, "Rainbow Sentinel (Unknown Version - Please report this to us on GitHub)"),
};
var match = MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
// Check the nonresident-name table
// Found in "SSWIN.dll" in IA item "pcwkcd-1296".
bool nonresidentNameTableEntries = nex.Model.NonResidentNameTable?
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
.Any(s => s.Contains("SentinelPro Windows Driver DLL")) ?? false;
if (nonresidentNameTableEntries)
return "Rainbow SentinelPro";
// Found in "INSTALL.EXE" in IA item "czchip199707cd".
nonresidentNameTableEntries = nex.Model.NonResidentNameTable?
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
.Any(s => s.Contains("Rainbow Technologies Installation Program")) ?? false;
if (nonresidentNameTableEntries)
return "Rainbow Sentinel";
// Found in "WNCEDITD.EXE" and "WNCEDITO.EXE" in IA item "czchip199707cd".
nonresidentNameTableEntries = nex.Model.NonResidentNameTable?
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
.Any(s => s.Contains("NetSentinel-C Editor for Windows")) ?? false;
if (nonresidentNameTableEntries)
return "NetSentinel-C Editor for Windows";
// TODO: Investigate "SentinelScribe Windows Driver DLL" found in "NKWIN.DLL" in IA item "czchip199707cd".
return null;
}
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
@@ -33,30 +141,6 @@ namespace BinaryObjectScanner.Protection
if (sections == null)
return null;
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
// Found in "ADESKSYS.DLL"/"WINADMIN.EXE"/"WINQUERY.EXE" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\netsetup\SUPPORT\IPX".
if (strs.Any(s => s.Contains("Rainbow SentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
}
// Get the .text section strings, if they exist
strs = pex.GetFirstSectionStrings(".text");
if (strs != null)
{
// Found in "ACLT.HWL" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\aclt\DRV\W95LOCK".
// Found in "ACAD.HWL" in BA entry "Autodesk AutoCAD r14 (1997)" and IA item "auto-cad-r14-cdrom".
if (strs.Any(s => s.Contains("SENTINEL.VXD")))
return "Rainbow Sentinel SuperPro";
// Found in "ADESKSYS.DLL" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\netsetup\SUPPORT\IPX".
// TODO: Investigate "Elan License Manager" mentioned here.
if (strs.Any(s => s.Contains("Rainbow SentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
}
// TODO: Figure out why resources for "RNBOVTMP.DLL", "SENTTEMP.DLL", "SNTI386.DLL", and "SX32W.DL_"/"SX32W.DLL" aren't getting read properly, causing checks for these files to not work.
var name = pex.FileDescription;
@@ -81,6 +165,19 @@ namespace BinaryObjectScanner.Protection
if (name?.Equals("Rainbow Technologies SentinelSuperPro WIN32 DLL", StringComparison.OrdinalIgnoreCase) == true)
return $"Rainbow Sentinel SuperPro {pex.ProductVersion}";
// Found in "SP32W.DLL" in IA item "pcwkcd-1296".
if (name?.Equals("Rainbow Technologies SentinelPro WIN32 DLL", StringComparison.OrdinalIgnoreCase) == true)
return $"Rainbow SentinelPro {pex.ProductVersion}";
// Found in "NSRVGX.EXE" in IA item "czchip199707cd".
if (name?.Equals("NetSentinel Server for WIN 32", StringComparison.OrdinalIgnoreCase) == true)
return "Rainbow NetSentinel Server for Win32";
// Found in "\disc4\cad\sdcc_200.zip\DISK1\_USER1.HDR\Language_Independent_Intel_32_Files\SNTNLUSB.SYS" in "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
// TODO: Check if the version included with this is useful.
if (name?.Equals("Rainbow Technologies Sentinel Device Driver", StringComparison.OrdinalIgnoreCase) == true)
return "Rainbow Sentinel Driver";
name = pex.ProductName;
// Found in multiple files in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", including "RNBOVTMP.DLL", "SENTTEMP.DLL", and "SNTI386.DLL".
@@ -95,6 +192,98 @@ namespace BinaryObjectScanner.Protection
if (name?.Equals("Rainbow Technologies SentinelSuperPro WIN32 DLL", StringComparison.OrdinalIgnoreCase) == true)
return $"Rainbow Sentinel SuperPro {pex.ProductVersion}";
// Found in "SP32W.DLL" in IA item "pcwkcd-1296".
if (name?.Equals("Rainbow Technologies SentinelPro WIN32 DLL", StringComparison.OrdinalIgnoreCase) == true)
return $"Rainbow SentinelPro {pex.ProductVersion}";
// Found in "F481_SetupSysDriver.exe.B391C18A_6953_11D4_82CB_00D0B72E1DB9"/"SetupSysDriver.exe" in IA item "chip-cds-2001-08".
if (name?.Equals("Sentinel System Driver", StringComparison.OrdinalIgnoreCase) == true)
return $"Rainbow Sentinel {pex.ProductVersion}";
// Found in "\disc4\cad\sdcc_200.zip\DISK1\_USER1.HDR\Language_Independent_Intel_32_Files\SNTNLUSB.SYS" in "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
// TODO: Check if the version included with this is useful.
if (name?.Equals("Rainbow Technologies USB Security Device Driver", StringComparison.OrdinalIgnoreCase) == true)
return "Rainbow Sentinel Driver";
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
// Found in "ADESKSYS.DLL"/"WINADMIN.EXE"/"WINQUERY.EXE" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\netsetup\SUPPORT\IPX".
if (strs.Any(s => s.Contains("Rainbow SentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
// Found in "SETUPAXP.EXE", "SETUPMPS.EXE", and "SETUPPPC.EXE" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("Sentinel Driver Setup Program")))
return "Rainbow Sentinel";
}
// Get the .rdata section strings, if they exist
strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
// Found in "SP32W.DLL" in IA item "pcwkcd-1296".
if (strs.Any(s => s.Contains("SentinelPro WIN32 DLL")))
return "Rainbow SentinelPro";
// Found in "NKWIN32.DLL" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("NetSentinel-C Windows NT Driver DLL")))
return "Rainbow NetSentinel-C Windows NT Driver";
// Found in "NSLMS32.DLL" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("NetSentinel 32-Bit Windows DLL")))
return "Rainbow NetSentinel Win32 Driver";
// Found in "W32EDITD.EXE" and "W32EDITO.EXE" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("NetSentinel-C Editor for Windows")))
return "NetSentinel-C Editor for Win32";
// Generic case to catch undetected versions.
if (strs.Any(s => s.Contains("SentinelPro")))
return "Rainbow SentinelPro (Unknown Version - Please report to us on GitHub)";
}
// Get the .rsrc section strings, if they exist
strs = pex.GetFirstSectionStrings(".rsrc");
if (strs != null)
{
// Found in "WINMON.exe" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("NetSentinel Monitor")))
return "Rainbow NetSentinel Monitor";
}
// Get the .text section strings, if they exist
strs = pex.GetFirstSectionStrings(".text");
if (strs != null)
{
// Found in "ACLT.HWL" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\aclt\DRV\W95LOCK".
// Found in "ACAD.HWL" in BA entry "Autodesk AutoCAD r14 (1997)" and IA item "auto-cad-r14-cdrom".
if (strs.Any(s => s.Contains("\\\\.\\SENTINEL.VXD")))
return "Rainbow Sentinel";
// Found in "ADESKSYS.DLL" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]", folder "\netsetup\SUPPORT\IPX".
// TODO: Investigate "Elan License Manager" mentioned here.
if (strs.Any(s => s.Contains("Rainbow SentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
// Found in "F1321_dorapro.exe" in IA item "chip-cds-2001-08".
if (strs.Any(s => s.Contains("modSentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
// Found in "F1321_dorapro.exe" in IA item "chip-cds-2001-08".
if (strs.Any(s => s.Contains("clsSentinelSuperPro")))
return "Rainbow Sentinel SuperPro";
// Found in "SENTSTRT.EXE" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("Sentinel Driver Startup Program")))
return "Rainbow Sentinel";
// Found in "SETUPX86.EXE" in IA item "czchip199707cd".
if (strs.Any(s => s.Contains("Sentinel Windows NT Driver Setup")))
return "Rainbow Sentinel";
}
return null;
}
@@ -107,8 +296,11 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
// The Parallel Port driver for Rainbow Sentinel on Win9x (https://www.rainbow.com.my/document/endusertroubleshooting.pdf).
// Unfortunately, the file name overlaps with a file used by Clam Sentinel (https://clamsentinel.sourceforge.net/).
// new(new FilePathMatch("SENTINEL.VXD"), "Rainbow Sentinel"),
// Found in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]" and IA item "auto-cad-r14-cdrom".
new(new FilePathMatch("SENTINEL.VXD"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTSTRT.EXE"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTW95.DLL"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTW95.EXE"), "Rainbow Sentinel"),
@@ -127,9 +319,78 @@ namespace BinaryObjectScanner.Protection
new(new FilePathMatch("RAINBNT.Z"), "Rainbow Sentinel"),
// Found in "wd126.zip/WDSHARE.EXE" in IA item "ASMEsMechanicalEngineeringToolkit1997December" and "WDSHARE.ZIP/WDSHARE.EXE/SX32W.DL_" in IA item "aplicaciones-windows".
new(new FilePathMatch("RainbowSentinel.386"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DL_"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DLL"), "Rainbow Sentinel"),
new(new FilePathMatch("RainbowSentinel.386"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DL_"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DLL"), "Rainbow Sentinel"),
// Found in IA item "pcwkcd-1296".
new(new FilePathMatch("SP32W.DLL"), "Rainbow Sentinel"),
new(new FilePathMatch("SSWIN.DLL"), "Rainbow Sentinel"),
// Found in IA item "czchip199707cd".
new(new FilePathMatch("SENTINEL.DPP"), "Rainbow Sentinel OS/2 Installation Script"),
new(new FilePathMatch("SENTDOS.SYS"), "Rainbow Sentinel DOS Driver"),
new(new FilePathMatch("SENTINEL.386"), "Rainbow Sentinel Windows 3.1 Driver"),
new(new FilePathMatch("SNTALPHA.DLL"), "Rainbow Sentinel Windows NT Alpha Platform Driver"),
new(new FilePathMatch("SNTI386.DLL"), "Rainbow Sentinel Windows NT Intel Platform Driver"),
new(new FilePathMatch("SNTMIPS.DLL"), "Rainbow Sentinel Windows NT MIPS Platform Driver"),
new(new FilePathMatch("SNTPPC.DLL"), "Rainbow Sentinel Windows NT PowerPC Platform Driver"),
new(new FilePathMatch("NSRVDI.EXE"), "Rainbow NetSentinel Server for DOS"),
new(new FilePathMatch("NSRVDN.EXE"), "Rainbow NetSentinel Server for DOS"),
new(new FilePathMatch("NSRVNI.NLM"), "Rainbow NetSentinel Server for Novell NetWare"),
new(new FilePathMatch("NSRVOM.EXE"), "Rainbow NetSentinel Server for OS/2"),
new(new FilePathMatch("NSRVGX.EXE"), "Rainbow NetSentinel Server for Win32"),
// Found in "\disc4\cad\sdcc_200.zip\DISK1\_USER1.HDR\Language_Independent_Intel_32_Files" in "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
// TODO: Add text file checks for these IFX files.
new(new FilePathMatch("SNTNLUSB.IFX"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTNLUSB.INF"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTNLUSB.SYS"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.IFX"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.INF"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.SYS"), "Rainbow Sentinel USB Driver"),
// Found in IA item "czchip199707cd".
new(new List<PathMatch>
{
new FilePathMatch("DOSMON.EXE"),
new FilePathMatch("FIND.EXE"),
new FilePathMatch("NCEDIT.EXE"),
new FilePathMatch("NETEVAL.EXE"),
}, "Rainbow NetSentinel Monitor for DOS"),
// Found in IA item "czchip199707cd".
new(new List<PathMatch>
{
new FilePathMatch("OS2MON.EXE"),
new FilePathMatch("RHPANELP.DLL"),
}, "Rainbow NetSentinel Monitor for OS/2"),
// Found in IA item "czchip199707cd".
new(new List<PathMatch>
{
new FilePathMatch("MAPFILE.TXT"),
new FilePathMatch("NKWIN32.DLL"),
new FilePathMatch("NSLMS32.DLL"),
new FilePathMatch("W32EDITD.EXE"),
new FilePathMatch("W32EDITO.EXE"),
new FilePathMatch("WINMON.DOC"),
new FilePathMatch("WINMON.EXE"),
new FilePathMatch("WINMON.HLP"),
new FilePathMatch("WMON_DOC.EXE"),
}, "Rainbow NetSentinel Monitor for Win32"),
// Found in IA item "chip-cds-2001-08".
// File names for Rainbow Sentinel files sometimes found in ".cab" files.
new(new FilePathMatch("F194_rnbovdd.dll.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F195_sentinel.sys.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F225_sentinel.hlp.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F227_snti386.dll.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F288_sentinel.vxd.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F317_sentstrt.exe.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F344_sentw9x.hlp.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F481_SetupSysDriver.exe.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F766_SentinelDriverInstall_Start.htm.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
@@ -140,8 +401,12 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
// The Parallel Port driver for Rainbow Sentinel (https://www.rainbow.com.my/document/endusertroubleshooting.pdf).
// Unforutnately, the file name overlaps with a file used by Clam Sentinel (https://clamsentinel.sourceforge.net/).
// TODO: Add LE check for "SENTINEL.VXD" once LE checks are implemented.
// new(new FilePathMatch("SENTINEL.VXD"), "Rainbow Sentinel"),
// Found in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]" and IA item "auto-cad-r14-cdrom".
new(new FilePathMatch("SENTINEL.VXD"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTSTRT.EXE"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTW95.DLL"), "Rainbow Sentinel"),
new(new FilePathMatch("SENTW95.EXE"), "Rainbow Sentinel"),
@@ -163,6 +428,40 @@ namespace BinaryObjectScanner.Protection
new(new FilePathMatch("RainbowSentinel.386"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DL_"), "Rainbow Sentinel"),
new(new FilePathMatch("SX32W.DLL"), "Rainbow Sentinel"),
// Found in IA item "pcwkcd-1296".
new(new FilePathMatch("SP32W.DLL"), "Rainbow Sentinel"),
new(new FilePathMatch("SSWIN.DLL"), "Rainbow Sentinel"),
// Found in IA item "czchip199707cd".
new(new FilePathMatch("SENTINEL.DPP"), "Rainbow Sentinel OS/2 Installation Script"),
new(new FilePathMatch("SENTDOS.SYS"), "Rainbow Sentinel DOS Driver"),
new(new FilePathMatch("SENTINEL.386"), "Rainbow Sentinel Windows 3.1 Driver"),
new(new FilePathMatch("SNTALPHA.DLL"), "Rainbow Sentinel Windows NT Alpha Platform Driver"),
new(new FilePathMatch("SNTI386.DLL"), "Rainbow Sentinel Windows NT Intel Platform Driver"),
new(new FilePathMatch("SNTMIPS.DLL"), "Rainbow Sentinel Windows NT MIPS Platform Driver"),
new(new FilePathMatch("SNTPPC.DLL"), "Rainbow Sentinel Windows NT PowerPC Platform Driver"),
// Found in "\disc4\cad\sdcc_200.zip\DISK1\_USER1.HDR\Language_Independent_Intel_32_Files" in "CICA 32 For Windows CD-ROM (Walnut Creek) (October 1999) (Disc 4).iso" in IA item "CICA_32_For_Windows_CD-ROM_Walnut_Creek_October_1999".
// TODO: Add text file checks for these IFX files.
new(new FilePathMatch("SNTNLUSB.IFX"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTNLUSB.INF"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTNLUSB.SYS"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.IFX"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.INF"), "Rainbow Sentinel USB Driver"),
new(new FilePathMatch("SNTUSB95.SYS"), "Rainbow Sentinel USB Driver"),
// Found in IA item "chip-cds-2001-08".
// File names for Rainbow Sentinel files sometimes found in ".cab" files.
new(new FilePathMatch("F194_rnbovdd.dll.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F195_sentinel.sys.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F225_sentinel.hlp.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F227_snti386.dll.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F288_sentinel.vxd.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F317_sentstrt.exe.B391C188_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F344_sentw9x.hlp.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F481_SetupSysDriver.exe.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
new(new FilePathMatch("F766_SentinelDriverInstall_Start.htm.B391C18A_6953_11D4_82CB_00D0B72E1DB9"), "Rainbow Sentinel"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -0,0 +1,75 @@
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.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// RealArcade was a game platform that allowed users to play timed demos of games, and then prompted them to purchase the game in order to play the game without a limit.
/// Although the servers are long dead, there is a community project actively being developed to allow users to properly download and play these games.
/// Links:
/// https://github.com/lightbulbatelier/RealArcade-DGA
/// https://archive.org/details/realrcade-games-preservation-project
/// </summary>
public class RealArcade : IPathCheck, 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 .data section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data");
if (strs != null)
{
// Found in "rebound.exe" in the installation directory for "Rebound" in IA item "Nova_RealArcadeCD_USA".
if (strs.Any(s => s.Contains("RngInterstitialDLL")))
return "RealArcade";
}
// Found in "RngInterstitial.dll" in the RealArcade installation directory in IA item "Nova_RealArcadeCD_USA".
var name = pex.FileDescription;
if (name?.Contains("RngInterstitial") == true)
return "RealArcade";
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// ".rgs" and ".mez" files are also associated with RealArcade.
new(new FilePathMatch("RngInterstitial.dll"), "RealArcade"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// ".rgs" and ".mez" files are also associated with RealArcade.
new(new FilePathMatch("RngInterstitial.dll"), "RealArcade"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -0,0 +1,92 @@
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.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Roxxe was a Czech DRM. It appears to have been a simple disc check that also relied on unusual disc manufacturing and dummy files to attempt to prevent copying.
///
/// DRML: https://github.com/TheRogueArchivist/DRML/blob/main/entries/Roxxe/Roxxe.md
/// </summary>
public class Roxxe : IPathCheck, 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 code/CODE section strings, if they exist
var strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
if (strs != null)
{
// Found in "Owar.exe" in IA item "game4u-22-cd".
if (strs.Any(s => s.Contains("TRCHANGER.INI")))
return "Roxxe";
}
// Get the .rsrc section strings, if they exist
// TODO: Check for these strings specifically within the application-defined resource that they're found in, not just the generic resource section.
strs = pex.GetFirstSectionStrings(".rsrc");
if (strs != null)
{
// Found in "Owar.exe" in IA items "game4u-22-cd" and "original-war".
// These checks are less reliable, as they are still found in a version of the game that appears to have patched out Roxxe (the version present in IA item "original-war").
if (strs.Any(s => s.Contains("PRRT01")))
return "Roxxe (Possibly remnants)";
if (strs.Any(s => s.Contains("CommonPRRT")))
return "Roxxe (Possibly remnants)";
// Currently overmatches, will likely be a viable check when better Delphi executable parsing is available.
// if (strs.Any(s => s.Contains("roxe")))
// return "Roxxe (Possibly remnants)";
}
// If any dialog boxes match
// Found in "Data6.OWP" in IA item "game4u-22-cd".
if (pex.FindDialogBoxByItemTitle("SharpTiny Version 1.0").Any())
return "Roxxe";
// Found in "Data8.OWP" in IA item "game4u-22-cd".
else if (pex.FindDialogBoxByItemTitle("T32xWin Version 1.0").Any())
return "Roxxe";
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Files such as "TRCHANGER.INI" may be present, but haven't been found yet.
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Files such as "TRCHANGER.INI" may be present, but haven't been found yet.
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -26,6 +26,14 @@ namespace BinaryObjectScanner.Protection
if (name?.Contains("SecuROM PA") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
name = pex.InternalName;
if (name?.Equals("paul.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
else if (name?.Equals("paul_dll_activate_and_play.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
else if (name?.Equals("paul_dll_preview_and_review.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
name = pex.OriginalFilename;
if (name?.Equals("paul_dll_activate_and_play.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
@@ -205,7 +213,7 @@ namespace BinaryObjectScanner.Protection
byte[] subSubVersion = new byte[2];
subSubVersion[0] = (byte)(fileContent[index] ^ 42);
index++;
subSubVersion[0] = (byte)(fileContent[index] ^ 8);
subSubVersion[1] = (byte)(fileContent[index] ^ 8);
index += 2;
byte[] subSubSubVersion = new byte[4];
@@ -226,31 +234,40 @@ namespace BinaryObjectScanner.Protection
// These live in the MS-DOS stub, for some reason
private static string GetV7Version(PortableExecutable pex)
{
int index = 172; // 64 bytes for DOS stub, 236 bytes in total
try
{
int index = 172; // 64 bytes for DOS stub, 236 bytes in total
#if NETFRAMEWORK
byte[] bytes = new byte[4];
Array.Copy(pex.StubExecutableData, index, bytes, 0, 4);
byte[] bytes = new byte[4];
Array.Copy(pex.StubExecutableData, index, bytes, 0, 4);
#else
byte[] bytes = new ReadOnlySpan<byte>(pex.StubExecutableData, index, 4).ToArray();
byte[] bytes = new ReadOnlySpan<byte>(pex.StubExecutableData, index, 4).ToArray();
#endif
//SecuROM 7 new and 8
if (bytes[3] == 0x5C) // if (bytes[0] == 0xED && bytes[3] == 0x5C {
{
return $"{bytes[0] ^ 0xEA}.{bytes[1] ^ 0x2C:00}.{bytes[2] ^ 0x8:0000}";
//SecuROM 7 new and 8
if (bytes[3] == 0x5C) // if (bytes[0] == 0xED && bytes[3] == 0x5C {
{
return $"{bytes[0] ^ 0xEA}.{bytes[1] ^ 0x2C:00}.{bytes[2] ^ 0x8:0000}";
}
// SecuROM 7 old
else
{
index = 58; // 64 bytes for DOS stub, 122 bytes in total
#if NETFRAMEWORK
bytes = new byte[2];
Array.Copy(pex.StubExecutableData, index, bytes, 0, 2);
#else
bytes = new ReadOnlySpan<byte>(pex.StubExecutableData, index, 2).ToArray();
#endif
return $"7.{bytes[0] ^ 0x10:00}.{bytes[1] ^ 0x10:0000}"; //return "7.01-7.10"
}
}
// SecuROM 7 old
else
catch (ArgumentException)
{
index = 58; // 64 bytes for DOS stub, 122 bytes in total
#if NETFRAMEWORK
bytes = new byte[2];
Array.Copy(pex.StubExecutableData, index, bytes, 0, 2);
#else
bytes = new ReadOnlySpan<byte>(pex.StubExecutableData, index, 2).ToArray();
#endif
return $"7.{bytes[0] ^ 0x10:00}.{bytes[1] ^ 0x10:0000}"; //return "7.01-7.10"
// If SecuROM is stripped, the MS-DOS stub might be shorter.
// We then know that SecuROM -was- there, but we don't know what exact version.
return "7 remnants";
}
}

View File

@@ -27,7 +27,35 @@ namespace BinaryObjectScanner.Protection
if (sections == null)
return null;
var name = pex.LegalCopyright;
// TODO: Find what fvinfo field actually maps to this
var name = pex.FileDescription;
// There are some File Description checks that are currently too generic to use.
// "Host Library" - Found in "protect.dll" in Redump entry 81756.
// "User Interface Application" - Found in "protect.exe" in Redump entry 81756.
// "Helper Application" - Found in "protect.x64" and "protect.x86" in Redump entry 81756.
// Found in "sfdrvrem.exe" in Redump entry 102677.
if (name?.Contains("FrontLine Drivers Removal Tool") == true)
return $"StarForce FrontLine Driver Removal Tool";
// Found in "protect.exe" in Redump entry 94805.
if (name?.Contains("FrontLine Protection GUI Application") == true)
return $"StarForce {pex.GetInternalVersion()}";
// Found in "protect.dll" in Redump entry 94805.
if (name?.Contains("FrontLine Protection Library") == true)
return $"StarForce {pex.GetInternalVersion()}";
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name?.Contains("FrontLine Helper") == true)
return $"StarForce {pex.GetInternalVersion()}";
// TODO: Find a sample of this check.
if (name?.Contains("Protected Module") == true)
return $"StarForce 5";
name = pex.LegalCopyright;
if (name?.StartsWith("(c) Protection Technology") == true) // (c) Protection Technology (StarForce)?
return $"StarForce {pex.GetInternalVersion()}";
else if (name?.Contains("Protection Technology") == true) // Protection Technology (StarForce)?
@@ -61,30 +89,6 @@ namespace BinaryObjectScanner.Protection
return $"StarForce {pex.GetInternalVersion()}";
}
// TODO: Find what fvinfo field actually maps to this
name = pex.FileDescription;
// There are some File Description checks that are currently too generic to use.
// "Host Library" - Found in "protect.dll" in Redump entry 81756.
// "User Interface Application" - Found in "protect.exe" in Redump entry 81756.
// "Helper Application" - Found in "protect.x64" and "protect.x86" in Redump entry 81756.
// Found in "protect.exe" in Redump entry 94805.
if (name?.Contains("FrontLine Protection GUI Application") == true)
return $"StarForce {pex.GetInternalVersion()}";
// Found in "protect.dll" in Redump entry 94805.
if (name?.Contains("FrontLine Protection Library") == true)
return $"StarForce {pex.GetInternalVersion()}";
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name?.Contains("FrontLine Helper") == true)
return $"StarForce {pex.GetInternalVersion()}";
// TODO: Find a sample of this check.
if (name?.Contains("Protected Module") == true)
return $"StarForce 5";
// TODO: Check to see if there are any missing checks
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/StarForce.2.sg

View File

@@ -55,7 +55,8 @@ namespace BinaryObjectScanner.Protection
new(new List<PathMatch>
{
// TODO: Identify based on "Steam(TM)" being present in "Description" but not in "File Description".
new FilePathMatch("steam.exe"),
// Overmatches on some files, such as IA item "ASMEsMechanicalEngineeringToolkit1997December".
// new FilePathMatch("steam.exe"),
new FilePathMatch("steam.ini"),

View File

@@ -76,10 +76,10 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// d37f70489207014d7d0fbaa43b081a93e8030498
new(Path.Combine("Sys", "Devx.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("Sys", "Devx.sys")),
// a0acbc2f8e321e4f30c913c095e28af444058249
new(Path.Combine("Sys", "VtPr.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("Sys", "VtPr.sys")),
// SHA-1 is variable, file size is 81,920 bytes
new FilePathMatch("Wave.aif"),
@@ -99,16 +99,16 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// f82339d797be6da92f5d9dadeae9025385159057
new(Path.Combine("9x", "Tamlx.alf").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "Tamlx.alf")),
// 933c004d3043863f019f5ffaf63402a30e65026c
new(Path.Combine("9x", "Tamlx.apt").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "Tamlx.apt")),
// d45745fa6b0d23fe0ee12e330ab85d5bf4e0e776
new(Path.Combine("NT", "enodpl.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "enodpl.sys")),
// f111eba05ca6e9061c557547420847d7fdee657d
new(Path.Combine("NT", "litdpl.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "litdpl.sys")),
}, "TAGES"),
// Currently only known to exist in "XIII" and "Beyond Good & Evil" (Redump entries 8774-8776, 45940-45941, 18690-18693, and presumably 21320, 21321, 21323, and 36124).
@@ -127,16 +127,16 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// 40826e95f3ad8031b6debe15aca052c701288e04
new(Path.Combine("9x", "hwpsgt.vxd").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "hwpsgt.vxd")),
// f82339d797be6da92f5d9dadeae9025385159057
new(Path.Combine("9x", "lemsgt.vxd").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "lemsgt.vxd")),
// 43f407ecdc0d87a3713126b757ccaad07ade285f
new(Path.Combine("NT", "hwpsgt.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "hwpsgt.sys")),
// 548dd6359abbcc8c84ce346d078664eeedc716f7
new(Path.Combine("NT", "lemsgt.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "lemsgt.sys")),
}, "TAGES"),
// The following files are supposed to only be found inside the driver setup executables, and are present in at least version 5.2.0.1 (Redump entry 15976).

View File

@@ -22,7 +22,7 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
new(Path.Combine("ZDAT", "webmast.dxx").Replace("\\", "/"), "Tivola Ring Protection [Check disc for physical ring]"),
new(Path.Combine("ZDAT", "webmast.dxx"), "Tivola Ring Protection [Check disc for physical ring]"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
@@ -33,7 +33,7 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
new(Path.Combine("ZDAT", "webmast.dxx").Replace("\\", "/"), "Tivola Ring Protection [Check disc for physical ring]"),
new(Path.Combine("ZDAT", "webmast.dxx"), "Tivola Ring Protection [Check disc for physical ring]"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -21,9 +21,9 @@ namespace BinaryObjectScanner.Protection
var matchers = new List<PathMatchSet>
{
#if NET20 || NET35
new(Path.Combine(Path.Combine(path, "Zzxzz"), "Zzz.aze").Replace("\\", "/"), "Zzxzz"),
new(Path.Combine(Path.Combine(path, "Zzxzz"), "Zzz.aze"), "Zzxzz"),
#else
new(Path.Combine(path, "Zzxzz", "Zzz.aze").Replace("\\", "/"), "Zzxzz"),
new(Path.Combine(path, "Zzxzz", "Zzz.aze"), "Zzxzz"),
#endif
new($"Zzxzz/", "Zzxzz"),
};

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