Compare commits

...

746 Commits
2.5.0 ... 3.1.7

Author SHA1 Message Date
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
Matt Nadareski
0e32abc76c Bump version 2023-11-22 13:28:56 -05:00
Matt Nadareski
94cb06a3bd Handle some messages 2023-11-22 13:28:13 -05:00
Matt Nadareski
907aea443e Support .NET Framework 2.0 2023-11-22 12:22:01 -05:00
Matt Nadareski
385922723c Upate packages 2023-11-22 10:48:08 -05:00
Matt Nadareski
3061c2f009 Reenable .NET Framework 4.0 2023-11-21 10:59:29 -05:00
Matt Nadareski
5c0ccbde35 Temporarily remove .NET Framework 4.0 2023-11-21 10:19:15 -05:00
Matt Nadareski
7b998de2ca Handle more C# 12 syntax 2023-11-21 10:17:25 -05:00
Matt Nadareski
b0d49f52a5 Bump version 2023-11-20 12:16:53 -05:00
Matt Nadareski
6f9bcc2111 Fix multiple invocation bug
This bug arose when all of the libraries were consoliated into the same library for better packaging. Each set of classes was being instantiated 3 times as a result.
2023-11-18 20:55:32 -05:00
Matt Nadareski
0fb0ecd28a Update ST libraries for bugfixes 2023-11-15 12:54:32 -05:00
Matt Nadareski
6194d88aec Correct the excludes 2023-11-15 11:26:00 -05:00
Matt Nadareski
b02c3121fe Use official package for IProgress 2023-11-15 00:24:47 -05:00
Matt Nadareski
580db0cb65 Minor tweaks to reduce warnings 2023-11-14 23:48:35 -05:00
Matt Nadareski
6bcdc0e3c6 Bump version 2023-11-14 16:16:08 -05:00
Matt Nadareski
9b4fd91717 Update build scripts 2023-11-14 16:13:49 -05:00
Matt Nadareski
9421249b8e Support ancient .NET 2023-11-14 16:10:10 -05:00
Matt Nadareski
e823cbaee5 Expand supported RIDs 2023-11-08 22:51:47 -05:00
Matt Nadareski
c34618554b Update project comment 2023-11-08 12:08:22 -05:00
Matt Nadareski
6ab7b4a004 Enable latest language version 2023-11-08 11:59:50 -05:00
Matt Nadareski
5b6bf3b73e Rename to BinaryObjectScanner 2023-11-08 11:37:27 -05:00
Matt Nadareski
2a30a13f5f Omit submodule code for modern .NET 2023-10-27 00:58:03 -04:00
Matt Nadareski
3c05a112ca Remove DLLs from modern .NET builds 2023-10-27 00:55:31 -04:00
Matt Nadareski
66af2d83b8 Bump version 2023-10-26 00:35:18 -04:00
Matt Nadareski
fc3be76657 Figure out last couple of nullability issues 2023-10-26 00:27:38 -04:00
Matt Nadareski
259a91dd77 Ensure that the nupkg has the right name 2023-10-26 00:18:48 -04:00
Matt Nadareski
e957b29bae Remove unncessary/broken appveyor zips 2023-10-26 00:10:18 -04:00
Matt Nadareski
33060d9787 Sync appveyor script further to build release 2023-10-26 00:08:22 -04:00
Matt Nadareski
71ca79a456 Update SharpCompress and SharpZipLib 2023-10-26 00:00:34 -04:00
Matt Nadareski
fc744d241a Normalize archive naming with MPF 2023-10-25 23:56:20 -04:00
Matt Nadareski
78b5b3dbc1 Add publish scripts for easier distribution 2023-10-25 23:51:07 -04:00
Matt Nadareski
cb3846261a Fix more nullability locations 2023-10-25 23:33:51 -04:00
Matt Nadareski
9a3dcf70de Slight reordering of XMID/XeMID 2023-10-25 23:16:51 -04:00
Matt Nadareski
670c78302f Add printing for IRD, XMID, XeMID 2023-10-25 23:03:40 -04:00
Matt Nadareski
f4cb97b3bf Bump all ST library versions 2023-10-25 23:03:20 -04:00
TheRogueArchivist
be6d44ed04 Add WEB-Cops detection to CD/DVD-Cops (#268) 2023-10-04 17:55:10 -07:00
TheRogueArchivist
cfc9092479 Add DigiGuard detection (#267)
* Add DigiGuard detection

* Use FilePathMatch instead of PathMatch
2023-10-01 19:05:04 -07:00
TheRogueArchivist
d674ae5b1f Add new CD/DVD-Cops detections (#266) 2023-10-01 11:59:20 -07:00
Matt Nadareski
864972e575 Update packages to fix printing issues 2023-09-29 11:48:42 -04:00
Matt Nadareski
7d97850cb0 Fix some more nullability warnings 2023-09-26 15:31:43 -04:00
Matt Nadareski
3e33f098a6 Fix solution file 2023-09-26 15:25:30 -04:00
Matt Nadareski
adf9ce5e2a Matching to 1.1.1, OpenMcdf to 2.3.0 2023-09-18 15:53:24 -04:00
Matt Nadareski
0c5dff71e9 More nullability fixes 2023-09-18 14:58:33 -04:00
Matt Nadareski
715f773672 Fix DLL inclusion issues 2023-09-18 14:15:51 -04:00
Matt Nadareski
a54b89d380 Make the leap to BinaryObjectScanner 2023-09-18 13:56:07 -04:00
Matt Nadareski
2085c306ab Move stormlibsharp to main library 2023-09-18 12:52:42 -04:00
Matt Nadareski
98b99da0bc Remove stormlibsharp from Compression 2023-09-18 12:15:24 -04:00
Matt Nadareski
e00238b24e Migrate to compression library, mostly 2023-09-18 12:09:54 -04:00
Matt Nadareski
aef2b756c9 Add warning in Extractor 2023-09-18 11:35:52 -04:00
Matt Nadareski
f1f1e20a3e Remove reference to incomplete compressions 2023-09-18 11:33:25 -04:00
Matt Nadareski
62a2fdeaa6 Remove incomplete compressions 2023-09-18 11:24:12 -04:00
Matt Nadareski
37c1852058 Remove unnecessary package references 2023-09-18 01:24:44 -04:00
Matt Nadareski
99c4a08d83 Remove two incomplete compressions 2023-09-18 01:14:01 -04:00
Matt Nadareski
9d4bc6bfab Move psxt001z to its own library 2023-09-18 00:59:37 -04:00
Matt Nadareski
71fd5af48e Move some classes to new library 2023-09-18 00:33:24 -04:00
Matt Nadareski
995521b789 Move Utilities to new library 2023-09-18 00:13:23 -04:00
Matt Nadareski
5031985883 Shift references around to be more accurate 2023-09-18 00:06:07 -04:00
Matt Nadareski
5759090291 Move FileType to new library 2023-09-17 23:58:42 -04:00
Matt Nadareski
008c1c89fb Move Protection to new library 2023-09-17 23:53:14 -04:00
Matt Nadareski
624eb40315 Move Packer to new library 2023-09-17 23:40:29 -04:00
Matt Nadareski
aaa12ae817 Move GameEngine to new library 2023-09-17 23:35:59 -04:00
Matt Nadareski
d37c90878c Move Interfaces to new library 2023-09-17 23:32:29 -04:00
Matt Nadareski
668a631c11 Create new base library 2023-09-17 23:28:27 -04:00
Matt Nadareski
f06c0f4553 Simplify some directives 2023-09-17 23:11:32 -04:00
Matt Nadareski
a0b13a6e6f Fix templated nullability issues 2023-09-17 22:37:01 -04:00
Matt Nadareski
1bd9f3fd88 Open the nullability floodgates 2023-09-17 00:20:33 -04:00
Matt Nadareski
93ba88a35f Enable nullable context and move WrapperFactory 2023-09-17 00:18:04 -04:00
Matt Nadareski
c86b1251a3 Extraction can go in FileType 2023-09-16 23:09:07 -04:00
Matt Nadareski
6f6954b270 Printing is only used by Test 2023-09-16 22:33:43 -04:00
Matt Nadareski
1d4ed425f1 Remove unnecessary dependency 2023-09-16 22:24:00 -04:00
Matt Nadareski
ba657e28ad Migrate to matching library 2023-09-16 22:08:18 -04:00
Matt Nadareski
7575353597 Add nullability to matching library, fix warnings 2023-09-16 21:25:50 -04:00
Matt Nadareski
10d3c09cfa Migrate to printing library 2023-09-16 16:28:41 -04:00
Matt Nadareski
5001c4a881 Fix build from previous updates 2023-09-16 02:04:47 -04:00
Matt Nadareski
7ecd0d1893 Fix using statements in interfaces 2023-09-16 01:00:47 -04:00
Matt Nadareski
ae802d5d75 Update serialization library 2023-09-16 00:58:24 -04:00
Matt Nadareski
3b4266246d Update serialization library 2023-09-16 00:50:48 -04:00
Matt Nadareski
a801e720b2 Use wrappers from Serialization (nw) 2023-09-16 00:44:22 -04:00
Matt Nadareski
a52d45f7c2 Use exposed model directly in more places 2023-09-15 22:21:05 -04:00
Matt Nadareski
57eaa1f04c Make wrapper model visible 2023-09-15 14:15:28 -04:00
Matt Nadareski
6cc2cc5be2 Port XZP to new printing 2023-09-15 13:55:56 -04:00
Matt Nadareski
ebcdc08a77 Port WAD to new printing 2023-09-15 12:01:56 -04:00
Matt Nadareski
7aebdf56fc Port VPK to new printing 2023-09-15 11:50:40 -04:00
Matt Nadareski
6de36eb71c Port VBSP to new printing 2023-09-15 11:37:04 -04:00
Matt Nadareski
5ebd392c5b Port SGA to new printing 2023-09-15 11:25:21 -04:00
Matt Nadareski
5fc2029725 Port Quantum to new printing 2023-09-15 02:48:19 -04:00
Matt Nadareski
45e4a01fc1 Port PE to new printing 2023-09-15 02:37:45 -04:00
Matt Nadareski
c4ea7891ea Port PlayJ to new printing 2023-09-15 01:29:29 -04:00
Matt Nadareski
de871fb8c1 Port PFF to new printing 2023-09-15 01:03:48 -04:00
Matt Nadareski
c322eebb98 Port PAK to new printing 2023-09-15 00:54:40 -04:00
Matt Nadareski
ea6b0f1ca3 Port Nitro to new printing 2023-09-15 00:47:44 -04:00
Matt Nadareski
a35a9a4ab6 Add byte array to encoding extension 2023-09-15 00:23:03 -04:00
Matt Nadareski
9a93c7b15d Port NE to new printing 2023-09-15 00:21:12 -04:00
Matt Nadareski
43eed75635 Port NCF to new printing 2023-09-14 23:52:06 -04:00
Matt Nadareski
74ea6e6002 Port N3DS to new printing 2023-09-14 23:36:29 -04:00
Matt Nadareski
91e2157622 Retrofit existing printers to use extensions 2023-09-14 23:25:39 -04:00
Matt Nadareski
87961e5451 Add StringBuilder extensions to be more consistent 2023-09-14 21:21:08 -04:00
Matt Nadareski
4ff203f393 Port MZ to new printing 2023-09-13 22:46:46 -04:00
Matt Nadareski
410b2bef2b Fix one nullability issue 2023-09-13 22:40:00 -04:00
Matt Nadareski
a9792fdff1 Port MS-CAB to new printing 2023-09-13 22:38:01 -04:00
Matt Nadareski
92e36527fd Port LE/LX to new printing 2023-09-13 22:03:11 -04:00
Matt Nadareski
aa1d7d475c Fix build from oversight 2023-09-13 21:28:09 -04:00
Matt Nadareski
91185c4fe1 Port IS-CAB to new printing 2023-09-13 21:21:19 -04:00
Matt Nadareski
c527b1911f Port GCF to new printing 2023-09-13 13:52:54 -04:00
Matt Nadareski
d1501b2e3e Remove .NET 8 entirely (thanks AppVeyor) 2023-09-13 13:17:08 -04:00
Matt Nadareski
03ac117844 Disable .NET 8 for Test 2023-09-13 13:14:11 -04:00
Matt Nadareski
515be8b025 Port CIA to new printing 2023-09-13 13:12:31 -04:00
Matt Nadareski
c3479450f5 Disable AppVeyor restore until .NET 8 support 2023-09-13 12:52:57 -04:00
Matt Nadareski
611aa3229c Port CFB to new printing 2023-09-13 12:49:46 -04:00
Matt Nadareski
5a865f3d08 Fix one nullability issue 2023-09-13 12:35:08 -04:00
Matt Nadareski
9d8d5c23c8 Clean up project files a little 2023-09-13 11:21:06 -04:00
Matt Nadareski
3fed1a3282 Allow building with .NET 8 2023-09-13 10:48:21 -04:00
Matt Nadareski
f47387c3a4 Port BSP to new printing 2023-09-13 10:41:24 -04:00
Matt Nadareski
133272acb7 Flatten some of the printing code 2023-09-13 10:32:02 -04:00
Matt Nadareski
c49ae98df5 Port BFPK to new printing 2023-09-13 01:37:13 -04:00
Matt Nadareski
a1672a9bc0 Port BD+ to new printing 2023-09-13 01:29:50 -04:00
Matt Nadareski
ffc2e23b2f Let's try a new library for this instead 2023-09-13 01:24:42 -04:00
Matt Nadareski
c481e73418 Take it one step further (test) 2023-09-13 01:15:57 -04:00
Matt Nadareski
06b3124b62 Attempt to make most printing static (test) 2023-09-13 01:14:25 -04:00
Matt Nadareski
d7d81665a0 Fix miscellaneous nullability warnings 2023-09-13 00:29:21 -04:00
Matt Nadareski
24c542c22f Fix "converting null literal" warnings 2023-09-13 00:16:27 -04:00
Matt Nadareski
ec616fcdac Fix "dereference" warnings 2023-09-13 00:08:11 -04:00
Matt Nadareski
24e9455733 Fix "possible null reference" warnings 2023-09-12 17:12:23 -04:00
Matt Nadareski
58aaf46a0e Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2023-09-12 12:35:41 -04:00
Matt Nadareski
54e92fe9c8 Fix "nullability of reference types" warnings 2023-09-12 12:35:19 -04:00
Matt Nadareski
4bb83c5d86 Don't allow model to be nullable 2023-09-11 23:38:51 -04:00
Matt Nadareski
2f9280460e Make wrappers more type-defined 2023-09-11 23:25:09 -04:00
Matt Nadareski
30e8e79cf7 Fix PE references 2023-09-11 21:08:08 -04:00
Matt Nadareski
7bb0d4f39a Migrate to ASN1 package 2023-09-11 20:59:11 -04:00
TheRogueArchivist
046814b7c4 Add new EasyAntiCheat file detections (#265)
* Add new EasyAntiCheat file detections

* Add additional EasyAntiCheat file detections
2023-09-11 07:42:54 -07:00
Matt Nadareski
cf00348d46 Update Serialization to 1.1.1 2023-09-11 01:21:38 -04:00
Matt Nadareski
8466edf80f Migrate to Serialization package 2023-09-10 23:51:38 -04:00
Matt Nadareski
ccdf539ed4 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2023-09-10 23:26:54 -04:00
Matt Nadareski
aeee6e9cda Fix build from package update 2023-09-10 23:26:32 -04:00
TheRogueArchivist
2af21cb245 Add DRML link to engine32 (#264) 2023-09-10 20:21:27 -07:00
Matt Nadareski
96fb5a2f93 Update Models to 1.1.1 2023-09-10 21:56:14 -04:00
Matt Nadareski
1eaefb16ba Use IO package for array and stream extensions 2023-09-08 16:33:06 -04:00
Matt Nadareski
1c972a29a7 Migrate INI reading to Nuget 2023-09-08 12:19:31 -04:00
Matt Nadareski
aa33c083fe Fix package reference for Models 2023-09-08 10:36:45 -04:00
Matt Nadareski
a9454e96ed Migrate to Nuget package for Models 2023-09-04 23:44:45 -04:00
Matt Nadareski
fb6fa85cd3 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2023-09-04 22:58:25 -04:00
TheRogueArchivist
3c12bdc212 Add Engine32 detection (#263)
* Add Engine32 detection

* Address PR comment
2023-08-28 12:09:25 -07:00
Matt Nadareski
5eeee760f7 Remove unnecessary param summaries 2023-08-26 22:53:35 -04:00
Matt Nadareski
cfe889d5b3 Add and use FilePathMatch (fixes #262) 2023-08-26 22:51:55 -04:00
TheRogueArchivist
3045c41eda Fix Uplay false positive (#261)
Fix a false positive that resulted in "yuPlay.exe" being detected as Uplay.
2023-08-26 19:02:26 -07:00
TheRogueArchivist
d194ef9dd8 Add new SafeCast version (#260) 2023-07-19 10:30:48 -07:00
Matt Nadareski
aeb379f307 Bump version to 2.8 2023-07-14 11:37:17 -04:00
TheRogueArchivist
cae0edfb49 Add DRML links to Denuvo AC and PlayJ (#259) 2023-07-14 08:35:09 -07:00
TheRogueArchivist
e97558db1f Add new HexaLock check (#254) 2023-05-30 17:56:19 -07:00
Matt Nadareski
06ecc1a571 Temporarily disable MS-CAB extraction
This only affects the code for normal protection scans. This does not affect trying to run extract separately, mainly for the purposes of testing.
2023-05-30 13:43:35 -04:00
TheRogueArchivist
adcf9ee27e Add hash check for RipGuard (#252)
* Add hash check for RipGuard

* Make sure the file exists before trying to hash it

* It's the safety dance
2023-05-14 12:45:30 -07:00
TheRogueArchivist
a8c759be55 Add basic RipGuard detection (#251)
* Add basic RipGuard detection and notes.
2023-05-04 05:24:33 -07:00
Matt Nadareski
ecf97de439 Use larger output buffer for MSZIP 2023-04-28 15:14:28 -04:00
TheRogueArchivist
f134de6609 Minor SecDrv cleanup (#249)
Update comments and improve output.
2023-04-22 18:18:09 -07:00
TheRogueArchivist
d91ce3100b Overhaul Macrovision and related protections (#248)
* Improve several SafeCast checks

* Add new SafeCast versions.

* Add SafeCast NE checks.

* Move stxt* checks to Macrovision, and add SafeCast specific check.

* Confirm SafeCast file and add relevant executable checks.

* Add empty file detection for some SafeDisc drivers.

* Various Macrovision improvements

* Move and improve stxt* section checks.

* Add proper Redump entry number for Puyo Puyo Fever.

* Add directory separator to some SafeDisc checks to avoid false positives.

* Add SafeWrap skeleton with notes.

* Minor Macrovision fixes

* Fix stxt* section checks.

* Add product identification for one CDS-300 version.

* Further Macrovision improvements

* Add product detection via version for SafeDisc Lite and SafeCast ESD.

* Add improved SafeDisc LT/Lite checks.

* Add various notes about SafeCast/SafeDisc.

* Add new secdrv version detection.

* Herald the upcoming secdrv cataclysm.

* Move SecDrv checks into Macrovision

* Move SecDrv checks into Macrovision, as it's known to be present on multiple Macrovision products.

* Improve SafeCast checks

* Add new SafeCast executable and path checks.

* Change a C-Dilla output.

* ah sweet, man-made horrors beyond my comprehension

* Split new and old "BoG" string checks to make finding an expunged version easier.

* Confirm unconfirmed SafeCast version, add new unconfirmed version.

* Remove now unneeded result list cleaning.

* Improve SafeCast notes.

* Add new SafeCast file description and file name checks.

* Remove "GetSafeDisc320to4xVersion" and improve CLCD16 version report.

* Address PR comments

* Address further PR comments
2023-04-21 19:38:18 -07:00
Matt Nadareski
20de40014d Fix version info reading 2023-03-27 10:46:05 -04:00
TheRogueArchivist
a7f9a99d10 Overhaul SVKP (#246)
* Begin SVKP Overhaul

* Add several entry point checks for SVKP, as well as a section check.

* Add SVKP notes.

* Add unconfirmed message in various ActiveMARK checks.

* Add file detections for SVKP

* Add file detections for SVKP.
* Cleanup notes.
* Update README.
2023-03-24 07:35:37 -07:00
TheRogueArchivist
4bdfbabaab Add new SafeDisc DrvMgt detection (#247)
* Add new SafeDisc DrvMgt detection.
2023-03-24 06:03:56 -07:00
TheRogueArchivist
5465c57d96 Add NeoLite detection (#245)
* Add NeoLite detection.
* Update README.
2023-03-22 11:26:25 -07:00
TheRogueArchivist
5082c8f705 Add RenderWare detection (#244)
* Add RenderWare detection.
* Remove unneeded note from SafeDisc.
* Update README.
2023-03-22 10:20:22 -07:00
Matt Nadareski
509fff4684 Reset state.ll for dynamic 2023-03-21 14:14:17 -04:00
Matt Nadareski
9d2c14f809 Fix MSZIP signature check (nw) 2023-03-21 13:39:25 -04:00
Matt Nadareski
b023549b87 Add note for IExtractable 2023-03-21 13:14:42 -04:00
Matt Nadareski
0983073538 Add game engine detection skeleton 2023-03-21 10:42:14 -04:00
TheRogueArchivist
815acf2ce0 Add NEAC Protect detection (#241)
* Add NEAC Protect detection

* Add NEAC Protect detection.
* Update README.

* Address PR comments
2023-03-16 12:38:30 -07:00
Matt Nadareski
6b8596466b Add unused MS-DOS executable check interface 2023-03-15 16:12:12 -04:00
Matt Nadareski
1e5bb7df64 Simplify packer handling code 2023-03-15 15:58:19 -04:00
Matt Nadareski
e920bfc69c Executable is not inherently extractable 2023-03-15 15:53:24 -04:00
Matt Nadareski
a85c6f4028 Rearrange Executable-related things 2023-03-15 15:51:38 -04:00
Matt Nadareski
a75bc15f29 Update IPathCheck helper a bit 2023-03-15 14:21:02 -04:00
Matt Nadareski
659aa30fb3 Update names, access permissions 2023-03-15 14:16:20 -04:00
Matt Nadareski
54a11916d2 Cleanup namespaces 2023-03-15 13:16:21 -04:00
Matt Nadareski
47f423d092 Implement IPathCheck helper 2023-03-15 12:55:08 -04:00
Matt Nadareski
5c5e68e31d Gut Executable for now 2023-03-15 11:37:20 -04:00
Matt Nadareski
9e917e2bb9 Create new Scanner helper classes 2023-03-15 11:06:29 -04:00
Matt Nadareski
4bd4d2f395 Remove errant using statement 2023-03-13 22:58:37 -04:00
Matt Nadareski
6406248840 Make extractable packers safer 2023-03-13 22:53:57 -04:00
Matt Nadareski
3d8134bbd3 Map out Executable extraction skeleton 2023-03-13 22:36:28 -04:00
Matt Nadareski
15310a6c47 Change namespaces but don't move yet 2023-03-13 22:22:52 -04:00
Matt Nadareski
450a8cd5bd Migrate wrapper methods to proper factory 2023-03-13 22:07:28 -04:00
Matt Nadareski
088f99942f Move file type helpers to Utilities 2023-03-13 22:03:10 -04:00
Matt Nadareski
3e97bd8d2d Move SupportedFileType to correct namespace 2023-03-13 21:54:40 -04:00
Matt Nadareski
866051c975 Fix MPQ namespace 2023-03-13 21:49:25 -04:00
Matt Nadareski
0be437f3cf Add skeleton to Scanner helpers 2023-03-13 21:47:40 -04:00
Matt Nadareski
11f3dec65d Add more notes about extraction 2023-03-13 21:45:17 -04:00
Matt Nadareski
912d151164 Add skeleton implementions in Executable 2023-03-13 21:12:11 -04:00
Matt Nadareski
863678f850 Add extractable protections to caches 2023-03-13 21:05:18 -04:00
Matt Nadareski
b82a6a8c5d Simplify some Executable code
Hopefully, simplifying this code will open the door to getting rid of `IScannable` in some way
2023-03-13 20:49:59 -04:00
Matt Nadareski
ab2daf2a80 Fix helper in Executable 2023-03-13 20:39:50 -04:00
Matt Nadareski
f734e3a58a Move MPQ to proper library, fix stormlibsharp 2023-03-13 16:41:53 -04:00
Matt Nadareski
212981fda9 Move stormlibsharp to Compression 2023-03-13 16:31:34 -04:00
Matt Nadareski
c64e138ba7 Figure out how to convert Textfile 2023-03-13 16:17:21 -04:00
Matt Nadareski
c43353d126 Move most detectables to new interface 2023-03-13 16:06:45 -04:00
Matt Nadareski
d439ba9592 Add unused IDetectable interface 2023-03-13 15:34:26 -04:00
Matt Nadareski
b7f06f0b59 Move extractable file types to new library 2023-03-10 13:48:24 -05:00
Matt Nadareski
60d666f8be Add skeleton file type library 2023-03-10 11:55:19 -05:00
Matt Nadareski
4ff4c2afef Move helper methods used in a single place 2023-03-10 11:41:08 -05:00
Matt Nadareski
655b8385f9 Rename tool class 2023-03-10 11:20:35 -05:00
Matt Nadareski
439c141c2c Move packer scans to their own library 2023-03-09 23:52:58 -05:00
Matt Nadareski
95755b930d Add packer library skeleton 2023-03-09 23:31:45 -05:00
Matt Nadareski
9cf54c1f2d Create dummy class for protection library 2023-03-09 23:26:18 -05:00
Matt Nadareski
e118418a23 Move protection scans to their own library
This change also removes a couple of things from `BurnOutSharp.Tools.Utilities` that are no longer needed there. Linear executables are included in the scanning classes. Update the guides accordingly.
2023-03-09 23:19:27 -05:00
Matt Nadareski
a3567d6eb2 Add protection library skeleton 2023-03-09 20:50:59 -05:00
Matt Nadareski
a359143bc7 Include debug in IExtractable 2023-03-09 17:16:39 -05:00
Matt Nadareski
77b7a24d85 Add TODO in Executable 2023-03-09 16:12:21 -05:00
Matt Nadareski
338b2593d5 Update guides 2023-03-09 16:08:56 -05:00
Matt Nadareski
ded5e27355 Migrate packers to extractable only 2023-03-09 16:02:51 -05:00
Matt Nadareski
ee1b005d96 Add call to packer extraction 2023-03-09 15:50:14 -05:00
Matt Nadareski
cd2673d1ba Implement unused packer extractions 2023-03-09 15:46:48 -05:00
Matt Nadareski
41d77085ae Add IExtractable skeletons to packers 2023-03-09 15:33:21 -05:00
Matt Nadareski
67059b2e43 Update guides 2023-03-09 15:17:35 -05:00
Matt Nadareski
f6157ef79b Implementations act the same 2023-03-09 15:07:35 -05:00
Matt Nadareski
6e5d517e82 Replace parts of Scan with Extract 2023-03-09 14:50:24 -05:00
Matt Nadareski
1dca51988a Implement unused extractions 2023-03-09 14:39:26 -05:00
Matt Nadareski
3c064bad55 Add skeleton IExtractable implementations 2023-03-09 14:04:31 -05:00
Matt Nadareski
d60a3ce05a Add extractable interface (unused) 2023-03-09 13:48:51 -05:00
Matt Nadareski
f68438ff8c Remove some errant temp directories 2023-03-09 13:45:42 -05:00
Matt Nadareski
d351f1d08e Create separate Options object 2023-03-09 13:26:20 -05:00
Matt Nadareski
70bdb8f37d Move most interfaces to separate library 2023-03-09 11:52:28 -05:00
TheRogueArchivist
3cd713e078 Add SafeDisc entry point check (#240)
* Add SafeDisc entry point check

* Add SafeDisc entry point check

* Address PR comments
2023-03-08 18:46:14 -08:00
Matt Nadareski
454655de5a Missed a couple in Wrappers 2023-03-08 17:53:26 -05:00
Matt Nadareski
268ed1a6a6 Clean up namespaces in Builders 2023-03-08 17:51:17 -05:00
Matt Nadareski
a42ce601b8 Simplify namespaces in Wrappers 2023-03-08 17:49:14 -05:00
Matt Nadareski
756b37ef6c Minor update for clarity 2023-03-08 17:16:29 -05:00
TheRogueArchivist
ab7e708e02 fuck macrovision (#239)
* Make SafeDisc stxt* section checks more accurate.
* Add unknown SafeDisc section notes.
2023-03-08 14:08:36 -08:00
TheRogueArchivist
326d916c0b Separate unconfirmed Macrovision checks (#238)
* Separate unconfirmed Macrovision checks

* Separate unconfirmed Macrovision checks.

* Separate unconfirmed SafeDisc version

* Separate unconfirmed SafeDisc version.
2023-03-08 13:21:34 -08:00
Matt Nadareski
db09bd931b Macrovision-adjacent additions (TheRogueArchivist) 2023-03-08 15:21:21 -05:00
TheRogueArchivist
d1e9eb90f1 Add DRML link to phenoProtect (#235)
* Add DRML link to phenoProtect.
* Fix case of the "phenoProtect" class name.
2023-03-08 11:59:57 -08:00
Matt Nadareski
20a5c4c78d Use new Macrovision helper method 2023-03-08 09:50:34 -05:00
Matt Nadareski
499f9888b1 Create helper for Macrovision version mapping 2023-03-08 09:40:19 -05:00
Matt Nadareski
7bb3364b43 Trim not TrimEnd 2023-03-08 08:47:46 -05:00
Matt Nadareski
473cbc5694 BOS.* -> BOS.* 2023-03-07 16:59:14 -05:00
Matt Nadareski
e32b24c9f6 BOS.ASN1 -> BOS.ASN1 2023-03-07 12:42:39 -05:00
Matt Nadareski
777fdc14c8 BOS.Utilities -> BOS.Utilities 2023-03-07 12:04:48 -05:00
Matt Nadareski
ffbb01c25c Migrate CDS path checks 2023-03-07 11:31:55 -05:00
Matt Nadareski
47380c2c1c Start migrating CDS, fix Macrovision directory check 2023-03-07 11:28:02 -05:00
Matt Nadareski
51e9121a6b Update generic Macrovision check 2023-03-07 11:22:45 -05:00
Matt Nadareski
94f51d518d Move SafeDisc-specific checks 2023-03-07 11:19:18 -05:00
Matt Nadareski
8fdc17b239 Missed an access modifier 2023-03-07 11:12:31 -05:00
Matt Nadareski
42bb29185f Macrovision cleanup 2023-03-07 11:10:56 -05:00
Matt Nadareski
05ae0f4e80 Add .NET 7 support 2023-03-06 09:34:51 -05:00
Matt Nadareski
092374a143 Bump version to 2.7 2023-03-06 08:57:43 -05:00
TheRogueArchivist
3cfb60430a Split SafeDisc and CDS-300 checks (#236)
* Split SafeDisc/CDS-300 checks.
* Add new DrvMgt.dll hash check.
2023-03-05 14:33:39 -08:00
TheRogueArchivist
370cc68fa4 Move Freelock notes to DRML (#233)
* Move Freelock notes to DRML.
* Add new Freelock checks.
* Tweak some Freelock output.,
* Fix existing DRML links from other protections.
2023-02-09 06:05:13 -08:00
TheRogueArchivist
8fe5046c19 Add new MGI Registration check (#232)
* Add new MGI Registration check

* Add new MGI Registration check

* Address PR comment

* Address PR comment
2023-02-08 13:04:47 -08:00
TheRogueArchivist
37e7604441 Add MGI Registration detection (#231)
* Add MGI Registration detection.
* Update README.
2023-02-08 11:43:15 -08:00
TheRogueArchivist
7651b34855 Add new CD-Key/Serial check (#230)
* Add new CD-Key/Serial check.
2023-02-07 07:00:04 -08:00
TheRogueArchivist
4bf89b1d5f Add new known C-Dilla versions (#229)
* Add two new known C-Dilla versions.

* Make IA samples more consistent.

* Remove TODO.
2023-02-07 06:59:49 -08:00
TheRogueArchivist
0287284909 Add more CD-Cops notes (#228)
* Add more CD-Cops notes and samples.
2023-02-07 06:59:31 -08:00
Matt Nadareski
a8453b3f21 Descriptions for all! 2023-01-18 11:18:53 -08:00
Matt Nadareski
2552564953 Create wrapper creation method 2023-01-18 10:56:19 -08:00
Matt Nadareski
0d4d19559a else if and a note 2023-01-18 08:39:27 -08:00
Matt Nadareski
52f4132ccb Be smarter about EXE checks 2023-01-18 08:36:16 -08:00
Matt Nadareski
cb6440662b Create LE during scan as well 2023-01-17 20:22:25 -08:00
Matt Nadareski
6293895611 Make it so debug doesn't return early 2023-01-17 20:21:25 -08:00
Matt Nadareski
f564fb6e9e Make JSON handling internally a bit easier 2023-01-16 22:15:45 -08:00
Matt Nadareski
3f2adfcf62 Add explicit note about JSON output 2023-01-16 22:12:54 -08:00
Matt Nadareski
2c979f291e Add Options class, allow multiple features 2023-01-16 21:52:32 -08:00
Matt Nadareski
7e7b2ee64a Support PFF version 0 (nw) 2023-01-16 14:34:28 -08:00
Matt Nadareski
87108405a8 Add PFF support (full) 2023-01-15 23:33:09 -08:00
Matt Nadareski
9fb055cbff Move file name into try/catch 2023-01-15 17:45:11 -08:00
Matt Nadareski
e690f0137e Don't try to unpack invalid IS-CAB files 2023-01-15 17:44:25 -08:00
Matt Nadareski
87c08d6fbd Replace EntryHeader with AudioHeader 2023-01-15 16:26:05 -08:00
Matt Nadareski
8c164d776e Start adding separate header information 2023-01-15 12:30:22 -08:00
Matt Nadareski
964271b4e1 Remove now-redundant note 2023-01-15 11:57:41 -08:00
Matt Nadareski
e99ba48f07 Determine PLJv2 Block 3 format, add notes 2023-01-15 02:07:56 -08:00
Matt Nadareski
62b1627b04 More PLJv2 notes/support 2023-01-15 00:19:16 -08:00
Matt Nadareski
3a54997d42 Fix corner case in rapid scans 2023-01-14 23:31:31 -08:00
Matt Nadareski
7d95a43b4b Fix RCDATA issue 2023-01-14 23:26:52 -08:00
Matt Nadareski
23ea8710c0 Read PLJv2 track ID and year 2023-01-14 23:14:50 -08:00
Matt Nadareski
0b62a52991 PLJv2 doesn't seem to have offsets 2023-01-14 23:06:50 -08:00
Matt Nadareski
1143c8a8b7 Add notes, fix v2 skipping 2023-01-14 22:52:22 -08:00
Matt Nadareski
a5b66caae6 "Support" PlayJ v2 by skipping fields 2023-01-14 22:36:57 -08:00
Matt Nadareski
b0b87d05fd Add PLJ builders/wrappers/printing 2023-01-14 22:24:25 -08:00
Matt Nadareski
cb3c666f64 Add PlayJ models 2023-01-14 21:43:59 -08:00
Matt Nadareski
12fdae7944 Fill in more notes before modelling 2023-01-14 21:20:45 -08:00
Matt Nadareski
e76bc70ec6 Fill out more PLJ notes before modelling 2023-01-14 19:47:24 -08:00
Matt Nadareski
e78bb8cb41 Add PLJ header format notes 2023-01-14 14:19:38 -08:00
Matt Nadareski
5153e73f42 Update README 2023-01-14 01:40:57 -08:00
Matt Nadareski
7f36ff8a2b More fixes to IS-CAB 2023-01-14 01:39:15 -08:00
TheRogueArchivist
99a8a39dda Move MediaCloQ notes to DRML (#227)
* Move MediaCloQ notes to DRML.
* Add TODO and fix typo.
2023-01-14 00:44:10 -08:00
Matt Nadareski
adbf983e65 Hook up IS-CAB printing 2023-01-14 00:42:03 -08:00
Matt Nadareski
d7639495ac Fill in some missing IS-CAB parts 2023-01-14 00:41:13 -08:00
Matt Nadareski
fbe09d9082 Add IS-CAB wrapper 2023-01-13 22:24:25 -08:00
Matt Nadareski
70468b72c3 Fix up IS-CAB a little 2023-01-13 21:40:01 -08:00
TheRogueArchivist
90f4af1121 Add version finding to DiscGuard (#226)
* Add version finding to DiscGuard

* Add version finding to DiscGuard.

* Update notes.

* Address PR comments
2023-01-13 20:30:42 -08:00
Matt Nadareski
aa37449bbf Update developer guide 2023-01-13 15:34:10 -08:00
Matt Nadareski
c835e04722 Update coding guide 2023-01-13 15:29:56 -08:00
Matt Nadareski
29b999b8ed Info should act like scan 2023-01-13 15:15:30 -08:00
Matt Nadareski
9ddd6cc317 Write info outputs to file for easier use 2023-01-13 14:20:41 -08:00
Matt Nadareski
3a694f0e31 Pretty print uses StringBuildernow 2023-01-13 14:04:21 -08:00
Matt Nadareski
080cbda588 Rename Print to PrettyPrint 2023-01-13 12:02:42 -08:00
Matt Nadareski
fd066e8aae Simplify printer code, don't duplicate print 2023-01-13 11:14:34 -08:00
Matt Nadareski
0fd0cf689a Add JSON serialization to wrappers (.NET 6) 2023-01-13 10:41:50 -08:00
Matt Nadareski
f85adda24c Add some DVD models 2023-01-12 23:38:09 -08:00
Matt Nadareski
2d1e8e02aa Overhaul BD+ to model/builder/wrapper 2023-01-12 14:45:04 -08:00
Matt Nadareski
371fbee7a4 Replace current AACS checks 2023-01-12 13:57:10 -08:00
Matt Nadareski
a5bb95e7c1 Hook up AACS media block printing 2023-01-12 13:29:02 -08:00
Matt Nadareski
53b5a443fe Add AACS wrapper and printing 2023-01-12 13:28:12 -08:00
Matt Nadareski
a230871f75 Add AACS media block builder 2023-01-12 12:28:31 -08:00
Matt Nadareski
f560ce17e8 Add AACS media key block to file types 2023-01-12 09:44:31 -08:00
Matt Nadareski
b96329bd33 Add AACS media key block models 2023-01-12 09:40:02 -08:00
Matt Nadareski
913f7802de Fix LE/LX debug parsing 2023-01-11 13:55:00 -08:00
Matt Nadareski
a9f61ed51e Hook up LE/LX printing 2023-01-11 13:39:49 -08:00
Matt Nadareski
04c0835228 Add LE/LX printing to wrapper 2023-01-11 13:39:23 -08:00
Matt Nadareski
af7ff05ecf Fill out LE/LX builder 2023-01-11 11:44:13 -08:00
Matt Nadareski
4ccf80189e Start filling out LE/LX builder 2023-01-10 23:41:15 -08:00
Matt Nadareski
b417229ee6 Add print debug, fix NE printing 2023-01-10 23:15:59 -08:00
Matt Nadareski
61457582b3 More summary info fleshing out 2023-01-10 12:23:48 -08:00
Matt Nadareski
ecc1613f49 Start adding some MSI-specific things 2023-01-10 11:59:33 -08:00
Matt Nadareski
5ea89eefe8 MSI was really CFB all along 2023-01-10 10:51:36 -08:00
Matt Nadareski
661808826a Add hex to outputs for debugging 2023-01-10 09:50:49 -08:00
Matt Nadareski
342f78ffd0 Add extension properties for sector sizes 2023-01-09 22:23:12 -08:00
Matt Nadareski
cc6a65d5e4 Slight reorganization 2023-01-09 22:17:58 -08:00
Matt Nadareski
068ee76983 Add generic data reading 2023-01-09 22:15:37 -08:00
Matt Nadareski
b980b33019 Add sector chain helpers 2023-01-09 22:04:29 -08:00
Matt Nadareski
4327ce7848 Fix typo in directory entry output 2023-01-09 21:40:56 -08:00
Matt Nadareski
2c813e7b3d Add CFB to the readme 2023-01-09 21:27:00 -08:00
Matt Nadareski
d69746f7ef Fix printing, hook up to printer 2023-01-09 21:18:45 -08:00
Matt Nadareski
ce8f73d30d Add CFB wrapper and printing 2023-01-09 21:14:21 -08:00
Matt Nadareski
d6602ac8a8 Make UPX a little safer 2023-01-09 16:34:45 -08:00
Matt Nadareski
6478af03e7 Add class IDs we care about 2023-01-09 16:34:22 -08:00
Matt Nadareski
f086e63914 Omit top 32-bits for version 3 2023-01-09 16:33:56 -08:00
Matt Nadareski
6fbb6bd8dc Implement directory section parsing 2023-01-09 15:58:10 -08:00
Matt Nadareski
008629b61f Add all but directory sectors 2023-01-09 14:32:40 -08:00
Matt Nadareski
b7704dbe57 Add skeleton builder for CFB 2023-01-09 13:24:11 -08:00
Matt Nadareski
5aff2d0b1b Add CFB models 2023-01-09 13:11:06 -08:00
Matt Nadareski
771bbeed6a Add DS/3DS to readme 2023-01-09 11:43:07 -08:00
Matt Nadareski
53dd1e9aa5 Add alignment, partition parsing, fix BE 2023-01-09 11:33:54 -08:00
Matt Nadareski
6b7ed456ac Hook up CIA to printer 2023-01-09 11:31:17 -08:00
Matt Nadareski
5e2185dffd Add CIA printing 2023-01-09 10:53:15 -08:00
Matt Nadareski
b5d318013b Add CIA builder 2023-01-09 09:53:57 -08:00
Matt Nadareski
07a926e50c Forgot references 2023-01-08 21:39:48 -08:00
Matt Nadareski
78bbb63c11 Fix formatting issue; clarification 2023-01-08 21:34:52 -08:00
Matt Nadareski
1fd613c2b2 "Library" not "utility"; clarification 2023-01-08 21:31:41 -08:00
Matt Nadareski
792833ebc8 Update readme and description 2023-01-08 21:27:23 -08:00
Matt Nadareski
7392fce770 Add NDS name table/FAT printing 2023-01-08 10:24:27 -08:00
Matt Nadareski
6c621c743d Add NDS FAT parsing 2023-01-08 00:20:57 -08:00
Matt Nadareski
50a7883958 Add NDS name table parsing 2023-01-08 00:16:01 -08:00
Matt Nadareski
3882db6fc6 Add RomFS header parsing/printing 2023-01-07 23:09:26 -08:00
Matt Nadareski
c91691f79b Remove duplicate TODO 2023-01-07 22:57:46 -08:00
Matt Nadareski
17fbf1163d Add ExeFS printing 2023-01-07 22:50:31 -08:00
Matt Nadareski
9a1bbd7e0d Add ExeFS header parsing 2023-01-07 22:44:31 -08:00
Matt Nadareski
bf6f3bad46 Print extended headers 2023-01-07 22:33:55 -08:00
Matt Nadareski
b99b2a53cf Add extended header parsing for N3DS 2023-01-07 22:12:58 -08:00
Matt Nadareski
1fec5c15d4 Fix N3DS parsing and printing 2023-01-07 21:42:13 -08:00
Matt Nadareski
a8b13e60b6 Fix printing if-statements 2023-01-07 20:55:17 -08:00
Matt Nadareski
4c0c44de6b Add DS/3DS to Test printer 2023-01-07 14:50:21 -08:00
Matt Nadareski
af0623beea Add DS/3DS to supported file types 2023-01-07 14:47:36 -08:00
Matt Nadareski
761b418d21 Fix DS/3DS sttuff, add 3DS wrapper/printing 2023-01-07 12:33:15 -08:00
Matt Nadareski
0316edb8cb Split header into 2 files 2023-01-06 23:48:26 -08:00
Matt Nadareski
48cf417d60 Add wrapper and printing for NDS 2023-01-06 23:39:32 -08:00
Matt Nadareski
83af2926aa Add N3DS builder 2023-01-06 16:14:00 -08:00
Matt Nadareski
ddfa820004 Add NDS builder 2023-01-06 15:34:04 -08:00
Matt Nadareski
80986978cb Add N3DS to models 2023-01-06 15:20:10 -08:00
Matt Nadareski
68283554e9 Add NDS to models 2023-01-06 14:37:40 -08:00
Matt Nadareski
0fcedfafbe Bump version to 2.6 2023-01-06 13:04:52 -08:00
Matt Nadareski
d075ce4ebd Relicense to MIT
I am relicensing this code with the permission of all code contributors to this port of the code. All code that this is based on is unaffected by this.
2023-01-06 11:43:50 -08:00
Matt Nadareski
3c6fcb4e4d Update to UnshieldSharp 1.6.9 2023-01-06 11:23:29 -08:00
Matt Nadareski
5d37b7947e Use license expression 2023-01-06 10:57:55 -08:00
Matt Nadareski
537b5c83f2 Add commit hash to artifacts 2023-01-06 10:56:49 -08:00
Matt Nadareski
44d2c90aea Update to WiseUnpacker 1.0.4 2023-01-05 23:19:44 -08:00
Matt Nadareski
af0c984b08 Skip trying to parse null debug data 2023-01-05 22:42:54 -08:00
Matt Nadareski
e9f01c7a10 Make ImpulseReactor check safer for null values 2023-01-05 22:30:56 -08:00
TheRogueArchivist
0c468e3489 Fix typo in SafeDisc detection (#224)
* Fix typo in SafeDisc detection.
2023-01-05 20:34:05 -08:00
TheRogueArchivist
aff43b7625 Add encrypted Link Data Security file detection (#223)
* Add encrypted Link Data Security file (LDSCRYPT) detection.

* Update CD-Cops notes.
2023-01-05 14:55:21 -08:00
Matt Nadareski
dc53ebd378 Try outputting directly to the correct folder 2023-01-05 13:15:06 -08:00
Matt Nadareski
7a7518d92a Buillders not Builder 2023-01-05 13:13:22 -08:00
Matt Nadareski
ee182b8ea7 Remove old Nuget remnants, fix relative path 2023-01-05 13:07:45 -08:00
Matt Nadareski
c1bf48480c Avoid moves, reference directly 2023-01-05 13:02:25 -08:00
Matt Nadareski
b5bb88553c Try quotes again, just differently 2023-01-05 12:57:12 -08:00
Matt Nadareski
9b9fc09bdf Add trailing slash for mv 2023-01-05 12:00:46 -08:00
Matt Nadareski
5709c88232 Disable Nuget, rely on dotnet instead 2023-01-05 12:00:13 -08:00
Matt Nadareski
522c9fba08 Try using different mv command 2023-01-05 11:55:14 -08:00
Matt Nadareski
3a7b15f231 Add Nuget packages to auto-build 2023-01-05 11:43:18 -08:00
TheRogueArchivist
cb2c96ef7d Add basic HyperTech CrackProof detection (#222)
* Add basic HyperTech CrackProof detection

* Add super basic, incomplete HyperTech CrackProof detection.

* Address PR comments
2023-01-05 11:24:40 -08:00
Matt Nadareski
f89f691ee3 Archive scanning is not content scanning 2023-01-05 11:00:29 -08:00
Matt Nadareski
a0f59b774a Enable content scanning flag in Test 2023-01-05 10:54:34 -08:00
Matt Nadareski
65adf2109d Add content scanning flag in Scanner/Test 2023-01-05 10:53:06 -08:00
Matt Nadareski
92da1695bf Add path scanning flag to Test 2023-01-05 10:49:01 -08:00
Matt Nadareski
e46011beff Add path scanning flag in Scanner 2023-01-05 10:46:13 -08:00
Matt Nadareski
e733dea80e CD-Cops path checks are case-sensitive 2023-01-05 10:38:11 -08:00
Matt Nadareski
6a27161322 Add WiseInst for old NE Wise 2023-01-04 23:53:46 -08:00
Matt Nadareski
6bb4193167 Hook up NE Wise extraction thru WiseUnpacker again 2023-01-04 23:31:52 -08:00
Matt Nadareski
52c34250ff Add NE Wise note for later 2023-01-04 23:13:45 -08:00
Matt Nadareski
cd72cccbaa Fix incorrect printer output 2023-01-04 23:00:00 -08:00
Matt Nadareski
ad9689440a Use NE format property too (nw) 2023-01-04 22:53:52 -08:00
Matt Nadareski
dd193352e2 Remove unused directory creation 2023-01-04 22:44:14 -08:00
Matt Nadareski
a376041be4 Separate out Wise PE extraction 2023-01-04 22:43:11 -08:00
Matt Nadareski
7d14eb35ba Support PKZIP-compressed Wise installer data 2023-01-04 22:37:44 -08:00
Matt Nadareski
fdad3b0c87 Print first 16 bytes of unknown resources 2023-01-04 20:29:41 -08:00
Matt Nadareski
8ebaa59b5f Add precursor position check for segment validity 2023-01-04 20:24:31 -08:00
Matt Nadareski
6037be404c Fix bad LaserLok check 2023-01-04 20:22:20 -08:00
Matt Nadareski
1ead65126f WIP bzip2 code 2023-01-04 20:19:15 -08:00
Matt Nadareski
cfa1bc8875 Port ADPCM compression from stormlib 2023-01-04 11:03:03 -08:00
Matt Nadareski
cfbac7a9ab Ensure required field marked as such 2023-01-04 10:27:37 -08:00
Matt Nadareski
6f62777033 Split files for clarity 2023-01-04 10:23:03 -08:00
Matt Nadareski
0a523d74d5 x, not e 2023-01-04 10:13:36 -08:00
Matt Nadareski
907d0eb724 Enable experimental extraction feature 2023-01-04 10:10:42 -08:00
Matt Nadareski
edcf20885c Extraction is possible 2023-01-04 10:05:21 -08:00
Matt Nadareski
bb838c5b1f Fix error for small executables 2023-01-03 23:43:34 -08:00
Matt Nadareski
fa90618200 Remove one more note in README 2023-01-03 23:14:24 -08:00
Matt Nadareski
b421d8f818 Order of operations is important 2023-01-03 23:01:43 -08:00
Matt Nadareski
c1151b7e93 Minor cleanup and bugfixing 2023-01-03 22:32:22 -08:00
Matt Nadareski
b1d6b1be9c Fix errantly deleted line in csproj 2023-01-03 22:24:41 -08:00
Matt Nadareski
cb45405e09 Remove remnants of Dtf and LibMSPackSharp 2023-01-03 22:21:29 -08:00
Matt Nadareski
6ef9f2856a Remove Dtf and LibMSPackSharp 2023-01-03 22:15:53 -08:00
Matt Nadareski
c14300ffbb Port MS-ZIP for MS-CAB 2023-01-03 22:11:57 -08:00
Matt Nadareski
42b4c40d87 Port LZX init and decompression 2023-01-03 19:00:21 -08:00
Matt Nadareski
1c78dac79f Port LZX read lengths 2023-01-03 16:11:30 -08:00
Matt Nadareski
bb6a045dd3 Port LZX macros 2023-01-03 16:08:50 -08:00
Matt Nadareski
b273d8314a Migrate some easy LZX stuff 2023-01-03 14:46:30 -08:00
Matt Nadareski
015b895177 Start trying to get Quantum archives to extract 2023-01-03 13:53:44 -08:00
Matt Nadareski
fce9ce4eb4 Handle unknown data better 2023-01-03 10:59:41 -08:00
Matt Nadareski
e6463adb65 Add Quantum to README 2023-01-03 10:46:09 -08:00
Matt Nadareski
b07fd29753 Minor tweaks from issues found during extraction 2023-01-03 10:42:57 -08:00
Matt Nadareski
2416a035c7 Add Quantum archive models/builder/wrapper 2023-01-03 09:28:16 -08:00
Matt Nadareski
c2c125fd29 Add extract all to BFPK 2023-01-03 09:19:35 -08:00
Matt Nadareski
580bf0494d Fix writing cabinet file data 2023-01-03 00:19:03 -08:00
Matt Nadareski
eefc52d1dd Be safer with uneven lengths 2023-01-03 00:14:42 -08:00
Matt Nadareski
c28de855e2 Take sligthly more academic approach 2023-01-03 00:12:31 -08:00
Matt Nadareski
5e2d7505da Consistency tweaks (nw) 2023-01-02 23:54:40 -08:00
Matt Nadareski
f550c96541 Take some cues from libmspack 2023-01-02 23:35:09 -08:00
Matt Nadareski
d222eec1b1 I want to get off the Quantum ride 2023-01-02 22:03:36 -08:00
Matt Nadareski
be129262da Next level is a set of values, not a single one 2023-01-02 15:04:00 -08:00
Matt Nadareski
87080c906d Port more of the easy stuff over 2023-01-02 15:01:24 -08:00
Matt Nadareski
cdeaf09ed6 Start doing a better job with MSZIP 2023-01-02 11:19:06 -08:00
Matt Nadareski
b17f8dac7a Start fixing Quantum with safeguards, hook up 2023-01-02 10:17:27 -08:00
Matt Nadareski
ec758e5c18 Finalize Quantum port to C# (pass 1) 2023-01-02 00:03:03 -08:00
Matt Nadareski
350f9630df Convert macros to methods, mostly 2023-01-01 23:45:13 -08:00
Matt Nadareski
557c760197 Move Quantum macro notes to Compression 2023-01-01 22:06:09 -08:00
Matt Nadareski
895f40414d Some Quantum things to models / compression 2023-01-01 22:02:54 -08:00
Matt Nadareski
96fbb38b1c Bring in the rest of CAB code commented 2023-01-01 21:34:56 -08:00
Matt Nadareski
650d01d7be Update README with SharpZipLib 2022-12-31 11:44:49 -08:00
Matt Nadareski
3977342a67 Fix empty-not-null data 2022-12-31 11:39:35 -08:00
Matt Nadareski
8a61f01e1b Handle last blocks more efficiently 2022-12-31 11:35:22 -08:00
Matt Nadareski
75a4371f36 Handle MS-CAB compression type masking better 2022-12-31 11:21:29 -08:00
Matt Nadareski
86ee4786a0 Add mostly-working MS-ZIP based on zlib 2022-12-31 10:57:49 -08:00
Matt Nadareski
ef710463ae Port more CAB code (nw, commented out) 2022-12-30 23:07:41 -08:00
Matt Nadareski
e6b153bcbd Add last models from headers 2022-12-30 21:25:46 -08:00
Matt Nadareski
9c9eb8ca7b Align to correct boundary, look for executables 2022-12-30 14:00:10 -08:00
Matt Nadareski
295f438ff1 Forgot the after_build tag 2022-12-30 11:15:06 -08:00
TheRogueArchivist
cc1ad3e690 Update Cenega ProtectDVD (#221)
* Add new export check for Cenega ProtectDVD.

* Update notes and add link to DRML.
2022-12-30 09:54:44 -08:00
Matt Nadareski
3ebb3822dd Revert changes to launch.json 2022-12-30 09:38:11 -08:00
Matt Nadareski
6e22bd4c8d Fix hidden resource parsing 2022-12-30 09:35:35 -08:00
Matt Nadareski
1027956892 Lock section names, scan for hidden resources 2022-12-30 09:09:42 -08:00
Matt Nadareski
a46d52ddbb Shout out DRML in README 2022-12-29 23:34:00 -08:00
Matt Nadareski
fd5e78eb8a Open the path to future .NET versions 2022-12-29 23:01:28 -08:00
Matt Nadareski
8a326cbb91 Fix build zipfile names 2022-12-29 22:15:55 -08:00
Matt Nadareski
09a7893021 Try to get better at artifacts 2022-12-29 22:01:07 -08:00
Matt Nadareski
9c10af58d8 Remove AnyCPU from configuration 2022-12-29 21:27:45 -08:00
Matt Nadareski
81fbe251ba Specify all files in publish directories 2022-12-29 21:22:08 -08:00
Matt Nadareski
5203f0ea57 Attempt to fix AppVeyor build issues 2022-12-29 21:13:42 -08:00
Matt Nadareski
51644c2178 Update to latest LibMSPackSharp 2022-12-29 21:11:12 -08:00
Matt Nadareski
f326a20019 Runtime identifiers, explicit .NET Framework 4.8 2022-12-29 21:06:14 -08:00
Matt Nadareski
daea4ea460 Add CrypKey PE content checks 2022-12-28 23:28:38 -08:00
Matt Nadareski
c9c14bcebf Add note of where to find implementation 2022-12-28 23:07:23 -08:00
Matt Nadareski
9dc21c01f1 Add Microsoft LZ-compressed files support 2022-12-28 22:54:56 -08:00
Matt Nadareski
555dbd592c Re-disable MS-CAB extraction on .NET 6.0 2022-12-28 22:31:46 -08:00
Matt Nadareski
5e027b75b2 Update README with CExe extraction support 2022-12-28 22:21:18 -08:00
Matt Nadareski
01a504dab7 Remove unused using 2022-12-28 22:20:32 -08:00
Matt Nadareski
70eeaaac28 Replace direct LZ ports with cleaned versions 2022-12-28 22:18:23 -08:00
Matt Nadareski
0397d529bb Add LZ decompression to CExe 2022-12-28 17:24:55 -08:00
Matt Nadareski
25bed747f2 First ported implementation of LZ 2022-12-28 17:24:30 -08:00
Matt Nadareski
d17b90e782 Fix constant strings 2022-12-28 17:15:42 -08:00
Matt Nadareski
7868e22a95 Fix constant strings 2022-12-28 17:10:42 -08:00
Matt Nadareski
81f6e2057e Add note for future work 2022-12-28 15:37:09 -08:00
Matt Nadareski
1c3e37ee2b Add and use XZP constants 2022-12-28 15:35:54 -08:00
Matt Nadareski
27756db621 Add and use WAD constants 2022-12-28 15:30:22 -08:00
Matt Nadareski
7f71b04ef7 Add and use VPK constants 2022-12-28 15:27:10 -08:00
Matt Nadareski
c48522e6c0 Add and use VBSP constants 2022-12-28 15:22:16 -08:00
Matt Nadareski
fbf629dd8b Add and use SGA constants 2022-12-28 15:17:34 -08:00
Matt Nadareski
404b2889ff Add SFFS constants 2022-12-28 15:13:38 -08:00
Matt Nadareski
5ccb9d16a8 Add and use PE constants 2022-12-28 15:09:31 -08:00
Matt Nadareski
66b562f24b Add and use PAK constants 2022-12-28 15:03:41 -08:00
Matt Nadareski
ef25b88717 Get CExe prepped for LZ 2022-12-28 15:01:59 -08:00
Matt Nadareski
f22f7273a9 Add and use MZ constants 2022-12-28 14:50:48 -08:00
Matt Nadareski
ea9902c946 Add and use MS-CAB constants 2022-12-28 14:40:40 -08:00
Matt Nadareski
051c38c6df Add and use MoPaQ constants 2022-12-28 14:39:22 -08:00
Matt Nadareski
6b832026b4 Add and use NE constants 2022-12-28 14:26:12 -08:00
Matt Nadareski
81d7151f8f Create new Compression library (nw) 2022-12-28 14:18:50 -08:00
Matt Nadareski
283672e909 Add and use NCF constants 2022-12-28 14:02:09 -08:00
Matt Nadareski
94dfba4b4f Add LZ models 2022-12-28 10:46:33 -08:00
Matt Nadareski
2b66efd11b Add LE/LX constants 2022-12-28 10:31:28 -08:00
Matt Nadareski
14fb3f5758 Add and use IS-CAB constants 2022-12-28 10:21:19 -08:00
Matt Nadareski
9354f0f092 Add and use GCF constants 2022-12-28 10:14:00 -08:00
Matt Nadareski
c3636a0743 Add and use BSP constants 2022-12-28 10:04:10 -08:00
Matt Nadareski
e07b66812c Add and use BFPK constants 2022-12-28 09:57:22 -08:00
Matt Nadareski
c1d231db60 Create Compression models subfolder 2022-12-28 09:47:25 -08:00
TheRogueArchivist
757ab1f228 Fix FreeLock False Positive (#219)
* Fix FreeLock False Positive
2022-12-27 23:30:46 -08:00
TheRogueArchivist
6e42e7fb6b Remove dummy Roxxe file (#217)
* Remove dummy Roxxe file. The notes have been moved to DRML.
2022-12-27 23:13:53 -08:00
TheRogueArchivist
92f88efd4e Fix false positives in Bitpool and LaserLok (#218)
* Fix false positives in Bitpool and LaserLok.
2022-12-27 23:13:47 -08:00
Matt Nadareski
7ba2194d97 Add CExe extraction (partial) 2022-12-27 23:12:52 -08:00
Matt Nadareski
a5f2e2f5c8 Use slightly different zlib port 2022-12-27 22:25:49 -08:00
Matt Nadareski
8658c24ef0 Be more overzealous when locking 2022-12-27 22:25:16 -08:00
Matt Nadareski
0cded076e4 Fix invocation of scannable classes 2022-12-27 22:11:01 -08:00
Matt Nadareski
135c0b6d38 Use slightly different zlib port 2022-12-27 21:47:56 -08:00
Matt Nadareski
769fe42a7a Add TAR skeleton models, for kicks 2022-12-27 21:46:42 -08:00
Matt Nadareski
ab6fcd73e0 Seal as many of the models as possible 2022-12-27 17:12:55 -08:00
Matt Nadareski
3278420d72 Create placeholder for IS-CAB info printing 2022-12-27 16:56:00 -08:00
Matt Nadareski
98395387a7 Add IS-CAB models and builder 2022-12-27 16:54:06 -08:00
TheRogueArchivist
180a097213 Remove dummy Alcatraz file (#215)
* Remove dummy Alcatraz file. The notes have been moved to DRML.
2022-12-27 11:00:17 -08:00
TheRogueArchivist
18ac00080a Move Bitpool comments into DRML (#213)
* Move Bitpool comments into DRML, tidying up BOS,
2022-12-27 11:00:00 -08:00
Matt Nadareski
4da713702a Add header matchers for Wise 2022-12-27 10:53:28 -08:00
Matt Nadareski
68be17de66 Fix SGA builder and wrapper 2022-12-27 10:19:11 -08:00
Matt Nadareski
18cdf9d7ed Use new SGA extraction 2022-12-27 01:07:46 -08:00
Matt Nadareski
c389ea1e49 Add SGA extraction 2022-12-27 00:55:24 -08:00
Matt Nadareski
1f65b0352d Add SGA wrapper 2022-12-26 23:22:03 -08:00
Matt Nadareski
0e63b6638c Do some more work on MSZIP (nw) 2022-12-26 21:39:52 -08:00
Matt Nadareski
fcda1f119b Split MS-CAB wrapper 2022-12-26 15:04:17 -08:00
Matt Nadareski
bb130849ee Fix build with missed changes 2022-12-26 14:52:12 -08:00
Matt Nadareski
7b209eec6c Update to latest LibMSPackSharp 2022-12-26 14:46:17 -08:00
Matt Nadareski
9e7a84d2d6 Remove generic "Valve" 2022-12-26 14:45:49 -08:00
Matt Nadareski
baf43ea307 Remove remnants of HLLibSharp 2022-12-26 14:42:41 -08:00
Matt Nadareski
f524f0da3e Remove HLLibSharp as submodule 2022-12-26 14:37:59 -08:00
Matt Nadareski
49781c47a9 Add executables to support table 2022-12-26 13:01:37 -08:00
Matt Nadareski
aa11ce807a Better container support matrix 2022-12-26 12:58:03 -08:00
Matt Nadareski
702115c55a Make interfaces public 2022-12-26 12:36:09 -08:00
Matt Nadareski
17cb1bf9b0 Add XZP wrapper, extraction, and use it 2022-12-26 12:33:58 -08:00
Matt Nadareski
590c4e0a23 Make extension checks better 2022-12-26 11:43:04 -08:00
Matt Nadareski
fd6196a880 Add WAD wrapper, extraction, and use it 2022-12-26 11:34:17 -08:00
Matt Nadareski
2875f7ff7a Add VBSP wrapper, extraction, and use it 2022-12-26 10:58:16 -08:00
Matt Nadareski
50fe127a8d Add PAK wrapper, extraction, and use it 2022-12-26 10:26:26 -08:00
Matt Nadareski
94ebe5b707 Add NCF wrapper 2022-12-25 23:33:52 -08:00
Matt Nadareski
dc3914e976 Use new GCF extraction code 2022-12-25 22:55:48 -08:00
Matt Nadareski
ef2f037909 Add GCF extraction 2022-12-25 22:53:01 -08:00
Matt Nadareski
374f286585 Add GCF wrapper 2022-12-25 21:27:06 -08:00
Matt Nadareski
34cd933f78 Reset launch.json 2022-12-24 22:31:21 -08:00
Matt Nadareski
f8d533e592 Use new BSP extarction code 2022-12-24 22:30:29 -08:00
Matt Nadareski
21263cf0fd Add BSP extraction 2022-12-24 22:02:30 -08:00
Matt Nadareski
1a62ac2006 Add BSP wrapper 2022-12-24 20:15:58 -08:00
Matt Nadareski
8f3d4d5fb2 Use new VPK extraction code 2022-12-24 15:31:38 -08:00
Matt Nadareski
81902455ff Fix VPK extraction 2022-12-24 15:25:56 -08:00
Matt Nadareski
fbb33d9ef8 Add VPK to info 2022-12-24 14:24:34 -08:00
Matt Nadareski
b025c7a7fa Add VPK wrapper (nw) 2022-12-24 13:49:03 -08:00
Matt Nadareski
d8aec5aa97 Migrate recent HLLib work to BOS
It's better suited for the model of BOS and not an update to HLLibSharp
2022-12-24 12:57:10 -08:00
Matt Nadareski
3a862f343c Add headers and extensions for Valve 2022-12-23 23:27:14 -08:00
Matt Nadareski
69724cfb1c Sync to newest HLLibSharp 2022-12-23 23:13:45 -08:00
Matt Nadareski
f75cdea678 Sync to newest HLLibSharp 2022-12-23 23:04:40 -08:00
Matt Nadareski
32e650eff5 Update README comment 2022-12-23 15:46:42 -08:00
Matt Nadareski
ab022f9049 Sync to newest HLLibSharp 2022-12-23 15:26:48 -08:00
Matt Nadareski
7962e148fa Sync to newest HLLibSharp 2022-12-23 14:29:34 -08:00
Matt Nadareski
efdf3a0691 Sync to newest HLLibSharp 2022-12-23 13:13:57 -08:00
Matt Nadareski
000ab5e856 Sync to newest HLLibSharp 2022-12-23 12:36:48 -08:00
Matt Nadareski
4873133c92 Sync to newest HLLibSharp 2022-12-23 11:10:55 -08:00
Matt Nadareski
360bbef43a Remove redundant note in README 2022-12-22 22:31:45 -08:00
Matt Nadareski
9a21f4987d Sync to newest HLLibSharp 2022-12-22 22:24:13 -08:00
Matt Nadareski
63948767ef Use more granular file opening 2022-12-22 22:03:32 -08:00
Matt Nadareski
e2098f6f71 Disable StormLibSharp for .NET 6.0 2022-12-22 21:58:26 -08:00
Matt Nadareski
609c30da38 Sync to newest HLLibSharp 2022-12-22 21:51:33 -08:00
Matt Nadareski
0896842268 Builder -> Builders 2022-12-22 16:02:10 -08:00
Matt Nadareski
ec9506b9eb Sync to newest HLLibSharp 2022-12-22 15:53:50 -08:00
Matt Nadareski
526526975c Sync to newest HLLibSharp 2022-12-22 15:18:51 -08:00
Matt Nadareski
098734c471 Remove outdated note 2022-12-22 13:06:18 -08:00
Matt Nadareski
47df62534e Add back ActiveMARK entry point checks 2022-12-20 14:40:43 -08:00
Matt Nadareski
7295001892 Read entry point data in safe way 2022-12-20 14:19:48 -08:00
Matt Nadareski
7c820b7fd2 Start re-adding entry point 2022-12-20 13:03:25 -08:00
Matt Nadareski
36429cc1e9 Fix build 2022-12-20 12:21:34 -08:00
Matt Nadareski
a1c22ca9da Make a couple things consistent 2022-12-20 11:52:50 -08:00
Matt Nadareski
0c37932631 Cleanup and notes for 3P-Lock 2022-12-20 11:26:22 -08:00
Matt Nadareski
dbf1f6dcca Integrate changes from TheRogueArchivist 2022-12-19 23:53:52 -08:00
Matt Nadareski
7bb26c0faf Add PE checks to ByteShield 2022-12-19 23:49:34 -08:00
Matt Nadareski
31a0b55556 Add new info to developer guide 2022-12-19 23:28:12 -08:00
Matt Nadareski
64cc4785ca Add PE checks to SoftLock 2022-12-19 21:39:24 -08:00
Matt Nadareski
28391de50c Confirm SoftLock path checks 2022-12-19 20:49:10 -08:00
Matt Nadareski
b2ed69ab78 Add 7-zip SFX detection 2022-12-18 14:18:35 -08:00
Matt Nadareski
2f08940927 Simplify Gefest checks 2022-12-17 22:52:35 -08:00
Matt Nadareski
70928227e4 Fix launch.json 2022-12-17 22:02:12 -08:00
Matt Nadareski
546bd70418 Start fixing MSZIP decoding (nw) 2022-12-17 22:01:00 -08:00
Matt Nadareski
f2521a0110 Write MS-CAB file extraction (nw) 2022-12-16 23:11:06 -08:00
Matt Nadareski
02b83513a1 Hook up MSZIP decompression (nw) 2022-12-16 22:58:07 -08:00
Matt Nadareski
f26b2ff61b Migrate MSZIP to wrapper, where possible 2022-12-16 22:41:36 -08:00
Matt Nadareski
4d26535d07 Add BitStream type and add BitArray extensions 2022-12-16 21:59:46 -08:00
Matt Nadareski
01a365033e MIgrate some Quantum stuff to models 2022-12-16 10:19:32 -08:00
Matt Nadareski
318a89a4bc Move some LZX things to models 2022-12-16 09:48:52 -08:00
Matt Nadareski
b20f22fb92 Subfolder it 2022-12-16 00:19:18 -08:00
Matt Nadareski
fedf76e534 Migrate some MSZIP pieces to Models 2022-12-15 23:51:12 -08:00
Matt Nadareski
e0e16292eb ASN.1 and OID to its own library 2022-12-15 22:07:12 -08:00
Matt Nadareski
b3c0e48bdd Address some MPQ issues 2022-12-15 16:50:24 -08:00
Matt Nadareski
aded5ee03a Stream safety and better streams 2022-12-15 14:20:27 -08:00
Matt Nadareski
16e71c910e Use MemoryStream in builders 2022-12-15 13:37:34 -08:00
Matt Nadareski
bbe234b459 Use MemoryStream in wrappers 2022-12-15 12:41:08 -08:00
Matt Nadareski
715b9eb156 Fix MS-CAB info 2022-12-15 12:20:06 -08:00
Matt Nadareski
4cc441afcf Get rid of code duplication 2022-12-15 00:13:24 -08:00
Matt Nadareski
f79cd759bd Add SFFS models, no encryption 2022-12-14 23:16:37 -08:00
Matt Nadareski
1b232e4405 Fix wrapper printing, add to info 2022-12-14 23:06:09 -08:00
Matt Nadareski
6d43afb258 Use wrapper in BFPK scans 2022-12-14 23:01:06 -08:00
Matt Nadareski
a47c778b0e Add BFPK wrapper 2022-12-14 22:58:18 -08:00
Matt Nadareski
ddb82842bc Add BFPK builder 2022-12-14 22:41:17 -08:00
Matt Nadareski
199914b19f Remove BinaryReader from BFPK 2022-12-14 22:28:35 -08:00
Matt Nadareski
9fadd84597 Add unused BFPK models 2022-12-14 22:25:35 -08:00
Matt Nadareski
95dd670c7c Add format note to SFFS, fix magic 2022-12-14 22:15:43 -08:00
Matt Nadareski
adc9def0c9 Slight MoPaQ builder cleanup 2022-12-14 22:07:11 -08:00
Matt Nadareski
8dcc9d9b0e Add BET/HET parsign to MoPaQ (nw) 2022-12-14 22:06:31 -08:00
Matt Nadareski
b5177b16ea Add hi-block table parsing to MoPaQ (nw) 2022-12-14 21:59:48 -08:00
Matt Nadareski
f9b4693aae Add block table parsing to MoPaQ (nw) 2022-12-14 21:48:22 -08:00
Matt Nadareski
f2a479e35c Update SafeDisc with better finding 2022-12-14 21:31:51 -08:00
Matt Nadareski
1f40c2e052 Fix locking exception 2022-12-14 21:30:53 -08:00
Matt Nadareski
b5c8d05814 Add CodeView debug parsing/finding 2022-12-14 21:07:02 -08:00
Matt Nadareski
f99634bc08 Add generic debug check to SafeDisc 2022-12-14 20:57:26 -08:00
Matt Nadareski
ab88e2f553 Add NB10 debug data type 2022-12-14 20:56:13 -08:00
Matt Nadareski
5465abe1ac Add RSDS debug data type 2022-12-14 20:47:18 -08:00
Matt Nadareski
b0df7a8f3b Add debug data to PE wrapper 2022-12-14 20:46:24 -08:00
Matt Nadareski
0d4fab100d Add PE table data/string caching 2022-12-14 17:24:14 -08:00
Matt Nadareski
8c5e10fd88 First attempt at MoPaQ hash table parsing 2022-12-14 17:03:34 -08:00
Matt Nadareski
e8aef1596b Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2022-12-14 16:48:52 -08:00
Matt Nadareski
386c86f04f Add placeholders for parsing in MoPaQ 2022-12-14 16:47:45 -08:00
TheRogueArchivist
3f5a66f170 Add support for Gefest Protection System (#185)
* Add detection and notes for Gefest Protection System.

* Add Gefest Protection System to README.
2022-12-14 16:37:06 -08:00
TheRogueArchivist
a961d9534c Add SafeDisc "SD0XXX.dll" checks (#184)
* Add detection and notes for SafeDisc "SD0XXX.dll" files.
2022-12-14 16:35:54 -08:00
TheRogueArchivist
d1919c18f5 Add nProtect DRM (#183)
* Add nProtect DRM

* Add detection and notes for nProtect GameGuard and nProtect KeyCrypt.

* Add nProtect DRM to README.

* Fix missing "|" character

* Fix missing "|" character.
2022-12-14 16:35:01 -08:00
Matt Nadareski
afa8b24ba9 Add MoPaQ printing skeleton 2022-12-14 16:33:26 -08:00
Matt Nadareski
b793b74b32 Add MoPaQ builder (nw) 2022-12-14 16:29:07 -08:00
Matt Nadareski
65499d1f46 Add MoPaQ models 2022-12-14 15:43:13 -08:00
Matt Nadareski
5f387cdb74 Migrate WIP MS-CAB to model/builder/wrapper 2022-12-14 15:23:54 -08:00
Matt Nadareski
ed2e88c781 Start filling out LZX 2022-12-14 13:57:54 -08:00
Matt Nadareski
1cb3157110 Add more notes, including Quantum 2022-12-14 13:17:29 -08:00
TheRogueArchivist
a480b53787 CD-Cops is a mess why don't we have more samples (#182)
* Confirm CD-Cops check.

* Add a few notes for CD-Cops.
2022-12-14 12:12:12 -08:00
TheRogueArchivist
405c895352 Add support for CD-Guard (#181)
* why is there so much DRM I am going to cry

* Add support for detecting CD-Guard, as well as notes.

* Add CD-Guard to README.

* Address PR comments

* Ignore case in import/export checks.
2022-12-14 12:11:23 -08:00
Matt Nadareski
53dc251a0c Continue with deflate 2022-12-14 12:10:59 -08:00
Matt Nadareski
d715072cbc Start writing Inflate implementation 2022-12-14 10:55:56 -08:00
Matt Nadareski
aaee56f44e Start adding MSZIP notes 2022-12-14 00:05:49 -08:00
Matt Nadareski
27ceb4ed48 Streamline MS-CAB reading, add to info printing 2022-12-13 23:06:49 -08:00
Matt Nadareski
2d51bd8f37 Implement MS-CAB checksum routine 2022-12-13 22:11:19 -08:00
Matt Nadareski
645a366dc5 Split MS-CAB into subfiles, LibMSPackSharp for .NET 6 2022-12-13 21:51:24 -08:00
Matt Nadareski
756a74eda6 Disable printing by default again 2022-12-13 21:13:20 -08:00
Matt Nadareski
8052ee2afb Some PE resource handling cleanup 2022-12-13 21:05:52 -08:00
Matt Nadareski
6171c0defd Fix SFFS not being scanned 2022-12-13 11:55:12 -08:00
TheRogueArchivist
56c27d0b8f Why is there so much StarForce, geez (#180)
* Begin work on overhauling StarForce detection, and to add notes.

* Attempt to add SFFS file detection.

* Fix minor TAGES issue.
2022-12-13 11:42:55 -08:00
Matt Nadareski
9c173fd3a1 Update extension method for AddD section 2022-12-12 21:40:29 -08:00
Matt Nadareski
fa3ccf9953 Add more SecuROM AddD section notes 2022-12-12 21:25:00 -08:00
423 changed files with 17774 additions and 59259 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, linux-x64, osx-x64] #[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

19
.gitmodules vendored
View File

@@ -1,12 +1,9 @@
[submodule "BurnOutSharp/External/stormlibsharp"]
path = BurnOutSharp/External/stormlibsharp
[submodule "BinaryObjectScanner/_EXTERNAL/stormlibsharp"]
path = BinaryObjectScanner/_EXTERNAL/stormlibsharp
url = https://github.com/robpaveza/stormlibsharp.git
[submodule "HLLibSharp"]
path = HLLibSharp
url = https://github.com/mnadareski/HLLibSharp
[submodule "LibMSPackSharp"]
path = LibMSPackSharp
url = https://github.com/mnadareski/LibMSPackSharp.git
[submodule "Dtf"]
path = Dtf
url = https://github.com/wixtoolset/Dtf.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

15
.vscode/launch.json vendored
View File

@@ -10,20 +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",
"args": [],
"cwd": "${workspaceFolder}/Test",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Launch (ExecutableTest)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/ExecutableTest/bin/Debug/net6.0/ExecutableTest.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

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "BinaryObjectScanner.sln"
}

6
.vscode/tasks.json vendored
View File

@@ -7,7 +7,7 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/BurnOutSharp.sln",
"${workspaceFolder}/BinaryObjectScanner.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -19,7 +19,7 @@
"type": "process",
"args": [
"publish",
"${workspaceFolder}/BurnOutSharp.sln",
"${workspaceFolder}/BinaryObjectScanner.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
@@ -32,7 +32,7 @@
"args": [
"watch",
"run",
"${workspaceFolder}/BurnOutSharp.sln",
"${workspaceFolder}/BinaryObjectScanner.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],

42
BinaryObjectScanner.sln Normal file
View File

@@ -0,0 +1,42 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32407.343
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{88735BA2-778D-4192-8EB2-FFF6843719E2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{68D10531-99CB-40B1-8912-73FA286C9433}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
Coding Guide.md = Coding Guide.md
Developer Guide.md = Developer Guide.md
LICENSE = LICENSE
publish-nix.sh = publish-nix.sh
publish-win.ps1 = publish-win.ps1
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner", "BinaryObjectScanner\BinaryObjectScanner.csproj", "{341EA3F5-847C-4739-B86F-2B051FFE4EF2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.Build.0 = Release|Any CPU
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{341EA3F5-847C-4739-B86F-2B051FFE4EF2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0B343DD2-8852-47B0-9647-DFCFBEDF933C}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,96 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.1.7</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS0162;CS0612;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Protection scanning library</Description>
<Copyright>Copyright (c)2018-2024 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/BinaryObjectScanner</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>protection copy-protection scanning packer</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<!-- 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>
<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 or non-Windows builds -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`)) OR !$(RuntimeIdentifier.StartsWith(`win-`))">
<DefaultItemExcludes>
$(DefaultItemExcludes);
_EXTERNAL\**
</DefaultItemExcludes>
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))">
<Content Include="*.dll">
<Pack>true</Pack>
<PackagePath>contentFiles;content</PackagePath>
<IncludeInPackage>true</IncludeInPackage>
<CopyToOutput>true</CopyToOutput>
<BuildAction>Content</BuildAction>
<copyToOutput>true</copyToOutput>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content>
</ItemGroup>
<!-- Support for old .NET versions -->
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="MinThreadingBridge" Version="0.11.4" />
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.4" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`))">
<PackageReference Include="OpenMcdf" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
<PackageReference Include="SharpCompress" Version="0.37.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.Compression" Version="0.5.0" />
<PackageReference Include="SabreTools.Hashing" Version="1.2.0" />
<PackageReference Include="SabreTools.IO" Version="1.4.0" />
<PackageReference Include="SabreTools.Matching" Version="1.3.1" />
<PackageReference Include="SabreTools.Models" Version="1.4.5" />
<PackageReference Include="SabreTools.Serialization" Version="1.5.6" />
<PackageReference Include="UnshieldSharp" Version="1.8.1" />
<PackageReference Include="WiseUnpacker" Version="1.4.1" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,72 @@
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
namespace BinaryObjectScanner
{
public static class Factory
{
/// <summary>
/// Create an instance of a detectable based on file type
/// </summary>
public static IDetectable? CreateDetectable(SupportedFileType 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.RealArcadeInstaller: return new FileType.RealArcadeInstaller();
case SupportedFileType.RealArcadeMezzanine: return new FileType.RealArcadeMezzanine();
case SupportedFileType.SFFS: return new FileType.SFFS();
case SupportedFileType.Textfile: return new FileType.Textfile();
default: return null;
}
}
/// <summary>
/// Create an instance of an extractable based on file type
/// </summary>
public static IExtractable? CreateExtractable(SupportedFileType 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();
default: return null;
}
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// AACS media key block
/// </summary>
public class AACSMediaKeyBlock : IDetectable
{
/// <inheritdoc/>
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)
{
// If the MKB file itself fails
try
{
// Create the wrapper
var mkb = SabreTools.Serialization.Wrappers.AACSMediaKeyBlock.Create(stream);
if (mkb == null)
return null;
// Derive the version, if possible
var typeAndVersion = mkb.Model.Records?.FirstOrDefault(r => r?.RecordType == SabreTools.Models.AACS.RecordType.TypeAndVersion);
if (typeAndVersion == null)
return "AACS (Unknown Version)";
else
return $"AACS {(typeAndVersion as SabreTools.Models.AACS.TypeAndVersionRecord)?.VersionNumber}";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// BD+ SVM
/// </summary>
public class BDPlusSVM : 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)
{
// If the BD+ file itself fails
try
{
// Create the wrapper
var svm = SabreTools.Serialization.Wrappers.BDPlusSVM.Create(stream);
if (svm == null)
return null;
// Format the date
string date = $"{svm.Model.Year:0000}/{svm.Model.Month:00}/{svm.Model.Day:00}";
// Return the formatted value
return $"BD+ {date}";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Compressors;
using SharpCompress.Compressors.Deflate;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// BFPK custom archive format
/// </summary>
public class BFPK : IExtractable
{
/// <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.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var bfpk = SabreTools.Serialization.Wrappers.BFPK.Create(stream);
if (bfpk == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Extract all files
ExtractAll(bfpk, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the BFPK to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.BFPK item, string outputDirectory)
{
// If we have no files
if (item.Model.Files == null || item.Model.Files.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.Files.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the BFPK to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.BFPK item, int index, string outputDirectory)
{
// If we have no files
if (item.Model.Files == null || item.Model.Files.Length == 0)
return false;
// If we have an invalid index
if (index < 0 || index >= item.Model.Files.Length)
return false;
// Get the file information
var file = item.Model.Files[index];
if (file == null)
return false;
// Get the read index and length
int offset = file.Offset + 4;
int compressedSize = file.CompressedSize;
// Some files can lack the length prefix
if (compressedSize > item.GetEndOfFile())
{
offset -= 4;
compressedSize = file.UncompressedSize;
}
try
{
// Ensure the output directory exists
Directory.CreateDirectory(outputDirectory);
// Create the output path
string filePath = Path.Combine(outputDirectory, file.Name ?? $"file{index}");
using FileStream fs = File.OpenWrite(filePath);
// Read the data block
var data = item.ReadFromDataSource(offset, compressedSize);
if (data == null)
return false;
// If we have uncompressed data
if (compressedSize == file.UncompressedSize)
{
fs.Write(data, 0, compressedSize);
}
#if NET462_OR_GREATER || NETCOREAPP
else
{
MemoryStream ms = new MemoryStream(data);
ZlibStream zs = new ZlibStream(ms, CompressionMode.Decompress);
zs.CopyTo(fs);
}
#endif
return true;
}
catch
{
return false;
}
}
}
}

View File

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

View File

@@ -0,0 +1,60 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// bzip2 archive
/// </summary>
public class BZip2 : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (BZip2Stream bz2File = new BZip2Stream(stream, CompressionMode.Decompress, true))
{
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempFile))
{
bz2File.CopyTo(fs);
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -1,37 +1,38 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using BinaryObjectScanner.Interfaces;
#if NET40_OR_GREATER || NETCOREAPP
using OpenMcdf;
#endif
namespace BurnOutSharp.FileType
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Microsoft installation package
/// Compound File Binary
/// </summary>
public class MSI : IScannable
public class CFB : IExtractable
{
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Extract(fs, file, includeDebug);
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(Stream? stream, string file, bool includeDebug)
{
// If the MSI file itself fails
#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
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
@@ -39,65 +40,59 @@ namespace BurnOutSharp.FileType
{
msi.RootStorage.VisitEntries((e) =>
{
if (!e.IsStream)
return;
var str = msi.RootStorage.GetStream(e.Name);
if (str == null)
return;
byte[] strData = str.GetData();
if (strData == null)
return;
string decoded = DecodeStreamName(e.Name).TrimEnd('\0');
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
// UTF-8 encoding of 0x4840.
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
decoded = decoded.Substring(3);
foreach (char c in Path.GetInvalidFileNameChars())
try
{
decoded = decoded.Replace(c, '_');
if (!e.IsStream)
return;
var str = msi.RootStorage.GetStream(e.Name);
if (str == null)
return;
byte[] strData = str.GetData();
if (strData == null)
return;
var decoded = DecodeStreamName(e.Name)?.TrimEnd('\0');
if (decoded == null)
return;
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
// UTF-8 encoding of 0x4840.
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
decoded = decoded.Substring(3);
foreach (char c in Path.GetInvalidFileNameChars())
{
decoded = decoded.Replace(c, '_');
}
string filename = Path.Combine(tempPath, decoded);
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(strData, 0, strData.Length);
}
}
string filename = Path.Combine(tempPath, decoded);
using (Stream fs = File.OpenWrite(filename))
catch (Exception ex)
{
fs.Write(strData, 0, strData.Length);
if (includeDebug) Console.WriteLine(ex);
}
}, recursive: true);
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
return tempPath;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
if (includeDebug) Console.WriteLine(ex);
return null;
}
return null;
#endif
}
/// <remarks>Adapted from LibMSI</remarks>
private static string DecodeStreamName(string input)
public static string? DecodeStreamName(string input)
{
if (input == null)
return null;

View File

@@ -0,0 +1,602 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
#if NET40_OR_GREATER || NETCOREAPP
using System.Threading.Tasks;
#endif
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Executable or library
/// </summary>
/// <remarks>
/// Due to the complexity of executables, all extraction handling
/// another class that is used by the scanner
/// </remarks>
public class Executable : IDetectable
{
#region Properties
/// <summary>
/// Determines if game engines are counted as detected protections or not
/// </summary>
public bool IncludeGameEngines { get; set; }
/// <summary>
/// Determines if packers are counted as detected protections or not
/// </summary>
public bool IncludePackers { get; set; }
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
public static IEnumerable<IContentCheck> ContentCheckClasses
{
get
{
contentCheckClasses ??= InitCheckClasses<IContentCheck>();
return contentCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all ILinearExecutableCheck types
/// </summary>
public static IEnumerable<ILinearExecutableCheck> LinearExecutableCheckClasses
{
get
{
linearExecutableCheckClasses ??= InitCheckClasses<ILinearExecutableCheck>();
return linearExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IMSDOSExecutableCheck types
/// </summary>
public static IEnumerable<IMSDOSExecutableCheck> MSDOSExecutableCheckClasses
{
get
{
msdosExecutableCheckClasses ??= InitCheckClasses<IMSDOSExecutableCheck>();
return msdosExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all INewExecutableCheck types
/// </summary>
public static IEnumerable<INewExecutableCheck> NewExecutableCheckClasses
{
get
{
newExecutableCheckClasses ??= InitCheckClasses<INewExecutableCheck>();
return newExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IPortableExecutableCheck types
/// </summary>
public static IEnumerable<IPortableExecutableCheck> PortableExecutableCheckClasses
{
get
{
portableExecutableCheckClasses ??= InitCheckClasses<IPortableExecutableCheck>();
return portableExecutableCheckClasses ?? [];
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
private static IEnumerable<IContentCheck>? contentCheckClasses;
/// <summary>
/// Cache for all ILinearExecutableCheck types
/// </summary>
private static IEnumerable<ILinearExecutableCheck>? linearExecutableCheckClasses;
/// <summary>
/// Cache for all IMSDOSExecutableCheck types
/// </summary>
private static IEnumerable<IMSDOSExecutableCheck>? msdosExecutableCheckClasses;
/// <summary>
/// Cache for all INewExecutableCheck types
/// </summary>
private static IEnumerable<INewExecutableCheck>? newExecutableCheckClasses;
/// <summary>
/// Cache for all IPortableExecutableCheck types
/// </summary>
private static IEnumerable<IPortableExecutableCheck>? portableExecutableCheckClasses;
#endregion
/// <inheritdoc/>
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 to create a wrapper for the proper executable type
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
if (wrapper == null)
return null;
// Create the internal queue
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// Only use generic content checks if we're in debug mode
if (includeDebug)
{
var subProtections = RunContentChecks(file, stream, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
}
if (wrapper is MSDOS mz)
{
var subProtections = RunMSDOSExecutableChecks(file, stream, mz, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
}
else if (wrapper is LinearExecutable lex)
{
var subProtections = RunLinearExecutableChecks(file, stream, lex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
}
else if (wrapper is NewExecutable nex)
{
var subProtections = RunNewExecutableChecks(file, stream, nex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
}
else if (wrapper is PortableExecutable pex)
{
var subProtections = RunPortableExecutableChecks(file, stream, pex, includeDebug);
if (subProtections != null)
protections.AddRange(subProtections.Values.ToArray());
}
return string.Join(";", [.. protections]);
}
#region Check Runners
/// <summary>
/// Handle a single file based on all content check implementations
/// </summary>
/// <param name="file">Name of the source file of the stream, for tracking</param>
/// <param name="stream">Stream to scan the contents of</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public Dictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
#else
public ConcurrentDictionary<IContentCheck, string>? RunContentChecks(string? file, Stream stream, bool includeDebug)
#endif
{
// If we have an invalid file
if (string.IsNullOrEmpty(file))
return null;
else if (!File.Exists(file))
return null;
// Read the file contents
byte[] fileContent = [];
try
{
#if NET20 || NET35 || NET40
using var br = new BinaryReader(stream, Encoding.Default);
#else
using var br = new BinaryReader(stream, Encoding.Default, true);
#endif
fileContent = br.ReadBytes((int)stream.Length);
if (fileContent == null)
return null;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<IContentCheck, string>();
#else
var protections = new ConcurrentDictionary<IContentCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in ContentCheckClasses)
#else
Parallel.ForEach(ContentCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckContents(file!, fileContent, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
return protections;
}
/// <summary>
/// Handle a single file based on all linear executable check implementations
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="lex">Executable to scan</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public Dictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
#else
public ConcurrentDictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<ILinearExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<ILinearExecutableCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in LinearExecutableCheckClasses)
#else
Parallel.ForEach(LinearExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckLinearExecutable(file, lex, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
return protections;
}
/// <summary>
/// Handle a single file based on all MS-DOS executable check implementations
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="mz">Executable to scan</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public Dictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
#else
public ConcurrentDictionary<IMSDOSExecutableCheck, string> RunMSDOSExecutableChecks(string file, Stream stream, MSDOS mz, bool includeDebug)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<IMSDOSExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<IMSDOSExecutableCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in MSDOSExecutableCheckClasses)
#else
Parallel.ForEach(MSDOSExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckMSDOSExecutable(file, mz, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
return protections;
}
/// <summary>
/// Handle a single file based on all new executable check implementations
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="nex">Executable to scan</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public Dictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
#else
public ConcurrentDictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<INewExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<INewExecutableCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in NewExecutableCheckClasses)
#else
Parallel.ForEach(NewExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
return protections;
}
/// <summary>
/// Handle a single file based on all portable executable check implementations
/// </summary>
/// <param name="file">Name of the source file of the executable, for tracking</param>
/// <param name="pex">Executable to scan</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public Dictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
#else
public ConcurrentDictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<IPortableExecutableCheck, string>();
#else
var protections = new ConcurrentDictionary<IPortableExecutableCheck, string>();
#endif
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in PortableExecutableCheckClasses)
#else
Parallel.ForEach(PortableExecutableCheckClasses, checkClass =>
#endif
{
// Get the protection for the class, if possible
var protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
if (string.IsNullOrEmpty(protection))
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
#if NET20 || NET35
continue;
#else
return;
#endif
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
#if NET20 || NET35
continue;
#else
return;
#endif
#if NET20 || NET35
protections[checkClass] = protection!;
}
#else
protections.TryAdd(checkClass, protection!);
});
#endif
return protections;
}
#endregion
#region Initializers
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>() =>
InitCheckClasses<T>(Assembly.GetExecutingAssembly()) ?? [];
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T>? InitCheckClasses<T>(Assembly assembly)
{
List<T> classTypes = [];
// If not all types can be loaded, use the ones that could be
List<Type> assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
}
// Loop through all types
foreach (Type type in assemblyTypes)
{
// If the type isn't a class or doesn't implement the interface
if (!type.IsClass || type.GetInterface(typeof(T).Name) == null)
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
#endregion
#region Helpers
/// <summary>
/// Check to see if an implementation is a game engine using reflection
/// </summary>
/// <param name="impl">Implementation that was last used to check</param>
private static bool CheckIfGameEngine(object impl)
{
return impl?.GetType()?.Namespace?.ToLowerInvariant()?.Contains("gameengine") ?? false;
}
/// <summary>
/// Check to see if an implementation is a packer using reflection
/// </summary>
/// <param name="impl">Implementation that was last used to check</param>
private static bool CheckIfPacker(object impl)
{
return impl.GetType()?.Namespace?.ToLowerInvariant()?.Contains("packer") ?? false;
}
#endregion
}
}

View File

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Half-Life Game Cache File
/// </summary>
public class GCF : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
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)
{
try
{
// Create the wrapper
var gcf = SabreTools.Serialization.Wrappers.GCF.Create(stream);
if (gcf == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAll(gcf, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the GCF to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.GCF item, string outputDirectory)
{
// If we have no files
if (item.Files == null || item.Files.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Files.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the GCF to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.GCF item, int index, string outputDirectory)
{
// If we have no files
if (item.Files == null || item.Files.Length == 0 || item.DataBlockOffsets == null)
return false;
// If the files index is invalid
if (index < 0 || index >= item.Files.Length)
return false;
// Get the file
var file = item.Files[index];
if (file?.BlockEntries == null || file.Size == 0)
return false;
// If the file is encrypted -- TODO: Revisit later
if (file.Encrypted)
return false;
// Get all data block offsets needed for extraction
var dataBlockOffsets = new List<long>();
for (int i = 0; i < file.BlockEntries.Length; i++)
{
var blockEntry = file.BlockEntries[i];
if (blockEntry == null)
continue;
uint dataBlockIndex = blockEntry.FirstDataBlockIndex;
long blockEntrySize = blockEntry.FileDataSize;
while (blockEntrySize > 0)
{
long dataBlockOffset = item.DataBlockOffsets[dataBlockIndex++];
dataBlockOffsets.Add(dataBlockOffset);
blockEntrySize -= item.Model.DataBlockHeader?.BlockSize ?? 0;
}
}
// Create the filename
var filename = file.Path;
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
// Now read the data sequentially and write out while we have data left
long fileSize = file.Size;
for (int i = 0; i < dataBlockOffsets.Count; i++)
{
int readSize = (int)Math.Min(item.Model.DataBlockHeader?.BlockSize ?? 0, fileSize);
var data = item.ReadFromDataSource((int)dataBlockOffsets[i], readSize);
if (data == null)
return false;
fs.Write(data, 0, data.Length);
}
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.GZip;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// gzip archive
/// </summary>
public class GZIP : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (GZipArchive zipFile = GZipArchive.Open(stream))
{
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// InstallShield archive v3
/// </summary>
public class InstallShieldArchiveV3 : IExtractable
{
/// <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.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file);
foreach (var cfile in archive.Files)
{
try
{
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.Key);
if (fileContents == null || !string.IsNullOrEmpty(error))
continue;
using (FileStream fs = File.OpenWrite(tempFile))
{
fs.Write(fileContents, 0, fileContents.Length);
}
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using BinaryObjectScanner.Interfaces;
using UnshieldSharp.Cabinet;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// InstallShield cabinet file
/// </summary>
public class InstallShieldCAB : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
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)
{
// Get the name of the first cabinet file or header
var directory = Path.GetDirectoryName(file);
string noExtension = Path.GetFileNameWithoutExtension(file);
bool shouldScanCabinet;
if (directory == null)
{
string filenamePattern = noExtension;
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
bool cabinetHeaderExists = File.Exists(filenamePattern + "1.hdr");
shouldScanCabinet = cabinetHeaderExists
? file.Equals(filenamePattern + "1.hdr", StringComparison.OrdinalIgnoreCase)
: file.Equals(filenamePattern + "1.cab", StringComparison.OrdinalIgnoreCase);
}
else
{
string filenamePattern = Path.Combine(directory, noExtension);
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr"));
shouldScanCabinet = cabinetHeaderExists
? file.Equals(Path.Combine(directory, filenamePattern + "1.hdr"), StringComparison.OrdinalIgnoreCase)
: file.Equals(Path.Combine(directory, filenamePattern + "1.cab"), StringComparison.OrdinalIgnoreCase);
}
// If we have anything but the first file
if (!shouldScanCabinet)
return null;
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
var cabfile = InstallShieldCabinet.Open(file);
if (cabfile?.HeaderList == null)
return null;
for (int i = 0; i < cabfile.HeaderList.FileCount; i++)
{
try
{
// Check if the file is valid first
if (!cabfile.HeaderList.FileIsValid(i))
continue;
string tempFile;
try
{
string? filename = cabfile.HeaderList.GetFileName(i);
tempFile = Path.Combine(tempPath, filename ?? string.Empty);
}
catch
{
tempFile = Path.Combine(tempPath, $"BAD_FILENAME{i}");
}
cabfile.FileSave(i, tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Link Data Security encrypted file
/// </summary>
public class LDSCRYPT : IDetectable
{
/// <inheritdoc/>
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);
if (magic.StartsWith(new byte?[] { 0x4C, 0x44, 0x53, 0x43, 0x52, 0x59, 0x50, 0x54 }))
return "Link Data Security encrypted file";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
using StormLibSharp;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// MoPaQ game data archive
/// </summary>
public class MPQ : IExtractable
{
/// <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.ReadWrite);
return Extract(fs, file, includeDebug);
}
// TODO: Add stream opening support
/// <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 mpqArchive = new MpqArchive(file, FileAccess.Read))
{
// Try to open the listfile
string? listfile = null;
MpqFileStream listStream = mpqArchive.OpenFile("(listfile)");
// If we can't read the listfile, we just return
if (!listStream.CanRead)
return null;
// Read the listfile in for processing
using (var sr = new StreamReader(listStream))
{
listfile = sr.ReadToEnd();
}
// Split the listfile by newlines
string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n');
// Loop over each entry
foreach (string sub in listfileLines)
{
try
{
string tempFile = Path.Combine(tempPath, sub);
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
mpqArchive.ExtractFile(sub, tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#endif
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if ((NETFRAMEWORK && !NET20 && !NET35 && !NET40) || NETCOREAPP) && WIN
using LibMSPackN;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Microsoft cabinet file
/// </summary>
/// <remarks>Specification available at <see href="http://download.microsoft.com/download/5/0/1/501ED102-E53F-4CE0-AA6B-B0F93629DDC6/Exchange/%5BMS-CAB%5D.pdf"/></remarks>
/// <see href="https://github.com/wine-mirror/wine/tree/master/dlls/cabinet"/>
public class MicrosoftCAB : IExtractable
{
/// <inheritdoc/>
public string? Extract(string file, bool includeDebug)
{
if (!File.Exists(file))
return null;
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

@@ -0,0 +1,69 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.LZ;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Microsoft LZ-compressed Files (LZ32)
/// </summary>
/// <remarks>This is treated like an archive type due to the packing style</remarks>
public class MicrosoftLZ : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
var data = Decompressor.Decompress(stream);
if (data == null)
return null;
// Create the temp filename
string tempFile = "temp.bin";
if (!string.IsNullOrEmpty(file))
{
var expandedFilePath = Decompressor.GetExpandedName(file, out _);
if (expandedFilePath != null)
tempFile = Path.GetFileName(expandedFilePath).TrimEnd('\0');
if (tempFile.EndsWith(".ex"))
tempFile += "e";
else if (tempFile.EndsWith(".dl"))
tempFile += "l";
}
tempFile = Path.Combine(tempPath, tempFile);
// Write the file data to a temp file
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
tempStream.Write(data, 0, data.Length);
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Half-Life Package File
/// </summary>
public class PAK : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var pak = SabreTools.Serialization.Wrappers.PAK.Create(stream);
if (pak == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAll(pak, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the PAK to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.PAK item, string outputDirectory)
{
// If we have no directory items
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.DirectoryItems.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the PAK to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.PAK item, int index, string outputDirectory)
{
// If we have no directory items
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
return false;
// If the directory item index is invalid
if (index < 0 || index >= item.Model.DirectoryItems.Length)
return false;
// Get the directory item
var directoryItem = item.Model.DirectoryItems[index];
if (directoryItem == null)
return false;
// Read the item data
var data = item.ReadFromDataSource((int)directoryItem.ItemOffset, (int)directoryItem.ItemLength);
if (data == null)
return false;
// Create the filename
var filename = directoryItem.ItemName;
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,122 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// NovaLogic Game Archive Format
/// </summary>
public class PFF : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var pff = SabreTools.Serialization.Wrappers.PFF.Create(stream);
if (pff == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Extract all files
ExtractAll(pff, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.Message);
return null;
}
}
/// <summary>
/// Extract all segments from the PFF to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all segments extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.PFF item, string outputDirectory)
{
// If we have no segments
if (item.Model.Segments == null || item.Model.Segments.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.Segments.Length; i++)
{
allExtracted &= ExtractSegment(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a segment from the PFF to an output directory by index
/// </summary>
/// <param name="index">Segment index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the segment extracted, false otherwise</returns>
public static bool ExtractSegment(SabreTools.Serialization.Wrappers.PFF item, int index, string outputDirectory)
{
// If we have no segments
if (item.Model.Header?.NumberOfFiles == null || item.Model.Header.NumberOfFiles == 0 || item.Model.Segments == null || item.Model.Segments.Length == 0)
return false;
// If we have an invalid index
if (index < 0 || index >= item.Model.Segments.Length)
return false;
// Get the segment information
var file = item.Model.Segments[index];
if (file == null)
return false;
// Get the read index and length
int offset = (int)file.FileLocation;
int size = (int)file.FileSize;
try
{
// Ensure the output directory exists
Directory.CreateDirectory(outputDirectory);
// Create the output path
string filePath = Path.Combine(outputDirectory, file.FileName ?? $"file{index}");
using (FileStream fs = File.OpenWrite(filePath))
{
// Read the data block
var data = item.ReadFromDataSource(offset, size);
if (data == null)
return false;
// Write the data -- TODO: Compressed data?
fs.Write(data, 0, size);
}
return true;
}
catch
{
return false;
}
}
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// PKWARE ZIP archive and derivatives
/// </summary>
public class PKZIP : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (ZipArchive zipFile = ZipArchive.Open(stream))
{
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If the entry is partial due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// PlayJ audio file
/// </summary>
public class PLJ : 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);
if (magic.StartsWith(new byte?[] { 0xFF, 0x9D, 0x53, 0x4B }))
return "PlayJ Audio File";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,158 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Quantum Archive
/// </summary>
public class Quantum : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var quantum = SabreTools.Serialization.Wrappers.Quantum.Create(stream);
if (quantum == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Extract all files
ExtractAll(quantum, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.Message);
return null;
}
}
/// <summary>
/// Extract all files from the Quantum archive to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.Quantum item, string outputDirectory)
{
// If we have no files
if (item.Model.FileList == null || item.Model.FileList.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.FileList.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the Quantum archive to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.Quantum item, int index, string outputDirectory)
{
// If we have no files
if (item.Model.Header == null || item.Model.Header.FileCount == 0 || item.Model.FileList == null || item.Model.FileList.Length == 0)
return false;
// If we have an invalid index
if (index < 0 || index >= item.Model.FileList.Length)
return false;
// Get the file information
var fileDescriptor = item.Model.FileList[index];
// Read the entire compressed data
int compressedDataOffset = (int)item.Model.CompressedDataOffset;
int compressedDataLength = item.GetEndOfFile() - compressedDataOffset;
var compressedData = item.ReadFromDataSource(compressedDataOffset, compressedDataLength);
// TODO: Figure out decompression
// - Single-file archives seem to work
// - Single-file archives with files that span a window boundary seem to work
// - The first files in each archive seem to work
return false;
// // Setup the decompression state
// State state = new State();
// Decompressor.InitState(state, TableSize, CompressionFlags);
// // Decompress the entire array
// int decompressedDataLength = (int)FileList.Sum(fd => fd.ExpandedFileSize);
// byte[] decompressedData = new byte[decompressedDataLength];
// Decompressor.Decompress(state, compressedData.Length, compressedData, decompressedData.Length, decompressedData);
// // Read the data
// int offset = (int)FileList.Take(index).Sum(fd => fd.ExpandedFileSize);
// byte[] data = new byte[fileDescriptor.ExpandedFileSize];
// Array.Copy(decompressedData, offset, data, 0, data.Length);
// // Loop through all files before the current
// for (int i = 0; i < index; i++)
// {
// // Decompress the next block of data
// byte[] tempData = new byte[FileList[i].ExpandedFileSize];
// int lastRead = Decompressor.Decompress(state, compressedData.Length, compressedData, tempData.Length, tempData);
// compressedData = new ReadOnlySpan<byte>(compressedData, (lastRead), compressedData.Length - (lastRead)).ToArray();
// }
// // Read the data
// byte[] data = new byte[fileDescriptor.ExpandedFileSize];
// _ = Decompressor.Decompress(state, compressedData.Length, compressedData, data.Length, data);
// // Create the filename
// string filename = fileDescriptor.FileName;
// // If we have an invalid output directory
// if (string.IsNullOrEmpty(outputDirectory))
// return false;
// // Create the full output path
// filename = Path.Combine(outputDirectory, filename);
// // Ensure the output directory is created
// Directory.CreateDirectory(Path.GetDirectoryName(filename));
// // Try to write the data
// try
// {
// // Open the output file for writing
// using (Stream fs = File.OpenWrite(filename))
// {
// fs.Write(data, 0, data.Length);
// }
// }
// catch
// {
// return false;
// }
return true;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// RAR archive
/// </summary>
public class RAR : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (RarArchive rarFile = RarArchive.Open(stream))
{
foreach (var entry in rarFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

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

@@ -0,0 +1,63 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// StarForce Filesystem file
/// </summary>
/// <see href="https://forum.xentax.com/viewtopic.php?f=21&t=2084"/>
public class SFFS : IExtractable, IDetectable
{
/// <inheritdoc/>
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);
if (magic.StartsWith(new byte?[] { 0x53, 0x46, 0x46, 0x53 }))
return "StarForce Filesystem Container";
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return null;
}
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
return null;
}
}
}

View File

@@ -0,0 +1,280 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.zlib;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// SGA game archive
/// </summary>
public class SGA : IExtractable
{
/// <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.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var sga = SabreTools.Serialization.Wrappers.SGA.Create(stream);
if (sga == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAll(sga, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the SGA to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.SGA item, string outputDirectory)
{
// Get the number of files
int filesLength;
switch (item.Model.Header?.MajorVersion)
{
case 4: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?.Length ?? 0; break;
case 5: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?.Length ?? 0; break;
case 6: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?.Length ?? 0; break;
case 7: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?.Length ?? 0; break;
default: return false;
}
// If we have no files
if (filesLength == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < filesLength; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the SGA to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.SGA item, int index, string outputDirectory)
{
// Get the number of files
int filesLength;
switch (item.Model.Header?.MajorVersion)
{
case 4: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?.Length ?? 0; break;
case 5: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?.Length ?? 0; break;
case 6: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?.Length ?? 0; break;
case 7: filesLength = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?.Length ?? 0; break;
default: return false;
}
// If we have no files
if (filesLength == 0)
return false;
// If the files index is invalid
if (index < 0 || index >= filesLength)
return false;
// Get the files
object? file;
switch (item.Model.Header?.MajorVersion)
{
case 4: file = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Files?[index]; break;
case 5: file = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Files?[index]; break;
case 6: file = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Files?[index]; break;
case 7: file = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Files?[index]; break;
default: return false;
}
if (file == null)
return false;
// Create the filename
var filename = string.Empty;
switch (item.Model.Header?.MajorVersion)
{
case 4:
case 5: filename = (file as SabreTools.Models.SGA.File4)?.Name; break;
case 6: filename = (file as SabreTools.Models.SGA.File6)?.Name; break;
case 7: filename = (file as SabreTools.Models.SGA.File7)?.Name; break;
default: return false;
}
// Loop through and get all parent directories
var parentNames = new List<string?> { filename };
// Get the parent directory
var folder = default(object);
switch (item.Model.Header?.MajorVersion)
{
case 4: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory4)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
case 5: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory5)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
case 6: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory6)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
case 7: folder = (item.Model.Directory as SabreTools.Models.SGA.Directory7)?.Folders?.FirstOrDefault(f => f != null && index >= f.FileStartIndex && index <= f.FileEndIndex); break;
default: return false;
}
// If we have a parent folder
if (folder != null)
{
switch (item.Model.Header?.MajorVersion)
{
case 4: parentNames.Add((folder as SabreTools.Models.SGA.Folder4)?.Name); break;
case 5:
case 6:
case 7: parentNames.Add((folder as SabreTools.Models.SGA.Folder5)?.Name); break;
default: return false;
}
}
// TODO: Should the section name/alias be used in the path as well?
// Reverse and assemble the filename
parentNames.Reverse();
#if NET20 || NET35
var parentNamesArray = parentNames.Cast<string>().ToArray();
filename = parentNamesArray[0];
for (int i = 1; i < parentNamesArray.Length; i++)
{
filename = Path.Combine(filename, parentNamesArray[i]);
}
#else
filename = Path.Combine(parentNames.Cast<string>().ToArray());
#endif
// Get the file offset
long fileOffset;
switch (item.Model.Header?.MajorVersion)
{
case 4:
case 5: fileOffset = (file as SabreTools.Models.SGA.File4)?.Offset ?? 0; break;
case 6: fileOffset = (file as SabreTools.Models.SGA.File6)?.Offset ?? 0; break;
case 7: fileOffset = (file as SabreTools.Models.SGA.File7)?.Offset ?? 0; break;
default: return false;
}
// Adjust the file offset
switch (item.Model.Header?.MajorVersion)
{
case 4: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header4)?.FileDataOffset ?? 0; break;
case 5: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header4)?.FileDataOffset ?? 0; break;
case 6: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header6)?.FileDataOffset ?? 0; break;
case 7: fileOffset += (item.Model.Header as SabreTools.Models.SGA.Header6)?.FileDataOffset ?? 0; break;
default: return false;
};
// Get the file sizes
long fileSize, outputFileSize;
switch (item.Model.Header?.MajorVersion)
{
case 4:
case 5:
fileSize = (file as SabreTools.Models.SGA.File4)?.SizeOnDisk ?? 0;
outputFileSize = (file as SabreTools.Models.SGA.File4)?.Size ?? 0;
break;
case 6:
fileSize = (file as SabreTools.Models.SGA.File6)?.SizeOnDisk ?? 0;
outputFileSize = (file as SabreTools.Models.SGA.File6)?.Size ?? 0;
break;
case 7:
fileSize = (file as SabreTools.Models.SGA.File7)?.SizeOnDisk ?? 0;
outputFileSize = (file as SabreTools.Models.SGA.File7)?.Size ?? 0;
break;
default: return false;
}
// Read the compressed data directly
var compressedData = item.ReadFromDataSource((int)fileOffset, (int)fileSize);
if (compressedData == null)
return false;
// If the compressed and uncompressed sizes match
byte[] data;
if (fileSize == outputFileSize)
{
data = compressedData;
}
else
{
// Inflate the data into the buffer
var zstream = new ZLib.z_stream_s();
data = new byte[outputFileSize];
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
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename);
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using Stream fs = File.OpenWrite(filename);
fs.Write(data, 0, data.Length);
}
catch
{
return false;
}
return false;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// 7-zip archive
/// </summary>
public class SevenZip : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(stream))
{
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;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Tar;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Tape archive
/// </summary>
public class TapeArchive : IExtractable
{
/// <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.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
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (TarArchive tarFile = TarArchive.Open(stream))
{
foreach (var entry in tarFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Various generic textfile formats
/// </summary>
public class Textfile : 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)
{
// Files can be protected in multiple ways
var protections = new List<string>();
try
{
// Load the current file content
var fileContent = string.Empty;
#if NET20 || NET35 || NET40
using (var sr = new StreamReader(stream, Encoding.Default, true, 1024 * 1024))
#else
using (var sr = new StreamReader(stream, Encoding.Default, true, 1024 * 1024, true))
#endif
{
fileContent = sr.ReadToEnd();
}
// AegiSoft License Manager
// Found in "setup.ins" (Redump entry 73521/IA item "Nova_HoyleCasino99USA").
if (fileContent.Contains("Failed to load the AegiSoft License Manager install program."))
protections.Add("AegiSoft License Manager");
// CD-Key
if (fileContent.Contains("a valid serial number is required"))
protections.Add("CD-Key / Serial");
else if (fileContent.Contains("serial number is located"))
protections.Add("CD-Key / Serial");
// Found in "Setup.Ins" ("Word Point 2002" in IA item "advantage-language-french-beginner-langmaster-2005").
else if (fileContent.Contains("Please enter a valid registration number"))
protections.Add("CD-Key / Serial");
// 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"))
protections.Add("Freelock 1.0");
else if (fileContent.Contains("FREELOCK 1.2"))
protections.Add("Freelock 1.2");
else if (fileContent.Contains("FREELOCK 1.2a"))
protections.Add("Freelock 1.2a");
else if (fileContent.Contains("FREELOCK 1.3"))
protections.Add("Freelock 1.3");
else if (fileContent.Contains("FREELOCK"))
protections.Add("Freelock");
// MediaCloQ
if (fileContent.Contains("SunnComm MediaCloQ"))
protections.Add("MediaCloQ");
else if (fileContent.Contains("http://download.mediacloq.com/"))
protections.Add("MediaCloQ");
else if (fileContent.Contains("http://www.sunncomm.com/mediacloq/"))
protections.Add("MediaCloQ");
// MediaMax
if (fileContent.Contains("MediaMax technology"))
protections.Add("MediaMax CD-3");
else if (fileContent.Contains("exclusive Cd3 technology"))
protections.Add("MediaMax CD-3");
else if (fileContent.Contains("<PROTECTION-VENDOR>MediaMAX</PROTECTION-VENDOR>"))
protections.Add("MediaMax CD-3");
else if (fileContent.Contains("MediaMax(tm)"))
protections.Add("MediaMax CD-3");
// phenoProtect
if (fileContent.Contains("phenoProtect"))
protections.Add("phenoProtect");
// Rainbow Sentinel
// Found in "SENTW95.HLP" and "SENTINEL.HLP" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".
if (fileContent.Contains("Rainbow Sentinel Driver Help"))
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.
//
// TODO: Use the filenames in this line to get the version out of it
// SecuROM
if (fileContent.Contains("SecuROM protected application"))
protections.Add("SecuROM");
// Steam
if (fileContent.Contains("All use of the Program is governed by the terms of the Steam Agreement as described below."))
protections.Add("Steam");
// XCP
if (fileContent.Contains("http://cp.sonybmg.com/xcp/"))
protections.Add("XCP");
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
return string.Join(";", [.. protections]);
}
}
}

View File

@@ -0,0 +1,138 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Half-Life 2 Level
/// </summary>
public class VBSP : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var vbsp = SabreTools.Serialization.Wrappers.VBSP.Create(stream);
if (vbsp == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAllLumps(vbsp, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex.ToString());
return null;
}
}
/// <summary>
/// Extract all lumps from the VBSP to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all lumps extracted, false otherwise</returns>
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.VBSP item, string outputDirectory)
{
// If we have no lumps
if (item.Model.Header?.Lumps == null || item.Model.Header.Lumps.Length == 0)
return false;
// Loop through and extract all lumps to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.Header.Lumps.Length; i++)
{
allExtracted &= ExtractLump(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a lump from the VBSP to an output directory by index
/// </summary>
/// <param name="index">Lump index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the lump extracted, false otherwise</returns>
public static bool ExtractLump(SabreTools.Serialization.Wrappers.VBSP item, int index, string outputDirectory)
{
// If we have no lumps
if (item.Model.Header?.Lumps == null || item.Model.Header.Lumps.Length == 0)
return false;
// If the lumps index is invalid
if (index < 0 || index >= item.Model.Header.Lumps.Length)
return false;
// Get the lump
var lump = item.Model.Header.Lumps[index];
if (lump == null)
return false;
// Read the data
var data = item.ReadFromDataSource((int)lump.Offset, (int)lump.Length);
if (data == null)
return false;
// Create the filename
string filename = $"lump_{index}.bin";
switch (index)
{
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_ENTITIES:
filename = "entities.ent";
break;
case SabreTools.Models.VBSP.Constants.HL_VBSP_LUMP_PAKFILE:
filename = "pakfile.zip";
break;
}
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename);
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,187 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Valve Package File
/// </summary>
public class VPK : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var vpk = SabreTools.Serialization.Wrappers.VPK.Create(stream);
if (vpk == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAll(vpk, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the VPK to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.VPK item, string outputDirectory)
{
// If we have no directory items
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.DirectoryItems.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the VPK to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.VPK item, int index, string outputDirectory)
{
// If we have no directory items
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
return false;
// If the directory item index is invalid
if (index < 0 || index >= item.Model.DirectoryItems.Length)
return false;
// Get the directory item
var directoryItem = item.Model.DirectoryItems[index];
if (directoryItem?.DirectoryEntry == null)
return false;
// If we have an item with no archive
var data = new byte[0];
if (directoryItem.DirectoryEntry.ArchiveIndex == SabreTools.Models.VPK.Constants.HL_VPK_NO_ARCHIVE)
{
if (directoryItem.PreloadData == null)
return false;
data = directoryItem.PreloadData;
}
else
{
// If we have invalid archives
if (item.ArchiveFilenames == null || item.ArchiveFilenames.Length == 0)
return false;
// If we have an invalid index
if (directoryItem.DirectoryEntry.ArchiveIndex < 0 || directoryItem.DirectoryEntry.ArchiveIndex >= item.ArchiveFilenames.Length)
return false;
// Get the archive filename
string archiveFileName = item.ArchiveFilenames[directoryItem.DirectoryEntry.ArchiveIndex];
if (string.IsNullOrEmpty(archiveFileName))
return false;
// If the archive doesn't exist
if (!File.Exists(archiveFileName))
return false;
// Try to open the archive
var archiveStream = default(Stream);
try
{
// Open the archive
archiveStream = File.Open(archiveFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Seek to the data
archiveStream.Seek(directoryItem.DirectoryEntry.EntryOffset, SeekOrigin.Begin);
// Read the directory item bytes
data = archiveStream.ReadBytes((int)directoryItem.DirectoryEntry.EntryLength);
}
catch
{
return false;
}
finally
{
archiveStream?.Close();
}
// If we have preload data, prepend it
if (data != null && directoryItem.PreloadData != null)
data = directoryItem.PreloadData.Concat(data).ToArray();
}
// If there is nothing to write out
if (data == null)
return false;
// Create the filename
string filename = $"{directoryItem.Name}.{directoryItem.Extension}";
if (!string.IsNullOrEmpty(directoryItem.Path))
filename = Path.Combine(directoryItem.Path, filename);
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename);
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,129 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// Half-Life Texture Package File
/// </summary>
public class WAD : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var wad = SabreTools.Serialization.Wrappers.WAD.Create(stream);
if (wad == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAllLumps(wad, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all lumps from the WAD to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all lumps extracted, false otherwise</returns>
public static bool ExtractAllLumps(SabreTools.Serialization.Wrappers.WAD item, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
return false;
// Loop through and extract all lumps to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.Lumps.Length; i++)
{
allExtracted &= ExtractLump(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a lump from the WAD to an output directory by index
/// </summary>
/// <param name="index">Lump index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the lump extracted, false otherwise</returns>
public static bool ExtractLump(SabreTools.Serialization.Wrappers.WAD item, int index, string outputDirectory)
{
// If we have no lumps
if (item.Model.Lumps == null || item.Model.Lumps.Length == 0)
return false;
// If the lumps index is invalid
if (index < 0 || index >= item.Model.Lumps.Length)
return false;
// Get the lump
var lump = item.Model.Lumps[index];
if (lump == null)
return false;
// Read the data -- TODO: Handle uncompressed lumps (see BSP.ExtractTexture)
var data = item.ReadFromDataSource((int)lump.Offset, (int)lump.Length);
if (data == null)
return false;
// Create the filename
string filename = $"{lump.Name}.lmp";
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename);
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.IO;
using BinaryObjectScanner.Interfaces;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Compressors.Xz;
#endif
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// xz archive
/// </summary>
public class XZ : IExtractable
{
/// <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.ReadWrite);
return Extract(fs, file, includeDebug);
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (XZStream xzFile = new XZStream(stream))
{
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempFile))
{
xzFile.CopyTo(fs);
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
namespace BinaryObjectScanner.FileType
{
/// <summary>
/// XBox Package File
/// </summary>
public class XZP : IExtractable
{
/// <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.ReadWrite))
{
return Extract(fs, file, includeDebug);
}
}
/// <inheritdoc/>
public string? Extract(Stream? stream, string file, bool includeDebug)
{
try
{
// Create the wrapper
var xzp = SabreTools.Serialization.Wrappers.XZP.Create(stream);
if (xzp == null)
return null;
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Loop through and extract all files
ExtractAll(xzp, tempPath);
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Extract all files from the XZP to an output directory
/// </summary>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if all files extracted, false otherwise</returns>
public static bool ExtractAll(SabreTools.Serialization.Wrappers.XZP item, string outputDirectory)
{
// If we have no directory entries
if (item.Model.DirectoryEntries == null || item.Model.DirectoryEntries.Length == 0)
return false;
// Loop through and extract all files to the output
bool allExtracted = true;
for (int i = 0; i < item.Model.DirectoryEntries.Length; i++)
{
allExtracted &= ExtractFile(item, i, outputDirectory);
}
return allExtracted;
}
/// <summary>
/// Extract a file from the XZP to an output directory by index
/// </summary>
/// <param name="index">File index to extract</param>
/// <param name="outputDirectory">Output directory to write to</param>
/// <returns>True if the file extracted, false otherwise</returns>
public static bool ExtractFile(SabreTools.Serialization.Wrappers.XZP item, int index, string outputDirectory)
{
// If we have no directory entries
if (item.Model.DirectoryEntries == null || item.Model.DirectoryEntries.Length == 0)
return false;
// If we have no directory items
if (item.Model.DirectoryItems == null || item.Model.DirectoryItems.Length == 0)
return false;
// If the directory entry index is invalid
if (index < 0 || index >= item.Model.DirectoryEntries.Length)
return false;
// Get the directory entry
var directoryEntry = item.Model.DirectoryEntries[index];
if (directoryEntry == null)
return false;
// Get the associated directory item
var directoryItem = item.Model.DirectoryItems.Where(di => di?.FileNameCRC == directoryEntry.FileNameCRC).FirstOrDefault();
if (directoryItem == null)
return false;
// Load the item data
var data = item.ReadFromDataSource((int)directoryEntry.EntryOffset, (int)directoryEntry.EntryLength);
if (data == null)
return false;
// Create the filename
var filename = directoryItem.Name;
// If we have an invalid output directory
if (string.IsNullOrEmpty(outputDirectory))
return false;
// Create the full output path
filename = Path.Combine(outputDirectory, filename ?? $"file{index}");
// Ensure the output directory is created
var directoryName = Path.GetDirectoryName(filename);
if (directoryName != null)
Directory.CreateDirectory(directoryName);
// Try to write the data
try
{
// Open the output file for writing
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(data, 0, data.Length);
}
}
catch
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,40 @@
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.GameEngine
{
/// <summary>
/// RenderWare (https://web.archive.org/web/20070214132346/http://www.renderware.com/) is an API and graphics engine created by Criterion in 1993.
/// It appears that version 4.X was exclusively used by EA internally, with version 3.X being the final public version (https://sigmaco.org/3782-renderware/).
/// It was available to use on many different platforms, with it being particularly useful for the PS2 (https://en.wikipedia.org/wiki/RenderWare).
///
/// Additional resources and documentation:
/// RenderWare interview: https://web.archive.org/web/20031208124348/http://www.homelanfed.com/index.php?id=9856
/// RenderWare V2.1 API reference: http://www.tnlc.com/rw/api/rwdoc.htm
/// RenderWare 2 official docs: https://github.com/electronicarts/RenderWare3Docs
/// RenderWare 3.7 SDK: https://github.com/sigmaco/rwsdk-v37-pc
/// Wikipedia list of RenderWare games: https://en.wikipedia.org/wiki/Category:RenderWare_games
/// </summary>
public class RenderWare : IPortableExecutableCheck
{
/// <inheritdoc/>
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 Redump entries 20138, 55823, and 102493.
bool rwcsegSection = pex.ContainsSection("_rwcseg", exact: true);
// Found in Redump entry 20138.
bool rwdsegSection = pex.ContainsSection("_rwdseg", exact: true);
// TODO: Check if this indicates a specific version, or if these sections are present in multiple.
if (rwcsegSection || rwdsegSection)
return "RenderWare";
return null;
}
}
}

View File

@@ -0,0 +1,478 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Dictionary;
namespace BinaryObjectScanner
{
internal static class Handler
{
#region Public Collections
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
public static IEnumerable<IPathCheck?> PathCheckClasses
{
get
{
pathCheckClasses ??= InitCheckClasses<IPathCheck>();
return pathCheckClasses;
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
private static IEnumerable<IPathCheck?>? pathCheckClasses;
#endregion
#region Multiple Implementation Wrappers
/// <summary>
/// Handle a single path based on all path check implementations
/// </summary>
/// <param name="path">Path of the file or directory to check</param>
/// <param name="scanner">Scanner object to use for options and scanning</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#endif
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
// Preprocess the list of files
files = files?.Select(f => f.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))?.ToList();
// Iterate through all checks
#if NET20 || NET35
foreach (var checkClass in PathCheckClasses)
#else
Parallel.ForEach(PathCheckClasses, checkClass =>
#endif
{
var subProtections = checkClass?.PerformCheck(path, files);
if (subProtections != null)
AppendToDictionary(protections, path, subProtections);
#if NET20 || NET35
}
#else
});
#endif
return protections;
}
#endregion
#region Single Implementation Handlers
/// <summary>
/// Handle files based on an IDetectable implementation
/// </summary>
/// <param name="impl">IDetectable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="stream">Stream to scan the contents of</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Queue<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
#else
public static ConcurrentQueue<string>? HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
#endif
{
var protection = impl.Detect(stream, fileName, includeDebug);
return ProcessProtectionString(protection);
}
/// <summary>
/// Handle files based on an IExtractable implementation
/// </summary>
/// <param name="impl">IExtractable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="stream">Stream to scan the contents of</param>
/// <param name="scanner">Scanner object to use on extractable contents</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(stream, fileName, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableMSDOSExecutable implementation
/// </summary>
/// <param name="impl">IExtractableMSDOSExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="mz">MSDOS to scan the contents of</param>
/// <param name="scanner">Scanner object to use on extractable contents</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, mz, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableLinearExecutable implementation
/// </summary>
/// <param name="impl">IExtractableLinearExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="lex">LinearExecutable to scan the contents of</param>
/// <param name="scanner">Scanner object to use on extractable contents</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, lex, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractableNewExecutable implementation
/// </summary>
/// <param name="impl">IExtractableNewExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="nex">NewExecutable to scan the contents of</param>
/// <param name="scanner">Scanner object to use on extractable contents</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, nex, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IExtractablePortableExecutable implementation
/// </summary>
/// <param name="impl">IExtractablePortableExecutable class representing the file type</param>
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
/// <param name="pex">PortableExecutable to scan the contents of</param>
/// <param name="scanner">Scanner object to use on extractable contents</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#endif
{
// If the extractable file itself fails
try
{
// Extract and get the output path
var tempPath = impl.Extract(fileName, pex, scanner.IncludeDebug);
if (tempPath == null)
return null;
// Collect and format all found protections
var subProtections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
return subProtections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <summary>
/// Handle files based on an IPathCheck implementation
/// </summary>
/// <param name="impl">IPathCheck class representing the file type</param>
/// <param name="path">Path of the file or directory to check</param>
/// <returns>Set of protections in path, null on error</returns>
#if NET20 || NET35
private static Queue<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
#else
private static ConcurrentQueue<string>? PerformCheck(this IPathCheck impl, string? path, IEnumerable<string>? files)
#endif
{
// If we have an invalid path
if (string.IsNullOrEmpty(path))
return null;
// Setup the output dictionary
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// If we have a file path
if (File.Exists(path))
{
var protection = impl.CheckFilePath(path!);
var subProtections = ProcessProtectionString(protection);
if (subProtections != null)
protections.AddRange(subProtections);
}
// If we have a directory path
if (Directory.Exists(path) && files?.Any() == true)
{
var subProtections = impl.CheckDirectoryPath(path!, files);
if (subProtections != null)
protections.AddRange(subProtections);
}
return protections;
}
#endregion
#region Initializers
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T?> InitCheckClasses<T>() =>
InitCheckClasses<T>(Assembly.GetExecutingAssembly());
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T?> InitCheckClasses<T>(Assembly assembly)
{
List<T?> classTypes = [];
// If not all types can be loaded, use the ones that could be
List<Type> assemblyTypes = [];
try
{
assemblyTypes = assembly.GetTypes().ToList<Type>();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types.Where(t => t != null)!.ToList<Type>();
}
// Loop through all types
foreach (Type type in assemblyTypes)
{
// If the type isn't a class or doesn't implement the interface
if (!type.IsClass || type.GetInterface(typeof(T).Name) == null)
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
#endregion
#region Helpers
/// <summary>
/// Process a protection string if it includes multiple protections
/// </summary>
/// <param name="protection">Protection string to process</param>
/// <returns>Set of protections parsed, null on error</returns>
#if NET20 || NET35
private static Queue<string>? ProcessProtectionString(string? protection)
#else
private static ConcurrentQueue<string>? ProcessProtectionString(string? protection)
#endif
{
// If we have an invalid protection string
if (string.IsNullOrEmpty(protection))
return null;
// Setup the output queue
#if NET20 || NET35
var protections = new Queue<string>();
#else
var protections = new ConcurrentQueue<string>();
#endif
// If we have an indicator of multiple protections
if (protection!.Contains(";"))
{
var splitProtections = protection.Split(';');
protections.AddRange(splitProtections);
}
else
{
protections.Enqueue(protection);
}
return protections;
}
#endregion
}
}

View File

@@ -1,9 +1,9 @@
namespace BurnOutSharp.Interfaces
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a generic file for protection
/// </summary>
internal interface IContentCheck
public interface IContentCheck
{
/// <summary>
/// Check a path for protections based on file contents
@@ -12,6 +12,6 @@
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
string CheckContents(string file, byte[] fileContent, bool includeDebug);
string? CheckContents(string file, byte[] fileContent, bool includeDebug);
}
}

View File

@@ -0,0 +1,28 @@
using System.IO;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a file type as being able to be detected
/// </summary>
public interface IDetectable
{
/// <summary>
/// Check if a file is detected as this file type
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Detected file or protection type, null on error</returns>
/// <remarks>Ideally, this should just point to the other detect implementation.</remarks>
string? Detect(string file, bool includeDebug);
/// <summary>
/// Check if a stream is detected as this file type
/// </summary>
/// <param name="stream">Stream representing the input file</param>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Detected file or protection type, null on error</returns>
string? Detect(Stream stream, string file, bool includeDebug);
}
}

View File

@@ -0,0 +1,30 @@
using System.IO;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Mark a file type as being able to be extracted
/// </summary>
/// TODO: Change to have output directory passed in
/// TODO: Change to return a bool
public interface IExtractable
{
/// <summary>
/// Extract a file to a temporary path, if possible
/// </summary>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
/// <remarks>Ideally, this should just point to the other extract implementation.</remarks>
string? Extract(string file, bool includeDebug);
/// <summary>
/// Extract a stream to a temporary path, if possible
/// </summary>
/// <param name="stream">Stream representing the input file</param>
/// <param name="file">Path to the input file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>Path to extracted files, null on error</returns>
string? Extract(Stream? stream, string file, bool includeDebug);
}
}

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,11 +1,11 @@
using BurnOutSharp.Wrappers;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.Interfaces
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a Linear Executable (LE) for protection
/// </summary>
internal interface ILinearExecutableCheck
public interface ILinearExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
@@ -14,6 +14,6 @@ namespace BurnOutSharp.Interfaces
/// <param name="lex">LinearExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
string CheckNewExecutable(string file, LinearExecutable lex, bool includeDebug);
string? CheckLinearExecutable(string file, LinearExecutable lex, bool includeDebug);
}
}

View File

@@ -0,0 +1,19 @@
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a MS-DOS Executable (MZ) for protection
/// </summary>
public interface IMSDOSExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
/// </summary>
/// <param name="file">File to check for protection indicators</param>
/// <param name="mz">MSDOS representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
string? CheckMSDOSExecutable(string file, MSDOS mz, bool includeDebug);
}
}

View File

@@ -1,11 +1,11 @@
using BurnOutSharp.Wrappers;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.Interfaces
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a New Executable (NE) for protection
/// </summary>
internal interface INewExecutableCheck
public interface INewExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
@@ -14,6 +14,6 @@ namespace BurnOutSharp.Interfaces
/// <param name="nex">NewExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug);
string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug);
}
}

View File

@@ -1,7 +1,9 @@
using System.Collections.Concurrent;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
namespace BurnOutSharp.Interfaces
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a file or directory path for protection
@@ -9,7 +11,7 @@ namespace BurnOutSharp.Interfaces
/// <remarks>
/// These checks rely primarily on filenames and paths, not file contents
/// </remarks>
internal interface IPathCheck
public interface IPathCheck
{
/// <summary>
/// Check a file path for protections based on path name
@@ -17,13 +19,17 @@ namespace BurnOutSharp.Interfaces
/// <param name="path">Path to check for protection indicators</param>
/// <param name="files">Enumerable of strings representing files in a directory</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use a content check instead, if possible</remarks>
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files);
#if NET20 || NET35
Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#else
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#endif
/// <summary>
/// Check a file path for protections based on path name
/// </summary>
/// <param name="path">Path to check for protection indicators</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use a content check instead, if possible</remarks>
string CheckFilePath(string path);
string? CheckFilePath(string path);
}
}

View File

@@ -1,11 +1,11 @@
using BurnOutSharp.Wrappers;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.Interfaces
namespace BinaryObjectScanner.Interfaces
{
/// <summary>
/// Check a Portable Executable (PE) for protection
/// </summary>
internal interface IPortableExecutableCheck
public interface IPortableExecutableCheck
{
/// <summary>
/// Check a path for protections based on file contents
@@ -14,6 +14,6 @@ namespace BurnOutSharp.Interfaces
/// <param name="pex">PortableExecutable representing the read-in file</param>
/// <param name="includeDebug">True to include debug data, false otherwise</param>
/// <returns>String containing any protections found in the file</returns>
string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug);
string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug);
}
}

View File

@@ -0,0 +1,38 @@
namespace BinaryObjectScanner
{
/// <summary>
/// Scanning options
/// </summary>
public class Options
{
/// <summary>
/// Determines whether archives are decompressed and scanned
/// </summary>
public bool ScanArchives { get; set; }
/// <summary>
/// Determines if content matches are used or not
/// </summary>
public bool ScanContents { get; set; }
/// <summary>
/// Determines if game engines are counted as detected protections or not
/// </summary>
public bool ScanGameEngines { get; set; }
/// <summary>
/// Determines if packers are counted as detected protections or not
/// </summary>
public bool ScanPackers { get; set; }
/// <summary>
/// Determines if path matches are used or not
/// </summary>
public bool ScanPaths { get; set; }
/// <summary>
/// Determines if debug information is output or not
/// </summary>
public bool IncludeDebug { get; set; }
}
}

View File

@@ -1,21 +1,19 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class ASPack : IPortableExecutableCheck, IScannable
public class ASPack : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
@@ -29,21 +27,21 @@ namespace BurnOutSharp.PackerType
// if (pex.EntryPointRaw != null)
// {
// var matchers = GenerateMatchers();
// string match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
// if (!string.IsNullOrWhiteSpace(match))
// var match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
// if (!string.IsNullOrEmpty(match))
// return match;
// }
// Get the .adata* section, if it exists
var adataSection = pex.GetFirstSection(".adata", exact: false);
if (adataSection != null)
if (adataSection?.Name != null)
{
var adataSectionRaw = pex.GetFirstSectionData(Encoding.UTF8.GetString(adataSection.Name));
if (adataSectionRaw != null)
{
var matchers = GenerateMatchers();
string match = MatchUtil.GetFirstMatch(file, adataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrWhiteSpace(match))
var match = MatchUtil.GetFirstMatch(file, adataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
}
@@ -52,19 +50,7 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
@@ -79,7 +65,7 @@ namespace BurnOutSharp.PackerType
{
#region No Wildcards (Long)
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x92, 0x1A, 0x44, 0x00, 0xB8, 0x8C, 0x1A,
@@ -88,7 +74,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0xC4, 0x1D, 0x44,
}, "ASPack 1.00b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xD2, 0x2A, 0x44, 0x00, 0xB8, 0xCC, 0x2A,
@@ -102,7 +88,7 @@ namespace BurnOutSharp.PackerType
0x44, 0x00, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.01b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xD2, 0x2A, 0x44, 0x00, 0xB8, 0xCC, 0x2A,
@@ -111,7 +97,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x9C, 0x2E, 0x44
}, "ASPack 1.01b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x96, 0x78, 0x43, 0x00, 0xB8, 0x90, 0x78,
@@ -125,7 +111,7 @@ namespace BurnOutSharp.PackerType
0x43, 0x00, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.02b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x96, 0x78, 0x43, 0x00, 0xB8, 0x90, 0x78,
@@ -135,7 +121,7 @@ namespace BurnOutSharp.PackerType
0x15, 0xFE, 0x85, 0x74, 0x7C, 0x43
}, "ASPack 1.02b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x8A, 0x1C, 0x40, 0x00, 0xB9, 0x9E, 0x00,
@@ -143,14 +129,14 @@ namespace BurnOutSharp.PackerType
0x8B, 0xF7, 0x33
}, "ASPack 1.02b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x96, 0x78, 0x43, 0x00, 0xB8, 0x90, 0x78,
0x43, 0x00, 0x03, 0xC5
}, "ASPack 1.02b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xAE, 0x98, 0x43, 0x00, 0xB8, 0xA8, 0x98,
@@ -159,7 +145,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x0E, 0x9D, 0x43
}, "ASPack 1.03b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xCE, 0x3A, 0x44, 0x00, 0xB8, 0xC8, 0x3A,
@@ -168,7 +154,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0xAC, 0x3E, 0x44
}, "ASPack 1.05b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xEA, 0xA8, 0x43, 0x00, 0xB8, 0xE4, 0xA8,
@@ -182,7 +168,7 @@ namespace BurnOutSharp.PackerType
0x43, 0x00, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.06.01b (DLL)"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0xEA, 0xA8, 0x43, 0x00, 0xB8, 0xE4, 0xA8,
@@ -192,7 +178,7 @@ namespace BurnOutSharp.PackerType
0x15, 0xFE, 0x85, 0x6E, 0xAD, 0x43
}, "ASPack 1.06.01b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x3E, 0xD9, 0x43, 0x00, 0xB8, 0x38, 0xD9,
@@ -206,7 +192,7 @@ namespace BurnOutSharp.PackerType
0x43, 0x00, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.07b (DLL)"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xEB, 0x03, 0x5D, 0xFF, 0xE5, 0xE8, 0xF8,
0xFF, 0xFF, 0xFF, 0x81, 0xED, 0x1B, 0x6A, 0x44,
@@ -214,7 +200,7 @@ namespace BurnOutSharp.PackerType
0x2B, 0x9D, 0x2A
}, "ASPack 1.08"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x0A, 0x4A, 0x44, 0x00, 0xBB, 0x04, 0x4A,
@@ -228,7 +214,7 @@ namespace BurnOutSharp.PackerType
0x53, 0x50, 0xFF, 0x95, 0x90, 0x51, 0x44, 0x00
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x0A, 0x4A, 0x44, 0x00, 0xBB, 0x04, 0x4A,
@@ -237,20 +223,20 @@ namespace BurnOutSharp.PackerType
0x00, 0x89, 0x9D, 0xBB, 0x4E
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x0A, 0x4A, 0x44, 0x00, 0xBB, 0x04, 0x4A,
0x44, 0x00, 0x03, 0xDD
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x72, 0x05, 0x00, 0x00, 0xEB, 0x33,
0x87, 0xDB, 0x90, 0x00
}, "ASPack 2.00.01"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xEB,
0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01, 0x00,
@@ -258,34 +244,34 @@ namespace BurnOutSharp.PackerType
0xFF, 0x03, 0xDD, 0x81, 0xEB
}, "ASPack 2.1"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xEB, 0x09,
0x5D, 0x55, 0x81, 0xED, 0x39, 0x39, 0x44, 0x00,
0xC3, 0xE9, 0x3D, 0x04, 0x00, 0x00
}, "ASPack 2.11b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xEB, 0x09,
0x5D, 0x55
}, "ASPack 2.11b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xEB, 0x09,
0x5D, 0x55, 0x81, 0xED, 0x39, 0x39, 0x44, 0x00,
0xC3, 0xE9, 0x59, 0x04, 0x00, 0x00
}, "ASPack 2.11c"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xCD, 0x20,
0xE8, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x2B, 0xC9,
0x58, 0x74, 0x02
}, "ASPack 2.11d"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xEB,
0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01
@@ -295,7 +281,7 @@ namespace BurnOutSharp.PackerType
#region Wildcards (Long)
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0x3E, 0xD9, 0x43, null, 0xB8, 0x38, null,
@@ -309,7 +295,7 @@ namespace BurnOutSharp.PackerType
0x43, null, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.00b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0xD2, 0x2A, 0x44, null, 0xB8, 0xCC, 0x2A,
@@ -318,7 +304,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x9C, 0x2E, 0x44
}, "ASPack 1.01b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0xCE, 0x3A, 0x44, null, 0xB8, 0xC8, 0x3A,
@@ -327,7 +313,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0xAC, 0x3E, 0x44
}, "ASPack 1.01b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, 0x3E, 0xD9, 0x43, 0x00, 0xB8, 0x38, null,
@@ -341,13 +327,13 @@ namespace BurnOutSharp.PackerType
0x43, 0x00, 0x89, 0x44, 0x24, 0x1C, 0x61, 0xFF
}, "ASPack 1.02a -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0x06, null, null, null, 0x64, 0xA0, 0x23
}, "ASPack 1.02a"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0x96, 0x78, 0x43, null, 0xB8, 0x90, 0x78,
@@ -356,7 +342,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x74, 0x7C, 0x43
}, "ASPack 1.02b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0xAE, 0x98, 0x43, null, 0xB8, 0xA8, 0x98,
@@ -365,7 +351,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x0E, 0x9D, 0x43
}, "ASPack 1.03b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, null, null, null, null, 0xE8, 0x0D, null,
@@ -373,7 +359,7 @@ namespace BurnOutSharp.PackerType
null, null, null, null, null, null, null, 0x58
}, "ASPack 1.03b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81,
0xED, null, null, null, 0x00, 0xB8, null, null,
@@ -382,7 +368,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x08, 0x9D, null, 0x00, 0x00
}, "ASPack 1.04b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, null, null, null, null, 0xB8, null, null,
@@ -391,7 +377,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x08, 0x9D
}, "ASPack 1.04b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, null, null, null, null, 0xB8, null, null,
@@ -400,7 +386,7 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x01, 0xDE
}, "ASPack 1.04b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, 0xEA, 0xA8, 0x43, null, 0xB8, 0xE4, 0xA8,
@@ -409,28 +395,28 @@ namespace BurnOutSharp.PackerType
0x80, 0xBD, 0x6E, 0xAD, 0x43
}, "ASPack 1.06.1b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x90, 0x61, 0xBE, null, null, null, null, 0x8D,
0xBE, null, null, null, null, 0x57, 0x83, 0xCD,
0xFF
}, "ASPack 1.06.1b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, null,
null, null, null, null, null, 0xB8, null, null,
null, null, 0x03, 0xC5
}, "ASPack 1.07b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, null, null, null, null, 0x5D, 0x81,
0xED, null, null, null, null, 0x60, 0xE8, 0x2B,
0x03, 0x00, 0x00
}, "ASPack 1.07b"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xEB, 0x0A, 0x5D, 0xEB, 0x02, 0xFF, 0x25,
0x45, 0xFF, 0xE5, 0xE8, 0xE9, 0xE8, 0xF1, 0xFF,
@@ -439,7 +425,7 @@ namespace BurnOutSharp.PackerType
0x2B, 0x9D
}, "ASPack 1.08.01"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xEB, 0x0A, 0x5D, 0xEB, 0x02, 0xFF, 0x25,
0x45, 0xFF, 0xE5, 0xE8, 0xE9, 0xE8, 0xF1, 0xFF,
@@ -448,7 +434,7 @@ namespace BurnOutSharp.PackerType
0x2B, 0x9D
}, "ASPack 1.08.01"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xEB, 0x0A, 0x5D, 0xEB, 0x02, 0xFF, 0x25,
0x45, 0xFF, 0xE5, 0xE8, 0xE9, 0xE8, 0xF1, 0xFF,
@@ -457,7 +443,7 @@ namespace BurnOutSharp.PackerType
0x2B, 0x9D, 0x72
}, "ASPack 1.08.02"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, null,
null, null, null, null, null, 0xBB, null, null,
@@ -466,14 +452,14 @@ namespace BurnOutSharp.PackerType
0x00, 0x89, 0x9D, 0xBB, 0x4E
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, null,
null, null, null, null, null, 0xBB, null, null,
null, null, 0x03, 0xDD
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x55, 0x57, 0x51, 0x53, 0xE8, null, null, null,
null, 0x5D, 0x8B, 0xC5, 0x81, 0xED, null, null,
@@ -482,27 +468,27 @@ namespace BurnOutSharp.PackerType
null, 0x0F, 0xB6
}, "ASPack 1.08.03"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE9, null, null, null, null, 0xEF, 0x40,
0x03, 0xA7, 0x07, 0x8F, 0x07, 0x1C, 0x37, 0x5D,
0x43, 0xA7, 0x04, 0xB9, 0x2C, 0x3A
}, "ASPack 1.08.x"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x02, 0x00, 0x00, 0x00, 0xEB, 0x09,
0x5D, 0x55, 0x81, 0xED, 0x39, 0x39, 0x44, 0x00,
0xC3, 0xE9, null, 0x04, 0x00, 0x00
}, "ASPack 2.11.x -> Alexey Solodovnikov"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
null, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xEB,
0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01
}, "ASPack 2.12 (without Poly) -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
null, 0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9,
0xEB, 0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01,
@@ -519,7 +505,7 @@ namespace BurnOutSharp.PackerType
0xFF, 0x95, 0x48, 0x0F
}, "ASPack 2.12b -> Solodovnikov Alexey"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xEB,
0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01, 0x00,
@@ -568,7 +554,7 @@ namespace BurnOutSharp.PackerType
0x08
}, "ASPack 2.2 -> Alexey Solodovnikov & StarForce * 2009408"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
null, 0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9,
0xEB, 0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01,
@@ -581,7 +567,7 @@ namespace BurnOutSharp.PackerType
#region 2.xx (Long)
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0xA8, 0x03, 0x00, 0x00, 0x61, 0x75, 0x08, 0xB8,
0x01, 0x00, 0x00, 0x00, 0xC2, 0x0C, 0x00, 0x68,
@@ -590,7 +576,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x51, 0x50, 0xFF, 0x95
}, "ASPack 2.xx"),
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0xA8, 0x03, null, null, 0x61, 0x75, 0x08, 0xB8,
0x01, null, null, null, 0xC2, 0x0C, null, 0x68,
@@ -603,55 +589,55 @@ namespace BurnOutSharp.PackerType
#region Short
new ContentMatchSet(new byte?[] { 0x75, 0x00, 0xE9 }, "ASPack 1.05b"),
new(new byte?[] { 0x75, 0x00, 0xE9 }, "ASPack 1.05b"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new(new byte?[] { 0x90, 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new ContentMatchSet(new byte?[] { 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new(new byte?[] { 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new(new byte?[] { 0x90, 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new ContentMatchSet(new byte?[] { 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new(new byte?[] { 0x90, 0x75, null, 0xE9 }, "ASPack 1.07b"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new(new byte?[] { 0x90, 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new ContentMatchSet(new byte?[] { 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new(new byte?[] { 0x90, 0x75, 0x01, 0xFF, 0xE9 }, "ASPack 1.08"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new(new byte?[] { 0x90, 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new ContentMatchSet(new byte?[] { 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new(new byte?[] { 0x90, 0x75, null, 0x90, 0xE9 }, "ASPack 1.08.01"),
new ContentMatchSet(new byte?[] { 0x90, 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08.02"),
new(new byte?[] { 0x90, 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08.02"),
new ContentMatchSet(new byte?[] { 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08.02"),
new(new byte?[] { 0x90, 0x75, 0x01, 0x90, 0xE9 }, "ASPack 1.08.02"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0x41, 0x06, 0x00, 0x00, 0xEB, 0x41 }, "ASPack 1.08.04"),
new(new byte?[] { 0x60, 0xE8, 0x41, 0x06, 0x00, 0x00, 0xEB, 0x41 }, "ASPack 1.08.04"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, null, null, null, null, 0xEB }, "ASPack 1.08.04"),
new(new byte?[] { 0x60, 0xE8, null, null, null, null, 0xEB }, "ASPack 1.08.04"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0x70, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.00"),
new(new byte?[] { 0x60, 0xE8, 0x70, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.00"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0x48, 0x11, 0x00, 0x00, 0xC3, 0x83 }, "ASPack 2.00.00"),
new(new byte?[] { 0x60, 0xE8, 0x48, 0x11, 0x00, 0x00, 0xC3, 0x83 }, "ASPack 2.00.00"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0x72, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.01"),
new(new byte?[] { 0x60, 0xE8, 0x72, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.01"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, null, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.x -> Alexey Solodovnikov"),
new(new byte?[] { 0x60, 0xE8, null, 0x05, 0x00, 0x00, 0xEB, 0x4C }, "ASPack 2.00.x -> Alexey Solodovnikov"),
new ContentMatchSet(new byte?[] { 0x60, 0xE9, 0x3D, 0x04, 0x00, 0x00 }, "ASPack 2.11"),
new(new byte?[] { 0x60, 0xE9, 0x3D, 0x04, 0x00, 0x00 }, "ASPack 2.11"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0xF9, 0x11, 0x00, 0x00, 0xC3, 0x83 }, "ASPack 2.11"),
new(new byte?[] { 0x60, 0xE8, 0xF9, 0x11, 0x00, 0x00, 0xC3, 0x83 }, "ASPack 2.11"),
new ContentMatchSet(new byte?[] { 0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81, 0xED }, "ASPack 1.02b/1.08.03"),
new(new byte?[] { 0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81, 0xED }, "ASPack 1.02b/1.08.03"),
#endregion
};

View File

@@ -0,0 +1,36 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// TODO: Verify that all versions are detected
public class AdvancedInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .rdata section strings, if they exist
var strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
if (strs.Any(s => s.Contains("Software\\Caphyon\\Advanced Installer")))
return "Caphyon Advanced Installer";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

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

View File

@@ -1,27 +1,24 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// Created by IndigoRose (creators of Setup Factory), primarily to be used to create autorun menus for various media.
// Official website: https://www.autoplay.org/
// TODO: Add extraction
public class AutoPlayMediaStudio : IPortableExecutableCheck, IScannable
public class AutoPlayMediaStudio : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Known to detect versions 5.0.0.3 - 8.1.0.0
string name = pex.ProductName;
var name = pex.ProductName;
if (name?.StartsWith("AutoPlay Media Studio", StringComparison.OrdinalIgnoreCase) == true)
return $"AutoPlay Media Studio {GetVersion(pex)}";
@@ -36,34 +33,22 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
private string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
string version = pex.ProductVersion;
var version = pex.ProductVersion;
if (!string.IsNullOrEmpty(version))
return version;
return version!;
// Check the internal versions
version = Utilities.GetInternalVersion(pex);
version = pex.GetInternalVersion();
if (!string.IsNullOrEmpty(version))
return version;
return version!;
return "(Unknown Version)";
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Compression.zlib;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// The official website for CExe also includes the source code (which does have to be retrieved by the Wayback Machine)
// http://www.scottlu.com/Content/CExe.html
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class CExe : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// If there are exactly 2 resources with type 99
if (pex.FindResourceByNamedType("99, ").Count() == 2)
return "CExe";
if (pex.StubExecutableData != null)
{
var matchers = new List<ContentMatchSet>
{
new(new byte?[]
{
0x25, 0x57, 0x6F, 0xC1, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x01, 0x92, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x00, 0x92, 0x7B, 0x36, 0x01, 0x92,
0x03, 0x29, 0x12, 0x92, 0x66, 0x36, 0x01, 0x92,
0x89, 0x29, 0x0A, 0x92, 0x60, 0x36, 0x01, 0x92,
0xD9, 0x30, 0x07, 0x92, 0x60, 0x36, 0x01, 0x92
}, "CExe")
};
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
try
{
// Get the first resource of type 99 with index 2
var payload = pex.FindResourceByNamedType("99, 2").FirstOrDefault();
if (payload == null || payload.Length == 0)
return null;
// Determine which compression was used
bool zlib = pex.FindResourceByNamedType("99, 1").Any();
// Create the output data buffer
var data = new byte[0];
// If we had the decompression DLL included, it's zlib
if (zlib)
{
try
{
// Inflate the data into the buffer
var zstream = new ZLib.z_stream_s();
data = new byte[payload.Length * 4];
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
uint read = zstream.total_out;
#if NET462_OR_GREATER || NETCOREAPP
data = new ReadOnlySpan<byte>(data, 0, (int)read).ToArray();
#else
var temp = new byte[read];
Array.Copy(data, 0, temp, 0, read);
data = temp;
#endif
}
catch
{
// Reset the data
data = null;
}
}
// Otherwise, LZ is used
else
{
try
{
data = SabreTools.Compression.LZ.Decompressor.Decompress(payload);
}
catch
{
// Reset the data
data = null;
}
}
// If we have no data
if (data == null)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
// Create the temp filename
string tempFile = string.IsNullOrEmpty(file) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(file)}.sxe";
tempFile = Path.Combine(tempPath, tempFile);
// Write the file data to a temp file
using (Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
tempStream.Write(data, 0, data.Length);
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
}
}

View File

@@ -1,20 +1,18 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Figure out how to more granularly determine versions like PiD
// TODO: Detect 3.15 and up (maybe looking for `Metamorphism`)
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class EXEStealth : IContentCheck, IPortableExecutableCheck, IScannable
public class EXEStealth : IContentCheck, IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includeDebug)
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
@@ -22,7 +20,7 @@ namespace BurnOutSharp.PackerType
var contentMatchSets = new List<ContentMatchSet>
{
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
@@ -39,10 +37,10 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
@@ -76,19 +74,7 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
/// <summary>
/// Though not technically a packer, this detection is for any executables that include
/// others in their resources in some uncompressed manner to be used at runtime.
/// </summary>
public class EmbeddedExecutable : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the resources that have an executable signature
if (pex.ResourceData?.Any(kvp => kvp.Value is byte[] ba && ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) == true)
return "Embedded Executable";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
try
{
// If there are no resources
if (pex.ResourceData == null)
return null;
// Get the resources that have an executable signature
var resources = pex.ResourceData
.Where(kvp => kvp.Value != null && kvp.Value is byte[])
.Select(kvp => kvp.Value as byte[])
.Where(b => b != null && b.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))
.ToList();
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
for (int i = 0; i < resources.Count; i++)
{
try
{
// Get the resource data
var data = resources[i];
if (data == null)
continue;
// Create the temp filename
string tempFile = $"embedded_resource_{i}.bin";
tempFile = Path.Combine(tempPath, tempFile);
// Write the resource data to a temp file
using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream?.Write(data, 0, data.Length);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System.Linq;
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 GenteeInstaller : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("Gentee installer")))
return "Gentee Installer";
if (strs.Any(s => s.Contains("ginstall.dll")))
return "Gentee Installer";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -0,0 +1,39 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// CrackProof is a packer/obfuscator created by Japanese company HyperTech (https://www.hypertech.co.jp/products/windows/).
// It is known to be used along with other DRM, such as Shury2 (Redump entry 97135) and BDL.
// https://www.reddit.com/r/riseofincarnates/comments/m3vbnm/subreddit_revival_does_anyone_still_have_rise_of/
// https://steamcommunity.com/app/310950/discussions/0/4224890554455490819/
// https://github.com/horsicq/Detect-It-Easy/blob/63a1aa8bb23ca02d8a7fd5936db8dbc5c5d52dea/db/PE/HyperTech%20Crackproof.2.sg
public class HyperTechCrackProof : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// This check may be overly limiting, as it excludes the sample provided to DiE (https://github.com/horsicq/Detect-It-Easy/issues/102).
// TODO: Find further samples and invesitgate if the "peC" section is only present on specific versions.
bool peCSection = pex.ContainsSection("peC", exact: true);
bool importTableMatch = (pex.Model.ImportTable?.ImportDirectoryTable?.Any(idte => idte?.Name == "KeRnEl32.dLl") ?? false);
if (peCSection && importTableMatch)
return "HyperTech CrackProof";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -1,29 +1,23 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction - https://github.com/dscharrer/InnoExtract
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InnoSetup : INewExecutableCheck, IPortableExecutableCheck, IScannable
public class InnoSetup : IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
{
// Check we have a valid executable
if (nex == null)
return null;
// Check for "Inno" in the reserved words
if (nex.Stub_Reserved2[4] == 0x6E49 && nex.Stub_Reserved2[5] == 0x6F6E)
if (nex.Model.Stub?.Header?.Reserved2?[4] == 0x6E49 && nex.Model.Stub?.Header?.Reserved2?[5] == 0x6F6E)
{
string version = GetOldVersion(file, nex);
if (!string.IsNullOrWhiteSpace(version))
if (!string.IsNullOrEmpty(version))
return $"Inno Setup {version}";
return "Inno Setup (Unknown Version)";
@@ -33,18 +27,18 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .data section strings, if they exist
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
string str = strs.FirstOrDefault(s => s.StartsWith("Inno Setup Setup Data"));
var str = strs.FirstOrDefault(s => s.StartsWith("Inno Setup Setup Data"));
if (str != null)
{
return str.Replace("Inno Setup Setup Data", "Inno Setup")
@@ -59,19 +53,7 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
@@ -90,7 +72,7 @@ namespace BurnOutSharp.PackerType
var matchers = new List<ContentMatchSet>
{
// "rDlPtS02" + (char)0x87 + "eVx"
new ContentMatchSet(new byte?[] { 0x72, 0x44, 0x6C, 0x50, 0x74, 0x53, 0x30, 0x32, 0x87, 0x65, 0x56, 0x78 }, "1.2.16 or earlier"),
new(new byte?[] { 0x72, 0x44, 0x6C, 0x50, 0x74, 0x53, 0x30, 0x32, 0x87, 0x65, 0x56, 0x78 }, "1.2.16 or earlier"),
};
return MatchUtil.GetFirstMatch(file, data, matchers, false) ?? "Unknown 1.X";

View File

@@ -1,25 +1,22 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, which may be possible with the current libraries but needs to be investigated further.
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class InstallAnywhere : IPortableExecutableCheck, IScannable
public class InstallAnywhere : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
string name = pex.FileDescription;
var name= pex.FileDescription;
if (name?.StartsWith("InstallAnywhere Self Extractor", StringComparison.OrdinalIgnoreCase) == true)
return $"InstallAnywhere {GetVersion(pex)}";
@@ -31,19 +28,7 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
@@ -51,9 +36,9 @@ namespace BurnOutSharp.PackerType
private string GetVersion(PortableExecutable pex)
{
// Check the internal versions
string version = Utilities.GetInternalVersion(pex);
var version = pex.GetInternalVersion();
if (!string.IsNullOrEmpty(version))
return version;
return version!;
return "(Unknown Version)";
}

View File

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

View File

@@ -0,0 +1,41 @@
using System;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, seems to primarily use MSZip compression.
public class IntelInstallationFramework : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
var name= pex.FileDescription;
if (name?.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase) == true
|| name?.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase) == true)
{
return $"Intel Installation Framework {pex.GetInternalVersion()}";
}
name = pex.ProductName;
if (name?.Equals("Intel(R) Installation Framework", StringComparison.OrdinalIgnoreCase) == true
|| name?.Equals("Intel Installation Framework", StringComparison.OrdinalIgnoreCase) == true)
{
return $"Intel Installation Framework {pex.GetInternalVersion()}";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -1,27 +1,23 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, which should be possible with LibMSPackN, but it refuses to extract due to SFX files lacking the typical CAB identifiers.
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class MicrosoftCABSFX : IPortableExecutableCheck, IScannable
public class MicrosoftCABSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
string name = pex.InternalName;
var name= pex.InternalName;
if (name?.Equals("Wextract", StringComparison.OrdinalIgnoreCase) == true)
return $"Microsoft CAB SFX {GetVersion(pex)}";
@@ -30,7 +26,7 @@ namespace BurnOutSharp.PackerType
return $"Microsoft CAB SFX {GetVersion(pex)}";
// Get the .data/DATA section strings, if they exist
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("wextract_cleanup")))
@@ -51,28 +47,16 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
private string GetVersion(PortableExecutable pex)
{
// Check the internal versions
string version = Utilities.GetInternalVersion(pex);
if (!string.IsNullOrWhiteSpace(version))
var version = pex.GetInternalVersion();
if (!string.IsNullOrEmpty(version))
return $"v{version}";
return string.Empty;

View File

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

View File

@@ -0,0 +1,45 @@
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
/// <summary>
/// NeoLite (https://web.archive.org/web/20000815214147/http://www.neoworx.com/products/neolite/default.asp) was a packer created by NeoWorx.
/// The most common version appears to be 2.0, with earlier versions existing but with no archived copies available.
/// NeoWorx was acquired by McAfee in October 2001, who seemingly dropped support for NeoLite (https://web.archive.org/web/20020603224725/http://www.mcafee.com/myapps/neoworx/default.asp).
///
/// Additional references and documentation:
/// NeoLite 2.0 evaluation installer: https://web.archive.org/web/20001012061916/http://www.neoworx.com/download/neolte20.exe
/// PEiD scanning definitions that include NeoLite: https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
/// Website listing various packers, including NeoLite: http://protools.narod.ru/packers.htm
/// </summary>
public class NeoLite : IExtractablePortableExecutable, IPortableExecutableCheck
{
// TODO: Find samples of NeoLite 1.X.
/// <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 .neolit section, if it exists.
// TODO: Check if this section is also present in NeoLite 1.X.
bool neolitSection = pex.ContainsSection(".neolit", exact: true);
if (neolitSection)
return "NeoLite";
// If more specific or additional checks are needed, "NeoLite Executable File Compressor" should be present
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -1,24 +1,22 @@
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Better version detection - https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
// TODO: Add extraction
public class PECompact : IPortableExecutableCheck, IScannable
public class PECompact : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// 0x4F434550 is "PECO"
if (pex.PointerToSymbolTable == 0x4F434550)
if (pex.Model.COFFFileHeader?.PointerToSymbolTable == 0x4F434550)
return "PE Compact v1.x";
// TODO: Get more granular version detection. PiD is somehow able to detect version ranges based
@@ -41,21 +39,9 @@ namespace BurnOutSharp.PackerType
return null;
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -0,0 +1,32 @@
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 : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .petite section, if it exists -- TODO: Is there a version number that can be found?
bool petiteSection = pex.ContainsSection(".petite", exact: true);
if (petiteSection)
return "PEtite";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -1,27 +1,24 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction, which is possible but the only tools available that can
// do this seem to be Universal Extractor 2 and InstallExplorer (https://totalcmd.net/plugring/InstallExplorer.html)
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class SetupFactory : IPortableExecutableCheck, IScannable
public class SetupFactory : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Known to detect versions 7.0.5.1 - 9.1.0.0
string name = pex.LegalCopyright;
var name = pex.LegalCopyright;
if (name?.StartsWith("Setup Engine", StringComparison.OrdinalIgnoreCase) == true)
return $"Setup Factory {GetVersion(pex)}";
@@ -41,34 +38,22 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
private string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
string version = pex.ProductVersion;
var version = pex.ProductVersion;
if (!string.IsNullOrEmpty(version))
return version;
return version!;
// Check the internal versions
version = Utilities.GetInternalVersion(pex);
version = pex.GetInternalVersion();
if (!string.IsNullOrEmpty(version))
return version;
return version!;
return "(Unknown Version)";
}

View File

@@ -0,0 +1,53 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class SevenZipSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the assembly description, if possible
if (pex.AssemblyDescription?.StartsWith("7-Zip Self-extracting Archive") == true)
return $"7-Zip SFX {pex.AssemblyDescription.Substring("7-Zip Self-extracting Archive ".Length)}";
// Get the file description, if it exists
if (pex.FileDescription?.Equals("7z SFX") == true)
return "7-Zip SFX";
if (pex.FileDescription?.Equals("7z Self-Extract Setup") == true)
return "7-Zip SFX";
// Get the original filename, if it exists
if (pex.OriginalFilename?.Equals("7z.sfx.exe") == true)
return "7-Zip SFX";
else if (pex.OriginalFilename?.Equals("7zS.sfx") == true)
return "7-Zip SFX";
// Get the internal name, if it exists
if (pex.InternalName?.Equals("7z.sfx") == true)
return "7-Zip SFX";
else if (pex.InternalName?.Equals("7zS.sfx") == true)
return "7-Zip SFX";
// If any dialog boxes match
if (pex.FindDialogByTitle("7-Zip self-extracting archive").Any())
return "7-Zip SFX";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -0,0 +1,33 @@
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 Shrinker : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .shrink0 and .shrink2 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
bool shrink0Section = pex.ContainsSection(".shrink0", true);
bool shrink2Section = pex.ContainsSection(".shrink2", true);
if (shrink0Section || shrink2Section)
return "Shrinker";
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -1,35 +1,32 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.PackerType
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class UPX : IPortableExecutableCheck, IScannable
public class UPX : IExtractablePortableExecutable, IPortableExecutableCheck
{
private static readonly Regex _oldUpxVersionMatch = new Regex(@"\$Id: UPX (.*?) Copyright \(C\)", RegexOptions.Compiled);
private static readonly Regex _upxVersionMatch = new Regex(@"^([0-9]\.[0-9]{2})$", RegexOptions.Compiled);
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Check header padding strings
if (pex.HeaderPaddingStrings.Any())
if (pex.HeaderPaddingStrings?.Any() == true)
{
string match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!"));
var match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!"));
//if (match != null)
// return "UPX";
@@ -44,7 +41,7 @@ namespace BurnOutSharp.PackerType
}
match = pex.HeaderPaddingStrings.FirstOrDefault(s => _upxVersionMatch.IsMatch(s));
if (pex.HeaderPaddingStrings.Any(s => s == "UPX!" && match != null))
if (match != null && pex.HeaderPaddingStrings.Any(s => s == "UPX!"))
{
var regexMatch = _upxVersionMatch.Match(match);
if (regexMatch.Success)
@@ -52,7 +49,7 @@ namespace BurnOutSharp.PackerType
else
return "UPX (Unknown Version)";
}
else if (pex.HeaderPaddingStrings.Any(s => s == "NOS " && match != null))
else if (match != null && pex.HeaderPaddingStrings.Any(s => s == "NOS "))
{
var regexMatch = _upxVersionMatch.Match(match);
if (regexMatch.Success)
@@ -66,19 +63,7 @@ namespace BurnOutSharp.PackerType
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}

View File

@@ -0,0 +1,84 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.Packer
{
public class WinRARSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <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.AssemblyDescription;
if (name?.Contains("WinRAR archiver") == true)
return "WinRAR SFX";
var resources = pex.FindDialogByTitle("WinRAR self-extracting archive");
if (resources.Any())
return "WinRAR SFX";
return null;
}
/// <inheritdoc/>
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 }))
{
if (!zipFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
return tempPath;
}
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -0,0 +1,813 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
#endif
namespace BinaryObjectScanner.Packer
{
public class WinZipSFX : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
{
// If the resident-name table doesnt exist
if (nex.Model.ResidentNameTable == null)
return null;
// Check for the WinZip name string
bool winZipNameFound = nex.Model.ResidentNameTable
.Select(rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString))
.Any(s => s.Contains("WZ-SE-01"));
// If we didn't find it
if (!winZipNameFound)
return null;
// Try to get a known version
var version = GetNEHeaderVersion(nex);
if (!string.IsNullOrEmpty(version))
return $"WinZip SFX {version}";
return $"WinZip SFX Unknown Version (16-bit)";
}
/// <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;
// Check the export directory table, if it exists
if (pex.Model.ExportTable?.ExportDirectoryTable != null)
{
var version = GetPEExportDirectoryVersion(pex);
if (!string.IsNullOrEmpty(version))
return $"WinZip SFX {version}";
}
// Get the _winzip_ section, if it exists
if (pex.ContainsSection("_winzip_", exact: true))
return "WinZip SFX Unknown Version (32-bit)";
return null;
}
// TODO: Find a way to generically detect 2.X versions and improve exact version detection for SFX PE versions bundled with WinZip 11+
/// <inheritdoc/>
public string? Extract(string file, NewExecutable nex, bool includeDebug)
=> Extract(file, includeDebug);
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
=> Extract(file, includeDebug);
/// <summary>
/// Handle common extraction between executable types
/// </summary>
/// <inheritdoc/>
public static string? Extract(string file, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (ZipArchive zipFile = ZipArchive.Open(file))
{
foreach (var entry in zipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
/// <summary>
/// Get the version from the NE header value combinations
/// </summary>
/// TODO: Reduce the checks to only the ones that differ between versions
/// TODO: Research to see if the versions are embedded elsewhere in these files
private static string? GetNEHeaderVersion(NewExecutable nex)
{
#region 2.0 Variants
// 2.0 (MS-DOS/16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0086
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x00012BE6
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000044B8
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.0 (MS-DOS/16-bit)";
// 2.0 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0086
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x00013174
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000198
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.0 (16-bit)";
// Compact 2.0 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0080
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x000124A0
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Compact 2.0 (16-bit)";
// Software Installation 2.0 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00CD
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x000136FA
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0005
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0097
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x00A3
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00AD
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001DF
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Software Installation 2.0 (16-bit)";
#endregion
#region 2.1 RC2 Variants
// 2.1 RC2 (MS-DOS/16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0086
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x00013386
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000043C8
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.1 RC2 (MS-DOS/16-bit)";
// 2.1 RC2 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00BE
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E56
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.1 RC2 (16-bit)";
// Compact 2.1 RC2 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0080
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x00012B84
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Compact 2.1 RC2 (16-bit)";
// Software Installation 2.1 RC2 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00BE
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x000143AC
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Software Installation 2.1 RC2 (16-bit)";
#endregion
#region 2.1 Variants
// 2.1 (MS-DOS/16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0086
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
&& nex.Model.Header?.InitialCSIPSetting == 0x00013396
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000043C8
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.1 (MS-DOS/16-bit)";
// 2.1 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00BE
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E7E
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "2.1 (16-bit)";
// Compact 2.1 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0080
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
&& nex.Model.Header?.InitialCSIPSetting == 0x00012B90
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0003
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006A
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000192
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Compact 2.1 (16-bit)";
// Software Installation 2.1 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00BE
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x3A00
&& nex.Model.Header?.InitialCSIPSetting == 0x00014408
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Software Installation 2.1 (16-bit)";
#endregion
#region Misc. Variants
// Personal Edition (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x0086
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.ProtectedModeOnly
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x4000
&& nex.Model.Header?.InitialCSIPSetting == 0x0001317C
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0058
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x0064
&& nex.Model.Header?.ImportedNamesTableOffset == 0x006C
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x00000198
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Personal Edition (16-bit)";
// Personal Edition 32-bit (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00BE
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x2000
&& nex.Model.Header?.InitialStackAlloc == 0x3C00
&& nex.Model.Header?.InitialCSIPSetting == 0x00013E7C
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0004
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A4
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D0
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Personal Edition 32-bit (16-bit)";
// Personal Edition 32-bit Build 1260/1285 (16-bit)
if (nex.Model.Header?.LinkerVersion == 0x11
&& nex.Model.Header?.LinkerRevision == 0x20
&& nex.Model.Header?.EntryTableOffset == 0x00C6
&& nex.Model.Header?.EntryTableSize == 0x0002
&& nex.Model.Header?.CrcChecksum == 0x00000000
&& nex.Model.Header?.FlagWord == (SabreTools.Models.NewExecutable.HeaderFlag.MULTIPLEDATA
| SabreTools.Models.NewExecutable.HeaderFlag.FullScreen
| SabreTools.Models.NewExecutable.HeaderFlag.WindowsPMCompatible)
&& nex.Model.Header?.AutomaticDataSegmentNumber == 0x0003
&& nex.Model.Header?.InitialHeapAlloc == 0x43DC
&& nex.Model.Header?.InitialStackAlloc == 0x2708
&& nex.Model.Header?.InitialCSIPSetting == 0x00014ADC
&& nex.Model.Header?.InitialSSSPSetting == 0x00030000
&& nex.Model.Header?.FileSegmentCount == 0x0003
&& nex.Model.Header?.ModuleReferenceTableSize == 0x0005
&& nex.Model.Header?.NonResidentNameTableSize == 0x004B
&& nex.Model.Header?.SegmentTableOffset == 0x0040
&& nex.Model.Header?.ResourceTableOffset == 0x0058
&& nex.Model.Header?.ResidentNameTableOffset == 0x0090
&& nex.Model.Header?.ModuleReferenceTableOffset == 0x009C
&& nex.Model.Header?.ImportedNamesTableOffset == 0x00A6
&& nex.Model.Header?.NonResidentNamesTableOffset == 0x000001D8
&& nex.Model.Header?.MovableEntriesCount == 0x0000
&& nex.Model.Header?.SegmentAlignmentShiftCount == 0x0001
&& nex.Model.Header?.ResourceEntriesCount == 0x0000
&& nex.Model.Header?.TargetOperatingSystem == SabreTools.Models.NewExecutable.OperatingSystem.WINDOWS
&& nex.Model.Header?.AdditionalFlags == 0x00
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.ReturnThunkOffset == 0x0000
&& nex.Model.Header?.MinCodeSwapAreaSize == 0x0000
&& nex.Model.Header?.WindowsSDKRevision == 0x00
&& nex.Model.Header?.WindowsSDKVersion == 0x03)
return "Personal Edition 32-bit Build 1260/1285 (16-bit)";
#endregion
return null;
}
/// <summary>
/// Get the version from the PE export directory table value combinations
/// </summary>
/// TODO: Research to see if the versions are embedded elsewhere in these files
private static string? GetPEExportDirectoryVersion(PortableExecutable pex)
{
string sfxFileName = pex.Model.ExportTable?.ExportDirectoryTable?.Name ?? string.Empty;
uint sfxTimeDateStamp = pex.Model.ExportTable?.ExportDirectoryTable?.TimeDateStamp ?? uint.MaxValue;
string assemblyVersion = pex.AssemblyVersion ?? "Unknown Version";
// Standard
if (sfxFileName == "VW95SE.SFX" || sfxFileName == "ST32E.SFX"
|| sfxFileName == "WZIPSE32.exe" || sfxFileName == "SI32LPG.SFX"
|| sfxFileName == "ST32E.WZE")
{
return sfxTimeDateStamp switch
{
842636344 => "2.0 (32-bit)",
865370756 => "2.1 RC2 (32-bit)",
869059925 => "2.1 (32-bit)",
979049321 => "2.2.4003",
1149714685 => "3.0.7158",
1185211734 => "3.1.7556",
1185211920 => "3.1.7556",
1235490556 => "4.0.8421",
1235490757 => "4.0.8421",
1235490687 => "4.0.8421",// 3.1.8421.0, SI32LPG?
1257193383 => "4.0.8672",// 3.1.8672.0
1257193543 => "4.0.8672",
1470410848 => "4.0.12218",// 4.0.1221.0
_ => $"{assemblyVersion} (32-bit)",
};
}
// Personal Edition
if (sfxFileName == "VW95LE.SFX" || sfxFileName == "PE32E.SFX"
|| sfxFileName == "wzsepe32.exe" || sfxFileName == "SI32PE.SFX"
|| sfxFileName == "SI32LPE.SFX")
{
return sfxTimeDateStamp switch
{
845061601 => "Personal Edition (32-bit)",// TODO: Find version
868303343 => "Personal Edition (32-bit)",// TODO: Find version
868304170 => "Personal Edition (32-bit)",// TODO: Find version
906039079 => "Personal Edition 2.2.1260 (32-bit)",
906040543 => "Personal Edition 2.2.1260 (32-bit)",
908628435 => "Personal Edition 2.2.1285 (32-bit)",
908628785 => "Personal Edition 2.2.1285 (32-bit)",
956165981 => "Personal Edition 2.2.3063",
956166038 => "Personal Edition 2.2.3063",
1006353695 => "Personal Edition 2.2.4325",
1006353714 => "Personal Edition 2.2.4325",// 8.1.0.0
1076515698 => "Personal Edition 2.2.6028",
1076515784 => "Personal Edition 2.2.6028",// 9.0.6028.0
1092688561 => "Personal Edition 2.2.6224",
1092688645 => "Personal Edition 2.2.6224",// 9.0.6224.0
1125074095 => "Personal Edition 2.2.6604",
1125074162 => "Personal Edition 2.2.6604",// 10.0.6604.0
1130153399 => "Personal Edition 2.2.6663",
1130153428 => "Personal Edition 2.2.6663",// 10.0.6663.0
1149714176 => "Personal Edition 3.0.7158",
1163137967 => "Personal Edition 3.0.7305",
1163137994 => "Personal Edition 3.0.7313",// 11.0.7313.0
1176345383 => "Personal Edition 3.0.7452",
1176345423 => "Personal Edition 3.1.7466",// 11.1.7466.0
1184106698 => "Personal Edition 3.1.7556",
1207280880 => "Personal Edition 4.0.8060",// 2.3.7382.0
1207280892 => "Personal Edition 4.0.8094",// 11.2.8094.0
1220904506 => "Personal Edition 4.0.8213",// 2.3.7382.0
1220904518 => "Personal Edition 4.0.8252",// 12.0.8252.0
1235490648 => "Personal Edition 4.0.8421",// 3.1.8421.0
1242049399 => "Personal Edition 4.0.8497",// 12.1.8497.0
1257193469 => "Personal Edition 4.0.8672",// 3.1.8672.0, SI32LPE?
_ => $"Personal Edition {assemblyVersion} (32-bit)",
};
}
// Software Installation
else if (sfxFileName == "VW95SRE.SFX" || sfxFileName == "SI32E.SFX"
|| sfxFileName == "SI32E.WZE")
{
return sfxTimeDateStamp switch
{
842636381 => "Software Installation 2.0 (32-bit)",
865370800 => "Software Installation 2.1 RC2 (32-bit)",
869059963 => "Software Installation 2.1 (32-bit)",
893107697 => "Software Installation 2.2.1110 (32-bit)",
952007369 => "Software Installation 2.2.3063",
1006352634 => "Software Installation 2.2.4325",// +Personal Edition?
979049345 => "Software Installation 2.2.4403",
1026227373 => "Software Installation 2.2.5196",// +Personal Edition?
1090582390 => "Software Installation 2.2.6202",// +Personal Edition?
1149714757 => "Software Installation 3.0.7158",
1154357628 => "Software Installation 3.0.7212",
1175234637 => "Software Installation 3.0.7454",
1185211802 => "Software Installation 3.1.7556",
1470410906 => "Software Installation 4.0.12218",// 4.0.1221.0
_ => $"Software Installation {assemblyVersion} (32-bit)",
};
}
return sfxFileName switch
{
// Standard
"VW95SE.SFX" => "Unknown Version (32-bit)",// TODO: Find starting version
"ST32E.SFX" => "Unknown Version (32-bit)",// TODO: Find starting version
"WZIPSE32.exe" => "Unknown Version (32-bit)",// TODO: Find starting version
"SI32LPG.SFX" => "Unknown Version (32-bit)",// TODO: Find starting version
"ST32E.WZE" => "Unknown Version (32-bit)",// TODO: Find starting version
// Personal Edition
"VW95LE.SFX" => "Unknown Version before Personal Edition Build 1285 (32-bit)",
"PE32E.SFX" => "Unknown Version after Personal Edition Build 1285 (32-bit)",
"wzsepe32.exe" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
"SI32PE.SFX" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
"SI32LPE.SFX" => "Unknown Version Personal Edition (32-bit)",// TODO: Find starting version
// Software Installation
"VW95SRE.SFX" => "Unknown Version before Software Installation 2.1 (32-bit)",
"SI32E.SFX" => "Unknown Version after Software Installation 2.1 (32-bit)",
"SI32E.WZE" => "Unknown Version Software Installation (32-bit)",// TODO: Find starting version
_ => null,
};
}
}
}

View File

@@ -0,0 +1,319 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
using WiseUnpacker;
using WiseUnpacker.EWISE;
namespace BinaryObjectScanner.Packer
{
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
public class WiseInstaller : IExtractableNewExecutable, IExtractablePortableExecutable, INewExecutableCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckNewExecutable(string file, NewExecutable nex, bool includeDebug)
{
// If we match a known header
if (MatchesNEVersion(nex) != null)
return "Wise Installation Wizard Module";
// TODO: Investigate STUB.EXE in nonresident-name table
// TODO: Don't read entire file
var data = nex.ReadArbitraryRange();
if (data == null)
return null;
var neMatchSets = new List<ContentMatchSet>
{
// WiseInst
new(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x49, 0x6E, 0x73, 0x74 }, "Wise Installation Wizard Module"),
// WiseMain
new(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
};
return MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
}
/// <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;
// If we match a known header
if (GetPEFormat(pex) != null)
return "Wise Installation Wizard Module";
// TODO: Investigate STUB32.EXE in export directory table
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("WiseMain")))
return "Wise Installation Wizard Module";
}
// Get the .rdata section strings, if they exist
strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
if (strs.Any(s => s.Contains("WiseMain")))
return "Wise Installation Wizard Module";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, NewExecutable nex, 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
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(string file, PortableExecutable pex, 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 = (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)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
}
/// <summary>
/// Checks an NE header to see if it matches a known signature
/// </summary>
/// <param name="nex">New executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? MatchesNEVersion(NewExecutable nex)
{
// TODO: Offset is _not_ the EXE header address, rather where the data starts. Fix this.
switch (nex.Model.Stub?.Header?.NewExeHeaderAddr)
{
case 0x84b0:
return new FormatProperty { Dll = false, ArchiveStart = 0x11, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = true };
case 0x3e10:
return new FormatProperty { Dll = false, ArchiveStart = 0x1e, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = false };
case 0x3e50:
return new FormatProperty { Dll = false, ArchiveStart = 0x1e, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = false };
case 0x3c20:
return new FormatProperty { Dll = false, ArchiveStart = 0x1e, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = false };
case 0x3c30:
return new FormatProperty { Dll = false, ArchiveStart = 0x22, ArchiveEnd = -1, InitText = false, FilenamePosition = 0x04, NoCrc = false };
case 0x3660:
return new FormatProperty { Dll = false, ArchiveStart = 0x40, ArchiveEnd = 0x3c, InitText = false, FilenamePosition = 0x04, NoCrc = false };
case 0x36f0:
return new FormatProperty { Dll = false, ArchiveStart = 0x48, ArchiveEnd = 0x44, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
case 0x3770:
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
case 0x3780:
return new FormatProperty { Dll = true, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
case 0x37b0:
return new FormatProperty { Dll = true, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
case 0x37d0:
return new FormatProperty { Dll = true, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
case 0x3c80:
return new FormatProperty { Dll = true, ArchiveStart = 0x5a, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
case 0x3bd0:
return new FormatProperty { Dll = true, ArchiveStart = 0x5a, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
case 0x3c10:
return new FormatProperty { Dll = true, ArchiveStart = 0x5a, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
default:
return null;
}
}
/// <summary>
/// Checks a PE header to see if it matches a known signature
/// </summary>
/// <param name="pex">Portable executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? GetPEFormat(PortableExecutable pex)
{
if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3cf4
&& pex.GetFirstSection(".data")?.VirtualSize == 0x1528)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3cf4
&& pex.GetFirstSection(".data")?.VirtualSize == 0x1568)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3d54)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3d44)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3d04)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
// Found in Binary.WiseCustomCalla
else if (pex.OverlayAddress == 0x6200)
return new FormatProperty { Dll = true, ArchiveStart = 0x62, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x3000)
return new FormatProperty { Dll = false, ArchiveStart = 0x50, ArchiveEnd = 0x4c, InitText = false, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x3800)
return new FormatProperty { Dll = true, ArchiveStart = 0x5a, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
else if (pex.OverlayAddress == 0x3a00)
return new FormatProperty { Dll = true, ArchiveStart = 0x5a, ArchiveEnd = 0x4c, InitText = true, FilenamePosition = 0x1c, NoCrc = false };
return null;
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class dotFuscator : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .text section strings, if they exist
var strs = pex.GetFirstSectionStrings(".text");
if (strs != null)
{
if (strs.Any(s => s.Contains("DotfuscatorAttribute")))
return "dotFuscator";
}
return null;
}
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
return null;
}
}
}

View File

@@ -0,0 +1,107 @@
#if NET20 || NET35 || NET40
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Threading;
using System.Diagnostics;
namespace System
{
/// <summary>
/// Provides an IProgress{T} that invokes callbacks for each reported progress value.
/// </summary>
/// <typeparam name="T">Specifies the type of the progress report value.</typeparam>
/// <remarks>
/// Any handler provided to the constructor or event handlers registered with
/// the <see cref="ProgressChanged"/> event are invoked through a
/// <see cref="SynchronizationContext"/> instance captured
/// when the instance is constructed. If there is no current SynchronizationContext
/// at the time of construction, the callbacks will be invoked on the ThreadPool.
/// </remarks>
/// <see href="https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Progress.cs"/>
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;
/// <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>
private readonly SendOrPostCallback _invokeHandlers;
/// <summary>Initializes the <see cref="Progress{T}"/>.</summary>
public Progress()
{
// Capture the current synchronization context.
// If there is no current context, we use a default instance targeting the ThreadPool.
_synchronizationContext = SynchronizationContext.Current ?? ProgressStatics.DefaultContext;
Debug.Assert(_synchronizationContext != null);
_invokeHandlers = new SendOrPostCallback(InvokeHandlers);
}
/// <summary>Initializes the <see cref="Progress{T}"/> with the specified callback.</summary>
/// <param name="handler">
/// A handler to invoke for each reported progress value. This handler will be invoked
/// in addition to any delegates registered with the <see cref="ProgressChanged"/> event.
/// Depending on the <see cref="SynchronizationContext"/> instance captured by
/// the <see cref="Progress{T}"/> at construction, it's possible that this handler instance
/// could be invoked concurrently with itself.
/// </param>
/// <exception cref="ArgumentNullException">The <paramref name="handler"/> is null (<see langword="Nothing" /> in Visual Basic).</exception>
public Progress(Action<T> handler) : this()
{
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
/// <summary>Raised for each reported progress value.</summary>
/// <remarks>
/// Handlers registered with this event will be invoked on the
/// <see cref="SynchronizationContext"/> captured when the instance was constructed.
/// </remarks>
public event EventHandler<T>? ProgressChanged;
/// <summary>Reports a progress change.</summary>
/// <param name="value">The value of the updated progress.</param>
protected virtual void OnReport(T value)
{
// If there's no handler, don't bother going through the sync context.
// Inside the callback, we'll need to check again, in case
// an event handler is removed between now and then.
Action<T>? handler = _handler;
EventHandler<T>? changedEvent = ProgressChanged;
if (handler != null || changedEvent != null)
{
// Post the processing to the sync context.
// (If T is a value type, it will get boxed here.)
_synchronizationContext?.Post(_invokeHandlers, value);
}
}
/// <summary>Reports a progress change.</summary>
/// <param name="value">The value of the updated progress.</param>
void IProgress<T>.Report(T value) { OnReport(value); }
/// <summary>Invokes the action and event callbacks.</summary>
/// <param name="state">The progress value.</param>
private void InvokeHandlers(object? state)
{
T value = (T)state!;
Action<T>? handler = _handler;
EventHandler<T>? changedEvent = ProgressChanged;
handler?.Invoke(value);
changedEvent?.Invoke(this, value);
}
}
/// <summary>Holds static values for <see cref="Progress{T}"/>.</summary>
/// <remarks>This avoids one static instance per type T.</remarks>
internal static class ProgressStatics
{
/// <summary>A default synchronization context that targets the ThreadPool.</summary>
internal static readonly SynchronizationContext DefaultContext = new();
}
}
#endif

View File

@@ -0,0 +1,120 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
// TODO: Figure out how to get version numbers
public class ActiveMARK : IContentCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
{
var contentMatchSets = new List<ContentMatchSet>
{
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new(new byte?[]
{
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5 (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
}
/// <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 entry point data, if it exists
if (pex.EntryPointData != null)
{
// Found in "Zuma.exe"
if (pex.EntryPointData.StartsWith(new byte?[] { 0x89, 0x25, 0x04, 0xF0, 0x86, 0x00, 0x68, 0x30 }))
return "ActiveMark v5.3.1078 (Packer Version)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x89, 0x25, null, null, null, null, 0xEB }))
return "ActiveMark -> Trymedia Systems Inc. (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x89, 0x25, null, null, null, null, 0x33, 0xED, 0x55, 0x8B, 0xEC, 0xE8, null, null, null, null, 0x8B, 0xD0, 0x81, 0xE2, 0xFF, 0x00, 0x00, 0x00, 0x89, 0x15, null, null, null, null, 0x8B, 0xD0, 0xC1, 0xEA, 0x08, 0x81, 0xE2, 0xFF, 0x00, 0x00, 0x00, 0xA3, null, null, null, null, 0xD1, 0xE0, 0x0F, 0x93, 0xC3, 0x33, 0xC0, 0x8A, 0xC3, 0xA3, null, null, null, null, 0x68, 0xFF, 0x00, 0x00, 0x00, 0xE8, null, null, null, null, 0x6A, 0x00, 0xE8, null, null, null, null, 0xA3, null, null, null, null, 0xBB, null, null, null, null, 0xC7, 0x03, 0x44, 0x00, 0x00, 0x00 }))
return "ActiveMark -> Trymedia Systems Inc. (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x20, 0x2D, 0x2D, 0x4D, 0x50, 0x52, 0x4D, 0x4D, 0x47, 0x56, 0x41, 0x2D, 0x2D, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6F, 0x78, 0x41, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67 }))
return "ActiveMARK 5.x -> Trymedia Systems Inc. (h) (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x20, 0x2D, 0x2D, 0x4D, 0x50, 0x52, 0x4D, 0x4D, 0x47, 0x56, 0x41, 0x2D, 0x2D, 0x00, 0x75, 0x73, 0x65, 0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6F, 0x78, 0x41, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x2E, 0x0D, 0x0A, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x75, 0x6E, 0x6C, 0x6F, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x67, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x00, 0x57, 0x61, 0x72, 0x6E, 0x69, 0x6E, 0x67 }))
return "ActiveMARK 5.x -> Trymedia Systems,Inc. (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x79, 0x11, 0x7F, 0xAB, 0x9A, 0x4A, 0x83, 0xB5, 0xC9, 0x6B, 0x1A, 0x48, 0xF9, 0x27, 0xB4, 0x25 }))
return "ActiveMARK[TM] (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0x79, 0x07, 0x0F, 0xB7, 0x07, 0x47, 0x50, 0x47, 0xB9, 0x57, 0x48, 0xF2, 0xAE, 0x55, 0xFF, 0x96, 0x84, null, 0x00, 0x00, 0x09, 0xC0, 0x74, 0x07, 0x89, 0x03, 0x83, 0xC3, 0x04, 0xEB, 0xD8, 0xFF, 0x96, 0x88, null, 0x00, 0x00, 0x61, 0xE9, null, null, null, 0xFF }))
return "ActiveMARK[TM] R5.31.1140 -> Trymedia (Unconfirmed - Please report to us on Github)";
// https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt
else if (pex.EntryPointData.StartsWith(new byte?[] { 0xBE, 0x48, 0x01, 0x40, 0x00, 0xAD, 0x8B, 0xF8, 0x95, 0xA5, 0x33, 0xC0, 0x33, 0xC9, 0xAB, 0x48, 0xAB, 0xF7, 0xD8, 0xB1, 0x04, 0xF3, 0xAB, 0xC1, 0xE0, 0x0A, 0xB5, 0x1C, 0xF3, 0xAB, 0xAD, 0x50, 0x97, 0x51, 0xAD, 0x87, 0xF5, 0x58, 0x8D, 0x54, 0x86, 0x5C, 0xFF, 0xD5, 0x72, 0x5A, 0x2C, 0x03, 0x73, 0x02, 0xB0, 0x00, 0x3C, 0x07, 0x72, 0x02, 0x2C, 0x03, 0x50, 0x0F, 0xB6, 0x5F, 0xFF, 0xC1, 0xE3, 0x03, 0xB3, 0x00, 0x8D, 0x1C, 0x5B, 0x8D, 0x9C, 0x9E, 0x0C, 0x10, 0x00, 0x00, 0xB0, 0x01, 0x67, 0xE3, 0x29, 0x8B, 0xD7, 0x2B, 0x56, 0x0C, 0x8A, 0x2A, 0x33, 0xD2, 0x84, 0xE9, 0x0F, 0x95, 0xC6, 0x52, 0xFE, 0xC6, 0x8A, 0xD0, 0x8D, 0x14, 0x93, 0xFF, 0xD5, 0x5A, 0x9F, 0x12, 0xC0, 0xD0, 0xE9, 0x74, 0x0E, 0x9E, 0x1A, 0xF2, 0x74, 0xE4, 0xB4, 0x00, 0x33, 0xC9, 0xB5, 0x01, 0xFF, 0x55, 0xCC, 0x33, 0xC9, 0xE9, 0xDF, 0x00, 0x00, 0x00, 0x8B, 0x5E, 0x0C, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x73, 0x50, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x72, 0x1B, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x72, 0x2B, 0x3C, 0x07, 0xB0, 0x09, 0x72, 0x02, 0xB0, 0x0B, 0x50, 0x8B, 0xC7, 0x2B, 0x46, 0x0C, 0xB1, 0x80, 0x8A, 0x00, 0xEB, 0xCF, 0x83, 0xC2, 0x60, 0xFF, 0xD5, 0x87, 0x5E, 0x10, 0x73, 0x0D, 0x83, 0xC2, 0x30, 0xFF, 0xD5, 0x87, 0x5E, 0x14, 0x73, 0x03, 0x87, 0x5E, 0x18, 0x3C, 0x07, 0xB0, 0x08, 0x72, 0x02, 0xB0, 0x0B, 0x50, 0x53, 0x8D, 0x96, 0x7C, 0x07, 0x00, 0x00, 0xFF, 0x55, 0xD0, 0x5B, 0x91, 0xEB, 0x77, 0x3C, 0x07, 0xB0, 0x07, 0x72, 0x02, 0xB0, 0x0A, 0x50, 0x87, 0x5E, 0x10, 0x87, 0x5E, 0x14, 0x89, 0x5E, 0x18, 0x8D, 0x96, 0xC4, 0x0B, 0x00, 0x00, 0xFF, 0x55, 0xD0, 0x50, 0x48 }))
return "ActiveMARK 5.x -> Trymedia Systems,Inc. (h) (Unconfirmed - Please report to us on Github)";
}
// Get the .data section strings, if they exist
var strs = pex.GetLastSectionStrings(".data");
if (strs != null)
{
if (strs.Any(s => s.Contains("MPRMMGVA"))
&& strs.Any(s => s.Contains("This application cannot run with an active debugger in memory.")))
{
return "ActiveMARK 6.x";
}
}
// Get "REGISTRY, AMINTERNETPROTOCOL" resource items
var resources = pex.FindResourceByNamedType("REGISTRY, AMINTERNETPROTOCOL");
if (resources.Any())
{
bool match = resources
.Select(r => r == null ? string.Empty : Encoding.ASCII.GetString(r))
.Any(r => r.Contains("ActiveMARK"));
if (match)
return "ActiveMARK";
}
// Get the overlay data, if it exists
if (pex.OverlayStrings != null)
{
if (pex.OverlayStrings.Any(s => s.Contains("TMSAMVOH")))
return "ActiveMARK";
}
// Get the last .bss section strings, if they exist
strs = pex.GetLastSectionStrings(".bss");
if (strs != null)
{
if (strs.Any(s => s.Contains("TMSAMVOF")))
return "ActiveMARK";
}
return null;
}
}
}

View File

@@ -1,11 +1,13 @@
using System.Collections.Concurrent;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// AegiSoft License Manager was made AegiSoft, which was later bought by Real Networks, the makes of RealArcade (https://www.crunchbase.com/organization/aegisoft).
@@ -20,10 +22,10 @@ namespace BurnOutSharp.ProtectionType
public class AegiSoft : IPathCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
@@ -51,15 +53,15 @@ namespace BurnOutSharp.ProtectionType
{
// Found in "Asc001.dll", "Asc002.dll", "Asc003.dll", "Asc005.dll", "Asc006.exe", and "AscLM.cpl" (Redump entry 73521/IA item "Nova_HoyleCasino99USA").
// ÿÿÿÿ\\.\ASCLM
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0x5C, 0x2E, 0x5C,
0x41, 0x53, 0x43, 0x4C, 0x4D
}, "AegiSoft License Manager"),
};
string match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrWhiteSpace(match))
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
@@ -67,14 +69,18 @@ namespace BurnOutSharp.ProtectionType
}
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
#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 entry 73521/IA item "Nova_HoyleCasino99USA".
new PathMatchSet(new PathMatch("AscLM.cpl", useEndsWith: true), "AegiSoft License Manager"),
new PathMatchSet(new PathMatch("AscLM.vxd", useEndsWith: true), "AegiSoft License Manager"),
new PathMatchSet(new PathMatch("AscLMd.vxd", useEndsWith: true), "AegiSoft License Manager"),
new(new FilePathMatch("AscLM.cpl"), "AegiSoft License Manager"),
new(new FilePathMatch("AscLM.vxd"), "AegiSoft License Manager"),
new(new FilePathMatch("AscLMd.vxd"), "AegiSoft License Manager"),
// There are a few other files present, but the file names on their own may be too overmatching. Due to the small sample size, it's not sure if these files are always present together.
// These files are "Asc001.dll", "Asc002.dll", "Asc003.dll", "Asc005.dll", and "Asc006.exe" (Found in Redump entry 73521/IA item "Nova_HoyleCasino99USA").
@@ -84,14 +90,14 @@ namespace BurnOutSharp.ProtectionType
}
/// <inheritdoc/>
public string CheckFilePath(string path)
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entry 73521/IA item "Nova_HoyleCasino99USA".
new PathMatchSet(new PathMatch("AscLM.cpl", useEndsWith: true), "AegiSoft License Manager"),
new PathMatchSet(new PathMatch("AscLM.vxd", useEndsWith: true), "AegiSoft License Manager"),
new PathMatchSet(new PathMatch("AscLMd.vxd", useEndsWith: true), "AegiSoft License Manager"),
new(new FilePathMatch("AscLM.cpl"), "AegiSoft License Manager"),
new(new FilePathMatch("AscLM.vxd"), "AegiSoft License Manager"),
new(new FilePathMatch("AscLMd.vxd"), "AegiSoft License Manager"),
// There are a few other files present, but the file names on their own may be too overmatching. Due to the small sample size, it's not sure if these files are always present together.
// These files are "Asc001.dll", "Asc002.dll", "Asc003.dll", "Asc005.dll", and "Asc006.exe" (Found in Redump entry 73521/IA item "Nova_HoyleCasino99USA").

View File

@@ -1,4 +1,4 @@
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
public class AlphaAudio
{

View File

@@ -1,9 +1,11 @@
using System.Collections.Concurrent;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Alpha-DVD is a DVD-Video copy protection created by SETTEC.
@@ -16,22 +18,26 @@ namespace BurnOutSharp.ProtectionType
public class AlphaDVD : IPathCheck
{
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
#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>
{
new PathMatchSet(new PathMatch("PlayDVD.exe", useEndsWith: true), "Alpha-DVD (Unconfirmed - Please report to us on Github)"),
new(new FilePathMatch("PlayDVD.exe"), "Alpha-DVD (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new PathMatchSet(new PathMatch("PlayDVD.exe", useEndsWith: true), "Alpha-DVD (Unconfirmed - Please report to us on Github"),
new(new FilePathMatch("PlayDVD.exe"), "Alpha-DVD (Unconfirmed - Please report to us on Github"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -1,10 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Alpha-ROM is a form of copy protection created by SETTEC. It is known to make use of twin sectors as well as region locking.
@@ -45,18 +44,18 @@ namespace BurnOutSharp.ProtectionType
public class AlphaROM : IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// TODO: Add support for detecting Alpha-ROM found in older games made with the RealLive engine.
// TODO: Add version detection for Alpha-ROM.
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Get the .data/DATA section strings, if they exist
List<string> strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
if (strs.Any(s => s.Contains("\\SETTEC")))

View File

@@ -0,0 +1,61 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Bitpool is a copy protection found most commonly in German releases.
/// It always has errors present on the disc (either between 1-4, or between 1,000-10,000+ depending on generation), and makes use of padded dummy files to prevent copying.
/// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/Bitpool/Bitpool.md"/>
/// </summary>
public class Bitpool : IPathCheck
{
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
new(new FilePathMatch("bitpool.rsc"), "Bitpool"),
new(new FilePathMatch("CD.IDX"), "Bitpool"),
// Completely empty file present on multiple discs with Bitpool (Redump entries 52626 and 50229).
new(new FilePathMatch("LEADOUT.OFS"), "Bitpool"),
// A set of 4 identically sized (within the same game, not between games), corrupted/padded files present in several games (Redump entries 31782 and 35476).
// Both examples with only having the first letter uppercase and as the whole file name being uppercase have been seen.
new(new List<PathMatch>
{
new FilePathMatch("Crc_a"),
new FilePathMatch("Crc_b"),
new FilePathMatch("Crc_c"),
new FilePathMatch("Crc_d"),
}, "Bitpool"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
new(new FilePathMatch("bitpool.rsc"), "Bitpool"),
new(new FilePathMatch("CD.IDX"), "Bitpool"),
// Completely empty file present on multiple discs with Bitpool (Redump entries 52626 and 50229).
new(new FilePathMatch("LEADOUT.OFS"), "Bitpool"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -0,0 +1,166 @@
#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>
/// ByteShield, Inc. (https://web.archive.org/web/20070216191623/http://www.byteshield.net/) was founded in 2004 (https://www.apollo.io/companies/ByteShield--Inc-/54a1357069702d4494ab9b00).
/// There is a website seemingly belonging to them that's been archived as early as 2004, but there doesn't appear to be anything useful on it (https://web.archive.org/web/20040615001350/http://byteshield.com/).
/// The ByteShield DRM itself is online activation based, using randomly generated activation codes it refers to as DACs (https://web.archive.org/web/20080921231346/http://www.byteshield.net/byteshield_whitepaper_0005.pdf).
/// It appears that ByteShield advertised itself around online web forums (https://gamedev.net/forums/topic/508082-net-copy-protection-c/508082/ and https://cboard.cprogramming.com/tech-board/106642-how-add-copy-protection-software.html).
/// Patent relating to ByteShield: https://patentimages.storage.googleapis.com/ed/76/c7/d98a56aeeca2e9/US7716474.pdf and https://patents.google.com/patent/US20100212028.
///
/// Games known to use it:
/// Line Rider 2: Unbound (https://fileforums.com/showthread.php?t=86909).
/// Football Manager 2011 (https://community.sigames.com/forums/topic/189163-for-those-of-you-struggling-with-byteshield-activation-issues/).
///
/// Publishers known to use it:
/// PAN Vision (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Company -> Milestones).
/// JIAN (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Company -> Milestones).
/// GamersGate (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Company -> Milestones).
/// Akella (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// All Interactive Distributuion (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// Beowulf (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// CroVortex (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// N3V Games (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// OnePlayS (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
/// YAWMA (http://web.archive.org/web/20120413160122/http://www.byteshield.net/ -> Customers).
///
/// Further links and resources:
/// https://www.cdmediaworld.com/hardware/cdrom/cd_protections_byteshield.shtml
/// https://www.bcs.org/articles-opinion-and-research/is-there-anything-like-acceptable-drm/
/// https://forums.auran.com/trainz/showthread.php?106673-Trainz-and-DRM/page22
/// https://www.auran.com/planetauran/byteshield_drm.php
/// https://www.ftc.gov/sites/default/files/documents/public_comments/ftc-town-hall-address-digital-rights-management-technologies-event-takes-place-wednesday-march-25/539814-00707.pdf
/// https://www.gamesindustry.biz/byteshield-drm-system-now-protecting-over-200-games
/// </summary>
public class ByteShield : IPortableExecutableCheck, IPathCheck
{
/// <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 "LineRider2.exe" in Redump entry 6236
var name = pex.FileDescription;
if (name?.Equals("ByteShield Client") == true)
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "LineRider2.exe" in Redump entry 6236
name = pex.InternalName;
if (name?.Equals("ByteShield") == true)
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "LineRider2.exe" in Redump entry 6236
name = pex.OriginalFilename;
if (name?.Equals("ByteShield.EXE") == true)
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "LineRider2.exe" in Redump entry 6236
name = pex.ProductName;
if (name?.Equals("ByteShield Client") == true)
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "ByteShield.dll" in Redump entry 6236
name = pex.Model.ExportTable?.ExportDirectoryTable?.Name;
if (name?.Equals("ByteShield Client") == true)
return "ByteShield Component Module";
// Found in "LineRider2.exe" in Redump entry 6236
var stMatch = pex.FindStringTableByEntry("ByteShield");
if (stMatch.Any())
return $"ByteShield Activation Client {pex.GetInternalVersion()}";
// Found in "LineRider2.exe" in Redump entry 6236
var dbMatch = pex.FindDialogByTitle("About ByteShield");
if (dbMatch.Any())
return "ByteShield";
// TODO: See if the version number is anywhere else
// TODO: Parse the version number out of the dialog box item
// Found in "LineRider2.exe" in Redump entry 6236
dbMatch = pex.FindDialogBoxByItemTitle("ByteShield Version 1.0");
if (dbMatch.Any())
return "ByteShield";
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
// Found in "LineRider2.exe" in Redump entry 6236
if (strs.Any(s => s?.Contains("ByteShield") == true))
return "ByteShield";
}
// Get the .rdata section strings, if they exist
strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{
// Found in "ByteShield.dll" in Redump entry 6236
if (strs.Any(s => s?.Contains("Byte|Shield") == true))
return "ByteShield Component Module";
// Found in "ByteShield.dll" in Redump entry 6236
else if (strs.Any(s => s?.Contains("Byteshield0") == true))
return "ByteShield Component Module";
// Found in "ByteShield.dll" in Redump entry 6236
else if (strs.Any(s => s?.Contains("ByteShieldLoader") == true))
return "ByteShield Component Module";
}
// Get the .ret section strings, if they exist
strs = pex.GetFirstSectionStrings(".ret");
if (strs != null)
{
// TODO: Figure out if this specifically indicates if the file is encrypted
// Found in "LineRider2.bbz" in Redump entry 6236
if (strs.Any(s => s?.Contains("ByteShield") == true))
return "ByteShield";
}
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
{
// TODO: Investigate reference to "bbz650.tmp" in "Byteshield.dll" (Redump entry 6236)
// Files with the ".bbz" extension are associated with ByteShield, but the extenstion is known to be used in other places as well.
var matchers = new List<PathMatchSet>
{
new(new FilePathMatch("Byteshield.dll"), "ByteShield Component Module"),
new(new FilePathMatch("Byteshield.ini"), "ByteShield"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
// TODO: Investigate reference to "bbz650.tmp" in "Byteshield.dll" (Redump entry 6236)
// Files with the ".bbz" extension are associated with ByteShield, but the extenstion is known to be used in other places as well.
var matchers = new List<PathMatchSet>
{
new(new FilePathMatch("Byteshield.dll"), "ByteShield Component Module"),
new(new FilePathMatch("Byteshield.ini"), "ByteShield"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,19 +1,19 @@
using BurnOutSharp.Interfaces;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
public class CDCheck : IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
string name = pex.Comments;
var name = pex.Comments;
if (name?.Contains("CDCheck utlity for Microsoft Game Studios") == true)
return "Microsoft Game Studios CD Check";

View File

@@ -0,0 +1,250 @@
using System;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Models.PortableExecutable;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// TODO: Investigate "Cops Copylock II" (https://www.cbmstuff.com/forum/showthread.php?tid=488).
/// TODO: Investigate additional products mentioned on the Link Data Security website (https://www.linkdatasecurity.com/index.htm#/protection-products/overview).
/// `AgentHugo.exe`
/// Embedded PE executable in one of the NE sections
/// `AgentHugo.exe` / `NE.EXE` (1.46) / `NETINST.EXE` (1.48) / `NETINST.QZ_`
/// Embedded PKZIP archive that may contain the CD-Cops files
/// `CDCOPS.DLL` (1.46) / `CDCOPS.DLL` (1.48)
/// `WINCOPS.INI`
///
/// TODO: Investigate if "DVD-Cops" is a separate product, or simply what CD-Cops is referred to when used on a DVD.
///
/// Known versions of CD-Cops:
/// * 1.08 (Unconfirmed) (Redump entry 84517).
/// * 1,13[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20040307124358/http://www.caprino.no:80/download/fgpgold_upd4.exe).
/// * 1.21 (Unconfirmed) (Redump entry 91713).
/// * 1,22[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20030430194917/http://www.caprino.no:80/download/fgpgold_upd2.exe).
/// * 1,28[sic] (Confirmed) ("RunMenu.exe" in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes").
/// * 1,31[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168).
/// * 1.31 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with Patch 11).
/// * 1.46 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20210103064517/http://www.caprino.no/download/FGPGOLD_UPD12.exe)
/// * 1,63[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20060926082522/http://www.caprino.no:80/download/fgpgold_upd7.exe).
/// * 1.72 (Confirmed) ("h3blade.exe" in Redump entry 85077).
/// * 1.73 (Confirmed) ("WETFLIPPER.EXE" in IA item "LULA_Erotic_Pinball_-_Windows95_Eng).
/// * 1,81[sic] (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168 patched with https://web.archive.org/web/20030308040529/http://www.caprino.no:80/download/fgpgold_upd1.exe).
/// * 2.03 (Confirmed) ("HyperBowl.exe" in IA item "hyperbowl_20190626").
///
/// Known versions of DVD-Cops:
/// * 1.69 (Confirmed) ("FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169).
///
/// Known samples of CD-Cops include:
/// * IA item "der-brockhaus-multimedial-2002-premium".
/// * IA item "der-brockhaus-multimedial-2003-premium".
/// * IA item "SCIENCESENCYCLOPEDIAV2.0ARISSCD1".
/// * IA item "SCIENCESENCYCLOPEDIAV2.0ARISSCD2".
/// * IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
/// * IA item "LULA_Erotic_Pinball_-_Windows95_Eng".
/// * IA item "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168.
/// * Patches for "flaklypa-grand-prix-gullutgave-2cd"/Redump entries 108167-108168, found at https://web.archive.org/web/*/http://www.caprino.no/download/* (FGPGOLD_UPD files).
/// * IA item "hyperbowl_20190626"/"hyperbowl-arcade-edition".
/// * Redump entries 51403(?), 84517, and 85077.
///
/// Known samples of DVD-Cops include:
/// * IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
///
/// Known samples of WEB-Cops include:
/// * https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe
///
/// A sample of CD-Cops that makes use of encrypted PDFs (LDSCRYPT) can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
///
/// List of applications that have CD/DVD/WEB-Cops relating to a Windows update: https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/924867
/// </summary>
public class CDDVDCops : IContentCheck, INewExecutableCheck, IPathCheck, IPortableExecutableCheck
{
// TODO: Investigate reference to "CD32COPS.DLL" in "WETFLIPP.QZ_" in IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
{
var contentMatchSets = new List<ContentMatchSet>
{
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops (Unconfirmed - Please report to us on Github)"),
// // DVD-Cops, ver.
new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
}
/// <inheritdoc/>
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>
{
// CD-Cops, ver.
// Found in "h3blade.exe" in Redump entry 85077.
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops"),
};
var match = MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
// Check the imported-name table
// Found in "h3blade.exe" in Redump entry 85077.
bool importedNameTableEntries = nex.Model.ImportedNameTable?
.Select(kvp => kvp.Value)
.Select(inte => inte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(inte.NameString))
.Any(s => s.Contains("CDCOPS")) ?? false;
if (importedNameTableEntries)
return "CD-Cops";
// Check the nonresident-name table
// Found in "CDCOPS.DLL" in Redump entry 85077.
bool nonresidentNameTableEntries = nex.Model.NonResidentNameTable?
.Select(nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString))
.Any(s => s.Contains("CDcops assembly-language DLL")) ?? false;
if (nonresidentNameTableEntries)
return "CD-Cops";
return null;
}
/// <inheritdoc/>
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 stub executable data, if it exists
if (pex.StubExecutableData != null)
{
var matchers = new List<ContentMatchSet>
{
// WEBCOPS
// Found in "HyperBowl.C_S" in https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe.
new(new byte?[]
{
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
}, "WEB-Cops")
};
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
// Get the .grand section, if it exists
// Found in "AGENTHUG.QZ_" in Redump entry 84517 and "h3blade.QZ_" in Redump entry 85077.
bool grandSection = pex.ContainsSection(".grand", exact: true);
if (grandSection)
return "CD/DVD/WEB-Cops";
// Get the UNICops section, if it exists
// Found in "FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
bool UNICopsSection = pex.ContainsSection("UNICops", exact: true);
if (UNICopsSection)
return "UNI-Cops";
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
// TODO: Original had "CDCOPS.DLL" required and all the rest in a combined OR
var matchers = new List<PathMatchSet>
{
// A 400+ MB file called "WASTE.DAT" that is fully 00 padded can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
// Found in Redump entry 84517.
new(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".GZ_", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
new(new PathMatch(".Qz", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// A 400+ MB file called "WASTE.DAT" that is fully 00 padded can be found in IA item "Faculty_Edition_People_Problems_and_Power_by_Joseph_Unekis_Textbytes".
// Presumably used to increase the amount of data written to the disc to allow DPM checking to be used for the protection. It's unknown if this file is used on any other protected discs.
// Found in Redump entry 84517.
new(new PathMatch("CDCOPS.DLL", useEndsWith: true), "CD-Cops"),
new(new PathMatch(".W_X", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".QZ_", matchExact: true, useEndsWith: true), "CD/DVD-Cops"),
new(new PathMatch(".GZ_", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
new(new PathMatch(".Qz", matchExact: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
public static string? GetVersion(string file, byte[]? fileContent, List<int> positions)
{
// If we have no content
if (fileContent == null)
return null;
#if NET20 || NET35 || NET40
byte[] versionBytes = new byte[4];
Array.Copy(fileContent, positions[0] + 15, versionBytes, 0, 4);
char[] version = versionBytes.Select(b => (char)b).ToArray();
#else
char[] version = new ArraySegment<byte>(fileContent, positions[0] + 15, 4).Select(b => (char)b).ToArray();
#endif
if (version[0] == 0x00)
return string.Empty;
return new string(version);
}
}
}

View File

@@ -0,0 +1,87 @@
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>
/// CD-Guard is a DRM from Russia that's similar to CD-Cops and may be related to StarForce, meaning it likely needs DPM.
/// It may have been developed by Russobit-M, though the same source also says that StarForce was created by the same company as well, which seems unlikely (https://m.linkdatasecurity.com/pnews6.htm).
/// Others online have been confused by this as well (https://forum.ixbt.com/topic.cgi?id=31:009712).
/// A game referred to as having CD-Guard by http://lastboss.ru/games/RUS/randevu-s-neznakomkoi-2 that was published by Russobit-M is known to have an early version of StarForce (Redump entry 97088).
/// The FAQ on the game's official website indicates that StarForce specifically is present (https://web.archive.org/web/20011220224222/http://www.aha.ru/~exe_soft/russian/exesoft.htm).
/// It's unknown for sure if there were two separate versions of this game that contained separate protections, or if the game never actually contained CD-Guard, or if CD-Guard was an early name for the StarForce line of products.
/// There is a re-release of an earlier game by the same developer that seems to include both CD-Guard and StarForce drivers, with the CD-Guard driver seemingly not used during installation, nor installed onto the system (IA item "pahgeby-he3hakomkou").
///
/// Additional resources and references:
/// https://gamecopyworld.com/games/pc_omikron.shtml
/// https://forum.ixbt.com/topic.cgi?id=31:3985
/// </summary>
public class CDGuard : 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;
// TODO: Investigate the numerous ".guard" sections present in "Randevu.exe" in Redump entry 97142.
// Get the export directory table
if (pex.Model.ExportTable?.ExportDirectoryTable != null)
{
// Found in "cdguard.dll" in Redump entry 97142 and IA item "pahgeby-he3hakomkou".
bool match = pex.Model.ExportTable.ExportDirectoryTable.Name?.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase) == true;
if (match)
return "CD-Guard Copy Protection System";
}
// Get the import directory table
if (pex.Model.ImportTable?.ImportDirectoryTable != null)
{
// Found in "Randevu.exe" in Redump entry 97142.
bool match = pex.Model.ImportTable.ImportDirectoryTable.Any(idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
if (match)
return "CD-Guard Copy Protection System";
}
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 entry 97142.
new(new FilePathMatch("cdguard.dll"), "CD-Guard Copy Protection System"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entry 97142.
new(new FilePathMatch("cdguard.dll"), "CD-Guard Copy Protection System"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -1,20 +1,20 @@
using System;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
public class CDKey : IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
string name = pex.InternalName;
var name = pex.InternalName;
if (name?.Equals("CDKey", StringComparison.OrdinalIgnoreCase) == true)
return "CD-Key / Serial";

View File

@@ -1,10 +1,12 @@
using System.Collections.Concurrent;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// CD-Lock (https://www.cdmediaworld.com/hardware/cdrom/cd_protections_dummy_files.shtml) is a copy protection most commonly used in Europe and active from 1998-2001 that seems to have a resemblance to Bitpool in a few ways.
@@ -27,10 +29,10 @@ namespace BurnOutSharp.ProtectionType
public class CDLock : IPathCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
@@ -43,7 +45,7 @@ namespace BurnOutSharp.ProtectionType
// Found in game executables protected with CD-Lock (Redump entries 24287 and 31615).
// TODO: Check for possible false postives (Redump entry 97942).
// 2 + (char)0xF2 + (char)0x02 + (char)0x82 + (char)0xC3 + (char)0xBC + (char)0x0B + $ + (char)0x99 + (char)0xAD + 'C + (char)0xE4 + (char)0x9D + st + (char)0x99 + (char)0xFA + 2$ + (char)0x9D + )4 + (char)0xFF + t
new ContentMatchSet(new byte?[]
new(new byte?[]
{
0x32, 0xF2, 0x02, 0x82, 0xC3, 0xBC, 0x0B, 0x24,
0x99, 0xAD, 0x27, 0x43, 0xE4, 0x9D, 0x73, 0x74,
@@ -52,8 +54,8 @@ namespace BurnOutSharp.ProtectionType
}, "CD-Lock"),
};
string match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrWhiteSpace(match))
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
@@ -61,14 +63,18 @@ namespace BurnOutSharp.ProtectionType
}
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
#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>
{
// TODO: Determine if there's any consistency in the naming of the additional AFP files.
// Found in every confirmed sample of CD-Lock, generally (but not always) appears to include markers relating to the additional AFP files present (Redump entries 24287 and 31615).
new PathMatchSet(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
new(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
// There is also a "$$$$$$$$.$$$" file present on some discs, but it isn't known if this is directly related to CD-Lock (Redump entries 37788 and 43221).
};
@@ -77,14 +83,14 @@ namespace BurnOutSharp.ProtectionType
}
/// <inheritdoc/>
public string CheckFilePath(string path)
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// TODO: Determine if there's any consistency in the naming of the additional AFP files.
// Found in every confirmed sample of CD-Lock, generally (but not always) appears to include markers relating to the additional AFP files present (Redump entries 24287 and 31615).
new PathMatchSet(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
new(new PathMatch("CONFIG.AFP", useEndsWith: true), "CD-Lock"),
// There is also a "$$$$$$$$.$$$" file present on some discs, but it isn't known if this is directly related to CD-Lock (Redump entries 37788 and 43221).
};

View File

@@ -1,9 +1,11 @@
using System.Collections.Concurrent;
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// CD-Protector is a form of DRM that allows users to create their own copy protected discs.
@@ -17,7 +19,11 @@ namespace BurnOutSharp.ProtectionType
public class CDProtector : IPathCheck
{
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
#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>
{
@@ -26,20 +32,20 @@ namespace BurnOutSharp.ProtectionType
// "_cdp32.dat" is actually an archive that contains the original executable.
// Another EXE is created, with the name of the original executable. I'm not sure what this executable does, but it appears to be compressed with NeoLite.
// TODO: Invesitage if this EXE itself can be detected in any way.
new PathMatchSet(new PathMatch("_cdp16.dat", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp16.dll", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp32.dat", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp32.dll", useEndsWith: true), "CD-Protector"),
new(new FilePathMatch("_cdp16.dat"), "CD-Protector"),
new(new FilePathMatch("_cdp16.dll"), "CD-Protector"),
new(new FilePathMatch("_cdp32.dat"), "CD-Protector"),
new(new FilePathMatch("_cdp32.dll"), "CD-Protector"),
// This is the "Phantom Trax" file generated by CD-Protector, intended to be burned to a protected CD as an audio track.
new PathMatchSet(new PathMatch("Track#1 - Track#2 Cd-Protector.wav", useEndsWith: true), "CD-Protector"),
new(new FilePathMatch("Track#1 - Track#2 Cd-Protector.wav"), "CD-Protector"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
@@ -48,13 +54,13 @@ namespace BurnOutSharp.ProtectionType
// "_cdp32.dat" is actually an archive that contains the original executable.
// Another EXE is created, with the name of the original executable. I'm not sure what this executable does, but it appears to be compressed with NeoLite.
// TODO: Invesitage if this EXE itself can be detected in any way.
new PathMatchSet(new PathMatch("_cdp16.dat", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp16.dll", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp32.dat", useEndsWith: true), "CD-Protector"),
new PathMatchSet(new PathMatch("_cdp32.dll", useEndsWith: true), "CD-Protector"),
new(new FilePathMatch("_cdp16.dat"), "CD-Protector"),
new(new FilePathMatch("_cdp16.dll"), "CD-Protector"),
new(new FilePathMatch("_cdp32.dat"), "CD-Protector"),
new(new FilePathMatch("_cdp32.dll"), "CD-Protector"),
// This is the "Phantom Trax" file generated by CD-Protector, intended to be burned to a protected CD as an audio track.
new PathMatchSet(new PathMatch("Track#1 - Track#2 Cd-Protector.wav", useEndsWith: true), "CD-Protector"),
new(new FilePathMatch("Track#1 - Track#2 Cd-Protector.wav"), "CD-Protector"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -1,31 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Wrappers;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BurnOutSharp.ProtectionType
namespace BinaryObjectScanner.Protection
{
public class CDSHiELDSE : IPortableExecutableCheck
{
/// <inheritdoc/>
public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex?.SectionTable;
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// TODO: Indicates Hypertech Crack Proof as well?
//// Get the import directory table
//if (pex.ImportTable?.ImportDirectoryTable != null)
//if (pex.Model.ImportTable?.ImportDirectoryTable != null)
//{
// bool match = pex.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
// bool match = pex.Model.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
// if (match)
// return "CDSHiELD SE";
//}
// Get the code/CODE section strings, if they exist
List<string> strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
var strs = pex.GetFirstSectionStrings("code") ?? pex.GetFirstSectionStrings("CODE");
if (strs != null)
{
if (strs.Any(s => s.Contains("~0017.tmp")))

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