Compare commits

..

747 Commits
1.4.1 ... 2.3.0

Author SHA1 Message Date
Matt Nadareski
1b0fcdcf32 Bump version to 2.3.0 2022-08-22 09:30:49 -07:00
Matt Nadareski
9fa1ef1d2e Slight cleanup of CDS 2022-08-21 20:36:37 -07:00
Matt Nadareski
e2492c9e5b Consolidate field string checks (fixes #141) 2022-08-21 20:34:59 -07:00
TheRogueArchivist
297514ef17 Overhaul SafeDisc detection (#133)
* Begin overhauling SafeDisc detection

* A new utility method for obtaining the SHA1 hash of a file.
* SHA1-based detection for drvmgt.dll, which is vastly more accurate than the existing size checks.
* (Currently nonfunctional) PEX based checks for newer secdrv.sys versions.
* General clean-up and minor additions.

* Address PR review comments

* Address further PR comments and remove some file size checks

Remove file size checks that are now redundant.

* Add CLCD16 hash based version detection

Add support for detecting a rough version range from the hash of CLCD16.dll, as well as general cleanup.

* Add CLCD32 hash based version detection

Add hash based version checks for CLCD32.dll, which provides reliable detection for 1.X, much more than CLCD16.dll.

* Add CLOKSPL hash based version detection

Add CLOKSPL hash based version detection, which is an excellent indicator of version within 1.X.

* Add detailed SafeDisc version notes, address PR reviews

* Add a note that includes every known SafeDisc and SafeCast version.

* General cleanup and minor detection additions.

* Address PR reviews.

* Various SafeDisc detection improvements

* Add broad version checks for 00000001.TMP.

* Add a few SafeDisc Lite specific CLCD32.DLL checks.

* Remove unneeded dplayerx.dll size checks that were already covered by executable string checks.

* Improve DPlayerX version size checks

Improve DPlayerX existing version size checks and add new ones.

Add new hash checks for previously undetected files.

* Improve secdrv.sys version detection

Improve secdrv.sys version detection using both file size checks and product version checks.

* Fix various false positives

Fix various false positives, as well as incomplete detections.

* Address PR comments

* Properly set check for File Description
2022-08-21 20:20:28 -07:00
SilasLaspada
2acb0a037c Add initial support for detecting Easy Anti-Cheat (#148)
Add initial support for detecting Easy Anti-Cheat. This is presumed to only detect later versions, though it's possible that older versions may be detected as well.
2022-08-13 20:09:46 -07:00
SilasLaspada
c38eb0cc71 Various note additions and minor fixes (#147)
- Add notes for Alpha-ROM, Hexalock, SVKP, and Zzxzz.

- Fix typos for Intenium.
2022-08-13 20:04:26 -07:00
SilasLaspada
258369bb9e Add support for detecting "AegiSoft License Manager" (#144)
Add support for "AegiSoft License Manager", as well as notes about what's known about the protection so far.
2022-08-13 20:03:27 -07:00
SilasLaspada
8cba9529d7 Overhaul DiscGuard detection (#140)
* Overhaul DiscGuard detection

* Verify some existing checks for DiscGuard.
* Add several new executable and path checks.
* Add note for remaining unconfirmed check.
* Add notes and research in comments.
* Add related protection "DiscAudit" to list of protections that needs to be added.

* Address DiscGuard PR review comments
2022-07-28 23:31:04 -07:00
SilasLaspada
10296f40b4 Improve Alpha-ROM detection for Siglus and RealLive games (#139)
* Improve Alpha-ROM detection for Siglus and RealLive games

Improve Alpha-ROM detection for games that use the Siglus and RealLive VN game engines.

* Address PR comments for Alpha-ROM

* Add comment and address PR review
2022-07-28 21:03:35 -07:00
Matt Nadareski
73d085deac Update stream path for VersionInfo 2022-07-27 22:31:15 -07:00
SilasLaspada
c7261c342a Vastly improve MediaCloQ checks (#138)
* Vastly improve MediaCloQ checks

Vastly improve MediaCloQ checks, including adding content and text file checks. Also, add notes relating to it in comments.

* Add comment to MediaCloQ

Add mention of "sunncomm.ico" being used as a previous check.
2022-07-27 13:06:52 -07:00
Matt Nadareski
14d905fba3 Handle alternatively named version resources 2022-07-27 11:28:24 -07:00
Matt Nadareski
1f66edc201 Fix some resource finding 2022-07-27 11:10:46 -07:00
SilasLaspada
ade95c3210 Improve Hexalock AutoLock detection (#136)
* Improve Hexalock AutoLock detection

Verify the last remaining unverified checks, and add more checks and notes.

* Add special thanks for Hexalock
2022-07-26 20:17:28 -07:00
SilasLaspada
8a419f50db Fix MediaMax CD-3 false positive (#135)
The LaunchCD files checked for were completely unrelated to the copy protection.
2022-07-23 23:55:04 -07:00
Matt Nadareski
52efca767e Make sure start/end not reset 2022-07-17 21:14:20 -07:00
Matt Nadareski
421dfa2591 Add LibMSPackSharp note in readme 2022-07-13 14:02:52 -07:00
Matt Nadareski
76183c529c Remove explicit .NET Core 3.1 and .NET 5.0 builds 2022-07-13 13:46:30 -07:00
Matt Nadareski
463506d1e8 Add note to Wise Installer 2022-07-13 12:54:42 -07:00
Matt Nadareski
1f2a187f55 Add note to UPX 2022-07-13 12:54:08 -07:00
Matt Nadareski
40de5c4d0a Add note to Shrinker 2022-07-13 12:53:28 -07:00
Matt Nadareski
5e72acb44c Add note to Setup Factory 2022-07-13 12:53:08 -07:00
Matt Nadareski
fab3c935f8 Add note to PEtite 2022-07-13 12:52:41 -07:00
Matt Nadareski
a498513662 Add note to PECompact 2022-07-13 12:52:20 -07:00
Matt Nadareski
3eaebffff1 Add note to MS-CAB SFX 2022-07-13 12:51:54 -07:00
Matt Nadareski
280ae5babe Add note to Installer VISE 2022-07-13 12:51:21 -07:00
Matt Nadareski
5bf64d46bd Add note to InstallAnywhere 2022-07-13 12:51:00 -07:00
Matt Nadareski
6fb510c852 Add note to Inno Setup 2022-07-13 12:50:36 -07:00
Matt Nadareski
20223eea87 Add note to Gentee Installer 2022-07-13 12:50:06 -07:00
Matt Nadareski
3f796e4e0e Add note to EXEStealth 2022-07-13 12:49:34 -07:00
Matt Nadareski
74732a1b50 Add note to CExe 2022-07-13 12:48:49 -07:00
Matt Nadareski
f252681364 Add note to Armadillo 2022-07-13 12:48:16 -07:00
Matt Nadareski
82cb0f934d Add note to Themida 2022-07-13 12:47:06 -07:00
Matt Nadareski
7dc5644d21 Add note to SVKP 2022-07-13 12:46:17 -07:00
Matt Nadareski
313cc2bfb8 Add another source for CrypKey 2022-07-13 12:18:39 -07:00
Matt Nadareski
f24a8763fd Add missing ActiveMark entry point checks 2022-07-13 12:14:39 -07:00
Matt Nadareski
47845a2409 Split Cucko into separate file 2022-07-13 11:52:49 -07:00
SilasLaspada
42da9f4a82 Add support for detecting Cucko (#132)
* Add support for detecting Cucko

Add support for detecting Cucko.

* Remove debug line
2022-07-12 22:57:22 -07:00
Matt Nadareski
e9fa86343a Add special thanks 2022-07-11 22:45:12 -07:00
Matt Nadareski
8ccf2272d6 Add proper SecuROM White Label detection 2022-07-11 22:38:02 -07:00
Matt Nadareski
8fb42bc12d Add ASPack 2022-07-11 21:23:44 -07:00
Matt Nadareski
6202ee5d5c Print sections during debug 2022-07-11 16:10:52 -07:00
Matt Nadareski
655a8adb1c Disable .shr section for SecuROM for now 2022-07-11 10:08:08 -07:00
Matt Nadareski
d7fcc99fc2 Add volitile by default 2022-07-08 14:50:03 -07:00
Matt Nadareski
8601f373bd More work on MS-CAB and MSZIP 2022-07-08 13:07:03 -07:00
Matt Nadareski
3c783fdc68 Re-format some info data 2022-07-07 17:02:43 -07:00
Matt Nadareski
a75388cf17 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2022-07-07 16:34:52 -07:00
Matt Nadareski
7968a79fe6 Add start of decompression 2022-07-07 16:33:15 -07:00
SilasLaspada
8502924083 Overhaul existing and add new audio CD protections (#131)
* Overhaul existing and add new audio CD protections

Overhaul many audio CD protections, on top of adding a few more. Unfortunately, disable key2Audio detection as well, as the existing checks were simply detecting OpenMG components and not key2Audio itself.

* Fix issues from PR review
2022-07-07 15:24:41 -07:00
Matt Nadareski
af95ca08c3 Add dec/hex outputs 2022-07-07 15:24:24 -07:00
Matt Nadareski
06995b75d6 Move printing to classes 2022-07-07 15:16:34 -07:00
Matt Nadareski
1a2be26c72 Finalize intial info output 2022-07-07 15:10:31 -07:00
Matt Nadareski
a2a583e317 Add GetInfo, fix MSCABCabinet deserialize 2022-07-07 14:55:29 -07:00
Matt Nadareski
289a55ca21 Seek to file header location instead 2022-07-07 14:20:31 -07:00
Matt Nadareski
598f625ed1 Add some deserialization for MPQ 2022-07-07 14:15:44 -07:00
Matt Nadareski
d604a6d784 Fix endregion tags 2022-07-07 13:27:31 -07:00
Matt Nadareski
cf34a0adee Add Quantum framework 2022-07-07 13:27:13 -07:00
Matt Nadareski
083ded8a7e Add framework for extract all files 2022-07-07 12:43:35 -07:00
Matt Nadareski
1517a66724 Add cabinet finding 2022-07-07 12:11:23 -07:00
Matt Nadareski
5385de0f0a Add MS-ZIP deserialize and deflate 2022-07-07 12:02:25 -07:00
Matt Nadareski
43729b53f0 Add multi-cabinet note 2022-07-07 11:51:27 -07:00
Matt Nadareski
e4aa618f0b Add automatic date-time translation 2022-07-07 11:49:57 -07:00
Matt Nadareski
4953673caf Start writing CAB extraction 2022-07-07 11:37:53 -07:00
Matt Nadareski
35c6d4f36c Add unused cabinet-level deserialization 2022-07-07 11:24:21 -07:00
Matt Nadareski
9108fa5a11 Add unused MS-CAB deserialization 2022-07-07 11:15:35 -07:00
Matt Nadareski
dc97feae39 Add unused structures for MS-CAB 2022-07-07 10:39:41 -07:00
Matt Nadareski
beac29c650 Re-add Wix for MS-CAB
Added until LibMSPackSharp can be fixed
2022-07-06 15:33:10 -07:00
Matt Nadareski
21a041dad6 Update MS-CAB 2022-07-06 15:17:02 -07:00
Matt Nadareski
26eee23511 Update LibMSPackSharp to newest Git version 2022-07-06 15:16:41 -07:00
Matt Nadareski
0915c7eccd Add a few more things for MPQ 2022-07-06 13:39:54 -07:00
Matt Nadareski
e2e65bfbdf Add some unused structures for MPQ 2022-07-05 22:35:58 -07:00
SilasLaspada
033f2e0a4e Improve Cenega ProtectDVD detection (#129)
Improve detection of Cenega ProtectDVD and add notes.
2022-07-05 21:03:27 -07:00
SilasLaspada
71ee0863eb Add shell for Themida (#128)
Add shell and a few notes for Themida/WinLicense/Code Virtualize.
2022-07-04 21:15:18 -07:00
SilasLaspada
3203c3ac83 Improve Steam detection (#127)
Improve Steam detection. Fixes #114
2022-06-30 16:18:12 -07:00
SilasLaspada
1733f60a0f Improve HexaLock AutoLock detection (#126)
Vastly improve HexaLock AutoLock detection, and add notes.
2022-06-30 16:17:18 -07:00
SilasLaspada
b01abdcce3 Improve Bitpool detection (#125)
Improve Bitpool detection on top of adding many more notes.
2022-06-30 16:14:09 -07:00
SilasLaspada
53c90533e3 Improve ProtectDISC checks (#124)
This check is known to be used in at ProtectDISC 6.8.
2022-06-29 14:30:13 -07:00
SilasLaspada
03bd7bd1f5 Add initial detection of WMDS, and improve detection of MediaMax CD-3 (#122)
* Add initial detection of WMDS, and improve detection of MediaMax CD-3

Add initial detection of Windows Media Data Session, and improve detection of MediaMax CD-3.

* Fix whitespace

Fix whitespace as requested in PR review.

* Add comment to WMDS

* Further improve MediaMax CD-3 checks
2022-06-29 14:28:46 -07:00
Matt Nadareski
637579b0fc Remove Wix 2022-06-23 14:02:18 -07:00
Matt Nadareski
bd40ca6d9d Use OpenMcdf for MSI 2022-06-23 13:58:48 -07:00
Matt Nadareski
3c1623cb22 Remove libgsf/libmsi/ComHandler 2022-06-23 13:57:41 -07:00
SilasLaspada
66da32b5c1 Initial Detection of "Dinamic Multimedia Protection"/LockBlocks (#121)
Add initial detection of and notes about "Dinamic Multimedia Protection"/LockBlocks.

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2022-06-22 13:52:58 -07:00
Matt Nadareski
c21b64b5bd Add initial Denuvo checks (fixes #75) 2022-06-22 13:40:28 -07:00
Matt Nadareski
e968eeea96 Add entry point note to Tages 2022-06-22 10:17:56 -07:00
Matt Nadareski
c14005dcc4 Add entry point note to Steam 2022-06-22 10:03:14 -07:00
Matt Nadareski
84c6c257df Add missing protection note for StarForce 2022-06-22 10:00:35 -07:00
Matt Nadareski
e28b930f85 Add entry point note to SafeDisc 2022-06-22 09:57:12 -07:00
Matt Nadareski
9dac2eb91b Add entry point note to LaserLok 2022-06-22 09:54:38 -07:00
Matt Nadareski
2209f362fa Add notes for CrypKey 2022-06-22 09:50:16 -07:00
Matt Nadareski
614413ab76 Add missing checks for ActiveMARK 2022-06-22 09:42:52 -07:00
Matt Nadareski
35c15d0ff8 Add missing SecuROM 8 check 2022-06-22 09:35:41 -07:00
Matt Nadareski
b521df2ad4 Fix finding, update SecuROM 2022-06-22 09:29:29 -07:00
Matt Nadareski
778fe106f9 Read overlay data (unused) 2022-06-22 09:13:01 -07:00
Matt Nadareski
9171014dcd Add missing PKZIP signature 2022-06-21 23:39:19 -07:00
Matt Nadareski
7ee74d9b81 Port remaining psxt001z code 2022-06-21 23:38:30 -07:00
Matt Nadareski
826011f532 More small cleanup (nw) 2022-06-20 22:37:46 -07:00
Matt Nadareski
adb349932f Start overlay framework 2022-06-20 21:39:19 -07:00
Matt Nadareski
f4f13c03fe Update SharpCompress 2022-06-20 21:38:01 -07:00
Matt Nadareski
e29e87444e ComHandler 2022-06-20 21:36:53 -07:00
Matt Nadareski
b233b3c17b Add data at PE entry point 2022-06-19 22:40:07 -07:00
Matt Nadareski
a8fca77331 Minor cleanup attempt 2022-06-18 23:19:57 -07:00
Matt Nadareski
5e4ee07646 Partially fix caching 2022-06-18 21:59:13 -07:00
Matt Nadareski
52b2a9bef8 Fix name decode 2022-06-18 21:49:06 -07:00
Matt Nadareski
dc7f8da52f Simplify and fix MS-OLE 2022-06-18 21:16:11 -07:00
Matt Nadareski
d46b0768a0 LibMSI cleanup and notes (nw) 2022-06-17 23:12:21 -07:00
Matt Nadareski
f136af3457 Cleanup and minor MS-OLE fixes 2022-06-17 23:11:12 -07:00
Matt Nadareski
2e2b6068c5 Fix SQL parsing 2022-06-17 21:22:06 -07:00
Matt Nadareski
7a29d8a8f9 Fix StringTable read/build 2022-06-17 14:53:18 -07:00
Matt Nadareski
ae0c47066e Safety and trimming 2022-06-17 14:47:32 -07:00
Matt Nadareski
11188c9488 Buffer pointer 2022-06-17 14:46:59 -07:00
Matt Nadareski
4d5d2d8690 Seek -> SeekImpl 2022-06-17 13:41:51 -07:00
SilasLaspada
1860a863b8 Add initial detection of phenoProtect (#120)
Add initial detection of phenoProtect, which is currently text file based only.
2022-06-16 22:13:02 -07:00
Matt Nadareski
8dbf6d9362 GsfInfileZip second pass 2022-06-16 22:11:09 -07:00
Matt Nadareski
e3e8a1170f GsfInfileTar second pass 2022-06-16 16:43:07 -07:00
Matt Nadareski
b22641b7ab GsfInfileStdio second pass 2022-06-16 15:43:10 -07:00
Matt Nadareski
d3d75b9e58 GsfInfileMSVBA second pass 2022-06-16 15:35:58 -07:00
Matt Nadareski
6083c64b87 GsfInfileMSOle second pass 2022-06-16 15:17:38 -07:00
Matt Nadareski
4185367a49 GsfBlob, GsfClipData, and GsfDocMetaData second pass 2022-06-16 13:54:35 -07:00
Matt Nadareski
c027b1798a Ensure consistent reads and writes 2022-06-16 13:07:41 -07:00
Matt Nadareski
76e52292a8 Fix GsfInputMemory.ReadImpl 2022-06-15 23:43:59 -07:00
Matt Nadareski
dd5f7c4e0b Fix GsfInputStdio.MakeLocalCopy 2022-06-15 23:35:06 -07:00
Matt Nadareski
6e70991e86 Fix build, add export all (nw) 2022-06-15 23:31:08 -07:00
Matt Nadareski
f1803b9f3a Organize files, clean up formatting, add TODOs 2022-06-15 22:53:41 -07:00
Matt Nadareski
9e0abe7c5d Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2022-06-15 17:19:59 -07:00
Matt Nadareski
1a01102252 LibMSI (nw) 2022-06-15 17:19:44 -07:00
Matt Nadareski
ce849d312f Fix naming in GSF 2022-06-15 17:19:25 -07:00
SilasLaspada
71da8a53c0 Add detection for new TAGES variant and add references to Redump entries (#119)
Add detection for new TAGES variant found in Robocop, and add the Redump entries for every listed file.
2022-06-13 00:12:34 -07:00
Matt Nadareski
b8f7d00dc9 Fix LibGSF build 2022-06-10 20:59:36 -07:00
Matt Nadareski
7e69a56892 LibGSF (nw) 2022-06-10 15:29:58 -07:00
Matt Nadareski
8cedd3e469 Handle malformed IS-CAB filenames 2022-06-04 22:02:13 -07:00
Matt Nadareski
d5e60439fb Remove now-unused Wix references 2022-06-04 22:01:02 -07:00
Matt Nadareski
1a0e16a05b Use new debug flag 2022-06-01 12:01:14 -07:00
Matt Nadareski
bee6d2b885 Update LibMSPackSharp 2022-06-01 11:50:49 -07:00
Matt Nadareski
5d515c7ddd Update LibMSPackSharp 2022-06-01 11:34:50 -07:00
Matt Nadareski
013301fa99 Update LibMSPackSharp 2022-05-31 16:40:12 -07:00
Matt Nadareski
152ae8bf6c Update LibMSPackSharp 2022-05-31 16:38:21 -07:00
Matt Nadareski
439f71ef5c Migrate to external libmspack 2022-05-31 16:34:40 -07:00
Matt Nadareski
66c7afe20b Use placeholder cabinet to start at first file 2022-05-31 16:06:29 -07:00
Matt Nadareski
6a609ea3f5 Break and set fixing flags if there's an appending error 2022-05-31 16:04:20 -07:00
Matt Nadareski
6752d0cfa3 Append cabinets where needed 2022-05-31 15:54:53 -07:00
Matt Nadareski
1d26b06592 Fix 0 checks, fix aligned table creation 2022-05-31 15:44:22 -07:00
Matt Nadareski
9ca24a3053 LZX and MSCAB format cleanup 2022-05-26 23:12:53 -07:00
Matt Nadareski
76ca87f7a9 Fully fix LZX 2022-05-25 23:52:26 -07:00
Matt Nadareski
c913b10286 Partially fix CAB decompression 2022-05-25 23:46:45 -07:00
Matt Nadareski
768c77a6bc Attempts at changes 2022-05-25 21:55:36 -07:00
Matt Nadareski
20d90d6a60 More reorganization 2022-05-24 21:39:33 -07:00
Matt Nadareski
54a48e0729 Less static methods 2022-05-24 17:05:34 -07:00
Matt Nadareski
15c05c65e7 Partial classes 2022-05-24 16:52:41 -07:00
Matt Nadareski
4dbaa415c5 Constants 2022-05-24 15:52:05 -07:00
Matt Nadareski
1a0b83a9f1 Split last MSB/LSB 2022-05-24 09:35:11 -07:00
Matt Nadareski
4316427980 Nearly finish demacroificiation 2022-05-24 00:47:09 -07:00
Matt Nadareski
21ecaca761 Properly implement methods from macros 2022-05-23 23:31:55 -07:00
Matt Nadareski
7022a957d6 Start making common read methods again 2022-05-23 22:36:24 -07:00
Matt Nadareski
32cfcbff0a Rename a couple things 2022-05-23 21:21:13 -07:00
Matt Nadareski
283fa425d4 Partial OAB cleanup 2022-05-23 21:16:42 -07:00
Matt Nadareski
d37eac02d5 KWAJ objectification and cleanup 2022-05-23 21:13:55 -07:00
Matt Nadareski
c3e0b99002 CHM decompressor cleanup 2022-05-23 20:48:34 -07:00
Matt Nadareski
9e49703bc5 Clean up some CAB decompressor code 2022-05-23 15:05:03 -07:00
Matt Nadareski
98a7149cc9 CHM objectification cleanup 2022-05-23 14:25:22 -07:00
Matt Nadareski
394b4e70fb libmspack cleanup 2022-05-23 13:36:19 -07:00
Matt Nadareski
b29198b3d4 CHM objectification 2022-05-22 23:46:29 -07:00
Matt Nadareski
044c398fa7 Minor LZX cleanup (nw) 2022-05-22 20:41:41 -07:00
Matt Nadareski
ae7087e8d0 Attempts at LZX fixes 2022-05-22 13:57:33 -07:00
Matt Nadareski
90bc78982c Safer opening of CABs 2022-05-22 13:13:42 -07:00
Matt Nadareski
2ce8bda394 Skip other null writes for other packages 2022-05-22 10:21:54 -07:00
Matt Nadareski
ac0ed050dc Partially fix MSZIP decompression 2022-05-22 10:17:41 -07:00
Matt Nadareski
e4aadb3794 Minor tweaks that might help 2022-05-22 00:19:04 -07:00
Matt Nadareski
80626f3b9e Cleanup to get some things working 2022-05-21 23:44:03 -07:00
Matt Nadareski
93263dfeb9 Finish KWAJ LZH and get building 2022-05-21 22:38:28 -07:00
Matt Nadareski
51e5f82cc2 Complete LZX implementation 2022-05-21 22:18:25 -07:00
Matt Nadareski
b69c5cf928 Huffman tree implement MSZIP (nw) 2022-05-21 21:47:54 -07:00
Matt Nadareski
e45b593c7b LZH KWAJ demacroificiation (nw) 2022-05-21 21:26:42 -07:00
Matt Nadareski
c245ebb80a Focus on QTM for demacroification 2022-05-21 21:00:26 -07:00
Matt Nadareski
cd38407e4e Continue demacroization (nw) 2022-05-20 23:33:57 -07:00
Matt Nadareski
f34b1ba5cf Continue demacroification (nw) 2022-05-20 22:29:43 -07:00
Matt Nadareski
08c97d291e Start of de-macro-ification 2022-05-19 23:52:08 -07:00
Matt Nadareski
3ea294f4d9 DefaultFileImpl -> FileStream 2022-05-19 22:32:58 -07:00
Matt Nadareski
ddb2be278a More CAB-specific cleanup 2022-05-19 22:19:06 -07:00
Matt Nadareski
b6b5dc4efa Make more objects for CAB 2022-05-19 20:46:58 -07:00
Matt Nadareski
218fecb273 Start cleanup on libmspack 2022-05-19 17:07:08 -07:00
Matt Nadareski
b23a504c7b Missed a few cast->as 2022-05-19 12:11:23 -07:00
Matt Nadareski
c54181e9ac "as" not "cast" 2022-05-19 11:56:38 -07:00
Matt Nadareski
7e100a261c Make Library static 2022-05-19 11:24:34 -07:00
Matt Nadareski
38e1154bad Add initial port of libmspack (nw) 2022-05-19 11:20:44 -07:00
Matt Nadareski
901804e9e4 Add OS limitation note to readme 2022-05-15 21:09:03 -07:00
Matt Nadareski
dfee4a8d76 Use debug flag for exception printing 2022-05-15 20:58:27 -07:00
Matt Nadareski
295b86fbd0 Replace HLExtract with HLLibSharp 2022-05-15 14:18:45 -07:00
Matt Nadareski
177543a51c Use WixToolset for MS-CAB 2022-05-14 21:25:41 -07:00
Matt Nadareski
dfff702e5d Remove x86 build limitation on test program 2022-05-14 14:37:52 -07:00
Matt Nadareski
c0ad427b5e Remove x86 build limitation on library 2022-05-14 14:33:15 -07:00
Matt Nadareski
2f68f95d80 Path.DirectorySeparatorChar 2022-05-13 21:03:13 -07:00
Matt Nadareski
a8ba104d0f Better interface comments 2022-05-01 21:06:52 -07:00
Matt Nadareski
6f9e92d222 Clean up interface comments 2022-05-01 21:03:48 -07:00
Matt Nadareski
1e20c1b147 Ensure packer consistency 2022-05-01 21:02:59 -07:00
Matt Nadareski
c16946ace7 Add IScannable to GenteeInstaller 2022-05-01 20:44:45 -07:00
Matt Nadareski
9d7cc4012c Move interfaces to own namespace 2022-05-01 17:41:50 -07:00
Matt Nadareski
a44bdf9013 Reorder inherited interfaces 2022-05-01 17:23:00 -07:00
Matt Nadareski
f9f2e0d932 Better naming 2022-05-01 17:17:15 -07:00
Matt Nadareski
2dd3e21ea6 Separate stream helper 2022-05-01 17:06:46 -07:00
Matt Nadareski
81bb47b634 Progress tracker doesn't need to be public 2022-05-01 16:59:03 -07:00
Matt Nadareski
c8efc1430a Get fancy 2022-05-01 14:46:01 -07:00
Matt Nadareski
7883638f0a Make helper method easier to read 2022-05-01 14:28:28 -07:00
Matt Nadareski
e930be12c8 Reduce parameters for helper 2022-05-01 14:27:04 -07:00
Matt Nadareski
c45ae4b693 Consolidate ShouldAddProtection checks 2022-05-01 14:24:46 -07:00
Matt Nadareski
478f28b513 Create Initializer class 2022-05-01 14:16:53 -07:00
Matt Nadareski
aac3c391db Simplify construction and access in Scanner 2022-05-01 14:11:09 -07:00
Matt Nadareski
802734b515 Remove another implicit assignment 2022-05-01 14:04:21 -07:00
Matt Nadareski
ef212fc8d9 Remove library-level assignments in Scanner 2022-05-01 14:00:20 -07:00
Matt Nadareski
ee85f2f6f0 Remove useless all files flag 2022-05-01 13:58:43 -07:00
Matt Nadareski
9a160b3127 Split Directory/File checks for SafeDisc 2022-04-25 12:34:39 -07:00
Matt Nadareski
4486c5ed62 ICD overmatches for SafeDisc, somehow 2022-04-25 12:27:07 -07:00
Matt Nadareski
d6feab3958 Bump version to 2.1.0 2022-04-17 22:02:43 -07:00
Matt Nadareski
2d2207a1ee Update UnshieldSharp to 1.6.8 2022-04-17 13:35:14 -07:00
Matt Nadareski
89b86630d8 Update WiseUnpacker to 1.0.3 2022-04-17 13:33:59 -07:00
Matt Nadareski
bcb1571a23 Use .NET Standard 2.0, add .NET 6.0 2022-04-16 21:58:54 -07:00
Matt Nadareski
5d658ebe4a Upgrade to VS2022 for AppVeyor 2022-04-16 21:56:45 -07:00
Matt Nadareski
7d2de80e77 Fix over-matching SafeLock 2022-04-02 21:36:29 -07:00
Matt Nadareski
b933249ff7 Add resource finding on creation 2022-04-02 16:12:23 -07:00
Matt Nadareski
61c09e3c97 Move resource helpers to PortableExecutable 2022-04-02 15:54:51 -07:00
SilasLaspada
32695ee6dd Add support for detecting AutoPlay Media Studio (#116)
* Add support for detecting AutoPlay Media Studio

* Comment out too vague AutoPlay Media Studio check

* Tweak comment
2022-04-01 23:23:32 -07:00
Matt Nadareski
4b66cd8cd2 Update file version resource handling 2022-04-01 10:16:31 -07:00
SilasLaspada
edc4cc1706 Refactor Setup Factory detection (#115)
* Refactor Setup Factory detection

* Address Setup Factory PR comments

* Fix whitespace
2022-04-01 09:58:02 -07:00
Matt Nadareski
35acb77bf7 Bump version to 2.0.0 2022-03-27 20:43:49 -07:00
Matt Nadareski
e970a7b4d9 Clean up SafeDisc a little more 2022-03-18 21:05:09 -07:00
Matt Nadareski
f155291139 Update comments after confirmation of existence 2022-03-17 12:18:08 -07:00
Matt Nadareski
b0293419e1 Add note to Tages for future research 2022-03-17 12:16:41 -07:00
Matt Nadareski
09db225929 Simplify TAGES version checking 2022-03-17 12:13:11 -07:00
Matt Nadareski
0c52b4e236 Update to UnshieldSharp 1.6.7 2022-03-17 10:03:39 -07:00
Matt Nadareski
5dc30942ff Add missing TAGES version byte 2022-03-15 23:04:10 -07:00
Matt Nadareski
cab200e893 Add Shrinker PE detection 2022-03-15 22:44:10 -07:00
Matt Nadareski
c349f3a3c4 Add Gentee Installer detection (fixes #93) 2022-03-15 22:35:44 -07:00
Matt Nadareski
0acb29f2e9 Add Steam Client Engine check 2022-03-15 22:23:23 -07:00
Matt Nadareski
b66e01f7b4 Fix SLL comment 2022-03-15 22:11:37 -07:00
Matt Nadareski
8d6d215e57 Remove commented debug code 2022-03-15 22:10:13 -07:00
Matt Nadareski
d54a90a034 Add some missing SecuROM checks 2022-03-15 22:09:28 -07:00
Matt Nadareski
e1e7172561 Make ReadArbitraryRange safer 2022-03-15 21:30:46 -07:00
Matt Nadareski
6606b388f6 Remove duplicate comment 2022-03-15 15:48:05 -07:00
Matt Nadareski
b6c6c01358 Slightly rearrange generic content check invocation 2022-03-15 15:47:37 -07:00
Matt Nadareski
6886c5a4a2 Convert SVKP to PE content check 2022-03-15 15:39:35 -07:00
Matt Nadareski
87546a3dc8 Remove lingering unconfirmed TAGES check 2022-03-15 15:37:13 -07:00
Matt Nadareski
6e3028639a Fix one TAGES PE check 2022-03-15 15:05:08 -07:00
Matt Nadareski
386da02e27 Convert CExe to PE content check 2022-03-15 13:19:06 -07:00
Matt Nadareski
ec8c395ffa Streams 2022-03-15 12:39:22 -07:00
Matt Nadareski
9b98215fc9 Make SourceArray private in NE 2022-03-15 11:18:53 -07:00
Matt Nadareski
40e037fb2a Make SourceStream private 2022-03-15 11:11:54 -07:00
Matt Nadareski
17f8569a7e Only read resource in WinZipSFX 2022-03-15 11:11:44 -07:00
Matt Nadareski
1105f36cee Add hacky thing for Inno for now 2022-03-15 11:11:22 -07:00
Matt Nadareski
f9fcd8749b Add arbitrary reads to NE 2022-03-15 10:50:40 -07:00
Matt Nadareski
eef76d362a Fix arbitrary reads, update SecuROM check 2022-03-15 10:39:06 -07:00
Matt Nadareski
3b0e3693eb Add arbitrary range reading 2022-03-15 10:26:29 -07:00
Matt Nadareski
ba4c56997a Add Relocation section skeleton 2022-03-15 10:15:05 -07:00
Matt Nadareski
ca4d08567d Fix resetting position for DebugSection 2022-03-15 10:02:10 -07:00
Matt Nadareski
3211149996 Remove NE Inno check from PE path 2022-03-15 09:01:54 -07:00
Matt Nadareski
5a7e60cabb Use backward read for UPX 2022-03-15 00:30:33 -07:00
Matt Nadareski
46ff4b6ef9 Remove one use of SourceArray in SecuROM 2022-03-14 23:44:17 -07:00
Matt Nadareski
dc252e8d86 Add comments around remaining SourceArray usages 2022-03-14 23:32:19 -07:00
Matt Nadareski
133e29dc2e Add NameString to SectionHeader 2022-03-14 23:28:31 -07:00
Matt Nadareski
368cec4fc6 Remove more explicit content array usages 2022-03-14 23:17:45 -07:00
Matt Nadareski
65eea4301d Hide section complexity from content checks 2022-03-14 23:01:06 -07:00
Matt Nadareski
ceae505f4d Switch order of interface parameters 2022-03-14 22:51:17 -07:00
Matt Nadareski
a7e9164f4f Use SourceArray for PE checks 2022-03-14 22:49:35 -07:00
Matt Nadareski
3820546c07 Use SourceArray for NE checks 2022-03-14 22:43:26 -07:00
Matt Nadareski
0fa6673d21 Add debug section (nw) 2022-03-14 15:27:42 -07:00
Matt Nadareski
0a486c2195 Add another Uplay check, note 2022-03-14 15:08:27 -07:00
Matt Nadareski
a723fbefc3 Add some resource checks for WTM 2022-03-14 15:00:20 -07:00
Matt Nadareski
70e64e57dd Add PE content checks for Uplay 2022-03-14 14:56:41 -07:00
Matt Nadareski
edfc3c6c5d Add PE checks for Steam 2022-03-14 12:16:38 -07:00
Matt Nadareski
c4447fc505 Modernize path check for SolidShield a little 2022-03-14 12:09:03 -07:00
Matt Nadareski
a1d2292381 Add content checks for key2AudioXS 2022-03-14 12:08:35 -07:00
Matt Nadareski
033fb0c1ac Add utility checks to ImpulseReactor 2022-03-14 11:56:18 -07:00
Matt Nadareski
e80034abf1 Simplify CDS code a bit 2022-03-14 11:52:49 -07:00
Matt Nadareski
27e4a6c452 Add comment to old interface 2022-03-14 11:31:57 -07:00
Matt Nadareski
914497b76f Slightly safer checks before invoking 2022-03-14 11:26:10 -07:00
Matt Nadareski
513e799aa3 Migrate protections to new interfaces 2022-03-14 11:20:11 -07:00
Matt Nadareski
fcbf006e4e Migrate packers to new interfaces 2022-03-14 11:00:17 -07:00
Matt Nadareski
bef26e0fd7 Add more helpers for NE/PE 2022-03-14 10:49:02 -07:00
Matt Nadareski
3dde84f683 Add new helpers for NE/PE specific 2022-03-14 10:45:01 -07:00
Matt Nadareski
74c6aa06e0 Add new interfaces 2022-03-14 10:43:08 -07:00
Matt Nadareski
ffb529edb3 Granularly separate out executable types 2022-03-14 10:40:44 -07:00
Matt Nadareski
d1279a471c Add NE Resident Name table structures 2022-03-14 10:01:01 -07:00
Matt Nadareski
a7f406537e Add more SecuROM checks (fixes #70) 2022-03-14 09:03:43 -07:00
Matt Nadareski
df7d5150c1 Add yet another Steam exe (fixes #92) 2022-03-14 08:54:58 -07:00
Matt Nadareski
73e4569b3b Clean up recent TAGES change 2022-03-09 14:35:38 -08:00
SilasLaspada
30c249ce74 Massively overhaul TAGES detection (#87)
* Massively overhaul TAGES detection

* Address TAGES PR comments

* Address further PR comments
2022-03-09 14:00:33 -08:00
Matt Nadareski
ec83669d7d Create Executable constructors 2022-03-08 23:03:26 -08:00
Matt Nadareski
e765fb6c0b Simplify PSX Anti-Modchip a little 2022-03-08 22:33:39 -08:00
Matt Nadareski
76465d30ec Change fileContent to sectionContent in SmartE 2022-03-08 22:30:12 -08:00
Matt Nadareski
71d3771c1d Add "check disc" to LaserLok 2022-03-07 13:44:10 -08:00
Matt Nadareski
bfd9c12163 Update nuget packages 2022-03-07 13:39:04 -08:00
Matt Nadareski
eb57065562 Aggregate paths instead of relying on breaking 2022-03-03 16:36:32 -08:00
Matt Nadareski
3875f3b8fb Fix potential off-by-one error 2022-03-02 14:58:29 -08:00
Matt Nadareski
8c2bedd21e Add test program parameters 2022-03-02 10:17:50 -08:00
Matt Nadareski
b199a6aa54 Update README 2022-03-02 09:12:59 -08:00
Matt Nadareski
1b1f64c2de Lock unknown checks behind debug flag
This also re-enables some previously commented out checks that could not be verified.
2022-03-02 08:56:26 -08:00
Matt Nadareski
7b73cc9d9b Add alternate checks for StarForce (fixes #79) 2022-02-10 11:06:35 -08:00
Matt Nadareski
d9d84a01e5 Fix crash in SolidShield scanning (fixes #76) 2022-02-10 10:37:57 -08:00
Matt Nadareski
56f009ac56 Fail slower on resource parsing (fixes #81) 2022-02-10 10:28:59 -08:00
Matt Nadareski
96daf90ae8 Update protection notes in README 2022-02-04 15:24:41 -08:00
Matt Nadareski
b581cb3124 Disable content checks for RPT/ProRing 2022-02-04 15:24:05 -08:00
Matt Nadareski
4b0e39b950 Add Steam API DLLs to detection 2022-02-04 15:19:24 -08:00
Matt Nadareski
3a1c476edc Remove StarForce directory checks for now (fixes #77) 2022-01-30 21:07:35 -08:00
Matt Nadareski
0d62d5336c Add older Uplay installer to file list 2022-01-15 11:46:38 -08:00
Matt Nadareski
cf87279dfc Add content notes to SafeLock 2021-11-24 21:59:54 -08:00
Matt Nadareski
0006f7932a Remove overly-broad CDS checks 2021-11-22 20:30:58 -08:00
Matt Nadareski
841a39c6c7 Overhaul SafeLock checks 2021-11-21 21:18:56 -08:00
Matt Nadareski
60b12f25a6 Disable SafeLock content check for now 2021-11-21 14:04:16 -08:00
SilasLaspada
f2b96b6c50 Fix InstallAnywhere reporting (#71)
* Fix InstallAnywhere reporting

* Fix formatting

* Fix formatting again
2021-11-20 23:22:10 -08:00
Matt Nadareski
d2fad1ab29 Fix Alpha-ROM... again (fixes #69) 2021-10-29 15:19:50 -07:00
Matt Nadareski
6f6755b218 Remove over-matching TAGES check 2021-10-27 23:08:16 -07:00
SilasLaspada
9a2f2e6f17 Add initial detection for InstallAnywhere (#67) 2021-10-26 10:23:08 -07:00
Matt Nadareski
d9ca550e3b Add ProRing path checks; add note (fixes #68) 2021-10-26 10:12:21 -07:00
Matt Nadareski
ec66e87ee6 Remove one note from Alpha-ROM 2021-10-21 21:33:50 -07:00
Matt Nadareski
53ce3aee74 Refine Alpha-ROM checks; add notes 2021-10-20 21:06:43 -07:00
Matt Nadareski
1ecb06f020 Bump AppVeyor version 2021-09-24 10:44:55 -07:00
Matt Nadareski
3ce4ac785e Comment out probable NE-only check 2021-09-23 15:13:57 -07:00
Matt Nadareski
1df157434d Remove debug print 2021-09-23 15:05:46 -07:00
Matt Nadareski
594f001dda Add NE check for CD-Cops; add notes 2021-09-23 15:05:30 -07:00
Matt Nadareski
c2c6bc268e Update README 2021-09-23 13:51:28 -07:00
Matt Nadareski
7aa2207edd Add PEtite detection; add notes 2021-09-23 13:43:57 -07:00
Matt Nadareski
22aa1642a6 Partial cleanup of CD/DVD-Cops; add notes 2021-09-23 13:33:48 -07:00
Matt Nadareski
844a9686af Bump version to 1.8.0 2021-09-22 11:06:34 -07:00
Matt Nadareski
8f929366b3 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-09-20 21:02:40 -07:00
Matt Nadareski
dfa0fab979 Update README 2021-09-20 21:02:14 -07:00
dependabot[bot]
415d6c587f Bump SharpCompress from 0.28.3 to 0.29.0 in /BurnOutSharp (#65)
Bumps [SharpCompress](https://github.com/adamhathcock/sharpcompress) from 0.28.3 to 0.29.0.
- [Release notes](https://github.com/adamhathcock/sharpcompress/releases)
- [Commits](https://github.com/adamhathcock/sharpcompress/compare/0.28.3...0.29)

---
updated-dependencies:
- dependency-name: SharpCompress
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-20 12:59:41 -07:00
Matt Nadareski
b1034b964e Update success/failure tracking in AppVeyor 2021-09-16 14:40:49 -07:00
Matt Nadareski
85d2382680 Only use extra checks for NE executables in Wise 2021-09-15 15:44:26 -07:00
Matt Nadareski
a6e694fe5d Convert EXE Stealth to section based; add notes 2021-09-15 14:52:11 -07:00
Matt Nadareski
a579bfea1f Fix reading generic sections 2021-09-15 11:47:12 -07:00
Matt Nadareski
ba97abed44 Convert dotFuscator to section based 2021-09-15 11:45:35 -07:00
Matt Nadareski
9fe6b101bd Convert CDSHiELD SE to section-based 2021-09-15 11:01:51 -07:00
Matt Nadareski
1345182eea Update small things about Ring PROTECH 2021-09-14 23:01:44 -07:00
Matt Nadareski
a84ac8d3cc Update CodeLock with a few things; notes 2021-09-14 22:57:17 -07:00
Matt Nadareski
1eb07c52e5 Address comments in SolidShield 2021-09-14 14:31:03 -07:00
Matt Nadareski
0d75ee135c Combine SafeCast into SafeDisc; improvements 2021-09-14 13:56:43 -07:00
Matt Nadareski
c915f29c05 Minor formatting changes 2021-09-14 13:53:30 -07:00
Matt Nadareski
38d35d1991 Convert remaining XCP full content check 2021-09-14 11:51:01 -07:00
Matt Nadareski
dbc841cb7f Clean up formatting of remaining full content checks 2021-09-14 11:33:53 -07:00
Matt Nadareski
46f53221c9 Clean up ActiveMARK 2021-09-14 00:51:44 -07:00
Matt Nadareski
708fd01d1e Clean up CD Check 2021-09-13 23:46:59 -07:00
Matt Nadareski
4aa3ba0545 Disable possibly overly-broad CD Check check 2021-09-13 23:43:24 -07:00
Matt Nadareski
57499002d2 Use beginning seek 2021-09-13 23:16:57 -07:00
Matt Nadareski
630f628598 Update UnshieldSharp to 1.6.6 2021-09-13 11:19:55 -07:00
Matt Nadareski
d66c890b71 Combine SafeDisc and Lite 2021-09-12 16:03:58 -07:00
Matt Nadareski
2b5649588a Remove errant content checks from Bitpool 2021-09-12 13:43:08 -07:00
Matt Nadareski
5425578f78 Clean up Origin 2021-09-12 13:40:29 -07:00
Matt Nadareski
8c39adcc04 Simplify EA checks, add note to Registration 2021-09-11 23:03:56 -07:00
Matt Nadareski
7773b32847 Update comment in Inno 2021-09-11 22:48:05 -07:00
Matt Nadareski
143b261a67 Fix NE reading for Inno 2021-09-11 22:40:01 -07:00
Matt Nadareski
25fc2b9b04 Last easilly-removed fileContent reliance removal 2021-09-11 22:31:06 -07:00
Matt Nadareski
d6fd0c4d2c Reduce reliance on fileContent; add notes 2021-09-11 22:27:52 -07:00
Matt Nadareski
44c44be412 Read MS-DOS stub data directly; use with CExe 2021-09-11 21:54:38 -07:00
Matt Nadareski
7b71d7b4bf Fix resource parsing, fix MS-CAB SFX 2021-09-11 21:41:17 -07:00
Matt Nadareski
2c2aee6797 Add a couple of sections to raw read with notes 2021-09-11 21:10:29 -07:00
Matt Nadareski
afdd032f73 Start using more methods to make life easier 2021-09-11 21:03:36 -07:00
Matt Nadareski
9d52ca4b4c Fix invalid reads 2021-09-11 20:58:44 -07:00
Matt Nadareski
1bc8fe7ff6 Fix version finding for MS-CAB SFX 2021-09-11 16:58:05 -07:00
Matt Nadareski
6ab7a06dd5 Lock stream when reading raw section 2021-09-11 16:54:00 -07:00
Matt Nadareski
7195ed3587 Combine CD-Cops and DVD-Cops 2021-09-11 16:49:54 -07:00
Matt Nadareski
214e8d41c7 Pre-read 3 most commonly-used section data
This also adds comprehensive notes around the sections used in various protections, how they're used, and what we can do with them. It also adds a couple of various notes based on the findings from the protection audit
2021-09-11 16:47:25 -07:00
Matt Nadareski
bd9f583659 Add sections note to PE 2021-09-11 15:22:17 -07:00
Matt Nadareski
abbf0b7ff5 Work on PE export data section 2021-09-11 15:08:58 -07:00
Matt Nadareski
f2b9e3a31b Clean up a significant number of TODOs 2021-09-11 00:32:48 -07:00
Matt Nadareski
73dd669c20 Add and use byte array extension methods 2021-09-10 22:35:32 -07:00
Matt Nadareski
32390149f3 Identify and use .rsrc item for 321 Studios 2021-09-10 22:19:24 -07:00
Matt Nadareski
9e73d8762e Clean up StarForce; add notes 2021-09-10 22:15:49 -07:00
Matt Nadareski
09854b469e Remove redundant .rsrc check in SolidShield 2021-09-10 22:09:03 -07:00
Matt Nadareski
e817063e53 Remove debug write from NSIS 2021-09-10 22:05:43 -07:00
Matt Nadareski
7cdf6a8c79 Identify and use .rsrc item for MediaMax 2021-09-10 22:02:57 -07:00
Matt Nadareski
d87087dcfb Add note to Itenium 2021-09-10 21:58:27 -07:00
Matt Nadareski
7c27fcd8a4 Identify and use .rsrc item for EA 2021-09-10 21:52:31 -07:00
Matt Nadareski
56408ed9f4 Add note and future code in Executable 2021-09-10 21:45:34 -07:00
Matt Nadareski
bf385f0bbf Identify and use .rsrc item for NSIS 2021-09-10 21:45:14 -07:00
Matt Nadareski
2a6a2930c1 Handle some TODOs 2021-09-10 21:42:42 -07:00
Matt Nadareski
9f676732a4 A little extra safety 2021-09-10 20:59:39 -07:00
Matt Nadareski
44fac8cc92 Fix reading resource table from stream 2021-09-10 16:21:55 -07:00
Matt Nadareski
e510915098 Add note about streams 2021-09-10 16:15:20 -07:00
Matt Nadareski
b779f2f546 Only deserialze a file once per round of checks 2021-09-10 16:10:15 -07:00
Matt Nadareski
5344de96b2 Cleanup and bugfixes; additional notes 2021-09-10 15:32:37 -07:00
Matt Nadareski
1e70d960ba Remove unnecessary trims 2021-09-10 13:59:35 -07:00
Matt Nadareski
e03808fbc5 Fix trailing whitespace in resource strings 2021-09-10 13:54:12 -07:00
Matt Nadareski
373268a6a8 Convert resource checks to header checks 2021-09-10 13:51:32 -07:00
Matt Nadareski
905d440367 Process file info resources; cleanup; refactors 2021-09-10 02:58:59 -07:00
Matt Nadareski
5628cf8d73 Add Wix to the solution 2021-09-09 18:51:04 -07:00
Matt Nadareski
4aaea417f0 Make generic resource finding methods 2021-09-09 18:45:50 -07:00
Matt Nadareski
892886b730 Ensure CodePage package is installed 2021-09-09 16:32:24 -07:00
Matt Nadareski
1028050464 Use resource section to find assembly manifest 2021-09-09 16:29:17 -07:00
Matt Nadareski
af79b00bd6 Finalize resource reading 2021-09-09 16:05:17 -07:00
Matt Nadareski
dc9a581e1c Fix resource entry checking 2021-09-09 15:10:22 -07:00
Matt Nadareski
4d800fd644 Fix ResourceDirectoryString reading 2021-09-09 11:25:02 -07:00
Matt Nadareski
126e8827de Move WixToolset to separate folder now that it supports .NET Standard 2021-09-09 10:51:18 -07:00
Matt Nadareski
23c79d4452 Update WixToolset version 2021-09-09 10:44:05 -07:00
Matt Nadareski
173fc69a08 Update UnshieldSharp to 1.6.5 2021-09-09 10:37:51 -07:00
Matt Nadareski
0411278f1d Remove unused and outdated classes 2021-09-08 10:33:28 -07:00
Matt Nadareski
bb1f9bdcdc Remove search result 2021-09-08 10:28:50 -07:00
Matt Nadareski
9d5ab935de Add .txt2 check to SafeDisc 2021-09-08 10:28:35 -07:00
Matt Nadareski
1df9d145e4 Add another note to IContentCheck 2021-09-08 10:22:28 -07:00
Matt Nadareski
fba30949bd Fix one ActiveMARK check; add note 2021-09-08 10:14:02 -07:00
Matt Nadareski
198c320ad8 Convert XCP to section based; add note 2021-09-08 09:58:11 -07:00
Matt Nadareski
e798ba1104 Convert WTM to section based 2021-09-08 00:51:25 -07:00
Matt Nadareski
f8f02a54f6 Combine VOB into ProtectDISC; add notes
This also means that EVORE is no longer relevant to the code and has been fully removed.
2021-09-07 23:53:05 -07:00
Matt Nadareski
da01668cbe Convert 321Studios Activation to section based 2021-09-07 21:08:25 -07:00
Matt Nadareski
95770c63af Convert 3PLock to section based 2021-09-07 21:02:52 -07:00
Matt Nadareski
af6e5d7441 Partially convert TAGES to section based; add notes 2021-09-07 21:02:19 -07:00
Matt Nadareski
ae5bdcc97a Convert Sisiphus to section based 2021-09-06 13:58:16 -07:00
Matt Nadareski
0fc415fb34 Convert SVKP to header based; add note 2021-09-05 23:31:10 -07:00
Matt Nadareski
0fe30392d8 Add note to Steam 2021-09-05 23:29:48 -07:00
Matt Nadareski
77fc11289c Convert StarForce to section-based; add notes 2021-09-05 23:22:48 -07:00
Matt Nadareski
9d3969d4ce Remove debug output 2021-09-05 23:08:41 -07:00
Matt Nadareski
2ba2756a8f Partially convert SolidShield to section based; add notes 2021-09-05 23:02:55 -07:00
Matt Nadareski
53088b4e60 Convert SmartE to section based 2021-09-03 13:26:52 -07:00
Matt Nadareski
0dc83739e7 Add v8 white label notes to SecuROM 2021-09-03 11:16:15 -07:00
Matt Nadareski
e8a205b221 Convert SecuROM to section based; add notes 2021-09-02 22:32:06 -07:00
Matt Nadareski
02c3d3fb4a Add note to SafeLock 2021-09-02 16:09:29 -07:00
Matt Nadareski
2d3d66f077 Convert SafeDisc to section based; add notes 2021-09-02 15:22:33 -07:00
Matt Nadareski
a5f21adeee Add content matches to SafeCast; add notes 2021-09-02 09:30:37 -07:00
Matt Nadareski
cbb4cdddfa Add note to Ring PROTECH 2021-09-02 00:54:36 -07:00
Matt Nadareski
e6b898882d Add notes to PSX Anti-modchip 2021-09-01 23:12:16 -07:00
Matt Nadareski
3bd7f5c890 Convert ProtectDisc to section based 2021-09-01 23:09:01 -07:00
Matt Nadareski
39c20fd0cd Wrap file scanning in try/catch for more safety 2021-09-01 22:22:14 -07:00
Matt Nadareski
21117e81a3 Fix EVORE IsPEExecutable check 2021-09-01 16:10:06 -07:00
Matt Nadareski
df172b49db Add note to Origin 2021-09-01 14:15:38 -07:00
Matt Nadareski
1ae0f694de Convert EReg to fvinfo and section based; add note 2021-09-01 14:10:12 -07:00
Matt Nadareski
040aa8daf6 Convert MediaMax CD-3 to section based 2021-09-01 14:06:19 -07:00
Matt Nadareski
3b9aa2d45c Convert LaserLok to section based; add notes 2021-09-01 13:46:08 -07:00
Matt Nadareski
8705cac648 Convert ImpulseReactor to section based; add notes 2021-09-01 10:27:16 -07:00
Matt Nadareski
5a4e3caea8 Add note to Key-Lock 2021-08-31 22:57:28 -07:00
Matt Nadareski
593d4a35b7 Convert JoWood to section based; add notes 2021-08-31 22:56:57 -07:00
SilasLaspada
801eef5f37 Improve Steam detection (#62) 2021-08-31 22:22:47 -07:00
Matt Nadareski
a0ac0ea189 Convert Itenium to section based 2021-08-31 21:15:56 -07:00
Matt Nadareski
f249455b00 Convert GFWL to fvinfo and section based; add note 2021-08-31 20:53:17 -07:00
Matt Nadareski
8dbb8d9fe1 Disable Valve scanning until further notice 2021-08-31 20:33:32 -07:00
Matt Nadareski
ed698e05d8 Partially convert EA to section based; add notes 2021-08-30 15:08:14 -07:00
Matt Nadareski
47b189bf87 Improve CD-Key matching 2021-08-30 14:24:16 -07:00
Matt Nadareski
460eb78ecd Improve Setup Factory matching 2021-08-30 14:18:15 -07:00
Matt Nadareski
ffcaf4d16b Improve MS-CAB SFX matching 2021-08-30 12:08:17 -07:00
Matt Nadareski
64de357257 Remove debug from IIF again 2021-08-30 12:06:29 -07:00
Matt Nadareski
cc3f6622b4 Improve IIF matching 2021-08-30 11:47:49 -07:00
Matt Nadareski
f0b66d4bfb Improve NSIS matching 2021-08-30 11:40:14 -07:00
Matt Nadareski
9c32f663b0 Add notes to DVD-Cops 2021-08-30 10:02:40 -07:00
Matt Nadareski
e0e22d91e1 Add notes to CopyKiller 2021-08-30 10:00:18 -07:00
Matt Nadareski
dbc72cb4c2 Fix typo in Wise Installer 2021-08-29 22:39:34 -07:00
Matt Nadareski
17d6c6aa6b Have exception dump all info 2021-08-29 22:39:04 -07:00
Matt Nadareski
7be5916041 Partially convert CodeLock to section based; add note 2021-08-29 22:26:58 -07:00
Matt Nadareski
2d8a25178e Fix Cenega naming 2021-08-29 22:20:25 -07:00
Matt Nadareski
5195025849 Remove leftover debug in CD Check 2021-08-29 22:14:46 -07:00
Matt Nadareski
c3c2fc6171 Convert Cenga to section based; add note 2021-08-29 21:51:43 -07:00
Matt Nadareski
6fa5e9a67f Add note to CDSHiELDSE 2021-08-29 21:49:56 -07:00
Matt Nadareski
834018b325 Convert CD-Lock to section based 2021-08-29 21:49:14 -07:00
Matt Nadareski
027388f587 Add fvinfo to CDKey; add note 2021-08-29 21:40:25 -07:00
Matt Nadareski
6452d39de1 Partially convert CD-Cops to section based; add note 2021-08-29 21:38:19 -07:00
Matt Nadareski
6d78e2fff7 Partially convert CD Check to section based; add notes 2021-08-29 21:13:50 -07:00
Matt Nadareski
56ae245305 Partially convert CDS to section based; add note 2021-08-29 21:07:26 -07:00
Matt Nadareski
76b16ca6d4 Add note to Bitpool 2021-08-29 20:58:10 -07:00
Matt Nadareski
d0a174d71c Add note to AlphaROM 2021-08-29 20:56:48 -07:00
Matt Nadareski
8e62f12f61 Add note to ActiveMARK 2021-08-29 20:55:36 -07:00
Matt Nadareski
621bcdf380 Convert Wise to section based; add note 2021-08-29 20:52:00 -07:00
Matt Nadareski
1b54dd92ab Convert WZ-SFX to section and header based 2021-08-29 11:43:43 -07:00
Matt Nadareski
2b0a43ca3e Disable possibility of ReadLine in Valve check 2021-08-29 11:31:17 -07:00
Matt Nadareski
81ce49c219 Fix manifest description finding 2021-08-29 11:15:37 -07:00
Matt Nadareski
b287c7236b Fix NE header deserialization 2021-08-28 15:55:08 -07:00
Matt Nadareski
b63d4a3da0 Update EVORE 2021-08-28 00:13:19 -07:00
Matt Nadareski
e652e43cba Add more NE structures 2021-08-27 23:29:34 -07:00
Matt Nadareski
e6b2be1738 Formalize New Executable classes; renames 2021-08-27 22:34:57 -07:00
Matt Nadareski
d2606e21fe Convert WinRAR SFX to section based 2021-08-27 21:58:05 -07:00
Matt Nadareski
22235cbe84 Add Setup Factory version info checks; add notes 2021-08-27 21:49:14 -07:00
Matt Nadareski
6bd5fae1cd Add TODO on IContentCheck 2021-08-27 21:42:05 -07:00
Matt Nadareski
ebb20bbe5e Fix overmatching on JoWooDX; add note 2021-08-27 21:37:46 -07:00
Matt Nadareski
82d7395b79 Make PE parsing attempts safer 2021-08-27 21:32:12 -07:00
Matt Nadareski
451cb04714 Reduce StarForce over-matching check 2021-08-27 21:12:09 -07:00
Matt Nadareski
15e5feafef Add helper methods to PE class for later 2021-08-27 14:30:03 -07:00
Matt Nadareski
4d19bd27f0 Make MachineType enum values consistent 2021-08-27 14:29:38 -07:00
Matt Nadareski
2400f2d0ad Convert PEC to section based; add notes 2021-08-27 14:28:17 -07:00
Matt Nadareski
ee0193eb71 Clean up some usings, add note to NSIS 2021-08-27 13:30:24 -07:00
Matt Nadareski
eb76acb767 Add note to MS-CAB SFX 2021-08-27 13:13:41 -07:00
Matt Nadareski
6c77cccf53 Clarify and comment out in IIF 2021-08-27 12:03:00 -07:00
Matt Nadareski
b4ab969f88 Reorganize and create Resource-related things 2021-08-27 10:38:42 -07:00
Matt Nadareski
2de4f3f808 Continue exe organization, start IIF migration 2021-08-27 09:42:05 -07:00
Matt Nadareski
4b5d0980f7 Convert Installer VISE to section based 2021-08-26 23:18:55 -07:00
Matt Nadareski
2bdbad1ba6 Convert Inno Setup to section based 2021-08-26 23:07:04 -07:00
Matt Nadareski
3b634877d0 Add note to EXE Stealth 2021-08-26 22:22:15 -07:00
Matt Nadareski
2996bbb18f Add note to dotFuscator 2021-08-26 22:13:14 -07:00
Matt Nadareski
c4ca27608b Convert Advanced Installer to section based 2021-08-26 21:57:56 -07:00
Matt Nadareski
5a85ff2ad3 Clean up Armadillo, fix edge case 2021-08-26 21:47:44 -07:00
Matt Nadareski
a27b3cc43f Add old version UPX detection 2021-08-26 20:43:58 -07:00
Matt Nadareski
ea8f557097 Start converting Armadillo checks 2021-08-26 20:38:01 -07:00
Matt Nadareski
7bbed5985b A little EVORE cleanup 2021-08-26 16:05:38 -07:00
Matt Nadareski
0ec6dfb287 Use UPX as a guinea pig for new exe handling 2021-08-26 15:50:38 -07:00
Matt Nadareski
3b753c137b Fill out and fix way more executable stuff 2021-08-26 15:48:56 -07:00
Matt Nadareski
6cde7b8bef Reduce redundant code in content matchers now 2021-08-25 20:26:43 -07:00
Matt Nadareski
d26a89b8ab Add time elapsed to debug output 2021-08-25 20:25:45 -07:00
Matt Nadareski
3ab0bcc0ae ContentMatchSets are now expected in IContentCheck 2021-08-25 19:37:32 -07:00
Matt Nadareski
7548646ba2 Create and use the Tools namespace 2021-08-25 15:09:42 -07:00
Matt Nadareski
0b75c6f046 What I like about EVORE... 2021-08-25 14:23:11 -07:00
SilasLaspada
958d306f42 Fix NullReferenceExceptions (#59) 2021-08-24 23:13:27 -07:00
Matt Nadareski
742b25e4dd Split manifest reading into helper methods 2021-08-24 15:28:23 -07:00
Matt Nadareski
43845cf722 Rename position flag -> debug flag 2021-08-24 15:19:23 -07:00
Matt Nadareski
a2a0e5c2ee Clean up TODOs in IContentCheck 2021-08-24 15:19:10 -07:00
Matt Nadareski
93e8322ba5 Add skeleton code to MS-CAB SFX 2021-08-24 14:29:30 -07:00
Matt Nadareski
8a07c9cf4e Add byte array checks for IIF 2021-08-24 09:26:27 -07:00
Matt Nadareski
6049eda580 Add byte array checks for MS-CAB SFX 2021-08-24 09:13:58 -07:00
Matt Nadareski
177641894e Clean up MS-CAB SFX a little 2021-08-23 23:09:05 -07:00
Matt Nadareski
dc49335ace Add notes for later 2021-08-23 23:04:01 -07:00
SilasLaspada
3dcce8a8ac Add support for Intel Installation Framework detection (#57)
* Add support for Intel Installation Framework detection

* Address reviews
2021-08-23 22:56:31 -07:00
Matt Nadareski
04651d46d8 Clean up usings 2021-08-23 22:07:24 -07:00
Matt Nadareski
56aeded8eb String and EVORE cleanups 2021-08-23 22:05:18 -07:00
SilasLaspada
97c9c7e5ed Add support for Microsoft SFX CAB detection (#56)
* Add support for Microsoft SFX CAB detection

* Address reviews

* Simplify GetVersion

* Fix GetVersion
2021-08-23 22:03:28 -07:00
Matt Nadareski
a891391879 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-08-23 20:58:24 -07:00
Matt Nadareski
5aae9b01d4 Make file version finding safer 2021-08-23 20:45:13 -07:00
SilasLaspada
b74a370b11 Fix WTM false positive (#55) 2021-08-16 21:58:36 -07:00
Matt Nadareski
5e560661d4 Add extra try/catch around Valve archives 2021-07-31 21:41:06 -07:00
Matt Nadareski
93e450c2bf Update README for IS-Z 2021-07-21 14:21:39 -07:00
Matt Nadareski
cc762754c5 Add support of IS-Z archives 2021-07-21 13:40:32 -07:00
Matt Nadareski
7065436033 Update nuget packages 2021-07-21 13:33:52 -07:00
Matt Nadareski
debe091502 Update protection list 2021-07-19 23:02:04 -07:00
Matt Nadareski
80905b56cd Better attempt at narrowing down 2021-07-19 21:56:31 -07:00
Matt Nadareski
0a7cd8a69e Comment out broader UPX (NOS) check 2021-07-19 21:38:19 -07:00
Matt Nadareski
c3957977a2 Reorder StarForce 3-5 checks for accuracy 2021-07-18 21:56:15 -07:00
Matt Nadareski
ff602c77ed Improve GFWL support
Adds support for the previously-undetected Games for Windows LIVE - Zero Day Piracy Protection Module as well as adding a generic check for any other modules
2021-07-18 21:50:58 -07:00
Matt Nadareski
3667a5b57a Concurrent protection scans per file (#52)
* Move to ConcurrentDictionary

* Convert to ConcurrentQueue
2021-07-18 09:44:23 -07:00
Matt Nadareski
3ac57b1c0c Fix static matcher issues (fixes #51)
Note: This may result in slower, but more accurate, scans
2021-07-17 23:40:16 -07:00
Matt Nadareski
957d82b2f7 Add new SecuROM PA detection 2021-07-17 23:06:11 -07:00
Matt Nadareski
6d0817ad15 Path protections separator-agnostic (fixes #47) 2021-07-17 22:31:29 -07:00
Matt Nadareski
5b10e6d614 Add check note for Tivola 2021-07-17 21:54:47 -07:00
Matt Nadareski
2d39b8c532 Add more GFWL checks 2021-07-17 21:45:37 -07:00
Matt Nadareski
2ae860e8ca Add Tivola Ring Protection detection (fixes #45) 2021-07-17 21:17:45 -07:00
Matt Nadareski
9e21c28e52 Temporary fix for StarForce directory scan 2021-07-17 21:11:38 -07:00
Matt Nadareski
2f5053b49f Make StarForce checks AND not OR (fixes #46) 2021-07-17 17:08:15 -07:00
Matt Nadareski
7024136919 Make large file parsing safer (fixes #44) 2021-07-15 09:57:06 -07:00
SilasLaspada
c74b5b3d29 Improve Bitpool detection (#43)
* Improve Bitpool detection

* Address comments
2021-07-02 10:16:06 -07:00
SilasLaspada
9c3201aa4b Improve XCP detection to prevent false positives (#42)
* Improve XCP detection to prevent false positives

* Address comments
2021-07-01 20:51:40 -07:00
SilasLaspada
dfd1141635 Vastly improve WTM detection (#41)
* Fix false positive in WTM detection

* Forgot to improve part of the detection

* Vastly improve detection
2021-06-30 09:36:02 -07:00
SilasLaspada
1188cad5e6 Slightly improve PE Compact version detection (#40)
* Slightly improve PE Compact version detection

* Address comments

* Address comments
2021-06-24 11:58:38 -07:00
SilasLaspada
65fa2f8481 Greatly improve WinZip SFX version detection (#39) 2021-06-21 21:48:25 -07:00
SilasLaspada
475e0b9d91 Add support for detecting Installer VISE (#38)
* Add support for detecting Installer VISE

* Add comment about extraction
2021-06-05 15:08:10 -07:00
SilasLaspada
b76d09aa20 Improve Inno Setup detection (#37)
* Improve Inno Setup detection

* Split "GetVersion"

* Remove unneeded check

* Make version detection more robust

* Add Unicode version detection

* Address review comments
2021-06-05 11:46:04 -07:00
Matt Nadareski
9a931eae67 Bump version 2021-04-14 09:09:48 -07:00
Matt Nadareski
47caa714c4 Remove pause from Valve entirely 2021-04-14 09:08:36 -07:00
Matt Nadareski
6740011c11 Bump version to 1.6.0 2021-04-09 09:32:12 -07:00
SilasLaspada
732078f24d Improve Steam detection (#35)
* Improve Steam detection

* Alphabetize the order of detections
2021-04-03 21:25:22 -07:00
Matt Nadareski
5218aaaeb1 Remove all uses of Pause in Valve 2021-04-03 20:49:53 -07:00
Matt Nadareski
6b9df94613 Remove unused library from README 2021-04-02 16:02:39 -07:00
Matt Nadareski
b1ac88fc20 Use submodule for WixToolset.Dtf 2021-04-02 16:01:23 -07:00
Matt Nadareski
ca83019a58 Move wix mirror to backup 2021-04-02 15:51:46 -07:00
Matt Nadareski
d68272a5bb Use submodule for stormlibsharp
This also gets CascLibSharp for free. Maybe keep that in mind
2021-04-02 15:48:57 -07:00
Matt Nadareski
6ab0fd5e3b Move StormLibSharp mirror to backup 2021-04-02 15:38:59 -07:00
Matt Nadareski
a0034b8fa8 Use submodule for hllib 2021-04-02 15:34:47 -07:00
Matt Nadareski
a884737242 Move HLLib mirror to backup 2021-04-02 15:19:00 -07:00
Matt Nadareski
c7b3776386 Use submodule for libmspack4n 2021-04-02 15:17:26 -07:00
Matt Nadareski
b387c77179 Move libmspack4n mirror to backup 2021-04-02 15:09:56 -07:00
Matt Nadareski
f6b58223de Replace LessIO code mirror with submodule 2021-04-02 15:08:05 -07:00
Matt Nadareski
8960ad3b16 Backup current LessIO code mirror 2021-04-02 14:54:46 -07:00
Matt Nadareski
28e95f9eb7 Slight SolidShield cleanup 2021-04-01 15:00:22 -07:00
Matt Nadareski
0bf5065cbc Add future work note 2021-04-01 14:53:25 -07:00
Matt Nadareski
579c9c0f84 Fix missing SafeDisc version 2021-04-01 11:38:32 -07:00
Matt Nadareski
b2e8b66eae Fix SmartE overmatching 2021-04-01 11:20:13 -07:00
Matt Nadareski
80e71f43de Try to make structs more marshalable 2021-04-01 11:09:20 -07:00
Matt Nadareski
e0497e6fee Migrate SafeDisc to modern path checking 2021-04-01 10:38:50 -07:00
Matt Nadareski
18a78f44c0 Make EVORE a bit safer 2021-04-01 10:36:03 -07:00
Matt Nadareski
f9e7fd5725 Fix marshalling issue 2021-04-01 10:34:53 -07:00
Matt Nadareski
e9c1a170ad Move generic CD key to own file 2021-03-31 19:07:00 -07:00
SilasLaspada
9ce84c75dd Comment out an overmatching definition (#34) 2021-03-31 18:58:34 -07:00
Matt Nadareski
0bd5339b78 Update to UnshieldSharp 1.5.0 2021-03-29 14:35:06 -07:00
Matt Nadareski
e06b1987b9 Update to WiseUnpacker 1.0.2 2021-03-29 14:17:42 -07:00
Matt Nadareski
c8b271ac76 Port over executable header code from Wise 2021-03-25 15:53:45 -07:00
Matt Nadareski
1672c73a57 Fix PECompact scanning
Thanks Silas for noticing the regression
2021-03-25 15:25:15 -07:00
Matt Nadareski
32f6e0e8fc Further making test executable a bit nicer 2021-03-24 20:50:58 -07:00
Matt Nadareski
5c21de5a0f Make the test executable a bit nicer 2021-03-23 16:55:19 -07:00
Matt Nadareski
9f40a8c4c0 Perform some post-removal cleanup 2021-03-23 16:43:23 -07:00
Matt Nadareski
c179f29e2e Remove .NET Framework 4.7.2, update SharpCompress 2021-03-23 16:37:21 -07:00
Matt Nadareski
f9d6fce3bd Reduce boilerplate for directory checks 2021-03-23 13:35:12 -07:00
Matt Nadareski
aa83896963 Final batch of first pass for path check conversions 2021-03-23 10:36:14 -07:00
Matt Nadareski
7d13b8c9db Optimize checking with better caching 2021-03-23 10:04:09 -07:00
Matt Nadareski
921292e077 Static list of content matchers
This also includes some more path matcher conversions that I couldn't reasonably split out
2021-03-23 09:52:09 -07:00
Matt Nadareski
c3e7f0b99f Return empty not null 2021-03-23 08:47:36 -07:00
Matt Nadareski
b9cc5e9ada Second batch of path check conversions 2021-03-22 23:02:01 -07:00
Matt Nadareski
76d76b2bf2 Convert a few more path checks 2021-03-22 22:23:55 -07:00
Matt Nadareski
532e912a2d Accidental comment issue 2021-03-22 22:12:25 -07:00
Matt Nadareski
8ada667dfe Be consistent with var naming 2021-03-22 22:11:01 -07:00
Matt Nadareski
28a4f7ce82 File path should only get first match 2021-03-22 22:09:35 -07:00
Matt Nadareski
3a66183d0e Convert AACS to use new matching 2021-03-22 22:07:14 -07:00
Matt Nadareski
7f91346878 Fix assumptions for path matching 2021-03-22 22:06:55 -07:00
Matt Nadareski
2af0dc4a8c Don't include PDBs 2021-03-22 21:38:49 -07:00
Matt Nadareski
5240f2eb70 Simplify util method naming 2021-03-22 21:32:58 -07:00
Matt Nadareski
f25800510b MatchSet is abstract 2021-03-22 21:30:30 -07:00
Matt Nadareski
6400c954ef Split matchers more cleanly, comment better 2021-03-22 21:25:14 -07:00
Matt Nadareski
e43423d2c9 Fix misleading version results 2021-03-22 16:25:40 -07:00
Matt Nadareski
bc613a0413 Fix build 2021-03-22 11:44:16 -07:00
Matt Nadareski
e47a52dbe0 Use framework in even more content protections 2021-03-22 11:43:51 -07:00
Matt Nadareski
da165345b6 Use framework for more content protections 2021-03-22 11:13:14 -07:00
Matt Nadareski
8ea54328ef Use framework for WZ-SFX v2 checks 2021-03-22 10:22:56 -07:00
Matt Nadareski
a4aeebee68 Split content and path version checks 2021-03-22 10:04:33 -07:00
Matt Nadareski
95a61c3b28 Add path matching to util 2021-03-22 09:55:29 -07:00
Matt Nadareski
9aadf5e948 Add invariance 2021-03-22 01:26:33 -07:00
Matt Nadareski
129ac1bb78 More granular on path search 2021-03-22 01:18:49 -07:00
Matt Nadareski
e4278c55b7 Add path matching matcher 2021-03-22 01:11:59 -07:00
Matt Nadareski
7aca58a6c9 Better split matching code, fix UPX name 2021-03-22 00:41:18 -07:00
Matt Nadareski
ea022de022 Fix a couple things:
- Fix PECompact 2 version string
- Fix UPX (NOS Variant) over-matching
2021-03-21 23:14:37 -07:00
Matt Nadareski
bb4f16d91f Use content matching helper, part 6 2021-03-21 22:45:06 -07:00
Matt Nadareski
f1c165845f Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-21 22:37:25 -07:00
Matt Nadareski
15ae2441c3 Use content matching helper, part 5 2021-03-21 22:37:16 -07:00
SilasLaspada
6b8f8957de Add Advanced Installer Detection (#32)
* Add Advanced Installer Detection

* Updated README

* Address comments
2021-03-21 22:36:01 -07:00
Matt Nadareski
cf9bd99f3d Use content matching helper, part 4 2021-03-21 22:19:38 -07:00
SilasLaspada
557114d92d Add CExe detection (#30)
* Add CExe detection

* Optimize check
2021-03-21 21:39:01 -07:00
Matt Nadareski
d01826ffa4 Use content matching helper, part 3 2021-03-21 15:34:19 -07:00
Matt Nadareski
7e3ef544f0 Use content matching helper, part 2 2021-03-21 15:24:23 -07:00
Matt Nadareski
ab07eb96ce Use content matching helper, part 1 2021-03-21 14:30:37 -07:00
Matt Nadareski
7c53eaab13 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-21 14:04:19 -07:00
SilasLaspada
fad7d87282 Add WinRAR SFX detection and extraction (#31) 2021-03-21 14:03:47 -07:00
Matt Nadareski
578519169a Add helper method for simple content matches 2021-03-20 22:37:56 -07:00
Matt Nadareski
fe106d23ec Fix BD+ in reverse 2021-03-20 22:28:57 -07:00
Matt Nadareski
e1669f031f BD+ using BitConverter 2021-03-20 22:00:38 -07:00
SilasLaspada
9bff6d5fe1 Improve version detection (#29)
* Improve version detection

* Address comments

* Address comments

Co-authored-by: Matt Nadareski <mnadareski@outlook.com>
2021-03-20 21:29:19 -07:00
Matt Nadareski
544aaed9da Modify array finding, part 2 2021-03-20 20:47:56 -07:00
Matt Nadareski
b6b7a5e7aa Clean up terminology 2021-03-20 19:23:59 -07:00
Matt Nadareski
cdc4d509ee Modify array finding, part 1 2021-03-20 19:00:22 -07:00
Matt Nadareski
07882f7632 Create and use manifesr version utility 2021-03-20 17:34:31 -07:00
Matt Nadareski
deb3c01362 Merge branch 'master' of https://github.com/mnadareski/BurnOutSharp 2021-03-20 16:26:19 -07:00
SilasLaspada
a51b16aed2 Add Setup Factory detection (#28)
* Add Setup Factory detection

* Improve version detection

* Address comments
2021-03-20 16:18:17 -07:00
Matt Nadareski
0e7d98158e Split out generic online registration 2021-03-20 13:29:46 -07:00
Matt Nadareski
56d8518ee4 Comment out over-matching EA check 2021-03-19 17:31:53 -07:00
Matt Nadareski
8897fd8650 Make SafeDisc more like Tages path check 2021-03-19 15:56:07 -07:00
Matt Nadareski
6f811e43d0 Split method in Scanner too 2021-03-19 15:48:53 -07:00
Matt Nadareski
a2888e3371 Split IPathCheck method 2021-03-19 15:41:49 -07:00
SilasLaspada
30d3312d87 Added BD+ version detection (#26)
* Added BD+ version detection

* Address Comments

* Address comment

* Remove unnecessary assignment
2021-03-18 10:50:45 -07:00
SilasLaspada
854a257fd6 Implement AACS version detection (#25)
* Implement AACS version detection

* Address comments

* Address more comments

* Address comment
2021-03-17 22:27:37 -07:00
Matt Nadareski
28344c6e3f Add WinZip SFX to readme 2021-03-14 14:39:31 -07:00
SilasLaspada
11a82addd8 Implement BD+ detection (#24) 2021-03-14 14:23:24 -07:00
Matt Nadareski
152f6c7051 Reduce size of 32-bit checks 2021-03-14 14:16:54 -07:00
Matt Nadareski
bedbceafa7 Use NE headers for all 16-bit versions 2021-03-14 13:55:26 -07:00
Matt Nadareski
2f19bf7ceb SFX cleanup and add missing check 2021-03-14 00:19:10 -08:00
SilasLaspada
a39ae9facf Add support for WinZip SFX archives (#23)
* Add inital check for WinZip SFX archives

Every version of WinZip SFX has the string "WinZip Self-Extractor" in it,

* Add basic version detection

Versions 3+ and 2.x are identified radically differently, so make separate methods for them.

* Implement version 3+ detection

Should be very thorough detection, detects every 3+ file I have accurately.

* Cleanup code

General clanup

* Improve version 3+ detection

Use an XML string to determine the version.

* Harden against false positives

* Implement basic extraction

* Partial 2.X version detection

Very crude but effective 2.X detection for 2.0 versions

* Add version detection for 2.1 RC2 variants

* Add 2.1 version detection

* Add 2.2 version detection

Aside from clean-ups, this is the final functional addition

* Address comments
2021-03-13 20:18:03 -08:00
Matt Nadareski
56b234bc96 A little cleanup 2021-03-02 15:21:14 -08:00
Matt Nadareski
633fe23b80 Reflection
This change eliminates the need to explicitly list out every single protection in the same way now that we have interfaces that we can rely on.
2021-03-02 15:10:52 -08:00
Matt Nadareski
2867ce2e9a Add more EA CDKey checks (fixes #21) 2021-03-02 13:48:10 -08:00
Matt Nadareski
ac0e5e95a9 Add note to RPT scan 2021-03-02 13:34:15 -08:00
Matt Nadareski
e3bed19e79 Import WixToolset code as external 2021-03-02 13:09:15 -08:00
Matt Nadareski
73aae8118f Wrap in libmspack4n and LessIO as external code 2021-03-02 12:14:14 -08:00
Matt Nadareski
b3671a430e Swap order of params for IPathCheck 2021-02-26 11:02:10 -08:00
Matt Nadareski
54465ff4e7 Move both installers to packers 2021-02-26 09:34:07 -08:00
Matt Nadareski
52eef84374 Make InnoSetup like WiseInstaller 2021-02-26 09:32:41 -08:00
Matt Nadareski
f4310206e9 Add IScannable interface 2021-02-26 09:26:23 -08:00
Matt Nadareski
7cfa9649e4 Add IContentCheck interface 2021-02-26 01:26:49 -08:00
Matt Nadareski
c6eaafebbe Add IPathCheck interface 2021-02-26 00:32:09 -08:00
Matt Nadareski
df1e14b6c9 Rename NOS variant of UPX 2021-02-25 13:38:13 -08:00
Matt Nadareski
ad2d854969 Add versioned NOS check, fix naming 2021-02-25 11:27:08 -08:00
Matt Nadareski
61202a87fb Add UPX detection for odd cases 2021-02-25 11:13:57 -08:00
Matt Nadareski
9ebbeaed0f Make EA CDKey checks more robust 2021-02-23 13:16:25 -08:00
Matt Nadareski
aebc139d52 I lied, keep it separate 2021-02-20 22:13:48 -08:00
Matt Nadareski
0e82eea891 Origin is an EA protection 2021-02-20 22:06:18 -08:00
Matt Nadareski
7ec76acf2f Remove Cucko until more investigation 2021-02-20 13:16:52 -08:00
Matt Nadareski
21f17791ff No... that's not right 2021-02-19 21:26:49 -08:00
Matt Nadareski
fff5f2610a Add Cucko notes 2021-02-19 10:14:02 -08:00
Matt Nadareski
d574fb5e44 Fix link to MPF in README 2021-01-25 09:53:18 -08:00
Matt Nadareski
d8aacbcc5d Treat Wise internally a bit strangely 2021-01-25 09:51:16 -08:00
Matt Nadareski
6467ef97d5 Only scan Wise internals if scanning archives 2021-01-24 21:23:05 -08:00
Matt Nadareski
5ec4872b36 Fix framework string 2021-01-22 11:25:24 -08:00
Matt Nadareski
30bfff833f Bump version to 1.5.1 2021-01-22 11:10:19 -08:00
Matt Nadareski
e37d5a80ab Add .NET 5.0 target framework 2021-01-21 13:17:59 -08:00
Matt Nadareski
df1081507d Thrown exceptions get logged to file in Test 2021-01-21 13:17:34 -08:00
Matt Nadareski
a140e1c444 Fix MPQ extraction (fixes #16) 2021-01-21 11:54:05 -08:00
Matt Nadareski
f9a990b27b Rename this to be more accurate 2020-11-12 22:47:33 -08:00
Matt Nadareski
b841c7aa94 More comments in EVORE for later 2020-11-12 22:40:50 -08:00
Matt Nadareski
554520ae1f Less EVORE code to fail 2020-11-12 22:33:18 -08:00
Matt Nadareski
3155b3fe41 Move EVORE things around 2020-11-12 22:10:45 -08:00
Matt Nadareski
e52cfd244a Little more reorganization 2020-11-12 22:00:50 -08:00
Matt Nadareski
c52b22fb4e Split things out for executables 2020-11-12 21:58:06 -08:00
Matt Nadareski
b3f72bbbe1 Add EVORE note, VSCode stuff 2020-11-12 21:35:43 -08:00
Matt Nadareski
9ebcfdba53 Bump version to 1.5.0 2020-11-03 21:15:36 -08:00
Matt Nadareski
15f020cb06 Fix textfile content scan 2020-11-03 14:57:23 -08:00
Matt Nadareski
4b387f86c1 Hook up MediaMax to scan 2020-11-03 14:47:15 -08:00
Matt Nadareski
1a3a73a86d Add MediaMax CD-3 content detections 2020-11-03 14:41:05 -08:00
Matt Nadareski
31eff196e6 Forgot to fix path in Wise 2020-11-02 15:18:03 -08:00
Matt Nadareski
828d3403f1 Upgrade UnshieldSharp, re-enable ISCab for Core 2020-11-01 23:13:35 -08:00
Matt Nadareski
28d6d06033 Unshield uses zlib.net which isn't .NET Core... 2020-11-01 22:13:46 -08:00
Matt Nadareski
0a2477e1b3 Remove console writes, make LibCrypt read better 2020-11-01 21:53:42 -08:00
Matt Nadareski
01451d7009 A bit of cleanup 2020-11-01 16:01:45 -08:00
Matt Nadareski
cff9582bf5 Comment out one of the 3PLock checks 2020-11-01 14:30:32 -08:00
Matt Nadareski
428d839700 Remove outdated TODOs 2020-11-01 14:18:01 -08:00
Matt Nadareski
50db0044b0 Fix MSCab corner case of trailing periods 2020-11-01 14:06:46 -08:00
SilasLaspada
68b1ec7b3f Fix name of INTENIUM protection (#15)
Change ITENIUM to INTENIUM
2020-11-01 10:45:30 -08:00
Matt Nadareski
fd524e1d5c List archive formats in README 2020-10-31 23:57:02 -07:00
Matt Nadareski
ef581c3f36 Add note for MS-CAB 2020-10-31 23:29:27 -07:00
Matt Nadareski
64e67b8daa Gate non-core compatible includes 2020-10-31 23:17:03 -07:00
Matt Nadareski
8624350b82 Why am I doing this? 2020-10-31 22:44:26 -07:00
Matt Nadareski
e3b32fd974 Clear empty keys as you go 2020-10-31 21:20:16 -07:00
Matt Nadareski
6f789d2454 Fix output of in-archive files 2020-10-31 14:57:47 -07:00
Matt Nadareski
d365dd1164 More consistent naming 2020-10-31 14:48:25 -07:00
Matt Nadareski
aa3afd676b Add option for including packers in scan 2020-10-31 14:46:08 -07:00
Matt Nadareski
69a04ff825 Hook up ITENIUM 2020-10-31 14:43:27 -07:00
Matt Nadareski
938e1f94bb Fix CDCheck message (non-false-positive in XCP) 2020-10-31 14:19:41 -07:00
Matt Nadareski
3eda785a5a Skip files with no protection on output 2020-10-31 14:16:51 -07:00
Matt Nadareski
6b895fa7c8 Fix invalid UPX packing versions 2020-10-31 14:15:33 -07:00
Matt Nadareski
45e10a84ae Strip temp paths, add archive name as prefix 2020-10-31 14:14:35 -07:00
Matt Nadareski
81f0400790 Pass-thru scanner, better return types 2020-10-31 14:00:31 -07:00
Matt Nadareski
df90583f73 Scanner shouldn't include path intrinsically 2020-10-31 13:20:54 -07:00
Matt Nadareski
5b980e138a Add scanner to all archive signatures (nw) 2020-10-31 00:06:41 -07:00
Matt Nadareski
0dd71d72ca Add new, but unused, Scanner class 2020-10-30 23:56:27 -07:00
Matt Nadareski
a7364eab67 Comments and a better guard 2020-10-30 21:43:40 -07:00
Matt Nadareski
99013e3448 Separate out archive and non-archive in code 2020-10-30 21:14:07 -07:00
Matt Nadareski
7f5e93db95 Fix 3PLock scanning finally 2020-10-30 17:02:58 -07:00
Matt Nadareski
4aa9662ebe Update README 2020-10-30 09:16:16 -07:00
Matt Nadareski
68dc6c3139 Region-ize the executable scans 2020-10-30 09:11:17 -07:00
Matt Nadareski
8b99577c66 New namespace for packers 2020-10-30 09:09:16 -07:00
Matt Nadareski
20ea1b4427 Fix formatting 2020-10-30 09:02:48 -07:00
SilasLaspada
cf0c6126b9 Add support for detecting NSIS (#14) 2020-10-30 08:56:34 -07:00
Matt Nadareski
49eef3f45a Update README with changes 2020-10-29 11:07:00 -07:00
Matt Nadareski
23e852bbdb Add first ITENIUM check, not hooked up 2020-10-29 11:01:52 -07:00
Matt Nadareski
f182dccbf2 21 -> 321, add a couple protection notes 2020-10-29 10:05:56 -07:00
Matt Nadareski
2d2cff4d0e Add MSI extraction and scanning 2020-10-28 22:51:33 -07:00
Matt Nadareski
c0621a83cb Enable 21Studios scan 2020-10-28 22:51:14 -07:00
Matt Nadareski
3c5da9f7ec Add 21Studios activator detection 2020-10-28 22:49:55 -07:00
Matt Nadareski
a7b5288277 One more EA CDKey detection 2020-10-28 21:03:45 -07:00
Matt Nadareski
fee980e048 CD Check has a valid case again 2020-10-28 16:33:20 -07:00
Matt Nadareski
21eac43e9f Remove unused vars 2020-10-28 13:31:15 -07:00
Matt Nadareski
b55698004c Make it blindingly obvious the files are from an archive 2020-10-28 13:25:58 -07:00
Matt Nadareski
40bdb9b2d9 Use 'i+1' during progress 2020-10-28 13:21:42 -07:00
Matt Nadareski
dfabb1a244 Strip out temp paths from results and progress 2020-10-28 13:17:26 -07:00
Matt Nadareski
cd5f9561bf Pre-scan progress indicator 2020-10-28 13:06:45 -07:00
Matt Nadareski
d8d6fac67e Fix issue with libmspack4n, again 2020-10-28 12:34:33 -07:00
Matt Nadareski
965c32482d Remove note 2020-10-28 12:24:04 -07:00
Matt Nadareski
c8c9d4ac64 Scan whole path for Wise 2020-10-28 12:23:25 -07:00
Matt Nadareski
5f5abf8a14 Scan whole path for Valve 2020-10-28 12:22:29 -07:00
Matt Nadareski
406791b938 Scan whole path for TAP 2020-10-28 12:21:59 -07:00
Matt Nadareski
eb2e6e7029 Scan whole path for 7zip 2020-10-28 12:21:44 -07:00
Matt Nadareski
9f0b41c6aa Scan whole path for RAR 2020-10-28 12:21:26 -07:00
Matt Nadareski
e2b72d8a5b Scan whole folder for PKZIP 2020-10-28 12:20:55 -07:00
Matt Nadareski
9802840309 Scan whole folder for MPQ 2020-10-28 12:20:36 -07:00
Matt Nadareski
4a6e2fd62d Scan whole folder for MSCab 2020-10-28 12:20:07 -07:00
Matt Nadareski
79c706e35a Scan whole folder for ISCab 2020-10-28 12:19:10 -07:00
Matt Nadareski
9be19d6925 Scan whole folder for BFPK 2020-10-28 12:17:10 -07:00
Matt Nadareski
0cfb9907d0 Make archives use full scan, not just content 2020-10-28 12:05:48 -07:00
Matt Nadareski
c18e9b3538 Combine EA protection checks, add/fix reg checks 2020-10-28 11:13:26 -07:00
Matt Nadareski
3754c3a65b Ensure mspack.dll exists for libmspack4n 2020-10-28 10:49:24 -07:00
Matt Nadareski
513a64df4c Rename Cucko and cleanup misc 2020-10-28 10:42:54 -07:00
Matt Nadareski
d18a51c7fa Add SolidShield wrapper check 2020-10-28 10:23:57 -07:00
Matt Nadareski
b43433b9ed Add more EA protection checks 2020-10-28 10:10:43 -07:00
Matt Nadareski
d553395f3f Reorder CDS path checks, change one to fit code 2020-10-27 17:13:35 -07:00
Matt Nadareski
28dbe8542b Add CDS content checks, fix XCP over-detection 2020-10-27 17:01:33 -07:00
Matt Nadareski
912e605dc8 Clarify SafeDisc version identifiers 2020-10-27 14:47:02 -07:00
Matt Nadareski
039982d02d Cleanup on Cactus for future dev work 2020-10-27 14:37:14 -07:00
Matt Nadareski
1a40c6cbb2 SafeDisc... one OR greater 2020-10-27 13:35:57 -07:00
Matt Nadareski
35921e3cac Be smarter about SecuROM strings 2020-10-26 23:30:35 -07:00
Matt Nadareski
a42040d644 Add UPX checking 2020-10-26 23:30:06 -07:00
Matt Nadareski
e1fb1c7bcf Minor renaming 2020-10-26 22:22:46 -07:00
Matt Nadareski
095de1441d Add XCP content checks (thanks to Silas) 2020-10-26 21:08:39 -07:00
Matt Nadareski
43cbafc0f5 Add better detection for XCP2 2020-10-26 20:34:47 -07:00
Matt Nadareski
9143e4c02c Disable CD Check in source due to false positives 2020-10-09 23:12:11 -07:00
244 changed files with 25696 additions and 8389 deletions

12
.gitmodules vendored Normal file
View File

@@ -0,0 +1,12 @@
[submodule "BurnOutSharp/External/stormlibsharp"]
path = BurnOutSharp/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

27
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,27 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Test/bin/Debug/netcoreapp3.1/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 Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

42
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,42 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Test/Test.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Test/Test.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/Test/Test.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@@ -1,18 +1,27 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29306.81
# Visual Studio Version 17
VisualStudioVersion = 17.1.32407.343
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BurnOutSharp", "BurnOutSharp\BurnOutSharp.csproj", "{1DA4212E-6071-4951-B45D-BB74A7838246}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{88735BA2-778D-4192-8EB2-FFF6843719E2}"
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
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HLLibSharp", "HLLibSharp\HLLibSharp\HLLibSharp.csproj", "{14E9764A-A8BF-44C0-A1A8-2C95EA307040}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibMSPackSharp", "LibMSPackSharp\LibMSPackSharp\LibMSPackSharp.csproj", "{BD8144B8-4857-47E6-9717-E9F2DB374A89}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Dtf.Compression.Cab", "Dtf\src\WixToolset.Dtf.Compression.Cab\WixToolset.Dtf.Compression.Cab.csproj", "{55B1D2D8-7470-4332-96EE-E18079C8A306}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Dtf.Compression", "Dtf\src\WixToolset.Dtf.Compression\WixToolset.Dtf.Compression.csproj", "{3065BE52-CB56-4557-80CD-E3AC57C242F2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +36,22 @@ Global
{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
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14E9764A-A8BF-44C0-A1A8-2C95EA307040}.Release|Any CPU.Build.0 = Release|Any CPU
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD8144B8-4857-47E6-9717-E9F2DB374A89}.Release|Any CPU.Build.0 = Release|Any CPU
{55B1D2D8-7470-4332-96EE-E18079C8A306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55B1D2D8-7470-4332-96EE-E18079C8A306}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55B1D2D8-7470-4332-96EE-E18079C8A306}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55B1D2D8-7470-4332-96EE-E18079C8A306}.Release|Any CPU.Build.0 = Release|Any CPU
{3065BE52-CB56-4557-80CD-E3AC57C242F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3065BE52-CB56-4557-80CD-E3AC57C242F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3065BE52-CB56-4557-80CD-E3AC57C242F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3065BE52-CB56-4557-80CD-E3AC57C242F2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472;net48;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Title>BurnOutSharp</Title>
<AssemblyName>BurnOutSharp</AssemblyName>
<Description>Port of BurnOut to C#, with additions</Description>
<Authors>Matt Nadareski;Gernot Knippen</Authors>
<Product>BurnOutSharp</Product>
<Copyright>Copyright (c)2005-2010 Gernot Knippen, Copyright (c)2018-2020 Matt Nadareski</Copyright>
<Copyright>Copyright (c)2005-2010 Gernot Knippen, Copyright (c)2018-2022 Matt Nadareski</Copyright>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
<Version>1.4.1</Version>
<AssemblyVersion>1.4.1</AssemblyVersion>
<FileVersion>1.04.1</FileVersion>
<Version>2.3.0</Version>
<AssemblyVersion>2.3.0</AssemblyVersion>
<FileVersion>2.3.0</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
@@ -22,14 +22,28 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LessIO" Version="0.6.16" />
<PackageReference Include="libmspack4n" Version="0.9.10" />
<PackageReference Include="SharpCompress" Version="0.26.0" />
<PackageReference Include="UnshieldSharp" Version="1.4.2.3" />
<PackageReference Include="WiseUnpacker" Version="1.0.1" />
<PackageReference Include="zlib.net" Version="1.0.4" />
<PackageReference Include="OpenMcdf" Version="2.2.1.9" />
<PackageReference Include="SharpCompress" Version="0.32.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="1.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="UnshieldSharp" Version="1.6.8" />
<PackageReference Include="WiseUnpacker" Version="1.0.3" />
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.6" />
</ItemGroup>
<!-- These are needed for dealing with submodules -->
<PropertyGroup>
<DefaultItemExcludes>
$(DefaultItemExcludes);
**\AssemblyInfo.cs;
External\stormlibsharp\lib\**;
External\stormlibsharp\TestConsole\**
</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE.txt" Pack="true" PackagePath="$(PackageLicenseFile)" />
</ItemGroup>
@@ -40,12 +54,12 @@
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</None>
<None Include="*.pdb" Pack="true">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</None>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dtf\src\WixToolset.Dtf.Compression.Cab\WixToolset.Dtf.Compression.Cab.csproj" />
<ProjectReference Include="..\HLLibSharp\HLLibSharp\HLLibSharp.csproj" />
<ProjectReference Include="..\LibMSPackSharp\LibMSPackSharp\LibMSPackSharp.csproj" />
</ItemGroup>
</Project>

BIN
BurnOutSharp/CascLib.dll Normal file

Binary file not shown.

View File

@@ -1,446 +0,0 @@
//this file is part of BurnOut
//Copyright (C)2005-2010 Gernot Knippen
//Ported code with augments Copyright (C)2018 Matt Nadareski
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You can get a copy of the GNU General Public License
//by writing to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace BurnOutSharp
{
internal static class EVORE
{
private struct Section
{
public uint iVirtualSize;
public uint iVirtualOffset;
public uint iRawOffset;
}
private const int WaitSeconds = 20;
private static Process StartSafe(string file)
{
if (file == null || !File.Exists(file))
return null;
Process startingprocess = new Process();
startingprocess.StartInfo.FileName = file;
startingprocess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
startingprocess.StartInfo.CreateNoWindow = true;
startingprocess.StartInfo.ErrorDialog = false;
try
{
startingprocess.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
return startingprocess;
}
private static string MakeTempFile(byte[] fileContent, string sExtension = ".exe")
{
string filei = Guid.NewGuid().ToString();
string tempPath = Path.Combine(Path.GetTempPath(), "tmp", $"{filei}{sExtension}");
try
{
File.Delete(tempPath);
}
catch { }
try
{
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(tempPath)))
{
bw.Write(fileContent);
}
return Path.GetFullPath(tempPath);
}
catch { }
return null;
}
private static bool IsEXE(byte[] fileContent)
{
int PEHeaderOffset = BitConverter.ToInt32(fileContent, 60);
short Characteristics = BitConverter.ToInt16(fileContent, PEHeaderOffset + 22);
// Check if file is dll
if ((Characteristics & 0x2000) == 0x2000)
return false;
else
return true;
}
private static string[] CopyDependentDlls(string file, byte[] fileContent)
{
Section[] sections = ReadSections(fileContent);
long lastPosition;
string[] saDependentDLLs = null;
int index = 60;
int PEHeaderOffset = BitConverter.ToInt32(fileContent, index);
index = PEHeaderOffset + 120 + 8; //120 Bytes till IMAGE_DATA_DIRECTORY array,8 Bytes=size of IMAGE_DATA_DIRECTORY
uint ImportTableRVA = BitConverter.ToUInt32(fileContent, index);
index += 4;
uint ImportTableSize = BitConverter.ToUInt32(fileContent, index);
index = (int)RVA2Offset(ImportTableRVA, sections);
index += 12;
uint DllNameRVA = BitConverter.ToUInt32(fileContent, index);
index += 4;
while (DllNameRVA != 0)
{
string sDllName = "";
byte bChar;
lastPosition = index;
uint DLLNameOffset = RVA2Offset(DllNameRVA, sections);
if (DLLNameOffset > 0)
{
index = (int)DLLNameOffset;
if ((char)fileContent[index] > -1)
{
do
{
bChar = fileContent[index];
index++;
sDllName += (char)bChar;
} while (bChar != 0 && (char)fileContent[index] > -1);
sDllName = sDllName.Remove(sDllName.Length - 1, 1);
if (File.Exists(Path.Combine(Path.GetDirectoryName(file), sDllName)))
{
if (saDependentDLLs == null)
saDependentDLLs = new string[0];
else
saDependentDLLs = new string[saDependentDLLs.Length];
FileInfo fiDLL = new FileInfo(Path.Combine(Path.GetDirectoryName(file), sDllName));
saDependentDLLs[saDependentDLLs.Length - 1] = fiDLL.CopyTo(Path.GetTempPath() + sDllName, true).FullName;
}
}
index = (int)lastPosition;
}
index += 4 + 12;
DllNameRVA = BitConverter.ToUInt32(fileContent, index);
index += 4;
}
return saDependentDLLs;
}
private static Section[] ReadSections(byte[] fileContent)
{
if (fileContent == null)
return null;
uint PEHeaderOffset = BitConverter.ToUInt32(fileContent, 60);
ushort NumberOfSections = BitConverter.ToUInt16(fileContent, (int)PEHeaderOffset + 6);
Section[] sections = new Section[NumberOfSections];
int index = (int)PEHeaderOffset + 120 + 16 * 8;
for (int i = 0; i < NumberOfSections; i++)
{
index += 8;
uint ivs = BitConverter.ToUInt32(fileContent, index);
index += 4;
uint ivo = BitConverter.ToUInt32(fileContent, index);
index += 4;
index += 4;
uint iro = BitConverter.ToUInt32(fileContent, index);
index += 4;
index += 16;
sections[i] = new Section()
{
iVirtualSize = ivs,
iVirtualOffset = ivo,
iRawOffset = iro,
};
}
return sections;
}
private static uint RVA2Offset(uint RVA, Section[] sections)
{
int i = 0;
while (i != sections.Length)
{
if (sections[i].iVirtualOffset <= RVA && sections[i].iVirtualOffset + sections[i].iVirtualSize > RVA)
return RVA - sections[i].iVirtualOffset + sections[i].iRawOffset;
i++;
}
return 0;
}
#region "EVORE version-search-functions"
public static string SearchProtectDiscVersion(string file, byte[] fileContent)
{
string version = "";
DateTime timestart;
if (!IsEXE(fileContent))
return "";
string tempexe = MakeTempFile(fileContent);
string[] DependentDlls = CopyDependentDlls(file, fileContent);
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "a*.tmp"));
}
catch { }
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "PCD*.sys"));
}
catch { }
if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc")))
{
try
{
File.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc", "p*.dll"));
}
catch { }
}
Process exe = StartSafe(tempexe);
if (exe == null)
return "";
Process[] processes = new Process[0];
timestart = DateTime.Now;
do
{
exe.Refresh();
string[] files = null;
//check for ProtectDisc 8.2-x
if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc")))
{
files = Directory.GetFiles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc"), "p*.dll");
}
if (files != null)
{
if (files.Length > 0)
{
FileVersionInfo fvinfo = FileVersionInfo.GetVersionInfo(files[0]);
if (fvinfo.FileVersion != "")
{
version = fvinfo.FileVersion.Replace(" ", "").Replace(",", ".");
//ProtectDisc 9 uses a ProtectDisc-Core dll version 8.0.x
if (version.StartsWith("8.0"))
version = "";
fvinfo = null;
break;
}
}
}
//check for ProtectDisc 7.1-8.1
files = Directory.GetFiles(Path.GetTempPath(), "a*.tmp");
if (files.Length > 0)
{
FileVersionInfo fvinfo = FileVersionInfo.GetVersionInfo(files[0]);
if (fvinfo.FileVersion != "")
{
version = fvinfo.FileVersion.Replace(" ", "").Replace(",", ".");
fvinfo = null;
break;
}
}
if (exe.HasExited)
break;
processes = Process.GetProcessesByName(exe.ProcessName);
if (processes.Length == 2)
{
processes[0].Refresh();
processes[1].Refresh();
if (processes[1].WorkingSet64 > exe.WorkingSet64)
exe = processes[1];
else if (processes[0].WorkingSet64 > exe.WorkingSet64) //else if (processes[0].Modules.Count > exe.Modules.Count)
exe = processes[0];
}
} while (processes.Length > 0 && DateTime.Now.Subtract(timestart).TotalSeconds < WaitSeconds);
Thread.Sleep(500);
if (!exe.HasExited)
{
processes = Process.GetProcessesByName(exe.ProcessName);
if (processes.Length == 2)
{
try
{
processes[0].Kill();
}
catch { }
processes[0].Close();
try
{
processes[1].Kill();
}
catch { }
}
else
{
exe.Refresh();
try
{
exe.Kill();
}
catch { }
}
}
exe.Close();
Thread.Sleep(500);
if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc")))
{
try
{
File.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc", "p*.dll"));
}
catch { }
}
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "a*.tmp"));
}
catch { }
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "PCD*.sys"));
}
catch { }
File.Delete(tempexe);
if (DependentDlls != null)
{
for (int i = 0; i < DependentDlls.Length; i++)
{
try
{
File.Delete(DependentDlls[i]);
}
catch (Exception ex)
{
Console.WriteLine("!error while deleting file " + DependentDlls[i] + "; " + ex.Message);
}
}
}
return version;
}
public static string SearchSafeDiscVersion(string file, byte[] fileContent)
{
Process exe = new Process();
string version = "";
DateTime timestart;
if (!IsEXE(fileContent))
return "";
string tempexe = MakeTempFile(fileContent);
string[] DependentDlls = CopyDependentDlls(file, fileContent);
try
{
Directory.Delete(Path.Combine(Path.GetTempPath(), "~e*"), true);
}
catch { }
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "~e*"));
}
catch { }
exe = StartSafe(tempexe);
if (exe == null)
return "";
timestart = DateTime.Now;
do
{
if (Directory.GetDirectories(Path.GetTempPath(), "~e*").Length > 0)
{
string[] files = Directory.GetFiles(Directory.GetDirectories(Path.GetTempPath(), "~e*")[0], "~de*.tmp");
if (files.Length > 0)
{
StreamReader sr;
try
{
sr = new StreamReader(files[0], Encoding.Default);
string FileContent = sr.ReadToEnd();
sr.Close();
int position = FileContent.IndexOf("%ld.%ld.%ld, %ld, %s,") - 1;
if (position > -1)
version = FileContent.Substring(position + 28, 12);
break;
}
catch { }
}
}
} while (!exe.HasExited && DateTime.Now.Subtract(timestart).TotalSeconds < WaitSeconds);
if (!exe.HasExited)
exe.Kill();
exe.Close();
try
{
Directory.Delete(Path.Combine(Path.GetTempPath(), "~e*"), true);
}
catch { }
try
{
File.Delete(Path.Combine(Path.GetTempPath(), "~e*"));
File.Delete(tempexe);
}
catch { }
if (DependentDlls != null)
{
for (int i = 0; i < DependentDlls.Length; i--)
{
try
{
File.Delete(DependentDlls[i]);
}
catch (Exception ex)
{
Console.WriteLine("!error while deleting file " + DependentDlls[i] + "; " + ex.Message);
}
}
}
return version;
}
#endregion
}
}

View File

@@ -0,0 +1,74 @@
namespace BurnOutSharp.ExecutableType.Microsoft
{
/// <summary>
/// All constant values needed for file header reading
/// </summary>
internal static class Constants
{
public const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
public const ushort IMAGE_OS2_SIGNATURE = 0x454E; // NE
public const ushort IMAGE_OS2_SIGNATURE_LE = 0x454C; // LE
public const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
#region IMAGE_DOS_HEADER
public const ushort ENEWEXE = 0x40; // Value of E_LFARLC for new .EXEs
public const ushort ENEWHDR = 0x003C; // Offset in old hdr. of ptr. to new
public const ushort ERESWDS = 0x0010; // No. of reserved words (OLD)
public const ushort ERES1WDS = 0x0004; // No. of reserved words in e_res
public const ushort ERES2WDS = 0x000A; // No. of reserved words in e_res2
public const ushort ECP = 0x0004; // Offset in struct of E_CP
public const ushort ECBLP = 0x0002; // Offset in struct of E_CBLP
public const ushort EMINALLOC = 0x000A; // Offset in struct of E_MINALLOC
#endregion
#region IMAGE_OS2_HEADER
public const ushort NERESWORDS = 3; // 6 bytes reserved
public const ushort NECRC = 8; //Offset into new header of NE_CRC
#endregion
#region NewSeg
public const ushort NSALIGN = 9; // Segment data aligned on 512 byte boundaries
public const ushort NSLOADED = 0x0004; // ns_sector field contains memory addr
#endregion
#region RsrcNameInfo
public const ushort RSORDID = 0x8000; /* if high bit of ID set then integer id */
/* otherwise ID is offset of string from
the beginning of the resource table */
/* Ideally these are the same as the */
/* corresponding segment flags */
public const ushort RNMOVE = 0x0010; /* Moveable resource */
public const ushort RNPURE = 0x0020; /* Pure (read-only) resource */
public const ushort RNPRELOAD = 0x0040; /* Preloaded resource */
public const ushort RNDISCARD = 0xF000; /* Discard priority level for resource */
#endregion
#region IMAGE_OPTIONAL_HEADER
public const ushort IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
#endregion
#region IMAGE_SECTION_HEADER
public const int IMAGE_SIZEOF_SHORT_NAME = 8;
#endregion
#region IMAGE_RESOURCE_DATA_ENTRY
public const uint IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000;
public const uint IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000;
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.MZ.Headers
{
/// <summary>
/// The MS-DOS EXE format, also known as MZ after its signature (the initials of Microsoft engineer Mark Zbykowski),
/// was introduced with MS-DOS 2.0 (version 1.0 only sported the simple COM format). It is designed as a relocatable
/// executable running under real mode. As such, only DOS and Windows 9x can use this format natively, but there are
/// several free DOS emulators (e.g., DOSBox) that support it and that run under various operating systems (e.g.,
/// Linux, Amiga, Windows NT, etc.). Although they can exist on their own, MZ executables are embedded in all NE, LE,
/// and PE executables, usually as stubs so that when they are ran under DOS, they display a warning.
/// </summary>
/// <remarks>https://wiki.osdev.org/MZ</remarks>
public class MSDOSExecutableHeader
{
#region Standard Fields
/// <summary>
/// 0x5A4D (ASCII for 'M' and 'Z') [00]
/// </summary>
public ushort Magic;
/// <summary>
/// Number of bytes in the last page. [02]
/// </summary>
public ushort LastPageBytes;
/// <summary>
/// Number of whole/partial pages. [04]
/// </summary>
public ushort Pages;
/// <summary>
/// Number of entries in the relocation table. [06]
/// </summary>
public ushort Relocations;
/// <summary>
/// The number of paragraphs taken up by the header.It can be any value, as the loader
/// just uses it to find where the actual executable data starts. It may be larger than
/// what the "standard" fields take up, and you may use it if you want to include your
/// own header metadata, or put the relocation table there, or use it for any other purpose. [08]
/// </summary>
public ushort HeaderParagraphSize;
/// <summary>
/// The number of paragraphs required by the program, excluding the PSP and program image.
/// If no free block is big enough, the loading stops. [0A]
/// </summary>
public ushort MinimumExtraParagraphs;
/// <summary>
/// The number of paragraphs requested by the program.
/// If no free block is big enough, the biggest one possible is allocated. [0C]
/// </summary>
public ushort MaximumExtraParagraphs;
/// <summary>
/// Relocatable segment address for SS. [0E]
/// </summary>
public ushort InitialSSValue;
/// <summary>
/// Initial value for SP. [10]
/// </summary>
public ushort InitialSPValue;
/// <summary>
/// When added to the sum of all other words in the file, the result should be zero. [12]
/// </summary>
public ushort Checksum;
/// <summary>
/// Initial value for IP. [14]
/// </summary>
public ushort InitialIPValue;
/// <summary>
/// Relocatable segment address for CS. [16]
/// </summary>
public ushort InitialCSValue;
/// <summary>
/// The (absolute) offset to the relocation table. [18]
/// </summary>
public ushort RelocationTableAddr;
/// <summary>
/// Value used for overlay management.
/// If zero, this is the main executable. [1A]
/// </summary>
public ushort OverlayNumber;
#endregion
#region PE Extensions
/// <summary>
/// Reserved words [1C]
/// </summary>
public ushort[] Reserved1;
/// <summary>
/// Defined by name but no other information is given; typically zeroes [24]
/// </summary>
public ushort OEMIdentifier;
/// <summary>
/// Defined by name but no other information is given; typically zeroes [26]
/// </summary>
public ushort OEMInformation;
/// <summary>
/// Reserved words [28]
/// </summary>
public ushort[] Reserved2;
/// <summary>
/// Starting address of the PE header [3C]
/// </summary>
public int NewExeHeaderAddr;
#endregion
/// <summary>
/// All data after the last item in the header but before the new EXE header address
/// </summary>
public byte[] ExecutableData;
public static MSDOSExecutableHeader Deserialize(Stream stream, bool asStub = true)
{
MSDOSExecutableHeader idh = new MSDOSExecutableHeader();
idh.Magic = stream.ReadUInt16();
idh.LastPageBytes = stream.ReadUInt16();
idh.Pages = stream.ReadUInt16();
idh.Relocations = stream.ReadUInt16();
idh.HeaderParagraphSize = stream.ReadUInt16();
idh.MinimumExtraParagraphs = stream.ReadUInt16();
idh.MaximumExtraParagraphs = stream.ReadUInt16();
idh.InitialSSValue = stream.ReadUInt16();
idh.InitialSPValue = stream.ReadUInt16();
idh.Checksum = stream.ReadUInt16();
idh.InitialIPValue = stream.ReadUInt16();
idh.InitialCSValue = stream.ReadUInt16();
idh.RelocationTableAddr = stream.ReadUInt16();
idh.OverlayNumber = stream.ReadUInt16();
// If we're not reading as a stub, return now
if (!asStub)
return idh;
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = stream.ReadUInt16();
}
idh.OEMIdentifier = stream.ReadUInt16();
idh.OEMInformation = stream.ReadUInt16();
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = stream.ReadUInt16();
}
idh.NewExeHeaderAddr = stream.ReadInt32();
idh.ExecutableData = stream.ReadBytes(idh.NewExeHeaderAddr - (int)stream.Position);
return idh;
}
public static MSDOSExecutableHeader Deserialize(byte[] content, ref int offset, bool asStub = true)
{
MSDOSExecutableHeader idh = new MSDOSExecutableHeader();
idh.Magic = content.ReadUInt16(ref offset);
idh.LastPageBytes = content.ReadUInt16(ref offset);
idh.Pages = content.ReadUInt16(ref offset);
idh.Relocations = content.ReadUInt16(ref offset);
idh.HeaderParagraphSize = content.ReadUInt16(ref offset);
idh.MinimumExtraParagraphs = content.ReadUInt16(ref offset);
idh.MaximumExtraParagraphs = content.ReadUInt16(ref offset);
idh.InitialSSValue = content.ReadUInt16(ref offset);
idh.InitialSPValue = content.ReadUInt16(ref offset);
idh.Checksum = content.ReadUInt16(ref offset);
idh.InitialIPValue = content.ReadUInt16(ref offset);
idh.InitialCSValue = content.ReadUInt16(ref offset);
idh.RelocationTableAddr = content.ReadUInt16(ref offset);
idh.OverlayNumber = content.ReadUInt16(ref offset);
// If we're not reading as a stub, return now
if (!asStub)
return idh;
idh.Reserved1 = new ushort[Constants.ERES1WDS];
for (int i = 0; i < Constants.ERES1WDS; i++)
{
idh.Reserved1[i] = content.ReadUInt16(ref offset);
}
idh.OEMIdentifier = content.ReadUInt16(ref offset);
idh.OEMInformation = content.ReadUInt16(ref offset);
idh.Reserved2 = new ushort[Constants.ERES2WDS];
for (int i = 0; i < Constants.ERES2WDS; i++)
{
idh.Reserved2[i] = content.ReadUInt16(ref offset);
}
idh.NewExeHeaderAddr = content.ReadInt32(ref offset);
idh.ExecutableData = content.ReadBytes(ref offset, idh.NewExeHeaderAddr - offset);
return idh;
}
}
}

View File

@@ -0,0 +1,79 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
{
/// <summary>
/// These name strings are case-sensitive and are not null-terminated
/// </summary>
public class ResidentNameTableEntry
{
/// <summary>
/// Length of the name string that follows.
/// A zero value indicates the end of the name table.
/// </summary>
public byte Length;
/// <summary>
/// ASCII text of the name string.
/// </summary>
public byte[] Data;
/// <summary>
/// Ordinal number (index into entry table).
/// This value is ignored for the module name.
/// </summary>
public ushort OrdinalNumber;
/// <summary>
/// ASCII text of the name string
/// </summary>
public string DataAsString
{
get
{
if (Data == null)
return string.Empty;
// Try to read direct as ASCII
try
{
return Encoding.ASCII.GetString(Data);
}
catch { }
// If ASCII encoding fails, then just return an empty string
return string.Empty;
}
}
public static ResidentNameTableEntry Deserialize(Stream stream)
{
var rnte = new ResidentNameTableEntry();
rnte.Length = stream.ReadByteValue();
if (rnte.Length == 0)
return rnte;
rnte.Data = stream.ReadBytes(rnte.Length);
rnte.OrdinalNumber = stream.ReadUInt16();
return rnte;
}
public static ResidentNameTableEntry Deserialize(byte[] content, ref int offset)
{
var rnte = new ResidentNameTableEntry();
rnte.Length = content.ReadByte(ref offset);
if (rnte.Length == 0)
return rnte;
rnte.Data = content.ReadBytes(ref offset, rnte.Length);
rnte.OrdinalNumber = content.ReadUInt16(ref offset);
return rnte;
}
}
}

View File

@@ -0,0 +1,44 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
{
/// <summary>
/// Resource type and name strings
/// </summary>
public class ResourceNameString
{
/// <summary>
/// Length of the type or name string that follows. A zero value
/// indicates the end of the resource type and name string, also
/// the end of the resource table.
/// </summary>
public byte Length;
/// <summary>
/// ASCII text of the type or name string.
/// </summary>
public char[] Value;
public static ResourceNameString Deserialize(Stream stream)
{
var rns = new ResourceNameString();
rns.Length = stream.ReadByteValue();
rns.Value = stream.ReadChars(rns.Length, Encoding.ASCII);
return rns;
}
public static ResourceNameString Deserialize(byte[] content, ref int offset)
{
var rns = new ResourceNameString();
rns.Length = content.ReadByte(ref offset);
rns.Value = Encoding.ASCII.GetChars(content, offset, rns.Length); offset += rns.Length;
return rns;
}
}
}

View File

@@ -0,0 +1,75 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
{
/// <summary>
/// A table of resources for this type
/// </summary>
public class ResourceTableEntry
{
/// <summary>
/// File offset to the contents of the resource data,
/// relative to beginning of file. The offset is in terms
/// of the alignment shift count value specified at
/// beginning of the resource table.
/// </summary>
public ushort Offset;
/// <summary>
/// Length of the resource in the file (in bytes).
/// </summary>
public ushort Length;
/// <summary>
/// Resource flags
/// </summary>
public ResourceTableEntryFlags Flags;
/// <summary>
/// This is an integer type if the high-order
/// bit is set (8000h), otherwise it is the offset to the
/// resource string, the offset is relative to the
/// beginning of the resource table.
/// </summary>
public ushort ResourceID;
/// <summary>
/// Reserved.
/// </summary>
public ushort Handle;
/// <summary>
/// Reserved.
/// </summary>
public ushort Usage;
public static ResourceTableEntry Deserialize(Stream stream)
{
var ni = new ResourceTableEntry();
ni.Offset = stream.ReadUInt16();
ni.Length = stream.ReadUInt16();
ni.Flags = (ResourceTableEntryFlags)stream.ReadUInt16();
ni.ResourceID = stream.ReadUInt16();
ni.Handle = stream.ReadUInt16();
ni.Usage = stream.ReadUInt16();
return ni;
}
public static ResourceTableEntry Deserialize(byte[] content, ref int offset)
{
var ni = new ResourceTableEntry();
ni.Offset = content.ReadUInt16(ref offset);
ni.Length = content.ReadUInt16(ref offset);
ni.Flags = (ResourceTableEntryFlags)content.ReadUInt16(ref offset);
ni.ResourceID = content.ReadUInt16(ref offset);
ni.Handle = content.ReadUInt16(ref offset);
ni.Usage = content.ReadUInt16(ref offset);
return ni;
}
}
}

View File

@@ -0,0 +1,69 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
{
/// <summary>
/// Resource type information block
/// </summary>
public class ResourceTypeInformationBlock
{
/// <summary>
/// Type ID. This is an integer type if the high-order bit is
/// set (8000h); otherwise, it is an offset to the type string,
/// the offset is relative to the beginning of the resource
/// table. A zero type ID marks the end of the resource type
/// information blocks.
/// </summary>
public ushort TypeID;
/// <summary>
/// Number of resources for this type.
/// </summary>
public ushort ResourceCount;
/// <summary>
/// Reserved.
/// </summary>
public uint Reserved;
/// <summary>
/// Reserved.
/// </summary>
public ResourceTableEntry[] ResourceTable;
public static ResourceTypeInformationBlock Deserialize(Stream stream)
{
var rtib = new ResourceTypeInformationBlock();
rtib.TypeID = stream.ReadUInt16();
rtib.ResourceCount = stream.ReadUInt16();
rtib.Reserved = stream.ReadUInt32();
rtib.ResourceTable = new ResourceTableEntry[rtib.ResourceCount];
for (int i = 0; i < rtib.ResourceCount; i++)
{
rtib.ResourceTable[i] = ResourceTableEntry.Deserialize(stream);
}
return rtib;
}
public static ResourceTypeInformationBlock Deserialize(byte[] content, ref int offset)
{
var rtib = new ResourceTypeInformationBlock();
rtib.TypeID = content.ReadUInt16(ref offset);
rtib.ResourceCount = content.ReadUInt16(ref offset);
rtib.Reserved = content.ReadUInt32(ref offset);
rtib.ResourceTable = new ResourceTableEntry[rtib.ResourceCount];
for (int i = 0; i < rtib.ResourceCount; i++)
{
rtib.ResourceTable[i] = ResourceTableEntry.Deserialize(content, ref offset);
}
return rtib;
}
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Entries
{
/// <summary>
/// The segment table contains an entry for each segment in the executable
/// file. The number of segment table entries are defined in the segmented
/// EXE header. The first entry in the segment table is segment number 1.
/// The following is the structure of a segment table entry.
/// </summary>
public class SegmentTableEntry
{
/// <summary>
/// Logical-sector offset (n byte) to the contents of the segment
/// data, relative to the beginning of the file. Zero means no
/// file data.
/// </summary>
public ushort StartFileSector;
/// <summary>
/// Length of the segment in the file, in bytes. Zero means 64K.
/// </summary>
public ushort BytesInFile;
/// <summary>
/// Attribute flags
/// </summary>
public SegmentTableEntryFlags Flags;
/// <summary>
/// Minimum allocation size of the segment, in bytes.
/// Total size of the segment. Zero means 64K
/// </summary>
public ushort MinimumAllocation;
public static SegmentTableEntry Deserialize(Stream stream)
{
var nste = new SegmentTableEntry();
nste.StartFileSector = stream.ReadUInt16();
nste.BytesInFile = stream.ReadUInt16();
nste.Flags = (SegmentTableEntryFlags)stream.ReadUInt16();
nste.MinimumAllocation = stream.ReadUInt16();
return nste;
}
public static SegmentTableEntry Deserialize(byte[] content, ref int offset)
{
var nste = new SegmentTableEntry();
nste.StartFileSector = content.ReadUInt16(ref offset);
nste.BytesInFile = content.ReadUInt16(ref offset);
nste.Flags = (SegmentTableEntryFlags)content.ReadUInt16(ref offset);
nste.MinimumAllocation = content.ReadUInt16(ref offset);
return nste;
}
}
}

View File

@@ -0,0 +1,256 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Headers
{
/// <summary>
/// The NE header is a relatively large structure with multiple characteristics.
/// Because of the age of the format some items are unclear in meaning.
/// </summary>
/// <remarks>http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm</remarks>
public class NewExecutableHeader
{
/// <summary>
/// Signature word. [00]
/// "N" is low-order byte.
/// "E" is high-order byte.
/// </summary>
public ushort Magic;
/// <summary>
/// Version number of the linker. [02]
/// </summary>
public byte LinkerVersion;
/// <summary>
/// Revision number of the linker. [03]
/// </summary>
public byte LinkerRevision;
/// <summary>
/// Entry Table file offset, relative to the beginning of the segmented EXE header. [04]
/// </summary>
public ushort EntryTableOffset;
/// <summary>
/// Number of bytes in the entry table. [06]
/// </summary>
public ushort EntryTableSize;
/// <summary>
/// 32-bit CRC of entire contents of file. [08]
/// These words are taken as 00 during the calculation.
/// </summary>
public uint CrcChecksum;
/// <summary>
/// Program flags, bitmapped [0C]
/// </summary>
public byte ProgramFlags;
/// <summary>
/// Application flags, bitmapped [0D]
/// </summary>
public byte ApplicationFlags;
/// <summary>
/// Automatic data segment number [0E]
/// </summary>
public ushort Autodata;
/// <summary>
/// Initial heap allocation [10]
/// </summary>
public ushort InitialHeapAlloc;
/// <summary>
/// Initial stack allocation [12]
/// </summary>
public ushort InitialStackAlloc;
/// <summary>
/// CS:IP entry point, CS is index into segment table [14]
/// </summary>
public uint InitialCSIPSetting;
/// <summary>
/// SS:SP inital stack pointer, SS is index into segment table [18]
/// </summary>
public uint InitialSSSPSetting;
/// <summary>
/// Number of segments in segment table [1C]
/// </summary>
public ushort FileSegmentCount;
/// <summary>
/// Entries in Module Reference Table [1E]
/// </summary>
public ushort ModuleReferenceTableSize;
/// <summary>
/// Size of non-resident name table [20]
/// </summary>
public ushort NonResidentNameTableSize;
/// <summary>
/// Offset of Segment Table [22]
/// </summary>
public ushort SegmentTableOffset;
/// <summary>
/// Offset of Resource Table [24]
/// </summary>
public ushort ResourceTableOffset;
/// <summary>
/// Offset of resident name table [26]
/// </summary>
public ushort ResidentNameTableOffset;
/// <summary>
/// Offset of Module Reference Table [28]
/// </summary>
public ushort ModuleReferenceTableOffset;
/// <summary>
/// Offset of Imported Names Table [2A]
/// </summary>
public ushort ImportedNamesTableOffset;
/// <summary>
/// Offset of Non-resident Names Table [2C]
/// </summary>
public uint NonResidentNamesTableOffset;
/// <summary>
/// Count of moveable entry points listed in entry table [30]
/// </summary>
public ushort MovableEntriesCount;
/// <summary>
/// File allignment size shift count (0-9 (default 512 byte pages)) [32]
/// </summary>
public ushort SegmentAlignmentShiftCount;
/// <summary>
/// Count of resource table entries [34]
/// </summary>
public ushort ResourceEntriesCount;
/// <summary>
/// Target operating system [36]
/// </summary>
public byte TargetOperatingSystem;
/// <summary>
/// Other OS/2 flags [37]
/// </summary>
public byte AdditionalFlags;
/// <summary>
/// Offset to return thunks or start of gangload area [38]
/// </summary>
public ushort ReturnThunkOffset;
/// <summary>
/// Offset to segment reference thunks or size of gangload area [3A]
/// </summary>
public ushort SegmentReferenceThunkOffset;
/// <summary>
/// Minimum code swap area size [3C]
/// </summary>
public ushort MinCodeSwapAreaSize;
/// <summary>
/// Windows SDK revison number [3E]
/// </summary>
public byte WindowsSDKRevision;
/// <summary>
/// Windows SDK version number [3F]
/// </summary>
public byte WindowsSDKVersion;
public static NewExecutableHeader Deserialize(Stream stream)
{
var neh = new NewExecutableHeader();
neh.Magic = stream.ReadUInt16();
neh.LinkerVersion = stream.ReadByteValue();
neh.LinkerRevision = stream.ReadByteValue();
neh.EntryTableOffset = stream.ReadUInt16();
neh.EntryTableSize = stream.ReadUInt16();
neh.CrcChecksum = stream.ReadUInt32();
neh.ProgramFlags = stream.ReadByteValue();
neh.ApplicationFlags = stream.ReadByteValue();
neh.Autodata = stream.ReadUInt16();
neh.InitialHeapAlloc = stream.ReadUInt16();
neh.InitialStackAlloc = stream.ReadUInt16();
neh.InitialCSIPSetting = stream.ReadUInt32();
neh.InitialSSSPSetting = stream.ReadUInt32();
neh.FileSegmentCount = stream.ReadUInt16();
neh.ModuleReferenceTableSize = stream.ReadUInt16();
neh.NonResidentNameTableSize = stream.ReadUInt16();
neh.SegmentTableOffset = stream.ReadUInt16();
neh.ResourceTableOffset = stream.ReadUInt16();
neh.ResidentNameTableOffset = stream.ReadUInt16();
neh.ModuleReferenceTableOffset = stream.ReadUInt16();
neh.ImportedNamesTableOffset = stream.ReadUInt16();
neh.NonResidentNamesTableOffset = stream.ReadUInt32();
neh.MovableEntriesCount = stream.ReadUInt16();
neh.SegmentAlignmentShiftCount = stream.ReadUInt16();
neh.ResourceEntriesCount = stream.ReadUInt16();
neh.TargetOperatingSystem = stream.ReadByteValue();
neh.AdditionalFlags = stream.ReadByteValue();
neh.ReturnThunkOffset = stream.ReadUInt16();
neh.SegmentReferenceThunkOffset = stream.ReadUInt16();
neh.MinCodeSwapAreaSize = stream.ReadUInt16();
neh.WindowsSDKRevision = stream.ReadByteValue();
neh.WindowsSDKVersion = stream.ReadByteValue();
return neh;
}
public static NewExecutableHeader Deserialize(byte[] content, ref int offset)
{
var neh = new NewExecutableHeader();
neh.Magic = content.ReadUInt16(ref offset);
neh.LinkerVersion = content.ReadByte(ref offset);
neh.LinkerRevision = content.ReadByte(ref offset);
neh.EntryTableOffset = content.ReadUInt16(ref offset);
neh.EntryTableSize = content.ReadUInt16(ref offset);
neh.CrcChecksum = content.ReadUInt32(ref offset);
neh.ProgramFlags = content.ReadByte(ref offset);
neh.ApplicationFlags = content.ReadByte(ref offset);
neh.Autodata = content.ReadUInt16(ref offset);
neh.InitialHeapAlloc = content.ReadUInt16(ref offset);
neh.InitialStackAlloc = content.ReadUInt16(ref offset);
neh.InitialCSIPSetting = content.ReadUInt32(ref offset);
neh.InitialSSSPSetting = content.ReadUInt32(ref offset);
neh.FileSegmentCount = content.ReadUInt16(ref offset);
neh.ModuleReferenceTableSize = content.ReadUInt16(ref offset);
neh.NonResidentNameTableSize = content.ReadUInt16(ref offset);
neh.SegmentTableOffset = content.ReadUInt16(ref offset);
neh.ResourceTableOffset = content.ReadUInt16(ref offset);
neh.ResidentNameTableOffset = content.ReadUInt16(ref offset);
neh.ModuleReferenceTableOffset = content.ReadUInt16(ref offset);
neh.ImportedNamesTableOffset = content.ReadUInt16(ref offset);
neh.NonResidentNamesTableOffset = content.ReadUInt32(ref offset);
neh.MovableEntriesCount = content.ReadUInt16(ref offset);
neh.SegmentAlignmentShiftCount = content.ReadUInt16(ref offset);
neh.ResourceEntriesCount = content.ReadUInt16(ref offset);
neh.TargetOperatingSystem = content.ReadByte(ref offset);
neh.AdditionalFlags = content.ReadByte(ref offset);
neh.ReturnThunkOffset = content.ReadUInt16(ref offset);
neh.SegmentReferenceThunkOffset = content.ReadUInt16(ref offset);
neh.MinCodeSwapAreaSize = content.ReadUInt16(ref offset);
neh.WindowsSDKRevision = content.ReadByte(ref offset);
neh.WindowsSDKVersion = content.ReadByte(ref offset);
return neh;
}
}
}

View File

@@ -0,0 +1,233 @@
using System;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.MZ.Headers;
using BurnOutSharp.ExecutableType.Microsoft.NE.Headers;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE
{
/// <summary>
/// The WIN-NE executable format, designed for Windows 3.x, was the "NE", or "New Executable" format.
/// Again, a 16bit format, it alleviated the maximum size restrictions that the MZ format had.
/// </summary>
public class NewExecutable
{
/// <summary>
/// Value determining if the executable is initialized or not
/// </summary>
public bool Initialized { get; } = false;
/// <summary>
/// Source array that the executable was parsed from
/// </summary>
private readonly byte[] _sourceArray = null;
/// <summary>
/// Source stream that the executable was parsed from
/// </summary>
private readonly Stream _sourceStream = null;
#region Headers
/// <summary>
/// he DOS stub is a valid MZ exe.
/// This enables the develper to package both an MS-DOS and Win16 version of the program,
/// but normally just prints "This Program requires Microsoft Windows".
/// The e_lfanew field (offset 0x3C) points to the NE header.
// </summary>
public MSDOSExecutableHeader DOSStubHeader;
/// <summary>
/// The NE header is a relatively large structure with multiple characteristics.
/// Because of the age of the format some items are unclear in meaning.
/// </summary>
public NewExecutableHeader NewExecutableHeader;
#endregion
#region Tables
#endregion
#region Constructors
// TODO: Add more and more parts of a standard NE executable, not just the header
// TODO: Tables? What about the tables?
// TODO: Implement the rest of the structures found at http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
// (Left off at RESIDENT-NAME TABLE)
/// <summary>
/// Create a NewExecutable object from a stream
/// </summary>
/// <param name="stream">Stream representing a file</param>
/// <remarks>
/// This constructor assumes that the stream is already in the correct position to start parsing
/// </remarks>
public NewExecutable(Stream stream)
{
if (stream == null || !stream.CanRead || !stream.CanSeek)
return;
this.Initialized = Deserialize(stream);
this._sourceStream = stream;
}
/// <summary>
/// Create a NewExecutable object from a byte array
/// </summary>
/// <param name="fileContent">Byte array representing a file</param>
/// <param name="offset">Positive offset representing the current position in the array</param>
public NewExecutable(byte[] fileContent, int offset)
{
if (fileContent == null || fileContent.Length == 0 || offset < 0)
return;
this.Initialized = Deserialize(fileContent, offset);
this._sourceArray = fileContent;
}
/// <summary>
/// Deserialize a NewExecutable object from a stream
/// </summary>
/// <param name="stream">Stream representing a file</param>
private bool Deserialize(Stream stream)
{
try
{
// Attempt to read the DOS header first
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
stream.Seek(this.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return false;
// If the new header address is invalid for the file, it's not a NE
if (this.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
return false;
// Then attempt to read the NE header
this.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
return false;
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
return false;
}
return true;
}
/// <summary>
/// Deserialize a NewExecutable object from a byte array
/// </summary>
/// <param name="fileContent">Byte array representing a file</param>
/// <param name="offset">Positive offset representing the current position in the array</param>
private bool Deserialize(byte[] content, int offset)
{
try
{
// Attempt to read the DOS header first
this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
offset = this.DOSStubHeader.NewExeHeaderAddr;
if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
return false;
// If the new header address is invalid for the file, it's not a PE
if (this.DOSStubHeader.NewExeHeaderAddr >= content.Length)
return false;
// Then attempt to read the NE header
this.NewExecutableHeader = NewExecutableHeader.Deserialize(content, ref offset);
if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
return false;
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
return false;
}
return true;
}
#endregion
#region Helpers
/// <summary>
/// Read an arbitrary range from the source
/// </summary>
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
/// <param name="length">How many bytes to read, -1 means read until end</param>
/// <returns></returns>
public byte[] ReadArbitraryRange(int rangeStart = -1, int length = -1)
{
try
{
// If we have a source stream, use that
if (this._sourceStream != null)
return ReadArbitraryRangeFromSourceStream(rangeStart, length);
// If we have a source array, use that
if (this._sourceArray != null)
return ReadArbitraryRangeFromSourceArray(rangeStart, length);
// Otherwise, return null
return null;
}
catch (Exception ex)
{
// TODO: How to handle this differently?
return null;
}
}
/// <summary>
/// Read an arbitrary range from the stream source, if possible
/// </summary>
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
/// <param name="length">How many bytes to read, -1 means read until end</param>
/// <returns></returns>
private byte[] ReadArbitraryRangeFromSourceStream(int rangeStart, int length)
{
lock (this._sourceStream)
{
int startingIndex = (int)Math.Max(rangeStart, 0);
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceStream.Length);
long originalPosition = this._sourceStream.Position;
this._sourceStream.Seek(startingIndex, SeekOrigin.Begin);
byte[] sectionData = this._sourceStream.ReadBytes(readLength);
this._sourceStream.Seek(originalPosition, SeekOrigin.Begin);
return sectionData;
}
}
/// <summary>
/// Read an arbitrary range from the array source, if possible
/// </summary>
/// <param name="rangeStart">The start of where to read data from, -1 means start of source</param>
/// <param name="length">How many bytes to read, -1 means read until end</param>
/// <returns></returns>
private byte[] ReadArbitraryRangeFromSourceArray(int rangeStart, int length)
{
int startingIndex = (int)Math.Max(rangeStart, 0);
int readLength = (int)Math.Min(length == -1 ? length = Int32.MaxValue : length, this._sourceArray.Length);
try
{
return this._sourceArray.ReadBytes(ref startingIndex, readLength);
}
catch
{
// Just absorb errors for now
// TODO: Investigate why and when this would be hit
return null;
}
}
#endregion
}
}

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.NE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Tables
{
/// <summary>
/// The resident-name table follows the resource table, and contains this
/// module's name string and resident exported procedure name strings. The
/// first string in this table is this module's name. These name strings
/// are case-sensitive and are not null-terminated.
/// </summary>
public class ResidentNameTable
{
/// <summary>
/// The first string in this table is this module's name.
/// These name strings are case-sensitive and are not null-terminated.
/// </summary>
public ResidentNameTableEntry[] NameTableEntries;
public static ResidentNameTable Deserialize(Stream stream)
{
var rnt = new ResidentNameTable();
var nameTableEntries = new List<ResidentNameTableEntry>();
while (true)
{
var rnte = ResidentNameTableEntry.Deserialize(stream);
if (rnte == null || rnte.Length == 0)
break;
nameTableEntries.Add(rnte);
}
rnt.NameTableEntries = nameTableEntries.ToArray();
return rnt;
}
public static ResidentNameTable Deserialize(byte[] content, ref int offset)
{
var rnt = new ResidentNameTable();
var nameTableEntries = new List<ResidentNameTableEntry>();
while (true)
{
var rnte = ResidentNameTableEntry.Deserialize(content, ref offset);
if (rnte == null || rnte.Length == 0)
break;
nameTableEntries.Add(rnte);
}
rnt.NameTableEntries = nameTableEntries.ToArray();
return rnt;
}
}
}

View File

@@ -0,0 +1,101 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.NE.Entries;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.NE.Tables
{
/// <summary>
/// The resource table follows the segment table and contains entries for
/// each resource in the executable file. The resource table consists of
/// an alignment shift count, followed by a table of resource records. The
/// resource records define the type ID for a set of resources. Each
/// resource record contains a table of resource entries of the defined
/// type. The resource entry defines the resource ID or name ID for the
/// resource. It also defines the location and size of the resource.
/// </summary>
/// <remarks>http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm</remarks>
public class ResourceTable
{
/// <summary>
/// Alignment shift count for resource data.
/// </summary>
public ushort AlignmentShiftCount;
/// <summary>
/// A table of resource type information blocks.
/// </summary>
public ResourceTypeInformationBlock[] TypeInformationBlocks;
/// <summary>
/// Resource type and name strings are stored at the end of the
/// resource table. Note that these strings are NOT null terminated and
/// are case sensitive.
/// </summary>
public ResourceNameString[] TypeAndNameStrings;
public static ResourceTable Deserialize(Stream stream)
{
var rt = new ResourceTable();
rt.AlignmentShiftCount = stream.ReadUInt16();
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
while (true)
{
var block = ResourceTypeInformationBlock.Deserialize(stream);
if (block.TypeID == 0)
break;
typeInformationBlocks.Add(block);
}
rt.TypeInformationBlocks = typeInformationBlocks.ToArray();
var typeAndNameStrings = new List<ResourceNameString>();
while (true)
{
var str = ResourceNameString.Deserialize(stream);
if (str.Length == 0)
break;
typeAndNameStrings.Add(str);
}
rt.TypeAndNameStrings = typeAndNameStrings.ToArray();
return rt;
}
public static ResourceTable Deserialize(byte[] content, ref int offset)
{
var rt = new ResourceTable();
rt.AlignmentShiftCount = content.ReadUInt16(ref offset);
var typeInformationBlocks = new List<ResourceTypeInformationBlock>();
while (true)
{
var block = ResourceTypeInformationBlock.Deserialize(content, ref offset);
if (block.TypeID == 0)
break;
typeInformationBlocks.Add(block);
}
rt.TypeInformationBlocks = typeInformationBlocks.ToArray();
var typeAndNameStrings = new List<ResourceNameString>();
while (true)
{
var str = ResourceNameString.Deserialize(content, ref offset);
if (str.Length == 0)
break;
typeAndNameStrings.Add(str);
}
rt.TypeAndNameStrings = typeAndNameStrings.ToArray();
return rt;
}
}
}

View File

@@ -0,0 +1,48 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// The base relocation table is divided into blocks.
/// Each block represents the base relocations for a 4K page.
/// Each block must start on a 32-bit boundary.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-block</remarks>
public class BaseRelocationBlock
{
/// <summary>
/// The image base plus the page RVA is added to each offset to create the VA where the base relocation must be applied.
/// </summary>
public uint PageRVA;
/// <summary>
/// The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow.
/// </summary>
public uint BlockSize;
public static BaseRelocationBlock Deserialize(Stream stream)
{
var brb = new BaseRelocationBlock();
brb.PageRVA = stream.ReadUInt32();
brb.BlockSize = stream.ReadUInt32();
// TODO: Read in the type/offset field entries
return brb;
}
public static BaseRelocationBlock Deserialize(byte[] content, ref int offset)
{
var brb = new BaseRelocationBlock();
brb.PageRVA = content.ReadUInt32(ref offset);
brb.BlockSize = content.ReadUInt32(ref offset);
// TODO: Read in the type/offset field entries
return brb;
}
}
}

View File

@@ -0,0 +1,69 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each entry in the export address table is a field that uses one of two formats in the following table.
/// If the address specified is not within the export section (as defined by the address and length that are indicated in the optional header), the field is an export RVA, which is an actual address in code or data.
/// Otherwise, the field is a forwarder RVA, which names a symbol in another DLL.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table</remarks>
public class ExportAddressTableEntry
{
/// <summary>
/// The address of the exported symbol when loaded into memory, relative to the image base.
/// For example, the address of an exported function.
/// </summary>
public uint ExportRVA;
/// <summary>
/// The pointer to a null-terminated ASCII string in the export section.
/// This string must be within the range that is given by the export table data directory entry.
/// This string gives the DLL name and the name of the export (for example, "MYDLL.expfunc") or the DLL name and the ordinal number of the export (for example, "MYDLL.#27").
/// </summary>
public uint ForwarderRVA; // TODO: Read this into a separate field
/// <summary>
/// A null-terminated ASCII string in the export section.
/// This string must be within the range that is given by the export table data directory entry.
/// This string gives the DLL name and the name of the export (for example, "MYDLL.expfunc") or the DLL name and the ordinal number of the export (for example, "MYDLL.#27").
/// </summary>
public string Forwarder;
public static ExportAddressTableEntry Deserialize(Stream stream, SectionHeader[] sections)
{
var eate = new ExportAddressTableEntry();
eate.ExportRVA = stream.ReadUInt32();
eate.ForwarderRVA = eate.ExportRVA;
int forwarderAddress = (int)PortableExecutable.ConvertVirtualAddress(eate.ForwarderRVA, sections);
if (forwarderAddress > -1 && forwarderAddress < stream.Length)
{
long originalPosition = stream.Position;
stream.Seek(forwarderAddress, SeekOrigin.Begin);
eate.Forwarder = stream.ReadString(Encoding.ASCII);
stream.Seek(originalPosition, SeekOrigin.Begin);
}
return eate;
}
public static ExportAddressTableEntry Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
var eate = new ExportAddressTableEntry();
eate.ExportRVA = content.ReadUInt32(ref offset);
eate.ForwarderRVA = eate.ExportRVA;
int forwarderAddress = (int)PortableExecutable.ConvertVirtualAddress(eate.ForwarderRVA, sections);
if (forwarderAddress > -1 && forwarderAddress < content.Length)
eate.Forwarder = content.ReadString(ref forwarderAddress, Encoding.ASCII);
return eate;
}
}
}

View File

@@ -0,0 +1,78 @@
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each entry in the export address table is a field that uses one of two formats in the following table.
/// If the address specified is not within the export section (as defined by the address and length that are indicated in the optional header), the field is an export RVA, which is an actual address in code or data.
/// Otherwise, the field is a forwarder RVA, which names a symbol in another DLL.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-pdata-section</remarks>
public class FunctionTableEntry
{
#region 32-bit MIPS
/// <summary>
/// The VA of the corresponding function.
/// </summary>
public uint MIPSBeginAddress;
/// <summary>
/// The VA of the end of the function.
/// </summary>
public uint MIPSEndAddress;
/// <summary>
/// The pointer to the exception handler to be executed.
/// </summary>
public uint MIPSExceptionHandler;
/// <summary>
/// The pointer to additional information to be passed to the handler.
/// </summary>
public uint MIPSHandlerData;
/// <summary>
/// The VA of the end of the function's prolog.
/// </summary>
public uint MIPSPrologEndAddress;
#endregion
#region ARM, PowerPC, SH3 and SH4 Windows CE
/// <summary>
/// The VA of the corresponding function.
/// </summary>
public uint ARMBeginAddress;
/// <summary>
/// The VA of the end of the function.
///
/// 8 bits Prolog Length The number of instructions in the function's prolog.
/// 22 bits Function Length The number of instructions in the function.
/// 1 bit 32-bit Flag If set, the function consists of 32-bit instructions. If clear, the function consists of 16-bit instructions.
/// 1 bit Exception Flag If set, an exception handler exists for the function. Otherwise, no exception handler exists.
/// </summary>
public uint ARMLengthsAndFlags;
#endregion
#region x64 and Itanium
/// <summary>
/// The RVA of the corresponding function.
/// </summary>
public uint X64BeginAddress;
/// <summary>
/// The RVA of the end of the function.
/// </summary>
public uint X64EndAddress;
/// <summary>
/// The RVA of the unwind information.
/// </summary>
public uint X64UnwindInformation;
#endregion
}
}

View File

@@ -0,0 +1,89 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each entry in the hint/name table has the following format
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#hintname-table</remarks>
public class HintNameTableEntry
{
/// <summary>
/// An index into the export name pointer table.
/// A match is attempted first with this value.
/// If it fails, a binary search is performed on the DLL's export name pointer table.
/// </summary>
public ushort Hint;
/// <summary>
/// An ASCII string that contains the name to import.
/// This is the string that must be matched to the public name in the DLL.
/// This string is case sensitive and terminated by a null byte.
/// </summary>
public string Name;
/// <summary>
/// A trailing zero-pad byte that appears after the trailing null byte, if necessary, to align the next entry on an even boundary.
/// </summary>
public byte Pad;
public static HintNameTableEntry Deserialize(Stream stream)
{
var hnte = new HintNameTableEntry();
hnte.Hint = stream.ReadUInt16();
hnte.Name = string.Empty;
while (true)
{
char c = stream.ReadChar();
if (c == (char)0x00)
break;
hnte.Name += c;
}
// If the name length is not even, read and pad
if (hnte.Name.Length % 2 != 0)
{
stream.ReadByte();
hnte.Pad = 1;
}
else
{
hnte.Pad = 0;
}
return hnte;
}
public static HintNameTableEntry Deserialize(byte[] content, ref int offset)
{
var hnte = new HintNameTableEntry();
hnte.Hint = content.ReadUInt16(ref offset);
hnte.Name = string.Empty;
while (true)
{
char c = (char)content[offset]; offset += 1;
if (c == (char)0x00)
break;
hnte.Name += c;
}
// If the name length is not even, read and pad
if (hnte.Name.Length % 2 != 0)
{
offset += 1;
hnte.Pad = 1;
}
else
{
hnte.Pad = 0;
}
return hnte;
}
}
}

View File

@@ -0,0 +1,81 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each import address entry has the following format
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-address-table</remarks>
public class ImportAddressTableEntry
{
/// <summary>
/// The RVA of the import lookup table.
/// This table contains a name or ordinal for each import.
/// (The name "Characteristics" is used in Winnt.h, but no longer describes this field.)
/// </summary>
public uint ImportLookupTableRVA;
/// <summary>
/// The stamp that is set to zero until the image is bound.
/// After the image is bound, this field is set to the time/data stamp of the DLL.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The index of the first forwarder reference.
/// </summary>
public uint ForwarderChain;
/// <summary>
/// The address of an ASCII string that contains the name of the DLL.
/// This address is relative to the image base.
/// </summary>
public uint NameRVA;
/// <summary>
/// The RVA of the import address table.
/// The contents of this table are identical to the contents of the import lookup table until the image is bound.
/// </summary>
public uint ImportAddressTableRVA;
/// <summary>
/// Determine if the entry is null or not
/// This indicates the last entry in a table
/// </summary>
public bool IsNull()
{
return ImportLookupTableRVA == 0
&& TimeDateStamp == 0
&& ForwarderChain == 0
&& NameRVA == 0
&& ImportAddressTableRVA == 0;
}
public static ImportAddressTableEntry Deserialize(Stream stream)
{
var iate = new ImportAddressTableEntry();
iate.ImportLookupTableRVA = stream.ReadUInt32();
iate.TimeDateStamp = stream.ReadUInt32();
iate.ForwarderChain = stream.ReadUInt32();
iate.NameRVA = stream.ReadUInt32();
iate.ImportAddressTableRVA = stream.ReadUInt32();
return iate;
}
public static ImportAddressTableEntry Deserialize(byte[] content, ref int offset)
{
var iate = new ImportAddressTableEntry();
iate.ImportLookupTableRVA = content.ReadUInt32(ref offset);
iate.TimeDateStamp = content.ReadUInt32(ref offset);
iate.ForwarderChain = content.ReadUInt32(ref offset);
iate.NameRVA = content.ReadUInt32(ref offset);
iate.ImportAddressTableRVA = content.ReadUInt32(ref offset);
return iate;
}
}
}

View File

@@ -0,0 +1,81 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each import directory entry has the following format
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table</remarks>
public class ImportDirectoryTableEntry
{
/// <summary>
/// The RVA of the import lookup table.
/// This table contains a name or ordinal for each import.
/// (The name "Characteristics" is used in Winnt.h, but no longer describes this field.)
/// </summary>
public uint ImportLookupTableRVA;
/// <summary>
/// The stamp that is set to zero until the image is bound.
/// After the image is bound, this field is set to the time/data stamp of the DLL.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The index of the first forwarder reference.
/// </summary>
public uint ForwarderChain;
/// <summary>
/// The address of an ASCII string that contains the name of the DLL.
/// This address is relative to the image base.
/// </summary>
public uint NameRVA;
/// <summary>
/// The RVA of the import address table.
/// The contents of this table are identical to the contents of the import lookup table until the image is bound.
/// </summary>
public uint ImportAddressTableRVA;
/// <summary>
/// Determine if the entry is null or not
/// This indicates the last entry in a table
/// </summary>
public bool IsNull()
{
return ImportLookupTableRVA == 0
&& TimeDateStamp == 0
&& ForwarderChain == 0
&& NameRVA == 0
&& ImportAddressTableRVA == 0;
}
public static ImportDirectoryTableEntry Deserialize(Stream stream)
{
var idte = new ImportDirectoryTableEntry();
idte.ImportLookupTableRVA = stream.ReadUInt32();
idte.TimeDateStamp = stream.ReadUInt32();
idte.ForwarderChain = stream.ReadUInt32();
idte.NameRVA = stream.ReadUInt32();
idte.ImportAddressTableRVA = stream.ReadUInt32();
return idte;
}
public static ImportDirectoryTableEntry Deserialize(byte[] content, ref int offset)
{
var idte = new ImportDirectoryTableEntry();
idte.ImportLookupTableRVA = content.ReadUInt32(ref offset);
idte.TimeDateStamp = content.ReadUInt32(ref offset);
idte.ForwarderChain = content.ReadUInt32(ref offset);
idte.NameRVA = content.ReadUInt32(ref offset);
idte.ImportAddressTableRVA = content.ReadUInt32(ref offset);
return idte;
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// Each Resource Data entry describes an actual unit of raw data in the Resource Data area.
/// </summary>
public class ResourceDataEntry
{
/// <summary>
/// The address of a unit of resource data in the Resource Data area.
/// </summary>
public uint OffsetToData;
/// <summary>
/// A unit of resource data in the Resource Data area.
/// </summary>
public byte[] Data;
/// <summary>
/// A unit of resource data in the Resource Data area.
/// </summary>
public string DataAsUTF8String
{
get
{
int codePage = (int)CodePage;
if (Data == null || codePage < 0)
return string.Empty;
// Try to convert to UTF-8 first
try
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var originalEncoding = Encoding.GetEncoding(codePage);
byte[] convertedData = Encoding.Convert(originalEncoding, Encoding.UTF8, Data);
return Encoding.UTF8.GetString(convertedData);
}
catch { }
// Then try to read direct as ASCII
try
{
return Encoding.ASCII.GetString(Data);
}
catch { }
// If both encodings fail, then just return an empty string
return string.Empty;
}
}
/// <summary>
/// The size, in bytes, of the resource data that is pointed to by the Data RVA field.
/// </summary>
public uint Size;
/// <summary>
/// The code page that is used to decode code point values within the resource data.
/// Typically, the code page would be the Unicode code page.
/// </summary>
public uint CodePage;
/// <summary>
/// Reserved, must be 0.
/// </summary>
public uint Reserved;
public static ResourceDataEntry Deserialize(Stream stream, SectionHeader[] sections)
{
var rde = new ResourceDataEntry();
rde.OffsetToData = stream.ReadUInt32();
rde.Size = stream.ReadUInt32();
rde.CodePage = stream.ReadUInt32();
rde.Reserved = stream.ReadUInt32();
int realOffsetToData = (int)PortableExecutable.ConvertVirtualAddress(rde.OffsetToData, sections);
if (realOffsetToData > -1 && realOffsetToData < stream.Length && (int)rde.Size > 0 && realOffsetToData + (int)rde.Size < stream.Length)
{
long lastPosition = stream.Position;
stream.Seek(realOffsetToData, SeekOrigin.Begin);
rde.Data = stream.ReadBytes((int)rde.Size);
stream.Seek(lastPosition, SeekOrigin.Begin);
}
return rde;
}
public static ResourceDataEntry Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
var rde = new ResourceDataEntry();
rde.OffsetToData = content.ReadUInt32(ref offset);
rde.Size = content.ReadUInt32(ref offset);
rde.CodePage = content.ReadUInt32(ref offset);
rde.Reserved = content.ReadUInt32(ref offset);
int realOffsetToData = (int)PortableExecutable.ConvertVirtualAddress(rde.OffsetToData, sections);
if (realOffsetToData > -1 && realOffsetToData < content.Length && (int)rde.Size > 0 && realOffsetToData + (int)rde.Size < content.Length)
rde.Data = new ArraySegment<byte>(content, realOffsetToData, (int)rde.Size).ToArray();
return rde;
}
}
}

View File

@@ -0,0 +1,50 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// The resource directory string area consists of Unicode strings, which are word-aligned.
/// These strings are stored together after the last Resource Directory entry and before the first Resource Data entry.
/// This minimizes the impact of these variable-length strings on the alignment of the fixed-size directory entries.
/// </summary>
public class ResourceDirectoryString
{
/// <summary>
/// The size of the string, not including length field itself.
/// </summary>
public ushort Length;
/// <summary>
/// The variable-length Unicode string data, word-aligned.
/// </summary>
public string UnicodeString;
public static ResourceDirectoryString Deserialize(Stream stream)
{
var rds = new ResourceDirectoryString();
rds.Length = stream.ReadUInt16();
if (rds.Length + stream.Position > stream.Length)
return null;
rds.UnicodeString = new string(stream.ReadChars(rds.Length, Encoding.Unicode));
return rds;
}
public static ResourceDirectoryString Deserialize(byte[] content, ref int offset)
{
var rds = new ResourceDirectoryString();
rds.Length = content.ReadUInt16(ref offset);
if (rds.Length + offset > content.Length)
return null;
rds.UnicodeString = Encoding.Unicode.GetString(content, offset, rds.Length); offset += rds.Length;
return rds;
}
}
}

View File

@@ -0,0 +1,140 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries
{
/// <summary>
/// The directory entries make up the rows of a table.
/// Each resource directory entry has the following format.
/// Whether the entry is a Name or ID entry is indicated by the
/// resource directory table, which indicates how many Name and
/// ID entries follow it (remember that all the Name entries
/// precede all the ID entries for the table). All entries for
/// the table are sorted in ascending order: the Name entries
/// by case-sensitive string and the ID entries by numeric value.
/// Offsets are relative to the address in the IMAGE_DIRECTORY_ENTRY_RESOURCE DataDirectory.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-entries</remarks>
public class ResourceDirectoryTableEntry
{
/// <summary>
/// The offset of a string that gives the Type, Name, or Language ID entry, depending on level of table.
/// </summary>
public uint NameOffset => (uint)(IntegerId ^ (1 << 31));
/// <summary>
/// The string that gives the Type, Name, or Language ID entry, depending on level of table pointed to by NameOffset
/// </summary>
public ResourceDirectoryString Name;
/// <summary>
/// A 32-bit integer that identifies the Type, Name, or Language ID entry.
/// </summary>
public uint IntegerId;
/// <summary>
/// High bit 0. Address of a Resource Data entry (a leaf).
/// </summary>
public uint DataEntryOffset;
/// <summary>
/// High bit 1. The lower 31 bits are the address of another resource directory table (the next level down).
/// </summary>
public uint SubdirectoryOffset => (uint)(DataEntryOffset ^ (1 << 31));
/// <summary>
/// Resource Data entry (a leaf).
/// </summary>
public ResourceDataEntry DataEntry;
/// <summary>
/// Another resource directory table (the next level down).
/// </summary>
public ResourceDirectoryTable Subdirectory;
/// <summary>
/// Determine if an entry has a name or integer identifier
/// </summary>
public bool IsIntegerIDEntry() => (IntegerId & (1 << 31)) == 0;
/// <summary>
/// Determine if an entry represents a leaf or another directory table
/// </summary>
public bool IsResourceDataEntry() => (DataEntryOffset & (1 << 31)) == 0;
public static ResourceDirectoryTableEntry Deserialize(Stream stream, long sectionStart, SectionHeader[] sections)
{
var rdte = new ResourceDirectoryTableEntry();
rdte.IntegerId = stream.ReadUInt32();
if (!rdte.IsIntegerIDEntry())
{
int nameAddress = (int)(rdte.NameOffset + sectionStart);
if (nameAddress >= 0 && nameAddress < stream.Length)
{
long lastPosition = stream.Position;
stream.Seek(nameAddress, SeekOrigin.Begin);
rdte.Name = ResourceDirectoryString.Deserialize(stream);
stream.Seek(lastPosition, SeekOrigin.Begin);
}
}
rdte.DataEntryOffset = stream.ReadUInt32();
if (rdte.IsResourceDataEntry())
{
int dataEntryAddress = (int)(rdte.DataEntryOffset + sectionStart);
if (dataEntryAddress > 0 && dataEntryAddress < stream.Length)
{
long lastPosition = stream.Position;
stream.Seek(dataEntryAddress, SeekOrigin.Begin);
rdte.DataEntry = ResourceDataEntry.Deserialize(stream, sections);
stream.Seek(lastPosition, SeekOrigin.Begin);
}
}
else
{
int subdirectoryAddress = (int)(rdte.SubdirectoryOffset + sectionStart);
if (subdirectoryAddress > 0 && subdirectoryAddress < stream.Length)
{
long lastPosition = stream.Position;
stream.Seek(subdirectoryAddress, SeekOrigin.Begin);
rdte.Subdirectory = ResourceDirectoryTable.Deserialize(stream, sectionStart, sections);
stream.Seek(lastPosition, SeekOrigin.Begin);
}
}
return rdte;
}
public static ResourceDirectoryTableEntry Deserialize(byte[] content, ref int offset, long sectionStart, SectionHeader[] sections)
{
var rdte = new ResourceDirectoryTableEntry();
rdte.IntegerId = content.ReadUInt32(ref offset);
if (!rdte.IsIntegerIDEntry())
{
int nameAddress = (int)(rdte.NameOffset + sectionStart);
if (nameAddress >= 0 && nameAddress < content.Length)
rdte.Name = ResourceDirectoryString.Deserialize(content, ref nameAddress);
}
rdte.DataEntryOffset = content.ReadUInt32(ref offset);
if (rdte.IsResourceDataEntry())
{
int dataEntryAddress = (int)(rdte.DataEntryOffset + sectionStart);
if (dataEntryAddress > 0 && dataEntryAddress < content.Length)
rdte.DataEntry = ResourceDataEntry.Deserialize(content, ref dataEntryAddress, sections);
}
else
{
int subdirectoryAddress = (int)(rdte.SubdirectoryOffset + sectionStart);
if (subdirectoryAddress > 0 && subdirectoryAddress < content.Length)
rdte.Subdirectory = ResourceDirectoryTable.Deserialize(content, ref subdirectoryAddress, sectionStart, sections);
}
return rdte;
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
{
public class CommonObjectFileFormatHeader
{
/// <summary>
/// After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte signature that identifies the file as a PE format image file.
// This signature is "PE\0\0" (the letters "P" and "E" followed by two null bytes).
/// </summary>
public uint Signature;
/// <summary>
/// The number that identifies the type of target machine.
/// </summary>
public MachineType Machine;
/// <summary>
/// The number of sections.
/// This indicates the size of the section table, which immediately follows the headers.
/// </summary>
public ushort NumberOfSections;
/// <summary>
/// The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value), which indicates when the file was created.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The file offset of the COFF symbol table, or zero if no COFF symbol table is present.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public uint PointerToSymbolTable;
/// <summary>
/// The number of entries in the symbol table. This data can be used to locate the string table, which immediately follows the symbol table.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public uint NumberOfSymbols;
/// <summary>
/// The size of the optional header, which is required for executable files but not for object files.
// This value should be zero for an object file.
/// </summary>
public ushort SizeOfOptionalHeader;
/// <summary>
/// The flags that indicate the attributes of the file.
/// </summary>
public ImageObjectCharacteristics Characteristics;
public static CommonObjectFileFormatHeader Deserialize(Stream stream)
{
var ifh = new CommonObjectFileFormatHeader();
ifh.Signature = stream.ReadUInt32();
ifh.Machine = (MachineType)stream.ReadUInt16();
ifh.NumberOfSections = stream.ReadUInt16();
ifh.TimeDateStamp = stream.ReadUInt32();
ifh.PointerToSymbolTable = stream.ReadUInt32();
ifh.NumberOfSymbols = stream.ReadUInt32();
ifh.SizeOfOptionalHeader = stream.ReadUInt16();
ifh.Characteristics = (ImageObjectCharacteristics)stream.ReadUInt16();
return ifh;
}
public static CommonObjectFileFormatHeader Deserialize(byte[] content, ref int offset)
{
var ifh = new CommonObjectFileFormatHeader();
ifh.Signature = content.ReadUInt32(ref offset);
ifh.Machine = (MachineType)content.ReadUInt16(ref offset);
ifh.NumberOfSections = content.ReadUInt16(ref offset);
ifh.TimeDateStamp = content.ReadUInt32(ref offset);
ifh.PointerToSymbolTable = content.ReadUInt32(ref offset);
ifh.NumberOfSymbols = content.ReadUInt32(ref offset);
ifh.SizeOfOptionalHeader = content.ReadUInt16(ref offset);
ifh.Characteristics = (ImageObjectCharacteristics)content.ReadUInt16(ref offset);
return ifh;
}
}
}

View File

@@ -0,0 +1,39 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
{
public class DataDirectoryHeader
{
/// <summary>
/// The first field, VirtualAddress, is actually the RVA of the table.
/// The RVA is the address of the table relative to the base address of the image when the table is loaded.
/// </summary>
public uint VirtualAddress;
/// <summary>
/// The second field gives the size in bytes.
/// </summary>
public uint Size;
public static DataDirectoryHeader Deserialize(Stream stream)
{
var ddh = new DataDirectoryHeader();
ddh.VirtualAddress = stream.ReadUInt32();
ddh.Size = stream.ReadUInt32();
return ddh;
}
public static DataDirectoryHeader Deserialize(byte[] content, ref int offset)
{
var ddh = new DataDirectoryHeader();
ddh.VirtualAddress = content.ReadUInt32(ref offset);
ddh.Size = content.ReadUInt32(ref offset);
return ddh;
}
}
}

View File

@@ -0,0 +1,369 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
{
/// <summary>
/// Every image file has an optional header that provides information to the loader.
/// This header is optional in the sense that some files (specifically, object files) do not have it.
/// For image files, this header is required. An object file can have an optional header, but generally
/// this header has no function in an object file except to increase its size.
///
/// Note that the size of the optional header is not fixed.
/// The SizeOfOptionalHeader field in the COFF header must be used to validate that a probe into the file
/// for a particular data directory does not go beyond SizeOfOptionalHeader.
///
/// The NumberOfRvaAndSizes field of the optional header should also be used to ensure that no probe for
/// a particular data directory entry goes beyond the optional header.
/// In addition, it is important to validate the optional header magic number for format compatibility.
/// </summary>
public class OptionalHeader
{
#region Standard Fields
/// <summary>
/// The unsigned integer that identifies the state of the image file.
/// The most common number is 0x10B, which identifies it as a normal executable file.
/// 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
/// </summary>
public OptionalHeaderType Magic;
/// <summary>
/// The linker major version number.
/// </summary>
public byte MajorLinkerVersion;
/// <summary>
/// The linker minor version number.
/// </summary>
public byte MinorLinkerVersion;
/// <summary>
/// The size of the code (text) section, or the sum of all code sections if there are multiple sections.
/// </summary>
public uint SizeOfCode;
/// <summary>
/// The size of the initialized data section, or the sum of all such sections if there are multiple data sections.
/// </summary>
public uint SizeOfInitializedData;
/// <summary>
/// The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.
/// </summary>
public uint SizeOfUninitializedData;
/// <summary>
/// The address of the entry point relative to the image base when the executable file is loaded into memory.
/// For program images, this is the starting address.
/// For device drivers, this is the address of the initialization function.
/// An entry point is optional for DLLs.
/// When no entry point is present, this field must be zero.
/// </summary>
public uint AddressOfEntryPoint;
/// <summary>
/// The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.
/// </summary>
public uint BaseOfCode;
/// <summary>
/// The address that is relative to the image base of the beginning-of-data section when it is loaded into memory.
/// </summary>
public uint BaseOfData;
#endregion
#region Windows-Specific Fields
/// <summary>
/// The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K.
/// The default for DLLs is 0x10000000.
/// The default for Windows CE EXEs is 0x00010000.
/// The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
/// </summary>
public uint ImageBasePE32;
/// <summary>
/// The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K.
/// The default for DLLs is 0x10000000.
/// The default for Windows CE EXEs is 0x00010000.
/// The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
/// </summary>
public ulong ImageBasePE32Plus;
/// <summary>
/// The alignment (in bytes) of sections when they are loaded into memory.
/// It must be greater than or equal to FileAlignment.
/// The default is the page size for the architecture.
/// </summary>
public uint SectionAlignment;
/// <summary>
/// The alignment factor (in bytes) that is used to align the raw data of sections in the image file.
/// The value should be a power of 2 between 512 and 64 K, inclusive.
/// The default is 512.
/// If the SectionAlignment is less than the architecture's page size, then FileAlignment must match SectionAlignment.
/// </summary>
public uint FileAlignment;
/// <summary>
/// The major version number of the required operating system.
/// </summary>
public ushort MajorOperatingSystemVersion;
/// <summary>
/// The minor version number of the required operating system.
/// </summary>
public ushort MinorOperatingSystemVersion;
/// <summary>
/// The major version number of the image.
/// </summary>
public ushort MajorImageVersion;
/// <summary>
/// The minor version number of the image.
/// </summary>
public ushort MinorImageVersion;
/// <summary>
/// The major version number of the subsystem.
/// </summary>
public ushort MajorSubsystemVersion;
/// <summary>
/// The minor version number of the subsystem.
/// </summary>
public ushort MinorSubsystemVersion;
/// <summary>
/// Reserved, must be zero.
/// </summary>
public uint Reserved1;
/// <summary>
/// The size (in bytes) of the image, including all headers, as the image is loaded in memory.
/// It must be a multiple of SectionAlignment.
/// </summary>
public uint SizeOfImage;
/// <summary>
/// The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment.
/// </summary>
public uint SizeOfHeaders;
/// <summary>
/// The image file checksum.
/// The algorithm for computing the checksum is incorporated into IMAGHELP.DLL.
/// The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process.
/// </summary>
public uint CheckSum;
/// <summary>
/// The subsystem that is required to run this image.
/// </summary>
public WindowsSubsystem Subsystem;
/// <summary>
/// DLL Characteristics
/// </summary>
public DllCharacteristics DllCharacteristics;
/// <summary>
/// The size of the stack to reserve.
/// Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached.
/// </summary>
public uint SizeOfStackReservePE32;
/// <summary>
/// The size of the stack to reserve.
/// Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached.
/// </summary>
public ulong SizeOfStackReservePE32Plus;
/// <summary>
/// The size of the stack to commit.
/// </summary>
public uint SizeOfStackCommitPE32;
/// <summary>
/// The size of the stack to commit.
/// </summary>
public ulong SizeOfStackCommitPE32Plus;
/// <summary>
/// The size of the local heap space to reserve.
/// Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached.
/// </summary>
public uint SizeOfHeapReservePE32;
/// <summary>
/// The size of the local heap space to reserve.
/// Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached.
/// </summary>
public ulong SizeOfHeapReservePE32Plus;
/// <summary>
/// The size of the local heap space to commit.
/// </summary>
public uint SizeOfHeapCommitPE32;
/// <summary>
/// The size of the local heap space to commit.
/// </summary>
public ulong SizeOfHeapCommitPE32Plus;
/// <summary>
/// Reserved, must be zero.
/// </summary>
public uint LoaderFlags;
/// <summary>
/// The number of data-directory entries in the remainder of the optional header.
/// Each describes a location and size.
/// </summary>
public uint NumberOfRvaAndSizes;
/// <summary>
/// Data-directory entries following the optional header
/// </summary>
public DataDirectoryHeader[] DataDirectories;
#endregion
public static OptionalHeader Deserialize(Stream stream)
{
var ioh = new OptionalHeader();
ioh.Magic = (OptionalHeaderType)stream.ReadUInt16();
ioh.MajorLinkerVersion = stream.ReadByteValue();
ioh.MinorLinkerVersion = stream.ReadByteValue();
ioh.SizeOfCode = stream.ReadUInt32();
ioh.SizeOfInitializedData = stream.ReadUInt32();
ioh.SizeOfUninitializedData = stream.ReadUInt32();
ioh.AddressOfEntryPoint = stream.ReadUInt32();
ioh.BaseOfCode = stream.ReadUInt32();
// Only standard PE32 has this value
if (ioh.Magic == OptionalHeaderType.PE32)
ioh.BaseOfData = stream.ReadUInt32();
// PE32+ has an 8-byte value here
if (ioh.Magic == OptionalHeaderType.PE32Plus)
ioh.ImageBasePE32Plus = stream.ReadUInt64();
else
ioh.ImageBasePE32 = stream.ReadUInt32();
ioh.SectionAlignment = stream.ReadUInt32();
ioh.FileAlignment = stream.ReadUInt32();
ioh.MajorOperatingSystemVersion = stream.ReadUInt16();
ioh.MinorOperatingSystemVersion = stream.ReadUInt16();
ioh.MajorImageVersion = stream.ReadUInt16();
ioh.MinorImageVersion = stream.ReadUInt16();
ioh.MajorSubsystemVersion = stream.ReadUInt16();
ioh.MinorSubsystemVersion = stream.ReadUInt16();
ioh.Reserved1 = stream.ReadUInt32();
ioh.SizeOfImage = stream.ReadUInt32();
ioh.SizeOfHeaders = stream.ReadUInt32();
ioh.CheckSum = stream.ReadUInt32();
ioh.Subsystem = (WindowsSubsystem)stream.ReadUInt16();
ioh.DllCharacteristics = (DllCharacteristics)stream.ReadUInt16();
// PE32+ uses 8-byte values
if (ioh.Magic == OptionalHeaderType.PE32Plus)
{
ioh.SizeOfStackReservePE32Plus = stream.ReadUInt64();
ioh.SizeOfStackCommitPE32Plus = stream.ReadUInt64();
ioh.SizeOfHeapReservePE32Plus = stream.ReadUInt64();
ioh.SizeOfHeapCommitPE32Plus = stream.ReadUInt64();
}
else
{
ioh.SizeOfStackReservePE32 = stream.ReadUInt32();
ioh.SizeOfStackCommitPE32 = stream.ReadUInt32();
ioh.SizeOfHeapReservePE32 = stream.ReadUInt32();
ioh.SizeOfHeapCommitPE32 = stream.ReadUInt32();
}
ioh.LoaderFlags = stream.ReadUInt32();
ioh.NumberOfRvaAndSizes = stream.ReadUInt32();
ioh.DataDirectories = new DataDirectoryHeader[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(stream);
}
return ioh;
}
public static OptionalHeader Deserialize(byte[] content, ref int offset)
{
var ioh = new OptionalHeader();
ioh.Magic = (OptionalHeaderType)content.ReadUInt16(ref offset);
ioh.MajorLinkerVersion = content[offset]; offset++;
ioh.MinorLinkerVersion = content[offset]; offset++;
ioh.SizeOfCode = content.ReadUInt32(ref offset);
ioh.SizeOfInitializedData = content.ReadUInt32(ref offset);
ioh.SizeOfUninitializedData = content.ReadUInt32(ref offset);
ioh.AddressOfEntryPoint = content.ReadUInt32(ref offset);
ioh.BaseOfCode = content.ReadUInt32(ref offset);
// Only standard PE32 has this value
if (ioh.Magic == OptionalHeaderType.PE32)
ioh.BaseOfData = content.ReadUInt32(ref offset);
// PE32+ has an 8-bit value here
if (ioh.Magic == OptionalHeaderType.PE32Plus)
{
ioh.ImageBasePE32Plus = content.ReadUInt64(ref offset);
}
else
{
ioh.ImageBasePE32 = content.ReadUInt32(ref offset);
}
ioh.SectionAlignment = content.ReadUInt32(ref offset);
ioh.FileAlignment = content.ReadUInt32(ref offset);
ioh.MajorOperatingSystemVersion = content.ReadUInt16(ref offset);
ioh.MinorOperatingSystemVersion = content.ReadUInt16(ref offset);
ioh.MajorImageVersion = content.ReadUInt16(ref offset);
ioh.MinorImageVersion = content.ReadUInt16(ref offset);
ioh.MajorSubsystemVersion = content.ReadUInt16(ref offset);
ioh.MinorSubsystemVersion = content.ReadUInt16(ref offset);
ioh.Reserved1 = content.ReadUInt32(ref offset);
ioh.SizeOfImage = content.ReadUInt32(ref offset);
ioh.SizeOfHeaders = content.ReadUInt32(ref offset);
ioh.CheckSum = content.ReadUInt32(ref offset);
ioh.Subsystem = (WindowsSubsystem)content.ReadUInt16(ref offset);
ioh.DllCharacteristics = (DllCharacteristics)content.ReadUInt16(ref offset);
// PE32+ uses 8-byte values
if (ioh.Magic == OptionalHeaderType.PE32Plus)
{
ioh.SizeOfStackReservePE32Plus = content.ReadUInt64(ref offset);
ioh.SizeOfStackCommitPE32Plus = content.ReadUInt64(ref offset);
ioh.SizeOfHeapReservePE32Plus = content.ReadUInt64(ref offset);
ioh.SizeOfHeapCommitPE32Plus = content.ReadUInt64(ref offset);
}
else
{
ioh.SizeOfStackReservePE32 = content.ReadUInt32(ref offset);
ioh.SizeOfStackCommitPE32 = content.ReadUInt32(ref offset);
ioh.SizeOfHeapReservePE32 = content.ReadUInt32(ref offset);
ioh.SizeOfHeapCommitPE32 = content.ReadUInt32(ref offset);
}
ioh.LoaderFlags = content.ReadUInt32(ref offset);
ioh.NumberOfRvaAndSizes = content.ReadUInt32(ref offset);
ioh.DataDirectories = new DataDirectoryHeader[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
{
ioh.DataDirectories[i] = DataDirectoryHeader.Deserialize(content, ref offset);
}
return ioh;
}
}
}

View File

@@ -0,0 +1,159 @@
using System;
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Headers
{
/// <summary>
/// Each row of the section table is, in effect, a section header.
/// This table immediately follows the optional header, if any.
/// This positioning is required because the file header does not contain a direct pointer to the section table.
/// Instead, the location of the section table is determined by calculating the location of the first byte after the headers.
/// Make sure to use the size of the optional header as specified in the file header.
/// </summary>
public class SectionHeader
{
/// <summary>
/// An 8-byte, null-padded UTF-8 encoded string.
/// If the string is exactly 8 characters long, there is no terminating null.
/// For longer names, this field contains a slash (/) that is followed by an ASCII representation of a decimal number
/// that is an offset into the string table.
/// Executable images do not use a string table and do not support section names longer than 8 characters.
/// Long names in object files are truncated if they are emitted to an executable file.
/// </summary>
public byte[] Name;
/// <summary>
/// Section name as a string, trimming any trailing null bytes
/// </summary>
public string NameString
{
get
{
if (this.Name == null || this.Name.Length == 0)
return null;
// First try decoding as UTF-8
try
{
return Encoding.UTF8.GetString(this.Name).TrimEnd('\0');
}
catch { }
// Then try decoding as ASCII
try
{
return Encoding.ASCII.GetString(this.Name).TrimEnd('\0');
}
catch { }
// If it fails, return null
return null;
}
}
/// <summary>
/// The total size of the section when loaded into memory.
/// If this value is greater than SizeOfRawData, the section is zero-padded.
/// This field is valid only for executable images and should be set to zero for object files.
/// </summary>
public uint VirtualSize;
/// <summary>
/// For executable images, the address of the first byte of the section relative to the image base when the section
/// is loaded into memory.
/// For object files, this field is the address of the first byte before relocation is applied; for simplicity,
/// compilers should set this to zero.
/// Otherwise, it is an arbitrary value that is subtracted from offsets during relocation.
/// </summary>
public uint VirtualAddress;
/// <summary>
/// The size of the section (for object files) or the size of the initialized data on disk (for image files).
/// For executable images, this must be a multiple of FileAlignment from the optional header.
/// If this is less than VirtualSize, the remainder of the section is zero-filled.
/// Because the SizeOfRawData field is rounded but the VirtualSize field is not, it is possible for SizeOfRawData
/// to be greater than VirtualSize as well.
/// When a section contains only uninitialized data, this field should be zero.
/// </summary>
public uint SizeOfRawData;
/// <summary>
/// The file pointer to the first page of the section within the COFF file.
/// For executable images, this must be a multiple of FileAlignment from the optional header.
/// For object files, the value should be aligned on a 4-byte boundary for best performance.
/// When a section contains only uninitialized data, this field should be zero.
/// </summary>
public uint PointerToRawData;
/// <summary>
/// The file pointer to the beginning of relocation entries for the section.
/// This is set to zero for executable images or if there are no relocations.
/// </summary>
public uint PointerToRelocations;
/// <summary>
/// The file pointer to the beginning of line-number entries for the section.
/// This is set to zero if there are no COFF line numbers.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public uint PointerToLinenumbers;
/// <summary>
/// The number of relocation entries for the section.
/// This is set to zero for executable images.
/// </summary>
public ushort NumberOfRelocations;
/// <summary>
/// The number of line-number entries for the section.
/// This value should be zero for an image because COFF debugging information is deprecated.
/// </summary>
[Obsolete]
public ushort NumberOfLinenumbers;
/// <summary>
/// The flags that describe the characteristics of the section.
/// </summary>
public SectionCharacteristics Characteristics;
public static SectionHeader Deserialize(Stream stream)
{
var ish = new SectionHeader();
ish.Name = stream.ReadBytes(Constants.IMAGE_SIZEOF_SHORT_NAME);
ish.VirtualSize = stream.ReadUInt32();
ish.VirtualAddress = stream.ReadUInt32();
ish.SizeOfRawData = stream.ReadUInt32();
ish.PointerToRawData = stream.ReadUInt32();
ish.PointerToRelocations = stream.ReadUInt32();
ish.PointerToLinenumbers = stream.ReadUInt32();
ish.NumberOfRelocations = stream.ReadUInt16();
ish.NumberOfLinenumbers = stream.ReadUInt16();
ish.Characteristics = (SectionCharacteristics)stream.ReadUInt32();
return ish;
}
public static SectionHeader Deserialize(byte[] content, ref int offset)
{
var ish = new SectionHeader();
ish.Name = new byte[Constants.IMAGE_SIZEOF_SHORT_NAME];
Array.Copy(content, offset, ish.Name, 0, Constants.IMAGE_SIZEOF_SHORT_NAME); offset += Constants.IMAGE_SIZEOF_SHORT_NAME;
ish.VirtualSize = content.ReadUInt32(ref offset);
ish.VirtualAddress = content.ReadUInt32(ref offset);
ish.SizeOfRawData = content.ReadUInt32(ref offset);
ish.PointerToRawData = content.ReadUInt32(ref offset);
ish.PointerToRelocations = content.ReadUInt32(ref offset);
ish.PointerToLinenumbers = content.ReadUInt32(ref offset);
ish.NumberOfRelocations = content.ReadUInt16(ref offset);
ish.NumberOfLinenumbers = content.ReadUInt16(ref offset);
ish.Characteristics = (SectionCharacteristics)content.ReadUInt32(ref offset);
return ish;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// The .debug section is used in object files to contain compiler-generated debug information and in image files to contain
/// all of the debug information that is generated.
/// This section describes the packaging of debug information in object and image files.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-debug-section</remarks>
public class DebugSection
{
/// <summary>
/// Image files contain an optional debug directory that indicates what form of debug information is present and where it is.
/// This directory consists of an array of debug directory entries whose location and size are indicated in the image optional header.
/// </summary>
public DebugDirectory DebugDirectory;
public static DebugSection Deserialize(Stream stream)
{
long originalPosition = stream.Position;
var ds = new DebugSection();
ds.DebugDirectory = DebugDirectory.Deserialize(stream);
// TODO: Read in raw debug data
stream.Seek(originalPosition, SeekOrigin.Begin);
return ds;
}
public static DebugSection Deserialize(byte[] content, ref int offset)
{
int originalPosition = offset;
var ds = new DebugSection();
ds.DebugDirectory = DebugDirectory.Deserialize(content, ref offset);
// TODO: Read in raw debug data
offset = originalPosition;
return ds;
}
}
}

View File

@@ -0,0 +1,19 @@
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// The .pdata section contains an array of function table entries that are used for exception handling.
/// It is pointed to by the exception table entry in the image data directory.
/// The entries must be sorted according to the function addresses (the first field in each structure) before being emitted into the final image.
/// The target platform determines which of the three function table entry format variations described below is used.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-edata-section-image-only</remarks>
public class ExceptionHandlingSection
{
/// <summary>
/// Array of function table entries that are used for exception handling
/// </summary>
public FunctionTable FunctionTable;
}
}

View File

@@ -0,0 +1,95 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// The export data section, named .edata, contains information about symbols that other images can access through dynamic linking.
/// Exported symbols are generally found in DLLs, but DLLs can also import symbols.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-edata-section-image-only</remarks>
public class ExportDataSection
{
/// <summary>
/// A table with just one row (unlike the debug directory).
/// This table indicates the locations and sizes of the other export tables.
/// </summary>
public ExportDirectoryTable ExportDirectoryTable;
/// <summary>
/// An array of RVAs of exported symbols.
/// These are the actual addresses of the exported functions and data within the executable code and data sections.
/// Other image files can import a symbol by using an index to this table (an ordinal) or, optionally, by using the public name that corresponds to the ordinal if a public name is defined.
/// </summary>
public ExportAddressTableEntry[] ExportAddressTable;
/// <summary>
/// An array of pointers to the public export names, sorted in ascending order.
/// </summary>
public uint[] ExportNamePointerTable;
/// <summary>
/// An array of the ordinals that correspond to members of the name pointer table.
/// The correspondence is by position; therefore, the name pointer table and the ordinal table must have the same number of members.
/// Each ordinal is an index into the export address table.
/// </summary>
public ExportOrdinalTable OrdinalTable;
public static ExportDataSection Deserialize(Stream stream, SectionHeader[] sections)
{
long originalPosition = stream.Position;
var eds = new ExportDataSection();
eds.ExportDirectoryTable = ExportDirectoryTable.Deserialize(stream);
stream.Seek((int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.ExportAddressTableRVA, sections), SeekOrigin.Begin);
eds.ExportAddressTable = new ExportAddressTableEntry[(int)eds.ExportDirectoryTable.AddressTableEntries];
for (int i = 0; i < eds.ExportAddressTable.Length; i++)
{
eds.ExportAddressTable[i] = ExportAddressTableEntry.Deserialize(stream, sections);
}
stream.Seek((int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.NamePointerRVA, sections), SeekOrigin.Begin);
eds.ExportNamePointerTable = new uint[(int)eds.ExportDirectoryTable.NumberOfNamePointers];
for (int i = 0; i < eds.ExportNamePointerTable.Length; i++)
{
eds.ExportNamePointerTable[i] = stream.ReadUInt32();
}
stream.Seek((int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.OrdinalTableRVA, sections), SeekOrigin.Begin);
// eds.OrdinalTable = ExportOrdinalTable.Deserialize(stream, count: 0); // TODO: Figure out where this count comes from
return eds;
}
public static ExportDataSection Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
int originalPosition = offset;
var eds = new ExportDataSection();
eds.ExportDirectoryTable = ExportDirectoryTable.Deserialize(content, ref offset);
offset = (int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.ExportAddressTableRVA, sections);
eds.ExportAddressTable = new ExportAddressTableEntry[(int)eds.ExportDirectoryTable.AddressTableEntries];
for (int i = 0; i < eds.ExportAddressTable.Length; i++)
{
eds.ExportAddressTable[i] = ExportAddressTableEntry.Deserialize(content, ref offset, sections);
}
offset = (int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.NamePointerRVA, sections);
eds.ExportNamePointerTable = new uint[(int)eds.ExportDirectoryTable.NumberOfNamePointers];
for (int i = 0; i < eds.ExportNamePointerTable.Length; i++)
{
eds.ExportNamePointerTable[i] = content.ReadUInt32(ref offset);
}
offset = (int)PortableExecutable.ConvertVirtualAddress(eds.ExportDirectoryTable.OrdinalTableRVA, sections);
// eds.OrdinalTable = ExportOrdinalTable.Deserialize(content, ref offset, count: 0); // TODO: Figure out where this count comes from
return eds;
}
}
}

View File

@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// All image files that import symbols, including virtually all executable (EXE) files, have an .idata section.
/// A typical file layout for the import information follows:
/// Directory Table
/// Null Directory Entry
/// DLL1 Import Lookup Table
/// Null
/// DLL2 Import Lookup Table
/// Null
/// DLL3 Import Lookup Table
/// Null
/// Hint-Name Table
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-idata-section</remarks>
public class ImportDataSection
{
/// <summary>
/// Import directory table
/// </summary>
public ImportDirectoryTable ImportDirectoryTable;
/// <summary>
/// Import lookup tables
/// </summary>
public ImportLookupTable[] ImportLookupTables;
/// <summary>
/// Hint/Name table
/// </summary>
public HintNameTable HintNameTable;
public static ImportDataSection Deserialize(Stream stream, bool pe32plus, int hintCount)
{
var ids = new ImportDataSection();
ids.ImportDirectoryTable = ImportDirectoryTable.Deserialize(stream);
List<ImportLookupTable> tempLookupTables = new List<ImportLookupTable>();
while (true)
{
var tempLookupTable = ImportLookupTable.Deserialize(stream, pe32plus);
if (tempLookupTable.EntriesPE32 == null && tempLookupTable.EntriesPE32Plus == null)
break;
tempLookupTables.Add(tempLookupTable);
}
ids.HintNameTable = HintNameTable.Deserialize(stream, hintCount);
return ids;
}
public static ImportDataSection Deserialize(byte[] content, ref int offset, bool pe32plus, int hintCount)
{
var ids = new ImportDataSection();
ids.ImportDirectoryTable = ImportDirectoryTable.Deserialize(content, ref offset);
List<ImportLookupTable> tempLookupTables = new List<ImportLookupTable>();
while (true)
{
var tempLookupTable = ImportLookupTable.Deserialize(content, ref offset, pe32plus);
if (tempLookupTable.EntriesPE32 == null && tempLookupTable.EntriesPE32Plus == null)
break;
tempLookupTables.Add(tempLookupTable);
}
ids.HintNameTable = HintNameTable.Deserialize(content, ref offset, hintCount);
return ids;
}
}
}

View File

@@ -0,0 +1,51 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// The base relocation table contains entries for all base relocations in the image.
/// The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table.
/// The base relocation table is divided into blocks.
/// Each block represents the base relocations for a 4K page.
/// Each block must start on a 32-bit boundary.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only</remarks>
public class RelocationSection
{
/// <summary>
/// The base relocation table is divided into blocks.
/// </summary>
public BaseRelocationBlock[] BaseRelocationTable;
public static RelocationSection Deserialize(Stream stream, int blockCount)
{
long originalPosition = stream.Position;
var rs = new RelocationSection();
rs.BaseRelocationTable = new BaseRelocationBlock[blockCount];
for (int i = 0; i < blockCount; i++)
{
rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(stream);
}
stream.Seek(originalPosition, SeekOrigin.Begin);
return rs;
}
public static RelocationSection Deserialize(byte[] content, ref int offset, int blockCount)
{
int originalPosition = offset;
var rs = new RelocationSection();
rs.BaseRelocationTable = new BaseRelocationBlock[blockCount];
for (int i = 0; i < blockCount; i++)
{
rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(content, ref offset);
}
offset = originalPosition;
return rs;
}
}
}

View File

@@ -0,0 +1,44 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
using BurnOutSharp.ExecutableType.Microsoft.PE.Tables;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections
{
/// <summary>
/// A series of resource directory tables relates all of the levels in the following way:
// Each directory table is followed by a series of directory entries that give the name or
// identifier (ID) for that level (Type, Name, or Language level) and an address of either
// a data description or another directory table. If the address points to a data description,
// then the data is a leaf in the tree. If the address points to another directory table,
// then that table lists directory entries at the next level down
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-rsrc-section</remarks>
public class ResourceSection
{
/// <summary>
/// A table with just one row (unlike the debug directory).
/// This table indicates the locations and sizes of the other export tables.
/// </summary>
public ResourceDirectoryTable ResourceDirectoryTable;
public static ResourceSection Deserialize(Stream stream, SectionHeader[] sections)
{
var rs = new ResourceSection();
long sectionStart = stream.Position;
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream, sectionStart, sections);
return rs;
}
public static ResourceSection Deserialize(byte[] content, ref int offset, SectionHeader[] sections)
{
var rs = new ResourceSection();
long sectionStart = offset;
rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, ref offset, sectionStart, sections);
return rs;
}
}
}

View File

@@ -0,0 +1,85 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// Image files contain an optional debug directory that indicates what form of debug information is present and where it is.
/// This directory consists of an array of debug directory entries whose location and size are indicated in the image optional header.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#debug-directory-image-only</remarks>
public class DebugDirectory
{
/// <summary>
/// Reserved, must be 0.
/// </summary>
public uint Characteristics;
/// <summary>
/// The time and date that the debug data was created.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The major version number of the debug data format.
/// </summary>
public ushort MajorVersion;
/// <summary>
/// The minor version number of the debug data format.
/// </summary>
public ushort MinorVersion;
/// <summary>
/// The format of debugging information. This field enables support of multiple debuggers.
/// </summary>
public DebugType DebugType;
/// <summary>
/// The size of the debug data (not including the debug directory itself).
/// </summary>
public uint SizeOfData;
/// <summary>
/// The address of the debug data when loaded, relative to the image base.
/// </summary>
public uint AddressOfRawData;
/// <summary>
/// The file pointer to the debug data.
/// </summary>
public uint PointerToRawData;
public static DebugDirectory Deserialize(Stream stream)
{
var dd = new DebugDirectory();
dd.Characteristics = stream.ReadUInt32();
dd.TimeDateStamp = stream.ReadUInt32();
dd.MajorVersion = stream.ReadUInt16();
dd.MinorVersion = stream.ReadUInt16();
dd.DebugType = (DebugType)stream.ReadUInt32();
dd.SizeOfData = stream.ReadUInt32();
dd.AddressOfRawData = stream.ReadUInt32();
dd.PointerToRawData = stream.ReadUInt32();
return dd;
}
public static DebugDirectory Deserialize(byte[] content, ref int offset)
{
var dd = new DebugDirectory();
dd.Characteristics = content.ReadUInt32(ref offset);
dd.TimeDateStamp = content.ReadUInt32(ref offset);
dd.MajorVersion = content.ReadUInt16(ref offset);
dd.MinorVersion = content.ReadUInt16(ref offset);
dd.DebugType = (DebugType)content.ReadUInt32(ref offset);
dd.SizeOfData = content.ReadUInt32(ref offset);
dd.AddressOfRawData = content.ReadUInt32(ref offset);
dd.PointerToRawData = content.ReadUInt32(ref offset);
return dd;
}
}
}

View File

@@ -0,0 +1,111 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// The export symbol information begins with the export directory table, which describes the remainder of the export symbol information.
/// The export directory table contains address information that is used to resolve imports to the entry points within this image.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table</remarks>
public class ExportDirectoryTable
{
/// <summary>
/// Reserved, must be 0.
/// </summary>
public uint ExportFlags;
/// <summary>
/// The time and date that the export data was created.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The major version number. The major and minor version numbers can be set by the user.
/// </summary>
public ushort MajorVersion;
/// <summary>
/// The minor version number.
/// </summary>
public ushort MinorVersion;
/// <summary>
/// The address of the ASCII string that contains the name of the DLL.
/// This address is relative to the image base.
/// </summary>
public uint NameRVA; // TODO: Read this into a separate field
/// <summary>
/// The starting ordinal number for exports in this image.
/// This field specifies the starting ordinal number for the export address table.
/// It is usually set to 1.
/// </summary>
public uint OrdinalBase;
/// <summary>
/// The number of entries in the export address table.
/// </summary>
public uint AddressTableEntries;
/// <summary>
/// The number of entries in the name pointer table.
/// This is also the number of entries in the ordinal table.
/// </summary>
public uint NumberOfNamePointers;
/// <summary>
/// The address of the export address table, relative to the image base.
/// </summary>
public uint ExportAddressTableRVA;
/// <summary>
/// The address of the export name pointer table, relative to the image base.
/// The table size is given by the Number of Name Pointers field.
/// </summary>
public uint NamePointerRVA;
/// <summary>
/// The address of the ordinal table, relative to the image base.
/// </summary>
public uint OrdinalTableRVA;
public static ExportDirectoryTable Deserialize(Stream stream)
{
var edt = new ExportDirectoryTable();
edt.ExportFlags = stream.ReadUInt32();
edt.TimeDateStamp = stream.ReadUInt32();
edt.MajorVersion = stream.ReadUInt16();
edt.MinorVersion = stream.ReadUInt16();
edt.NameRVA = stream.ReadUInt32();
edt.OrdinalBase = stream.ReadUInt32();
edt.AddressTableEntries = stream.ReadUInt32();
edt.NumberOfNamePointers = stream.ReadUInt32();
edt.ExportAddressTableRVA = stream.ReadUInt32();
edt.NamePointerRVA = stream.ReadUInt32();
edt.OrdinalTableRVA = stream.ReadUInt32();
return edt;
}
public static ExportDirectoryTable Deserialize(byte[] content, ref int offset)
{
var edt = new ExportDirectoryTable();
edt.ExportFlags = content.ReadUInt32(ref offset);
edt.TimeDateStamp = content.ReadUInt32(ref offset);
edt.MajorVersion = content.ReadUInt16(ref offset);
edt.MinorVersion = content.ReadUInt16(ref offset);
edt.NameRVA = content.ReadUInt32(ref offset);
edt.OrdinalBase = content.ReadUInt32(ref offset);
edt.AddressTableEntries = content.ReadUInt32(ref offset);
edt.NumberOfNamePointers = content.ReadUInt32(ref offset);
edt.ExportAddressTableRVA = content.ReadUInt32(ref offset);
edt.NamePointerRVA = content.ReadUInt32(ref offset);
edt.OrdinalTableRVA = content.ReadUInt32(ref offset);
return edt;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// The export ordinal table is an array of 16-bit unbiased indexes into the export address table.
/// Ordinals are biased by the Ordinal Base field of the export directory table.
/// In other words, the ordinal base must be subtracted from the ordinals to obtain true indexes into the export address table.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-ordinal-table</remarks>
public class ExportOrdinalTable
{
/// <remarks>Number of entries is defined externally</remarks>
public ushort[] Entries;
public static ExportOrdinalTable Deserialize(Stream stream, int count)
{
var edt = new ExportOrdinalTable();
edt.Entries = new ushort[count];
for (int i = 0; i < count; i++)
{
edt.Entries[i] = stream.ReadUInt16();
}
return edt;
}
public static ExportOrdinalTable Deserialize(byte[] content, ref int offset, int count)
{
var edt = new ExportOrdinalTable();
edt.Entries = new ushort[count];
for (int i = 0; i < count; i++)
{
edt.Entries[i] = content.ReadUInt16(ref offset);
}
return edt;
}
}
}

View File

@@ -0,0 +1,17 @@
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// The .pdata section contains an array of function table entries that are used for exception handling.
/// It is pointed to by the exception table entry in the image data directory.
/// The entries must be sorted according to the function addresses (the first field in each structure) before being emitted into the final image.
/// The target platform determines which of the three function table entry format variations described below is used.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-pdata-section</remarks>
public class FunctionTable
{
/// <remarks>Number of entries is defined externally</remarks>
public FunctionTableEntry[] Entries;
}
}

View File

@@ -0,0 +1,42 @@
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// One hint/name table suffices for the entire import section.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#hintname-table</remarks>
public class HintNameTable
{
/// <remarks>Number of entries is defined externally</remarks>
public HintNameTableEntry[] Entries;
public static HintNameTable Deserialize(Stream stream, int count)
{
var hnt = new HintNameTable();
hnt.Entries = new HintNameTableEntry[count];
for (int i = 0; i < count; i++)
{
hnt.Entries[i] = HintNameTableEntry.Deserialize(stream);
}
return hnt;
}
public static HintNameTable Deserialize(byte[] content, ref int offset, int count)
{
var hnt = new HintNameTable();
hnt.Entries = new HintNameTableEntry[count];
for (int i = 0; i < count; i++)
{
hnt.Entries[i] = HintNameTableEntry.Deserialize(content, ref offset);
offset += 2 + hnt.Entries[i].Name.Length + hnt.Entries[i].Pad;
}
return hnt;
}
}
}

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// The structure and content of the import address table are identical to those of the import lookup table, until the file is bound.
/// During binding, the entries in the import address table are overwritten with the 32-bit (for PE32) or 64-bit (for PE32+) addresses of the symbols that are being imported.
/// These addresses are the actual memory addresses of the symbols, although technically they are still called "virtual addresses."
/// The loader typically processes the binding.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-address-table</remarks>
public class ImportAddressTable
{
/// <remarks>Number of entries is known after parsing</remarks>
public ImportAddressTableEntry[] Entries;
public static ImportAddressTable Deserialize(Stream stream)
{
var iat = new ImportAddressTable();
List<ImportAddressTableEntry> tempEntries = new List<ImportAddressTableEntry>();
while (true)
{
var entry = ImportAddressTableEntry.Deserialize(stream);
tempEntries.Add(entry);
if (entry.IsNull())
break;
}
iat.Entries = tempEntries.ToArray();
return iat;
}
public static ImportAddressTable Deserialize(byte[] content, ref int offset)
{
var iat = new ImportAddressTable();
List<ImportAddressTableEntry> tempEntries = new List<ImportAddressTableEntry>();
while (true)
{
var entry = ImportAddressTableEntry.Deserialize(content, ref offset);
tempEntries.Add(entry);
if (entry.IsNull())
break;
}
iat.Entries = tempEntries.ToArray();
return iat;
}
}
}

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// The import information begins with the import directory table, which describes the remainder of the import information.
/// The import directory table contains address information that is used to resolve fixup references to the entry points within a DLL image.
/// The import directory table consists of an array of import directory entries, one entry for each DLL to which the image refers.
/// The last directory entry is empty (filled with null values), which indicates the end of the directory table.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table</remarks>
public class ImportDirectoryTable
{
/// <remarks>Number of entries is known after parsing</remarks>
public ImportDirectoryTableEntry[] Entries;
public static ImportDirectoryTable Deserialize(Stream stream)
{
var idt = new ImportDirectoryTable();
List<ImportDirectoryTableEntry> tempEntries = new List<ImportDirectoryTableEntry>();
while (true)
{
var entry = ImportDirectoryTableEntry.Deserialize(stream);
tempEntries.Add(entry);
if (entry.IsNull())
break;
}
idt.Entries = tempEntries.ToArray();
return idt;
}
public static ImportDirectoryTable Deserialize(byte[] content, ref int offset)
{
var idt = new ImportDirectoryTable();
List<ImportDirectoryTableEntry> tempEntries = new List<ImportDirectoryTableEntry>();
while (true)
{
var entry = ImportDirectoryTableEntry.Deserialize(content, ref offset);
tempEntries.Add(entry);
if (entry.IsNull())
break;
}
idt.Entries = tempEntries.ToArray();
return idt;
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// An import lookup table is an array of 32-bit numbers for PE32 or an array of 64-bit numbers for PE32+.
/// Each entry uses the bit-field format that is described in the following table.
/// In this format, bit 31 is the most significant bit for PE32 and bit 63 is the most significant bit for PE32+.
/// The collection of these entries describes all imports from a given DLL.
/// The last entry is set to zero (NULL) to indicate the end of the table.
/// </summary>
/// <remarks>https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-lookup-table</remarks>
public class ImportLookupTable
{
/// <remarks>Number of entries is known after parsing</remarks>
public uint[] EntriesPE32;
/// <remarks>Number of entries is known after parsing</remarks>
public ulong[] EntriesPE32Plus;
public static ImportLookupTable Deserialize(Stream stream, bool pe32plus)
{
var ilt = new ImportLookupTable();
// PE32+ has 8-byte values
if (pe32plus)
{
List<ulong> tempEntries = new List<ulong>();
while (true)
{
ulong bitfield = stream.ReadUInt64();
tempEntries.Add(bitfield);
if (bitfield == 0)
break;
}
if (tempEntries.Count > 0)
ilt.EntriesPE32Plus = tempEntries.ToArray();
}
else
{
List<uint> tempEntries = new List<uint>();
while (true)
{
uint bitfield = stream.ReadUInt32();
tempEntries.Add(bitfield);
if (bitfield == 0)
break;
}
if (tempEntries.Count > 0)
ilt.EntriesPE32 = tempEntries.ToArray();
}
return ilt;
}
public static ImportLookupTable Deserialize(byte[] content, ref int offset, bool pe32plus)
{
var ilt = new ImportLookupTable();
// PE32+ has 8-byte values
if (pe32plus)
{
List<ulong> tempEntries = new List<ulong>();
while (true)
{
ulong bitfield = content.ReadUInt64(ref offset);
tempEntries.Add(bitfield);
if (bitfield == 0)
break;
}
if (tempEntries.Count > 0)
ilt.EntriesPE32Plus = tempEntries.ToArray();
}
else
{
List<uint> tempEntries = new List<uint>();
while (true)
{
uint bitfield = content.ReadUInt32(ref offset);
tempEntries.Add(bitfield);
if (bitfield == 0)
break;
}
if (tempEntries.Count > 0)
ilt.EntriesPE32 = tempEntries.ToArray();
}
return ilt;
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.IO;
using BurnOutSharp.ExecutableType.Microsoft.PE.Entries;
using BurnOutSharp.ExecutableType.Microsoft.PE.Headers;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.PE.Tables
{
/// <summary>
/// Each resource directory table has the following format.
/// This data structure should be considered the heading of a table
/// because the table actually consists of directory entries and this structure
/// </summary>
public class ResourceDirectoryTable
{
/// <summary>
/// Resource flags.
/// This field is reserved for future use.
/// It is currently set to zero.
/// </summary>
public uint Characteristics;
/// <summary>
/// The time that the resource data was created by the resource compiler.
/// </summary>
public uint TimeDateStamp;
/// <summary>
/// The major version number, set by the user.
/// </summary>
public ushort MajorVersion;
/// <summary>
/// The minor version number, set by the user.
/// </summary>
public ushort MinorVersion;
/// <summary>
/// The number of directory entries immediately following
/// the table that use strings to identify Type, Name, or
/// Language entries (depending on the level of the table).
/// </summary>
public ushort NumberOfNamedEntries;
/// <summary>
/// The number of directory entries immediately following
/// the Name entries that use numeric IDs for Type, Name,
/// or Language entries.
/// </summary>
public ushort NumberOfIdEntries;
/// <summary>
/// The directory entries immediately following
/// the table that use strings to identify Type, Name, or
/// Language entries (depending on the level of the table).
/// </summary>
public ResourceDirectoryTableEntry[] NamedEntries;
/// <summary>
/// The directory entries immediately following
/// the Name entries that use numeric IDs for Type, Name,
/// or Language entries.
/// </summary>
public ResourceDirectoryTableEntry[] IdEntries;
public static ResourceDirectoryTable Deserialize(Stream stream, long sectionStart, SectionHeader[] sections)
{
var rdt = new ResourceDirectoryTable();
rdt.Characteristics = stream.ReadUInt32();
rdt.TimeDateStamp = stream.ReadUInt32();
rdt.MajorVersion = stream.ReadUInt16();
rdt.MinorVersion = stream.ReadUInt16();
rdt.NumberOfNamedEntries = stream.ReadUInt16();
rdt.NumberOfIdEntries = stream.ReadUInt16();
rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries];
for (int i = 0; i < rdt.NumberOfNamedEntries; i++)
{
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sectionStart, sections);
}
rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries];
for (int i = 0; i < rdt.NumberOfIdEntries; i++)
{
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sectionStart, sections);
}
return rdt;
}
public static ResourceDirectoryTable Deserialize(byte[] content, ref int offset, long sectionStart, SectionHeader[] sections)
{
var rdt = new ResourceDirectoryTable();
rdt.Characteristics = content.ReadUInt32(ref offset);
rdt.TimeDateStamp = content.ReadUInt32(ref offset);
rdt.MajorVersion = content.ReadUInt16(ref offset);
rdt.MinorVersion = content.ReadUInt16(ref offset);
rdt.NumberOfNamedEntries = content.ReadUInt16(ref offset);
rdt.NumberOfIdEntries = content.ReadUInt16(ref offset);
rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries];
for (int i = 0; i < rdt.NumberOfNamedEntries; i++)
{
rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, ref offset, sectionStart, sections);
}
rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries];
for (int i = 0; i < rdt.NumberOfIdEntries; i++)
{
rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, ref offset, sectionStart, sections);
}
return rdt;
}
}
}

View File

@@ -0,0 +1,147 @@
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class FixedFileInfo
{
/// <summary>
/// Contains the value 0xFEEF04BD.
/// This is used with the szKey member of the VS_VERSIONINFO structure when searching a file for the VS_FIXEDFILEINFO structure.
/// </summary>
public uint Signature;
/// <summary>
/// The binary version number of this structure.
/// The high-order word of this member contains the major version number, and the low-order word contains the minor version number.
/// </summary>
public uint StrucVersion;
/// <summary>
/// The most significant 32 bits of the file's binary version number.
/// This member is used with dwFileVersionLS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint FileVersionMS;
/// <summary>
/// The least significant 32 bits of the file's binary version number.
/// This member is used with dwFileVersionMS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint FileVersionLS;
/// <summary>
/// The most significant 32 bits of the binary version number of the product with which this file was distributed.
/// This member is used with dwProductVersionLS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint ProductVersionMS;
/// <summary>
/// The least significant 32 bits of the binary version number of the product with which this file was distributed.
/// This member is used with dwProductVersionMS to form a 64-bit value used for numeric comparisons.
/// </summary>
public uint ProductVersionLS;
/// <summary>
/// Contains a bitmask that specifies the valid bits in dwFileFlags.
/// A bit is valid only if it was defined when the file was created.
/// </summary>
public uint FileFlagsMask;
/// <summary>
/// Contains a bitmask that specifies the Boolean attributes of the file. This member can include one or more of the following values.
/// </summary>
public FileInfoFileFlags FileFlags;
/// <summary>
/// The operating system for which this file was designed. This member can be one of the following values.
///
/// An application can combine these values to indicate that the file was designed for one operating system running on another.
/// The following dwFileOS values are examples of this, but are not a complete list.
/// </summary>
public FileInfoOS FileOS;
/// <summary>
/// The general type of file. This member can be one of the following values. All other values are reserved.
/// </summary>
public FileInfoFileType FileType;
/// <summary>
/// The function of the file. The possible values depend on the value of dwFileType.
/// For all values of dwFileType not described in the following list, dwFileSubtype is zero.
///
/// If dwFileType is VFT_DRV, dwFileSubtype can be one of the following values.
///
/// If dwFileType is VFT_FONT, dwFileSubtype can be one of the following values.
///
/// If dwFileType is VFT_VXD, dwFileSubtype contains the virtual device identifier included in the virtual device control block.
/// All dwFileSubtype values not listed here are reserved.
/// </summary>
public FileInfoFileSubtype FileSubtype;
/// <summary>
/// The most significant 32 bits of the file's 64-bit binary creation date and time stamp.
/// </summary>
public uint FileDateMS;
/// <summary>
/// The least significant 32 bits of the file's 64-bit binary creation date and time stamp.
/// </summary>
public uint FileDateLS;
public static FixedFileInfo Deserialize(Stream stream)
{
FixedFileInfo ffi = new FixedFileInfo();
ushort temp;
while ((temp = stream.ReadUInt16()) == 0x0000);
stream.Seek(-2, SeekOrigin.Current);
ffi.Signature = stream.ReadUInt32();
ffi.StrucVersion = stream.ReadUInt32();
ffi.FileVersionMS = stream.ReadUInt32();
ffi.FileVersionLS = stream.ReadUInt32();
ffi.ProductVersionMS = stream.ReadUInt32();
ffi.ProductVersionLS = stream.ReadUInt32();
ffi.FileFlagsMask = stream.ReadUInt32();
ffi.FileFlags = (FileInfoFileFlags)stream.ReadUInt32();
ffi.FileOS = (FileInfoOS)stream.ReadUInt32();
ffi.FileType = (FileInfoFileType)stream.ReadUInt32();
ffi.FileSubtype = (FileInfoFileSubtype)stream.ReadUInt32();
ffi.FileDateMS = stream.ReadUInt32();
ffi.FileDateLS = stream.ReadUInt32();
return ffi;
}
public static FixedFileInfo Deserialize(byte[] content, ref int offset)
{
FixedFileInfo ffi = new FixedFileInfo();
ushort temp;
bool padded = false;
while ((temp = content.ReadUInt16(ref offset)) == 0x0000)
{
padded = true;
}
if (padded)
offset -= 2;
ffi.Signature = content.ReadUInt32(ref offset);
ffi.StrucVersion = content.ReadUInt32(ref offset);
ffi.FileVersionMS = content.ReadUInt32(ref offset);
ffi.FileVersionLS = content.ReadUInt32(ref offset);
ffi.ProductVersionMS = content.ReadUInt32(ref offset);
ffi.ProductVersionLS = content.ReadUInt32(ref offset);
ffi.FileFlagsMask = content.ReadUInt32(ref offset);
ffi.FileFlags = (FileInfoFileFlags)content.ReadUInt32(ref offset);
ffi.FileOS = (FileInfoOS)content.ReadUInt32(ref offset);
ffi.FileType = (FileInfoFileType)content.ReadUInt32(ref offset);
ffi.FileSubtype = (FileInfoFileSubtype)content.ReadUInt32(ref offset);
ffi.FileDateMS = content.ReadUInt32(ref offset);
ffi.FileDateLS = content.ReadUInt32(ref offset);
return ffi;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.IO;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
/// <summary>
/// If you use the Var structure to list the languages your application or DLL supports instead of using multiple version resources,
/// use the Value member to contain an array of DWORD values indicating the language and code page combinations supported by this file.
/// The low-order word of each DWORD must contain a Microsoft language identifier, and the high-order word must contain the IBM code page number.
/// Either high-order or low-order word can be zero, indicating that the file is language or code page independent.
/// If the Var structure is omitted, the file will be interpreted as both language and code page independent.
/// </summary>
public class LanguageCodePage
{
/// <summary>
/// The low-order word of each DWORD must contain a Microsoft language identifier
/// </summary>
public ushort MicrosoftLanguageIdentifier;
/// <summary>
/// The high-order word must contain the IBM code page number
/// </summary>
public ushort IBMCodePageNumber;
public static LanguageCodePage Deserialize(Stream stream)
{
LanguageCodePage lcp = new LanguageCodePage();
lcp.MicrosoftLanguageIdentifier = stream.ReadUInt16();
lcp.IBMCodePageNumber = stream.ReadUInt16();
return lcp;
}
public static LanguageCodePage Deserialize(byte[] content, ref int offset)
{
LanguageCodePage lcp = new LanguageCodePage();
lcp.MicrosoftLanguageIdentifier = content.ReadUInt16(ref offset);
lcp.IBMCodePageNumber = content.ReadUInt16(ref offset);
return lcp;
}
}
}

View File

@@ -0,0 +1,58 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class Resource
{
/// <summary>
/// The length, in bytes, of the resource structure.
/// This length does not include any padding that aligns any subsequent version resource data on a 32-bit boundary.
/// </summary>
public ushort Length;
/// <summary>
/// The length, in bytes, of the Value member.
/// This value is zero if there is no Value member associated with the current version structure.
/// </summary>
public ushort ValueLength;
/// <summary>
/// The type of data in the version resource.
/// This member is 1 if the version resource contains text data and 0 if the version resource contains binary data.
/// </summary>
public ushort Type;
/// <summary>
/// A Unicode string representing the key
/// </summary>
public string Key;
public static Resource Deserialize(Stream stream)
{
Resource r = new Resource();
while ((r.Length = stream.ReadUInt16()) == 0x0000);
r.ValueLength = stream.ReadUInt16();
r.Type = stream.ReadUInt16();
r.Key = stream.ReadString(Encoding.Unicode);
return r;
}
public static Resource Deserialize(byte[] content, ref int offset)
{
Resource r = new Resource();
while ((r.Length = content.ReadUInt16(ref offset)) == 0x0000);
r.ValueLength = content.ReadUInt16(ref offset);
r.Type = content.ReadUInt16(ref offset);
r.Key = content.ReadString(ref offset, Encoding.Unicode);
return r;
}
}
}

View File

@@ -0,0 +1,45 @@
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class StringFileInfo : Resource
{
/// <summary>
/// An array of one or more StringTable structures.
/// Each StringTable structure's szKey member indicates the appropriate language and code page for displaying the text in that StringTable structure.
/// </summary>
public StringTable Children;
public StringFileInfo(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key?.TrimStart('\u0001') ?? default;
}
public static new StringFileInfo Deserialize(Stream stream)
{
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "StringFileInfo" && resource.Key != "\u0001StringFileInfo")
return null;
StringFileInfo sfi = new StringFileInfo(resource);
sfi.Children = StringTable.Deserialize(stream);
return sfi;
}
public static new StringFileInfo Deserialize(byte[] content, ref int offset)
{
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "StringFileInfo" && resource.Key != "\u0001StringFileInfo")
return null;
StringFileInfo sfi = new StringFileInfo(resource);
sfi.Children = StringTable.Deserialize(content, ref offset);
return sfi;
}
}
}

View File

@@ -0,0 +1,42 @@
using System.IO;
using System.Text;
using BurnOutSharp.Tools;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class StringStruct : Resource
{
/// <summary>
/// Typically contains a list of languages that the application or DLL supports.
/// </summary>
public string Value;
public StringStruct(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key ?? default;
}
public static new StringStruct Deserialize(Stream stream)
{
Resource resource = Resource.Deserialize(stream);
StringStruct s = new StringStruct(resource);
stream.Seek(stream.Position % 4 == 0 ? 0 : 4 - (stream.Position % 4), SeekOrigin.Current);
s.Value = new string(stream.ReadChars(s.ValueLength));
return s;
}
public static new StringStruct Deserialize(byte[] content, ref int offset)
{
Resource resource = Resource.Deserialize(content, ref offset);
StringStruct s = new StringStruct(resource);
offset += offset % 4 == 0 ? 0 : 4 - (offset % 4);
s.Value = Encoding.Unicode.GetString(content, offset, s.ValueLength * 2); offset += s.ValueLength * 2;
return s;
}
}
}

View File

@@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class StringTable : Resource
{
/// <summary>
/// An array of one or more String structures.
/// </summary>
public StringStruct[] Children;
public StringTable(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key ?? default;
}
public static new StringTable Deserialize(Stream stream)
{
long originalPosition = stream.Position;
Resource resource = Resource.Deserialize(stream);
if (resource.Key.Length != 8)
return null;
StringTable st = new StringTable(resource);
var tempValue = new List<StringStruct>();
while (stream.Position - originalPosition < st.Length)
{
tempValue.Add(StringStruct.Deserialize(stream));
}
st.Children = tempValue.ToArray();
return st;
}
public static new StringTable Deserialize(byte[] content, ref int offset)
{
int originalPosition = offset;
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key.Length != 8)
return null;
StringTable st = new StringTable(resource);
var tempValue = new List<StringStruct>();
while (offset - originalPosition < st.Length)
{
tempValue.Add(StringStruct.Deserialize(content, ref offset));
}
st.Children = tempValue.ToArray();
return st;
}
}
}

View File

@@ -0,0 +1,67 @@
using System.Collections.Generic;
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class Var : Resource
{
/// <summary>
/// An array of one or more values that are language and code page identifier pairs.
///
/// If you use the Var structure to list the languages your application or DLL supports instead of using multiple version resources,
/// use the Value member to contain an array of DWORD values indicating the language and code page combinations supported by this file.
/// The low-order word of each DWORD must contain a Microsoft language identifier, and the high-order word must contain the IBM code page number.
/// Either high-order or low-order word can be zero, indicating that the file is language or code page independent.
/// If the Var structure is omitted, the file will be interpreted as both language and code page independent.
/// </summary>
public LanguageCodePage[] Value;
public Var(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key ?? default;
}
public static new Var Deserialize(Stream stream)
{
long originalPosition = stream.Position;
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "Translation")
return null;
Var v = new Var(resource);
var tempValue = new List<LanguageCodePage>();
while (stream.Position - originalPosition < v.Length)
{
tempValue.Add(LanguageCodePage.Deserialize(stream));
}
v.Value = tempValue.ToArray();
return v;
}
public static new Var Deserialize(byte[] content, ref int offset)
{
int originalPosition = offset;
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "Translation")
return null;
Var v = new Var(resource);
var tempValue = new List<LanguageCodePage>();
while (offset - originalPosition < v.Length)
{
tempValue.Add(LanguageCodePage.Deserialize(content, ref offset));
}
v.Value = tempValue.ToArray();
return v;
}
}
}

View File

@@ -0,0 +1,44 @@
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class VarFileInfo : Resource
{
/// <summary>
/// Typically contains a list of languages that the application or DLL supports.
/// </summary>
public Var Children;
public VarFileInfo(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key ?? default;
}
public static new VarFileInfo Deserialize(Stream stream)
{
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "VarFileInfo")
return null;
VarFileInfo vfi = new VarFileInfo(resource);
vfi.Children = Var.Deserialize(stream);
return vfi;
}
public static new VarFileInfo Deserialize(byte[] content, ref int offset)
{
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "VarFileInfo")
return null;
VarFileInfo vfi = new VarFileInfo(resource);
vfi.Children = Var.Deserialize(content, ref offset);
return vfi;
}
}
}

View File

@@ -0,0 +1,129 @@
using System.IO;
namespace BurnOutSharp.ExecutableType.Microsoft.Resources
{
public class VersionInfo : Resource
{
/// <summary>
/// Arbitrary data associated with this VS_VERSIONINFO structure.
/// The wValueLength member specifies the length of this member;
/// if wValueLength is zero, this member does not exist.
/// </summary>
public FixedFileInfo Value;
/// <summary>
/// An array of zero or one StringFileInfo structures, and zero or one VarFileInfo structures
/// that are children of the current VS_VERSIONINFO structure.
/// </summary>
public StringFileInfo ChildrenStringFileInfo;
/// <summary>
/// An array of zero or one StringFileInfo structures, and zero or one VarFileInfo structures
/// that are children of the current VS_VERSIONINFO structure.
/// </summary>
public VarFileInfo ChildrenVarFileInfo;
public VersionInfo(Resource resource)
{
this.Length = resource?.Length ?? default;
this.ValueLength = resource?.ValueLength ?? default;
this.Type = resource?.Type ?? default;
this.Key = resource?.Key ?? default;
}
public static new VersionInfo Deserialize(Stream stream)
{
long originalPosition = stream.Position;
Resource resource = Resource.Deserialize(stream);
if (resource.Key != "VS_VERSION_INFO")
return null;
VersionInfo vi = new VersionInfo(resource);
if (vi.ValueLength > 0)
vi.Value = FixedFileInfo.Deserialize(stream);
if (stream.Position - originalPosition > vi.Length)
return vi;
long preChildOffset = stream.Position;
Resource firstChild = Resource.Deserialize(stream);
if (firstChild.Key == "StringFileInfo" || firstChild.Key == "\u0001StringFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(stream);
}
else if (firstChild.Key == "VarFileInfo" || firstChild.Key == "\u0001VarFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(stream);
}
if (stream.Position - originalPosition > vi.Length)
return vi;
preChildOffset = stream.Position;
Resource secondChild = Resource.Deserialize(stream);
if (secondChild.Key == "StringFileInfo" || secondChild.Key == "\u0001StringFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(stream);
}
else if (secondChild.Key == "VarFileInfo" || secondChild.Key == "\u0001VarFileInfo")
{
stream.Seek(preChildOffset, SeekOrigin.Begin);
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(stream);
}
return vi;
}
public static new VersionInfo Deserialize(byte[] content, ref int offset)
{
int originalOffset = offset;
Resource resource = Resource.Deserialize(content, ref offset);
if (resource.Key != "VS_VERSION_INFO")
return null;
VersionInfo vi = new VersionInfo(resource);
if (vi.ValueLength > 0)
vi.Value = FixedFileInfo.Deserialize(content, ref offset);
if (offset - originalOffset > vi.Length)
return vi;
int preChildOffset = offset;
Resource firstChild = Resource.Deserialize(content, ref offset);
if (firstChild.Key == "StringFileInfo" || firstChild.Key == "\u0001StringFileInfo")
{
offset = preChildOffset;
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(content, ref offset);
}
else if (firstChild.Key == "VarFileInfo" || firstChild.Key == "\u0001VarFileInfo")
{
offset = preChildOffset;
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(content, ref offset);
}
if (offset - originalOffset > vi.Length)
return vi;
preChildOffset = offset;
Resource secondChild = Resource.Deserialize(content, ref offset);
if (secondChild.Key == "StringFileInfo" || secondChild.Key == "\u0001StringFileInfo")
{
offset = preChildOffset;
vi.ChildrenStringFileInfo = StringFileInfo.Deserialize(content, ref offset);
}
else if (secondChild.Key == "VarFileInfo" || secondChild.Key == "\u0001VarFileInfo")
{
offset = preChildOffset;
vi.ChildrenVarFileInfo = VarFileInfo.Deserialize(content, ref offset);
}
return vi;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

8
BurnOutSharp/External/README.MD vendored Normal file
View File

@@ -0,0 +1,8 @@
# External Library Notes
This directory contains multiple external libraries. Here is the status of each:
| Directory | Library | Status |
| --------- | ------- | ------ |
| psxt001z | [psxt001z](https://github.com/Dremora/psxt001z) | 90% ported to C#, device reading disabled |
| stormlibsharp | [stormlibsharp](https://github.com/robpaveza/stormlibsharp) | External submodule |

View File

@@ -1,414 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp
{
public class MpqArchive : IDisposable
{
private MpqArchiveSafeHandle _handle;
private List<MpqFileStream> _openFiles = new List<MpqFileStream>();
private FileAccess _accessType;
private List<MpqArchiveCompactingEventHandler> _compactCallbacks = new List<MpqArchiveCompactingEventHandler>();
private SFILE_COMPACT_CALLBACK _compactCallback;
#region Constructors / Factories
public MpqArchive(string filePath, FileAccess accessType)
{
_accessType = accessType;
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(filePath, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
public MpqArchive(MemoryMappedFile file, FileAccess accessType)
{
_accessType = accessType;
string fileName = Win32Methods.GetFileNameOfMemoryMappedFile(file);
if (fileName == null)
throw new ArgumentException("Could not retrieve the name of the file to initialize.");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsMemoryMapped;
if (accessType == FileAccess.Read)
flags |= SFileOpenArchiveFlags.AccessReadOnly;
else
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
if (!NativeMethods.SFileOpenArchive(fileName, 2, flags, out _handle))
throw new Win32Exception(); // Implicitly calls GetLastError
}
private MpqArchive(string filePath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes, MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
if (maxFileCount < 0)
throw new ArgumentException("maxFileCount");
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsFile | SFileOpenArchiveFlags.AccessReadWriteShare;
flags |= (SFileOpenArchiveFlags)version;
//SFILE_CREATE_MPQ create = new SFILE_CREATE_MPQ()
//{
// cbSize = unchecked((uint)Marshal.SizeOf(typeof(SFILE_CREATE_MPQ))),
// dwMaxFileCount = unchecked((uint)maxFileCount),
// dwMpqVersion = (uint)version,
// dwFileFlags1 = (uint)listfileAttributes,
// dwFileFlags2 = (uint)attributesFileAttributes,
// dwStreamFlags = (uint)flags,
//};
//if (!NativeMethods.SFileCreateArchive2(filePath, ref create, out _handle))
// throw new Win32Exception();
if (!NativeMethods.SFileCreateArchive(filePath, (uint)flags, int.MaxValue, out _handle))
throw new Win32Exception();
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version)
{
return CreateNew(mpqPath, version, MpqFileStreamAttributes.None, MpqFileStreamAttributes.None, int.MaxValue);
}
public static MpqArchive CreateNew(string mpqPath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes,
MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
{
return new MpqArchive(mpqPath, version, listfileAttributes, attributesFileAttributes, maxFileCount);
}
#endregion
#region Properties
// TODO: Move to common location.
// This is a global setting, not per-archive setting.
//public int Locale
//{
// get
// {
// throw new NotImplementedException();
// }
// set
// {
// throw new NotImplementedException();
// }
//}
public long MaxFileCount
{
get
{
VerifyHandle();
return NativeMethods.SFileGetMaxFileCount(_handle);
}
set
{
if (value < 0 || value > uint.MaxValue)
throw new ArgumentException("value");
VerifyHandle();
if (!NativeMethods.SFileSetMaxFileCount(_handle, unchecked((uint)value)))
throw new Win32Exception();
}
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid)
throw new ObjectDisposedException("MpqArchive");
}
public bool IsPatchedArchive
{
get
{
VerifyHandle();
return NativeMethods.SFileIsPatchedArchive(_handle);
}
}
#endregion
public void Flush()
{
VerifyHandle();
if (!NativeMethods.SFileFlushArchive(_handle))
throw new Win32Exception();
}
public int AddListFile(string listfileContents)
{
VerifyHandle();
return NativeMethods.SFileAddListFile(_handle, listfileContents);
}
public void AddFileFromDisk(string filePath, string archiveName)
{
VerifyHandle();
if (!NativeMethods.SFileAddFile(_handle, filePath, archiveName, 0))
throw new Win32Exception();
}
public void Compact(string listfile)
{
VerifyHandle();
if (!NativeMethods.SFileCompactArchive(_handle, listfile, false))
throw new Win32Exception();
}
private void _OnCompact(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes)
{
MpqArchiveCompactingEventArgs args = new MpqArchiveCompactingEventArgs(dwWorkType, bytesProcessed, totalBytes);
OnCompacting(args);
}
protected virtual void OnCompacting(MpqArchiveCompactingEventArgs e)
{
foreach (var cb in _compactCallbacks)
{
cb(this, e);
}
}
public event MpqArchiveCompactingEventHandler Compacting
{
add
{
VerifyHandle();
_compactCallback = _OnCompact;
if (!NativeMethods.SFileSetCompactCallback(_handle, _compactCallback, IntPtr.Zero))
throw new Win32Exception();
_compactCallbacks.Add(value);
}
remove
{
_compactCallbacks.Remove(value);
VerifyHandle();
if (_compactCallbacks.Count == 0)
{
if (!NativeMethods.SFileSetCompactCallback(_handle, null, IntPtr.Zero))
{
// Don't do anything here. Remove shouldn't fail hard.
}
}
}
}
// TODO: Determine if SFileGetAttributes/SFileSetAttributes/SFileUpdateFileAttributes deserves a projection.
// It's unclear - these seem to affect the (attributes) file but I can't figure out exactly what that means.
public void AddPatchArchive(string patchPath)
{
VerifyHandle();
if (!NativeMethods.SFileOpenPatchArchive(_handle, patchPath, null, 0))
throw new Win32Exception();
}
public void AddPatchArchives(IEnumerable<string> patchPaths)
{
if (patchPaths == null)
throw new ArgumentNullException("patchPaths");
VerifyHandle();
foreach (string path in patchPaths)
{
// Don't sublet to AddPatchArchive to avoid having to repeatedly call VerifyHandle()
if (!NativeMethods.SFileOpenPatchArchive(_handle, path, null, 0))
throw new Win32Exception();
}
}
public bool HasFile(string fileToFind)
{
VerifyHandle();
return NativeMethods.SFileHasFile(_handle, fileToFind);
}
public MpqFileStream OpenFile(string fileName)
{
VerifyHandle();
MpqFileSafeHandle fileHandle;
if (!NativeMethods.SFileOpenFileEx(_handle, fileName, 0, out fileHandle))
throw new Win32Exception();
MpqFileStream fs = new MpqFileStream(fileHandle, _accessType, this);
_openFiles.Add(fs);
return fs;
}
public void ExtractFile(string fileToExtract, string destinationPath)
{
VerifyHandle();
if (!NativeMethods.SFileExtractFile(_handle, fileToExtract, destinationPath, 0))
throw new Win32Exception();
}
public MpqFileVerificationResults VerifyFile(string fileToVerify)
{
VerifyHandle();
return (MpqFileVerificationResults)NativeMethods.SFileVerifyFile(_handle, fileToVerify, 0);
}
// TODO: Consider SFileVerifyRawData
public MpqArchiveVerificationResult VerifyArchive()
{
VerifyHandle();
return (MpqArchiveVerificationResult)NativeMethods.SFileVerifyArchive(_handle);
}
#region IDisposable implementation
public void Dispose()
{
Dispose(true);
}
~MpqArchive()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Release owned files first.
if (_openFiles != null)
{
foreach (var file in _openFiles)
{
file.Dispose();
}
_openFiles.Clear();
_openFiles = null;
}
// Release
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
}
}
internal void RemoveOwnedFile(MpqFileStream file)
{
_openFiles.Remove(file);
}
#endregion
}
public enum MpqArchiveVersion
{
Version1 = 0,
Version2 = 0x01000000,
Version3 = 0x02000000,
Version4 = 0x03000000,
}
[Flags]
public enum MpqFileStreamAttributes
{
None = 0x0,
}
[Flags]
public enum MpqFileVerificationResults
{
/// <summary>
/// There were no errors with the file.
/// </summary>
Verified = 0,
/// <summary>
/// Failed to open the file
/// </summary>
Error = 0x1,
/// <summary>
/// Failed to read all data from the file
/// </summary>
ReadError = 0x2,
/// <summary>
/// File has sector CRC
/// </summary>
HasSectorCrc = 0x4,
/// <summary>
/// Sector CRC check failed
/// </summary>
SectorCrcError = 0x8,
/// <summary>
/// File has CRC32
/// </summary>
HasChecksum = 0x10,
/// <summary>
/// CRC32 check failed
/// </summary>
ChecksumError = 0x20,
/// <summary>
/// File has data MD5
/// </summary>
HasMd5 = 0x40,
/// <summary>
/// MD5 check failed
/// </summary>
Md5Error = 0x80,
/// <summary>
/// File has raw data MD5
/// </summary>
HasRawMd5 = 0x100,
/// <summary>
/// Raw MD5 check failed
/// </summary>
RawMd5Error = 0x200,
}
public enum MpqArchiveVerificationResult
{
/// <summary>
/// There is no signature in the MPQ
/// </summary>
NoSignature = 0,
/// <summary>
/// There was an error during verifying signature (like no memory)
/// </summary>
VerificationFailed = 1,
/// <summary>
/// There is a weak signature and sign check passed
/// </summary>
WeakSignatureVerified = 2,
/// <summary>
/// There is a weak signature but sign check failed
/// </summary>
WeakSignatureFailed = 3,
/// <summary>
/// There is a strong signature and sign check passed
/// </summary>
StrongSignatureVerified = 4,
/// <summary>
/// There is a strong signature but sign check failed
/// </summary>
StrongSignatureFailed = 5,
}
}

View File

@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp
{
public delegate void MpqArchiveCompactingEventHandler(MpqArchive sender, MpqArchiveCompactingEventArgs e);
public class MpqArchiveCompactingEventArgs : EventArgs
{
internal MpqArchiveCompactingEventArgs(uint dwWorkType, ulong processed, ulong total)
{
unchecked
{
WorkType = (MpqCompactingWorkType)dwWorkType;
BytesProcessed = (long)processed;
TotalBytes = (long)total;
}
}
public MpqCompactingWorkType WorkType
{
get;
private set;
}
public long BytesProcessed
{
get;
private set;
}
public long TotalBytes
{
get;
private set;
}
}
public enum MpqCompactingWorkType
{
CheckingFiles = 1,
CheckingHashTable = 2,
CopyingNonMpqData = 3,
CompactingFiles = 4,
ClosingArchive = 5,
}
}

View File

@@ -1,185 +0,0 @@
using StormLibSharp.Native;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace StormLibSharp
{
public class MpqFileStream : Stream
{
private MpqFileSafeHandle _handle;
private FileAccess _accessType;
private MpqArchive _owner;
internal MpqFileStream(MpqFileSafeHandle handle, FileAccess accessType, MpqArchive owner)
{
_handle = handle;
_accessType = accessType;
_owner = owner;
}
private void VerifyHandle()
{
if (_handle == null || _handle.IsInvalid || _handle.IsClosed)
throw new ObjectDisposedException("MpqFileStream");
}
public override bool CanRead
{
get { VerifyHandle(); return true; }
}
public override bool CanSeek
{
get { VerifyHandle(); return true; }
}
public override bool CanWrite
{
get { VerifyHandle(); return _accessType != FileAccess.Read; }
}
public override void Flush()
{
VerifyHandle();
_owner.Flush();
}
public override long Length
{
get
{
VerifyHandle();
uint high = 0;
uint low = NativeMethods.SFileGetFileSize(_handle, ref high);
ulong val = (high << 32) | low;
return unchecked((long)val);
}
}
public override long Position
{
get
{
VerifyHandle();
return NativeMethods.SFileGetFilePointer(_handle);
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
public override unsafe int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
uint read;
fixed (byte* pb = &buffer[offset])
{
NativeOverlapped overlapped = default(NativeOverlapped);
success = NativeMethods.SFileReadFile(_handle, new IntPtr(pb), unchecked((uint)count), out read, ref overlapped);
}
if (!success)
{
int lastError = Win32Methods.GetLastError();
if (lastError != 38) // EOF
throw new Win32Exception(lastError);
}
return unchecked((int)read);
}
public override long Seek(long offset, SeekOrigin origin)
{
VerifyHandle();
uint low, high;
low = unchecked((uint)(offset & 0xffffffffu));
high = unchecked((uint)(offset >> 32));
return NativeMethods.SFileSetFilePointer(_handle, low, ref high, (uint)origin);
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override unsafe void Write(byte[] buffer, int offset, int count)
{
VerifyHandle();
if (buffer == null)
throw new ArgumentNullException("buffer");
if (offset > buffer.Length || (offset + count) > buffer.Length)
throw new ArgumentException();
if (count < 0)
throw new ArgumentOutOfRangeException("count");
VerifyHandle();
bool success;
fixed (byte* pb = &buffer[offset])
{
success = NativeMethods.SFileWriteFile(_handle, new IntPtr(pb), unchecked((uint)count), 0u);
}
if (!success)
throw new Win32Exception();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
if (_handle != null && !_handle.IsInvalid)
{
_handle.Close();
_handle = null;
}
if (_owner != null)
{
_owner.RemoveOwnedFile(this);
_owner = null;
}
}
}
// TODO: Seems like the right place for SFileGetFileInfo, but will need to determine
// what value add these features have except for sophisticated debugging purposes
// (like in Ladis' MPQ Editor app).
public int ChecksumCrc32
{
get
{
throw new NotImplementedException();
}
}
public byte[] GetMd5Hash()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_DOWNLOAD_CALLBACK(IntPtr pvUserData, ulong byteOffset, uint dwTotalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_COMPACT_CALLBACK(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
internal delegate void SFILE_ADDFILE_CALLBACK(IntPtr pvUserData, uint dwBytesWritte, uint dwTotalBytes, bool bFinalCall);
}

View File

@@ -1,26 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqArchiveSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqArchiveSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqArchiveSafeHandle()
: base(true) { }
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseArchive(this.handle);
}
}
}

View File

@@ -1,27 +0,0 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal sealed class MpqFileSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MpqFileSafeHandle(IntPtr handle)
: base(true)
{
this.SetHandle(handle);
}
public MpqFileSafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.SFileCloseFile(this.handle);
}
}
}

View File

@@ -1,497 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class NativeMethods
{
private const string STORMLIB = "stormlib.dll";
#region Functions for manipulation with StormLib global flags
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetLocale();
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetLocale(uint lcNewLocale);
#endregion
#region Functions for archive manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwPriority,
SFileOpenArchiveFlags dwFlags,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
uint dwCreateFlags,
uint dwMaxFileCount,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateArchive2(
[MarshalAs(UnmanagedType.LPTStr)] string szMpqName,
ref SFILE_CREATE_MPQ pCreateInfo,
out MpqArchiveSafeHandle phMpq
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDownloadCallback(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.FunctionPtr)] SFILE_DOWNLOAD_CALLBACK pfnCallback,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFlushArchive(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(IntPtr hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Adds another listfile into MPQ.
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileAddListFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
#endregion
#region Archive compacting
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetCompactCallback(
MpqArchiveSafeHandle hMpq,
SFILE_COMPACT_CALLBACK compactCB,
IntPtr pvUserData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCompactArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
bool bReserved
);
#endregion
#region Maximum file count
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetMaxFileCount(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetMaxFileCount(MpqArchiveSafeHandle hMpq, uint dwMaxFileCount);
#endregion
#region Changing (attributes) file
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetAttributes(MpqArchiveSafeHandle hMpq);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAttributes(MpqArchiveSafeHandle hMpq, uint dwFlags);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileUpdateFileAttributes(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
#endregion
#region Functions for manipulation with patch archives
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenPatchArchive(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szPatchMpqName,
[MarshalAs(UnmanagedType.LPStr)] string szPatchPathPrefix,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileIsPatchedArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file manipulation
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileHasFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileOpenFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope,
out MpqFileSafeHandle phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileGetFileSize(MpqFileSafeHandle hFile, ref uint pdwFileSizeHigh);
public static unsafe uint SFileGetFilePointer(
MpqFileSafeHandle hFile
)
{
if (hFile.IsInvalid || hFile.IsClosed)
throw new InvalidOperationException();
IntPtr handle = hFile.DangerousGetHandle();
_TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
return header->dwFilePos;
}
//public static unsafe uint SFileGetFileSize(
// MpqFileSafeHandle hFile
// )
//{
// if (hFile.IsInvalid || hFile.IsClosed)
// throw new InvalidOperationException();
// IntPtr handle = hFile.DangerousGetHandle();
// _TMPQFileHeader* header = (_TMPQFileHeader*)handle.ToPointer();
// return header->pFileEntry->dwFileSize;
//}
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileSetFilePointer(
MpqFileSafeHandle hFile,
uint lFilePos,
ref uint plFilePosHigh,
uint dwMoveMethod
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileReadFile(
MpqFileSafeHandle hFile,
IntPtr lpBuffer,
uint dwToRead,
out uint pdwRead,
ref System.Threading.NativeOverlapped lpOverlapped
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(IntPtr hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCloseFile(MpqFileSafeHandle hFile);
#region Retrieving info about a file in the archive
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
IntPtr hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqArchiveSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileInfo(
MpqFileSafeHandle hMpqOrFile,
SFileInfoClass InfoClass,
IntPtr pvFileInfo,
uint cbFileInfoSize,
out uint pcbLengthNeeded
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileName(
MpqFileSafeHandle hFile,
[MarshalAs(UnmanagedType.LPStr)] out string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFreeFileInfo(
IntPtr pvFileInfo,
SFileInfoClass infoClass
);
#endregion
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileExtractFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szToExtract,
[MarshalAs(UnmanagedType.LPTStr)] string szExtracted,
uint dwSearchScope
);
#endregion
#region Functions for file and archive verification
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileGetFileChecksums(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
out uint pdwCrc32,
IntPtr pMD5
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileVerifyRawData(
MpqArchiveSafeHandle hMpq,
uint dwWhatToVerify,
[MarshalAs(UnmanagedType.LPStr)] string szFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern uint SFileVerifyArchive(MpqArchiveSafeHandle hMpq);
#endregion
#region Functions for file searching
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
out _SFILE_FIND_DATA lpFindFileData,
[MarshalAs(UnmanagedType.LPStr)] string szListFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFindClose(IntPtr hFind);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern IntPtr SListFileFindFirstFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szListFile,
[MarshalAs(UnmanagedType.LPStr)] string szMask,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindNextFile(
IntPtr hFind,
[In, Out] ref _SFILE_FIND_DATA lpFindFileData
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SListFileFindClose(IntPtr hFind);
#endregion
#region Locale support
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SFileEnumLocales(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
IntPtr plcLocales,
ref uint pdwMaxLocales,
uint dwSearchScope
);
#endregion
#region Support for adding files to the MPQ
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileCreateFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szArchiveName,
ulong fileTime,
uint dwFileSize,
uint lcLocale,
uint dwFlags,
out IntPtr phFile
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileWriteFile(
MpqFileSafeHandle hFile,
IntPtr pvData,
uint dwSize,
uint dwCompression
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileFinishFile(MpqFileSafeHandle hFile);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFileEx(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwCompression,
uint dwCompressionNext
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileAddWave(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPTStr)] string szFileName,
[MarshalAs(UnmanagedType.LPStr)] string szArchivedName,
uint dwFlags,
uint dwQuality
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRemoveFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szFileName,
uint dwSearchScope
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileRenameFile(
MpqArchiveSafeHandle hMpq,
[MarshalAs(UnmanagedType.LPStr)] string szOldFileName,
[MarshalAs(UnmanagedType.LPStr)] string szNewFileName
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetFileLocale(
MpqFileSafeHandle hFile,
uint lcNewLocale
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetDataCompression(uint DataCompression);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern bool SFileSetAddFileCallback(
MpqArchiveSafeHandle hMpq,
SFILE_ADDFILE_CALLBACK AddFileCB,
IntPtr pvUserData
);
#endregion
#region Compression and decompression
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompImplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompExplode(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompCompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer,
uint uCompressionMask,
int nCmpType,
int nCmpLevel
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
[DllImport(STORMLIB, CallingConvention = CallingConvention.Winapi, ExactSpelling = true, PreserveSig = true, SetLastError = true, ThrowOnUnmappableChar = false)]
public static extern int SCompDecompress2(
IntPtr pvOutBuffer,
ref int pcbOutBuffer,
IntPtr pvInBuffer,
int cbInBuffer
);
#endregion
}
#pragma warning disable 0169,0649
internal struct SFILE_CREATE_MPQ
{
public uint cbSize;
public uint dwMpqVersion;
private IntPtr pvUserData;
private uint cbUserData;
public uint dwStreamFlags;
public uint dwFileFlags1;
public uint dwFileFlags2;
public uint dwAttrFlags;
public uint dwSectorSize;
public uint dwRawChunkSize;
public uint dwMaxFileCount;
}
internal unsafe struct _SFILE_FIND_DATA
{
public fixed char cFileName[260]; // Full name of the found file
public IntPtr szPlainName; // Plain name of the found file
public uint dwHashIndex; // Hash table index for the file
public uint dwBlockIndex; // Block table index for the file
public uint dwFileSize; // File size in bytes
public uint dwFileFlags; // MPQ file flags
public uint dwCompSize; // Compressed file size
public uint dwFileTimeLo; // Low 32-bits of the file time (0 if not present)
public uint dwFileTimeHi; // High 32-bits of the file time (0 if not present)
public uint lcLocale; // Locale version
}
internal unsafe struct _TFileEntry
{
public ulong FileNameHash;
public ulong ByteOffset;
public ulong FileTime;
public uint dwHashIndex;
public uint dwFileSize;
public uint dwCmpSize;
public uint dwFlags;
public ushort lcLocale;
public ushort wPlatform;
public uint dwCrc32;
public fixed byte md5[16];
public IntPtr szFileName;
}
// Provides enough of _TMPQFile to get to the file size and current position.
internal unsafe struct _TMPQFileHeader
{
public IntPtr pStream;
public IntPtr ha;
public _TFileEntry* pFileEntry;
public uint dwFileKey;
public uint dwFilePos;
}
#pragma warning restore 0169,0649
}

View File

@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
internal enum SFileInfoClass
{
// Info classes for archives
SFileMpqFileName, // Name of the archive file (TCHAR [])
SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE [])
SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG)
SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData)
SFileMpqUserData, // MPQ USer data, without the header (BYTE [])
SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG)
SFileMpqHeaderSize, // Fixed size of the MPQ header
SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader)
SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG)
SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG)
SFileMpqHetHeader, // HET table header (TMPQHetHeader)
SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG)
SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG)
SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[])
SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo
SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG)
SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG)
SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD)
SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock [])
SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG)
SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG)
SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD)
SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock [])
SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG)
SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG)
SFileMpqHiBlockTable, // The hi-block table (USHORT [])
SFileMpqSignatures, // Signatures present in the MPQ (DWORD)
SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG)
SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD)
SFileMpqStrongSignature, // The strong signature (BYTE [])
SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG)
SFileMpqArchiveSize, // Archive size from the header (DWORD)
SFileMpqMaxFileCount, // Max number of files in the archive (DWORD)
SFileMpqFileTableSize, // Number of entries in the file table (DWORD)
SFileMpqSectorSize, // Sector size (DWORD)
SFileMpqNumberOfFiles, // Number of files (DWORD)
SFileMpqRawChunkSize, // Size of the raw data chunk for MD5
SFileMpqStreamFlags, // Stream flags (DWORD)
SFileMpqIsReadOnly, // Nonzero if the MPQ is read only (DWORD)
// Info classes for files
SFileInfoPatchChain, // Chain of patches where the file is (TCHAR [])
SFileInfoFileEntry, // The file entry for the file (TFileEntry)
SFileInfoHashEntry, // Hash table entry for the file (TMPQHash)
SFileInfoHashIndex, // Index of the hash table entry (DWORD)
SFileInfoNameHash1, // The first name hash in the hash table (DWORD)
SFileInfoNameHash2, // The second name hash in the hash table (DWORD)
SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG)
SFileInfoLocale, // File locale (DWORD)
SFileInfoFileIndex, // Block index (DWORD)
SFileInfoByteOffset, // File position in the archive (ULONGLONG)
SFileInfoFileTime, // File time (ULONGLONG)
SFileInfoFileSize, // Size of the file (DWORD)
SFileInfoCompressedSize, // Compressed file size (DWORD)
SFileInfoFlags, // File flags from (DWORD)
SFileInfoEncryptionKey, // File encryption key
SFileInfoEncryptionKeyRaw, // Unfixed value of the file key
}
}

View File

@@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StormLibSharp.Native
{
[Flags]
internal enum SFileOpenArchiveFlags : uint
{
None = 0,
TypeIsFile = None,
TypeIsMemoryMapped = 1,
TypeIsHttp = 2,
AccessReadOnly = 0x100,
AccessReadWriteShare = 0x200,
AccessUseBitmap = 0x400,
DontOpenListfile = 0x10000,
DontOpenAttributes = 0x20000,
DontSearchHeader = 0x40000,
ForceVersion1 = 0x80000,
CheckSectorCRC = 0x100000,
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StormLibSharp.Native
{
internal static class Win32Methods
{
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetMappedFileName(
IntPtr hProcess,
IntPtr fileHandle,
IntPtr lpFilename,
uint nSize
);
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
public static extern uint GetFinalPathNameByHandle(
IntPtr hFile,
IntPtr lpszFilePath,
uint cchFilePath,
uint dwFlags
);
[DllImport("kernel32", SetLastError = false, ExactSpelling = false)]
public static extern int GetLastError();
public static string GetFileNameOfMemoryMappedFile(MemoryMappedFile file)
{
const uint size = 522;
IntPtr path = Marshal.AllocCoTaskMem(unchecked((int)size)); // MAX_PATH + 1 char
string result = null;
try
{
// constant 0x2 = VOLUME_NAME_NT
uint test = GetFinalPathNameByHandle(file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size, 0x2);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
catch
{
uint test = GetMappedFileName(Process.GetCurrentProcess().Handle, file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size);
if (test != 0)
throw new Win32Exception();
result = Marshal.PtrToStringAuto(path);
}
return result;
}
}
}

View File

@@ -1,9 +1,9 @@
namespace BurnOutSharp.External.psxt001z
namespace psxt001z
{
public class CRC16
{
// Table of CRC constants - implements x^16+x^12+x^5+1
private static ushort[] crc16_tab = new ushort[]
private static ushort[] CRC16Table = new ushort[]
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
@@ -44,7 +44,7 @@
ushort cksum = 0;
for (int i = 0; i < len; i++)
{
cksum = (ushort)(crc16_tab[((cksum >> 8) ^ buf[bufPtr++]) & 0xFF] ^ (cksum << 8));
cksum = (ushort)(CRC16Table[((cksum >> 8) ^ buf[bufPtr++]) & 0xFF] ^ (cksum << 8));
}
return (ushort)(~cksum);

57
BurnOutSharp/External/psxt001z/CRC32.cs vendored Normal file
View File

@@ -0,0 +1,57 @@
namespace psxt001z
{
internal class CRC32
{
#region Constants
private const uint CRC_POLY = 0xEDB88320;
private const uint CRC_MASK = 0xD202EF8D;
#endregion
#region Properties
protected uint[] Table { get; private set; } = new uint[256];
public uint m_crc32 { get; set; }
#endregion
#region Constructor
public CRC32()
{
for (uint i = 0; i < 256; i++)
{
uint r, j;
for (r = i, j = 8; j != 0; j--)
{
r = ((r & 1) != 0) ? (r >> 1) ^ CRC_POLY : r >> 1;
}
Table[i] = r;
}
m_crc32 = 0;
}
#endregion
#region Functions
public void ProcessCRC(byte[] pData, int pDataPtr, int nLen)
{
uint crc = m_crc32;
while (nLen-- != 0)
{
crc = Table[(byte)(crc ^ pData[pDataPtr++])] ^ crc >> 8;
crc ^= CRC_MASK;
}
m_crc32 = crc;
}
#endregion
}
}

View File

@@ -0,0 +1,19 @@
namespace psxt001z
{
public static class Common
{
public const int ZERO = 0;
public const string VERSION = "v0.21 beta 1";
/// <summary>
/// BCD to u_char
/// </summary>
public static byte btoi(byte b) => (byte)(((b) / 16 * 10 + (b) % 16));
/// <summary>
/// u_char to BCD
/// </summary>
public static byte itob(byte i) => (byte)(((i) / 10 * 16 + (i) % 10));
}
}

View File

@@ -0,0 +1,178 @@
using System;
using System.IO;
using System.Text;
namespace psxt001z
{
internal class FileTools
{
#region Properties
private Stream InputStream { get; set; }
private byte[] ExeName { get; set; } = new byte[20];
private byte[] DateValue { get; set; } = new byte[11];
#endregion
#region Constructor
public FileTools(Stream file)
{
InputStream = file;
}
#endregion
#region Functions
/// <summary>
/// Get file size
/// </summary>
public long size() => InputStream.Length;
/// <summary>
/// Get executable name
/// </summary>
public string exe()
{
InputStream.Seek(51744, SeekOrigin.Begin);
string filename = string.Empty;
while (filename != "SYSTEM.CNF")
{
byte[] buf = new byte[10];
InputStream.Read(buf, 0, 10);
filename = Encoding.ASCII.GetString(buf);
InputStream.Seek(-9, SeekOrigin.Current);
}
byte[] buffer = new byte[20];
InputStream.Seek(-32, SeekOrigin.Current);
InputStream.Read(buffer, 0, 4);
uint lba = BitConverter.ToUInt32(buffer, 0);
InputStream.Seek((2352 * lba) + 29, SeekOrigin.Begin);
InputStream.Read(buffer, 0, 6);
string iniLine = Encoding.ASCII.GetString(buffer);
while (iniLine != "cdrom:")
{
InputStream.Seek(-5, SeekOrigin.Current);
InputStream.Read(buffer, 0, 6);
iniLine = Encoding.ASCII.GetString(buffer);
}
InputStream.Read(buffer, 0, 1);
if (buffer[0] != '\\')
InputStream.Seek(-1, SeekOrigin.Current);
int i = -1;
do
{
InputStream.Read(buffer, ++i, 1);
} while (buffer[i] != ';');
for (long a = 0; a < i; a++)
{
ExeName[a] = (byte)char.ToUpper((char)buffer[a]);
}
return Encoding.ASCII.GetString(ExeName);
}
/// <summary>
/// Get human-readable date
/// </summary>
public string date()
{
byte[] buffer = new byte[12], datenofrmt = new byte[3];
InputStream.Seek(51744, SeekOrigin.Begin);
do
{
InputStream.Read(buffer, 0, 11);
buffer[11] = 0;
InputStream.Seek(-10, SeekOrigin.Current);
} while (Encoding.ASCII.GetString(ExeName) != Encoding.ASCII.GetString(buffer));
InputStream.Seek(-16, SeekOrigin.Current);
InputStream.Read(datenofrmt, 0, 3);
if (datenofrmt[0] < 50)
{
byte[] year = Encoding.ASCII.GetBytes($"{2000 + datenofrmt[0]}");
Array.Copy(year, 0, buffer, 0, 4);
}
else
{
byte[] year = Encoding.ASCII.GetBytes($"{1900 + datenofrmt[0]}");
Array.Copy(year, 0, buffer, 0, 4);
}
DateValue[4] = (byte)'-';
if (datenofrmt[1] < 10)
{
byte[] month = Encoding.ASCII.GetBytes($"0{datenofrmt[1]}");
Array.Copy(month, 0, buffer, 5, 2);
}
else
{
byte[] month = Encoding.ASCII.GetBytes($"{datenofrmt[1]}");
Array.Copy(month, 0, buffer, 5, 2);
}
DateValue[7] = (byte)'-';
if (datenofrmt[2] < 10)
{
byte[] day = Encoding.ASCII.GetBytes($"0{datenofrmt[2]}");
Array.Copy(day, 0, buffer, 8, 2);
}
else
{
byte[] day = Encoding.ASCII.GetBytes($"{datenofrmt[2]}");
Array.Copy(day, 0, buffer, 8, 2);
}
return Encoding.ASCII.GetString(DateValue);
}
/// <summary>
/// Resize the image
/// </summary>
public int resize(long newsize)
{
long oldsize = size();
if (oldsize < newsize)
{
InputStream.SetLength(newsize);
return 1;
}
else if (oldsize > newsize)
{
InputStream.SetLength(newsize);
return 2;
}
else
{
return 0;
}
}
/// <summary>
/// Get the reported sector count from the image
/// </summary>
public int imagesize()
{
InputStream.Seek(0x9368, SeekOrigin.Begin);
byte[] sizebuf = new byte[4];
InputStream.Read(sizebuf, 0, 4);
return BitConverter.ToInt32(sizebuf, 0);
}
#endregion
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.IO;
using System.Text;
using static psxt001z.Common;
namespace psxt001z
{
internal static class Functions
{
public static int CalculateEDC(in byte[] src, int srcPtr, int size, int[] edc_lut)
{
int edc = 0;
while (size-- != 0)
{
edc = (edc >> 8) ^ edc_lut[(edc ^ src[srcPtr++]) & 0xFF];
}
return edc;
}
public static bool ZeroCompare(byte[] buffer, int bufferPtr, int bsize)
{
for (int i = 0; i < bsize; i++)
{
if (buffer[bufferPtr + i] != 0x00)
return false;
}
return true;
}
public static void MSF(long lba, byte[] buffer, int bufferOffset)
{
lba += 150;
double mindbl = lba / 60 / 75;
byte min = (byte)Math.Floor(mindbl);
double secdbl = (lba - (min * 60 * 75)) / 75;
byte sec = (byte)Math.Floor(secdbl);
byte frame = (byte)(lba - (min * 60 * 75) - (sec * 75));
buffer[bufferOffset] = itob(min);
buffer[bufferOffset + 1] = itob(sec);
buffer[bufferOffset + 2] = itob(frame);
return;
}
public static bool GetEDCStatus(Stream file)
{
long currentposition = file.Position;
file.Seek(30572, SeekOrigin.Begin);
byte[] buffer = new byte[4];
file.Read(buffer, 0, 4);
file.Seek(currentposition, SeekOrigin.Begin);
return BitConverter.ToInt32(buffer, 0) == 0;
}
public static byte[] ExecutableName(Stream file)
{
byte[] buffer = new byte[20];
byte[] exename = new byte[20];
//Searching for SYSTEM.CNF
file.Seek(51744, SeekOrigin.Begin);
while (Encoding.ASCII.GetString(buffer) != "SYSTEM.CNF")
{
file.Read(buffer, 0, 10);
buffer[10] = 0;
file.Seek(-9, SeekOrigin.Current);
}
file.Seek(-32, SeekOrigin.Current);
byte[] lba = new byte[4];
file.Read(lba, 0, 4);
file.Seek((2352 * BitConverter.ToInt32(lba, 0)) + 29, SeekOrigin.Begin);
file.Read(buffer, 0, 6);
buffer[6] = 0;
while (Encoding.ASCII.GetString(buffer) != "cdrom:")
{
file.Seek(-5, SeekOrigin.Current);
file.Read(buffer, 0, 6);
}
file.Read(buffer, 0, 1);
if (buffer[0] != '\\')
file.Seek(-1, SeekOrigin.Current);
int i = -1;
do
{
file.Read(buffer, ++i, 1);
} while (buffer[i] != ';');
for (int a = 0; a < i; a++)
{
exename[a] = (byte)char.ToUpper((char)buffer[a]);
}
exename[i] = 0;
return exename;
}
}
}

293
BurnOutSharp/External/psxt001z/Info.cs vendored Normal file
View File

@@ -0,0 +1,293 @@
using System;
using System.IO;
using System.Linq;
using static psxt001z.Functions;
namespace psxt001z
{
public class Info
{
#region Constants
private static readonly byte[] edc_form_2 = { 0x3F, 0x13, 0xB0, 0xBE };
private static readonly byte[] syncheader = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
private static readonly byte[] subheader = { 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00 };
#endregion
#region Functions
public static int GetInfo(string filename, bool fix)
{
// Variables
bool errors = false;
byte[] buffer = new byte[2352], buffer2 = new byte[2352];
int mode = 15; // synñheader[15];
#region Opening image
Stream image;
try
{
FileAccess open_mode = fix ? FileAccess.ReadWrite : FileAccess.Read;
image = File.Open(filename, FileMode.Open, open_mode);
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return 1;
}
long size = image.Length;
Console.WriteLine($"File: {filename}");
#endregion
#region Type
image.Read(buffer, 0, 12);
int sectorsize;
if (buffer.Take(12).SequenceEqual(syncheader.Take(12)))
{
sectorsize = 2352;
}
else
{
sectorsize = 2048;
}
if (size % sectorsize != 0)
{
Console.WriteLine($"{filename}: not ModeX/{sectorsize} image!");
return 1;
}
long sectors = size / sectorsize;
#endregion
#region Mode
if (sectorsize == 2352)
{
image.Seek(0xF, SeekOrigin.Begin);
mode = image.ReadByte();
if (mode != 1 && mode != 2)
{
Console.WriteLine($"{filename}: unknown mode!");
return 1;
}
}
else
{
mode = -1;
}
#endregion
#region Size
image.Seek(sectorsize * 16 + ((mode == 2) ? 24 : ((mode == 1) ? 16 : 0)) + 0x50, SeekOrigin.Begin);
// ISO size
byte[] buf = new byte[4];
image.Read(buf, 0, 4);
int realsectors = BitConverter.ToInt32(buf, 0);
image.Seek(0, SeekOrigin.Begin);
int realsize = realsectors * sectorsize;
if (sectors == realsectors)
{
Console.WriteLine($"Size (bytes): {size} (OK)");
Console.WriteLine($"Size (sectors): {sectors} (OK)");
}
else
{
Console.WriteLine($"Size (bytes): {size}");
Console.WriteLine($"From image: {realsize}");
Console.WriteLine($"Size (sectors): {sectors}");
Console.WriteLine($"From image: {realsectors}");
}
#endregion
#region Mode
if (mode > 0)
Console.WriteLine($"Mode: {mode}");
if (mode == 2)
{
#region EDC in Form 2
bool imageedc = GetEDCStatus(image);
Console.WriteLine($"EDC in Form 2 sectors: {(imageedc ? "YES" : "NO")}");
#endregion
#region Sysarea
string systemArea = "System area: ";
image.Seek(0, SeekOrigin.Begin);
CRC32 crc = new CRC32();
for (int i = 0; i < 16; i++)
{
image.Read(buffer, 0, 2352);
crc.ProcessCRC(buffer, 0, 2352);
}
uint imagecrc = crc.m_crc32;
systemArea += GetEdcType(imagecrc);
Console.WriteLine(systemArea);
#endregion
#region Postgap
image.Seek((sectors - 150) * sectorsize + 16, SeekOrigin.Begin);
image.Read(buffer, 0, 2336);
string postgap = "Postgap type: Form ";
if ((buffer[2] >> 5 & 0x1) != 0)
{
postgap += "2";
if (buffer.Take(8).SequenceEqual(subheader))
postgap += ", zero subheader";
else
postgap += ", non-zero subheader";
if (ZeroCompare(buffer, 8, 2324))
postgap += ", zero data";
else
postgap += ", non-zero data";
if (ZeroCompare(buffer, 2332, 4))
postgap += ", no EDC";
else
postgap += ", EDC";
}
else
{
postgap += "1";
if (ZeroCompare(buffer, 0, 8))
postgap += ", zero subheader";
else
postgap += ", non-zero subheader";
if (ZeroCompare(buffer, 8, 2328))
postgap += ", zero data";
else
postgap += ", non-zero data";
}
Console.WriteLine(postgap);
Array.Copy(buffer, buffer2, 2336);
#endregion
}
if (mode < 0)
return 0;
for (long sector = sectors - 150; sector < sectors; sector++)
{
bool bad = false;
image.Seek(sector * sectorsize, SeekOrigin.Begin);
image.Read(buffer, 0, sectorsize);
// Sync
string sectorInfo = string.Empty;
MSF(sector, syncheader, 12);
if (!syncheader.SequenceEqual(buffer.Take(16)))
{
sectorInfo += $"Sector {sector}: Sync/Header";
bad = true;
if (fix)
{
image.Seek(sector * sectorsize, SeekOrigin.Begin);
image.Write(syncheader, 0, 16);
sectorInfo += (" (fixed)");
}
}
// Mode 2
if (mode == 2 && buffer.Skip(16).Take(2336).SequenceEqual(buffer2))
{
if (bad)
{
sectorInfo += ", Subheader/Data/EDC/ECC";
}
else
{
sectorInfo = $"Sector {sector}: Subheader/Data/EDC/ECC";
bad = true;
}
if (fix)
{
image.Seek(sector * sectorsize + 16, SeekOrigin.Begin);
image.Write(buffer2, 0, 2336);
sectorInfo += " (fixed)";
}
}
Console.WriteLine(sectorInfo);
if (bad && (sector + 1 != sectors))
errors = true;
}
if (errors)
{
Console.WriteLine("NOTICE: One or more errors were found not in the last sector.");
Console.WriteLine("Please mention this when submitting dump info.");
}
else
{
Console.WriteLine("Done.");
}
#endregion
return 0;
}
#endregion
#region Utilities
internal static string GetEdcType(uint imageCrc)
{
switch (imageCrc)
{
case 0x11e3052d:
return "Eu EDC";
case 0x808c19f6:
return "Eu NoEDC";
case 0x70ffa73e:
return "Eu Alt NoEDC";
case 0x7f9a25b1:
return "Eu Alt 2 EDC";
case 0x783aca30:
return "Jap EDC";
case 0xe955d6eb:
return "Jap NoEDC";
case 0x9b519a2e:
return "US EDC";
case 0x0a3e86f5:
return "US NoEDC";
case 0x6773d4db:
return "US Alt NoEDC";
default:
return $"Unknown, crc {imageCrc:8x}";
}
}
#endregion
}
}

View File

@@ -1,146 +1,825 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using static psxt001z.Common;
namespace BurnOutSharp.External.psxt001z
namespace psxt001z
{
/// <summary>
/// LibCrypt detection code
/// Originally written by Dremora: https://github.com/Dremora/psxt001z
/// Ported and changed by darksabre76
/// </summary>
public class LibCrypt
internal class ScsiPassThroughDirect
{
public ushort Length { get; set; }
public byte ScsiStatus { get; set; }
public byte PathId { get; set; }
public byte TargetId { get; set; }
public byte Lun { get; set; }
public byte CDBLength { get; set; }
public byte SenseInfoLength { get; set; }
public byte DataIn { get; set; }
public uint DataTransferLength { get; set; }
public uint TimeOutValue { get; set; }
public byte[] DataBuffer { get; set; }
public uint SenseInfoOffset { get; set; }
public byte[] CDB { get; set; } = new byte[16];
}
public class LibCrypt
{
#region OLD
public static bool CheckSubfile(string subFilePath)
{
// Check the file exists first
if (!File.Exists(subFilePath))
{
Console.WriteLine($"{subFilePath} could not be found");
return false;
}
// Check the file exists first
if (!File.Exists(subFilePath))
return false;
// Check the extension is a subfile
string ext = Path.GetExtension(subFilePath).TrimStart('.').ToLowerInvariant();
if (ext != "sub")
{
Console.WriteLine($"{ext}: unknown file extension");
return false;
}
// Check the extension is a subfile
string ext = Path.GetExtension(subFilePath).TrimStart('.').ToLowerInvariant();
if (ext != "sub")
return false;
// Open and check the subfile for LibCrypt
try
{
using (FileStream subfile = File.OpenRead(subFilePath))
{
return CheckSubfile(subfile);
}
}
catch
{
Console.WriteLine($"Error processing {subFilePath}");
return false;
}
}
// Open and check the subfile for LibCrypt
try
{
using (FileStream subfile = File.OpenRead(subFilePath))
{
return CheckSubfile(subfile);
}
}
catch
{
return false;
}
}
public static bool CheckSubfile(Stream subfile)
{
// Check the length is valid for subfiles
long size = subfile.Length;
if (size % 96 != 0)
{
Console.WriteLine($"Wrong size");
return false;
}
public static bool CheckSubfile(Stream subfile)
{
// Check the length is valid for subfiles
long size = subfile.Length;
if (size % 96 != 0)
return false;
// Persistent values
byte[] buffer = new byte[16];
byte[] sub = new byte[16];
int tpos = 0;
int modifiedSectors = 0;
// Persistent values
byte[] buffer = new byte[16];
byte[] sub = new byte[16];
int tpos = 0;
int modifiedSectors = 0;
// Check each sector for modifications
for (uint sector = 150; sector < ((size / 96) + 150); sector++)
{
subfile.Seek(12, SeekOrigin.Current);
if (subfile.Read(buffer, 0, 12) == 0)
return modifiedSectors != 0;
// Check each sector for modifications
for (uint sector = 150; sector < ((size / 96) + 150); sector++)
{
subfile.Seek(12, SeekOrigin.Current);
if (subfile.Read(buffer, 0, 12) == 0)
return modifiedSectors != 0;
subfile.Seek(72, SeekOrigin.Current);
subfile.Seek(72, SeekOrigin.Current);
// New track
if ((btoi(buffer[1]) == (btoi(sub[1]) + 1)) && (buffer[2] == 0 || buffer[2] == 1))
{
Array.Copy(buffer, sub, 6);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New track
if ((btoi(buffer[1]) == (btoi(sub[1]) + 1)) && (buffer[2] == 0 || buffer[2] == 1))
{
Array.Copy(buffer, sub, 6);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New index
else if (btoi(buffer[2]) == (btoi(sub[2]) + 1) && buffer[1] == sub[1])
{
Array.Copy(buffer, 2, sub, 2, 4);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New index
else if (btoi(buffer[2]) == (btoi(sub[2]) + 1) && buffer[1] == sub[1])
{
Array.Copy(buffer, 2, sub, 2, 4);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// MSF1 [3-5]
else
{
if (sub[2] == 0)
tpos--;
else
tpos++;
// MSF1 [3-5]
else
{
if (sub[2] == 0)
tpos--;
else
tpos++;
sub[3] = itob((byte)(tpos / 60 / 75));
sub[4] = itob((byte)((tpos / 75) % 60));
sub[5] = itob((byte)(tpos % 75));
}
sub[3] = itob((byte)(tpos / 60 / 75));
sub[4] = itob((byte)((tpos / 75) % 60));
sub[5] = itob((byte)(tpos % 75));
}
// MSF2 [7-9]
sub[7] = itob((byte)(sector / 60 / 75));
sub[8] = itob((byte)((sector / 75) % 60));
sub[9] = itob((byte)(sector % 75));
// MSF2 [7-9]
sub[7] = itob((byte)(sector / 60 / 75));
sub[8] = itob((byte)((sector / 75) % 60));
sub[9] = itob((byte)(sector % 75));
// CRC-16 [10-11]
ushort crc = CRC16.Calculate(sub, 0, 10);
byte[] crcBytes = BitConverter.GetBytes(crc);
sub[10] = crcBytes[0];
sub[11] = crcBytes[1];
// CRC-16 [10-11]
ushort crc = CRC16.Calculate(sub, 0, 10);
byte[] crcBytes = BitConverter.GetBytes(crc);
sub[10] = crcBytes[0];
sub[11] = crcBytes[1];
// TODO: This *was* a memcmp, but that's harder to do. Fix this for C# later
if (buffer[10] != sub[10] && buffer[11] != sub[11] && (buffer[3] != sub[3] || buffer[4] != sub[4] || buffer[5] != sub[5] || buffer[7] != sub[7] || buffer[8] != sub[8] || buffer[9] != sub[9]))
{
if (buffer[3] != sub[3] || buffer[4] != sub[4] || buffer[5] != sub[5] || buffer[7] != sub[7] || buffer[8] != sub[8] || buffer[9] != sub[9] || buffer[10] != sub[10] || buffer[11] != sub[11])
{
Console.Write($"MSF: {sub[7]:x}:{sub[8]:x}:{sub[9]:x} Q-Data: {buffer[0]:x}{buffer[1]:x}{buffer[2]:x} {buffer[3]:x}:{buffer[4]:x}:{buffer[5]:x} {buffer[6]:x} {buffer[7]:x}:{buffer[8]:x}:{buffer[9]:x} {buffer[10]:x}{buffer[11]:x} xor {crc ^ ((buffer[10] << 8) + buffer[11]):x} % {CRC16.Calculate(buffer, 0, 10) ^ ((buffer[10] << 8) + buffer[11]):x}");
//Console.Write($"\nMSF: {sub[7]:x}:{sub[8]:x}:{sub[9]:x} Q-Data: {sub[0]:x}{sub[1]:x}{sub[2]:x} {sub[3]:x}:{sub[4]:x}:{sub[5]:x} {sub[6]:x} {sub[7]:x}:{sub[8]:x}:{sub[9]:x} {sub[10]:x}{sub[11]:x}");
if (buffer[3] != sub[3] && buffer[7] != sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.Write($" P1 xor {buffer[3] ^ sub[3]:x} {buffer[7] ^ sub[7]:x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] != sub[4] && buffer[8] != sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.Write($" P2 xor {buffer[4] ^ sub[4]:x} {buffer[8] ^ sub[8]:x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] != sub[5] && buffer[9] != sub[9])
Console.Write($" P3 xor {buffer[5] ^ sub[5]:x} {buffer[9] ^ sub[9]:x}");
else
Console.Write(" ?");
// If any byte (except position 6) is different, it's a modified sector
for (int i = 0; i < 12; i++)
{
if (i == 6)
continue;
Console.Write("\n");
modifiedSectors++;
}
}
}
if (buffer[i] != sub[i])
{
modifiedSectors++;
break;
}
}
}
Console.WriteLine($"Number of modified sectors: {modifiedSectors}");
return modifiedSectors != 0;
}
return modifiedSectors != 0;
}
private static byte btoi(byte b)
{
/* BCD to u_char */
return (byte)((b) / 16 * 10 + (b) % 16);
}
#endregion
private static byte itob(byte i)
{
/* u_char to BCD */
return (byte)((i) / 10 * 16 + (i) % 10);
}
}
#region Constants
private const uint IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014;
private const byte SCSI_IOCTL_DATA_IN = 0x1;
private const byte RAW_READ_CMD = 0xBE;
private const int BUFFER_LEN = 96;
private const int SENSE_SIZE = 0; //14
private const string F_NAME = "sectors.log";
private const int CYCLES = 5;
private const int LIBCRYPT_NUM_SECTORS = 64;
private const int READ_TIMES = 5;
private static readonly uint[] lc_addresses = new uint[LIBCRYPT_NUM_SECTORS]
{
13955, 13960, 14081, 14086, 14335, 14340, 14429, 14434,
14499, 14504, 14749, 14754, 14906, 14911, 14980, 14985,
15092, 15097, 15162, 15167, 15228, 15233, 15478, 15483,
15769, 15774, 15881, 15886, 15951, 15956, 16017, 16022,
41895, 41900, 42016, 42021, 42282, 42287, 42430, 42435,
42521, 42526, 42663, 42668, 42862, 42867, 43027, 43032,
43139, 43144, 43204, 43209, 43258, 43263, 43484, 43489,
43813, 43818, 43904, 43909, 44009, 44014, 44162, 44167
};
private static readonly byte[] lc1_sectors_contents = new byte[768]
{
0x41, 0x01, 0x01, 0x07, 0x06, 0x05, 0x00, 0x23, 0x08, 0x05, 0x38, 0x39,
0x41, 0x01, 0x01, 0x03, 0x06, 0x11, 0x00, 0x03, 0x08, 0x90, 0x5d, 0xa0,
0x41, 0x01, 0x01, 0x07, 0x07, 0x56, 0x00, 0x23, 0x09, 0x56, 0xdf, 0xde,
0x41, 0x01, 0x01, 0x03, 0x07, 0x60, 0x00, 0x03, 0x09, 0xe1, 0xf2, 0x50,
0x41, 0x01, 0x01, 0x03, 0x13, 0x10, 0x00, 0x03, 0x53, 0x10, 0x50, 0xec,
0x41, 0x01, 0x01, 0x43, 0x11, 0x15, 0x00, 0x01, 0x13, 0x15, 0x23, 0x1e,
0x41, 0x01, 0x01, 0x03, 0x12, 0x09, 0x00, 0x03, 0x14, 0x2d, 0x04, 0x73,
0x41, 0x01, 0x01, 0x03, 0x1a, 0x34, 0x00, 0x03, 0x04, 0x34, 0xe2, 0xcf,
0x41, 0x01, 0x01, 0x03, 0x13, 0x20, 0x00, 0x03, 0x15, 0x04, 0x82, 0x35,
0x41, 0x01, 0x01, 0x01, 0x13, 0x29, 0x00, 0x43, 0x15, 0x29, 0x72, 0xe2,
0x41, 0x01, 0x01, 0x03, 0x1e, 0x49, 0x00, 0x03, 0x08, 0x49, 0x32, 0xc5,
0x41, 0x01, 0x01, 0x01, 0x16, 0x54, 0x00, 0x43, 0x18, 0x54, 0xd4, 0x79,
0x41, 0x01, 0x01, 0x03, 0x18, 0x57, 0x00, 0x03, 0x20, 0xd6, 0xbc, 0x27,
0x41, 0x01, 0x01, 0x03, 0x38, 0x61, 0x00, 0x03, 0x24, 0x61, 0x91, 0xa9,
0x41, 0x01, 0x01, 0x0b, 0x19, 0x55, 0x00, 0x13, 0x21, 0x55, 0x14, 0x07,
0x41, 0x01, 0x01, 0x03, 0x19, 0x62, 0x00, 0x03, 0x21, 0x20, 0x5d, 0x48,
0x41, 0x01, 0x01, 0x03, 0x23, 0x17, 0x00, 0x03, 0x63, 0x17, 0x6d, 0xc6,
0x41, 0x01, 0x01, 0x43, 0x21, 0x22, 0x00, 0x01, 0x23, 0x22, 0x24, 0x89,
0x41, 0x01, 0x01, 0x03, 0x02, 0x12, 0x00, 0x03, 0x20, 0x12, 0x49, 0x43,
0x41, 0x01, 0x01, 0x03, 0x22, 0x07, 0x00, 0x03, 0x24, 0x1f, 0x3a, 0xb1,
0x41, 0x01, 0x01, 0x03, 0x23, 0x13, 0x00, 0x03, 0x25, 0x0b, 0x93, 0xc9,
0x41, 0x01, 0x01, 0x0b, 0x23, 0x08, 0x00, 0x13, 0x25, 0x08, 0xce, 0x5d,
0x41, 0x01, 0x01, 0x03, 0x06, 0x28, 0x00, 0x03, 0x2c, 0x28, 0xd7, 0xd6,
0x41, 0x01, 0x01, 0x0b, 0x26, 0x33, 0x00, 0x13, 0x28, 0x33, 0x9c, 0x29,
0x41, 0x01, 0x01, 0x03, 0x30, 0x59, 0x00, 0x03, 0x32, 0x1b, 0x2c, 0xc6,
0x41, 0x01, 0x01, 0x03, 0x20, 0x24, 0x00, 0x03, 0x3a, 0x24, 0xe6, 0xac,
0x41, 0x01, 0x01, 0x13, 0x31, 0x56, 0x00, 0x0b, 0x33, 0x56, 0x97, 0xed,
0x41, 0x01, 0x01, 0x03, 0x31, 0x65, 0x00, 0x03, 0x33, 0x41, 0xba, 0x63,
0x41, 0x01, 0x01, 0x01, 0x32, 0x51, 0x00, 0x43, 0x34, 0x51, 0xd7, 0xa9,
0x41, 0x01, 0x01, 0x03, 0x33, 0x56, 0x00, 0x03, 0xb4, 0x56, 0xc0, 0x9a,
0x41, 0x01, 0x01, 0x03, 0x32, 0x42, 0x00, 0x03, 0xb5, 0x42, 0x69, 0xe2,
0x41, 0x01, 0x01, 0x03, 0x33, 0x07, 0x00, 0x03, 0x35, 0x45, 0x1a, 0x10,
0x41, 0x01, 0x01, 0x09, 0x18, 0x65, 0x00, 0x09, 0x20, 0x41, 0x40, 0x72,
0x41, 0x01, 0x01, 0x19, 0x18, 0x50, 0x00, 0x01, 0x20, 0x50, 0x25, 0xeb,
0x41, 0x01, 0x01, 0x08, 0x20, 0x16, 0x00, 0x89, 0x22, 0x16, 0x95, 0xa8,
0x41, 0x01, 0x01, 0x09, 0x20, 0x01, 0x00, 0x09, 0x22, 0x25, 0xb8, 0x26,
0x41, 0x01, 0x01, 0x09, 0x23, 0x53, 0x00, 0x09, 0x25, 0x77, 0x21, 0x03,
0x41, 0x01, 0x01, 0x0b, 0x23, 0x62, 0x00, 0x49, 0x25, 0x62, 0x68, 0x4c,
0x41, 0x01, 0x01, 0x0d, 0x25, 0x55, 0x00, 0x29, 0x27, 0x55, 0xae, 0x41,
0x41, 0x01, 0x01, 0x09, 0x25, 0x61, 0x00, 0x09, 0x27, 0xe0, 0xe7, 0x0e,
0x41, 0x01, 0x01, 0x08, 0x26, 0x71, 0x00, 0x89, 0x28, 0x71, 0x95, 0xcb,
0x41, 0x01, 0x01, 0x09, 0x27, 0x21, 0x00, 0x09, 0x29, 0x05, 0x80, 0x4b,
0x41, 0x01, 0x01, 0x0b, 0x28, 0x63, 0x00, 0x49, 0x30, 0x63, 0xed, 0x18,
0x41, 0x01, 0x01, 0x09, 0x29, 0x68, 0x00, 0x09, 0xb0, 0x68, 0xb0, 0x8c,
0x41, 0x01, 0x01, 0x29, 0x31, 0x37, 0x00, 0x0d, 0x33, 0x37, 0x6c, 0x68,
0x41, 0x01, 0x01, 0x09, 0x31, 0x4a, 0x00, 0x09, 0x33, 0x52, 0x7c, 0x8b,
0x41, 0x01, 0x01, 0x09, 0x73, 0x52, 0x00, 0x09, 0x37, 0x52, 0x4b, 0x06,
0x41, 0x01, 0x01, 0x19, 0x33, 0x57, 0x00, 0x01, 0x35, 0x57, 0x38, 0xf4,
0x41, 0x01, 0x01, 0x09, 0x35, 0x04, 0x00, 0x09, 0x37, 0x1c, 0x54, 0x6a,
0x41, 0x01, 0x01, 0x09, 0x31, 0x19, 0x00, 0x09, 0x17, 0x19, 0xa4, 0xbd,
0x41, 0x01, 0x01, 0x01, 0x36, 0x04, 0x00, 0x19, 0x38, 0x04, 0x9c, 0xdf,
0x41, 0x01, 0x01, 0x09, 0x36, 0x0b, 0x00, 0x09, 0x38, 0x49, 0x6c, 0x08,
0x41, 0x01, 0x01, 0x49, 0x36, 0x58, 0x00, 0x0b, 0x38, 0x58, 0x99, 0xbf,
0x41, 0x01, 0x01, 0x09, 0x36, 0x73, 0x00, 0x09, 0x38, 0x6b, 0xfe, 0x96,
0x41, 0x01, 0x01, 0x0b, 0x39, 0x59, 0x00, 0x49, 0x41, 0x59, 0x54, 0x0d,
0x41, 0x01, 0x01, 0x09, 0x39, 0x24, 0x00, 0x09, 0x41, 0x66, 0x9e, 0x67,
0x41, 0x01, 0x01, 0x09, 0x44, 0x1b, 0x00, 0x09, 0x46, 0x03, 0x78, 0x0d,
0x41, 0x01, 0x01, 0x09, 0x46, 0x18, 0x00, 0x09, 0x06, 0x18, 0x25, 0x99,
0x41, 0x01, 0x01, 0x09, 0x45, 0x2b, 0x00, 0x09, 0x47, 0x69, 0xd3, 0xc5,
0x41, 0x01, 0x01, 0x09, 0x05, 0x34, 0x00, 0x09, 0x45, 0x34, 0x35, 0x79,
0x41, 0x01, 0x01, 0x09, 0x44, 0x59, 0x00, 0x09, 0x08, 0x59, 0x6e, 0x0a,
0x41, 0x01, 0x01, 0x49, 0x46, 0x64, 0x00, 0x0b, 0x48, 0x64, 0xa4, 0x60,
0x41, 0x01, 0x01, 0x09, 0x08, 0x62, 0x00, 0x09, 0x52, 0x62, 0x03, 0x5a,
0x41, 0x01, 0x01, 0x19, 0x48, 0x67, 0x00, 0x01, 0x50, 0x67, 0x70, 0xa8
};
#endregion
// TODO: Enable the following only if reading from a drive directly
/*
internal static byte LibCryptDrive(string[] args)
{
byte offset = 0;
string path = $"\\\\.\\{args[0][0]}:";
byte i;
byte[] sub = new byte[12], buffer = new byte[BUFFER_LEN], buffer2352 = new byte[23520], buffer2 = new byte[BUFFER_LEN], buffer3 = new byte[BUFFER_LEN], buffer4 = new byte[BUFFER_LEN];
byte[] status;
ushort crc;
uint sector, sector_start, sector_end, a, lcsectors = 0, todo = 9300, done = 0;
if (args.Length != 1 || (args.Length == 1 && (args[0][1] != 0 && (args[0][1] != ':' || args[0][2] != 0))))
{
Console.WriteLine("LibCrypt drive detector");
Console.WriteLine("nUsage: psxt001z.exe --libcryptdrv <drive letter>");
return 0;
}
Stream hDevice;
try
{
hDevice = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
}
catch (Exception ex)
{
Console.WriteLine("Can't open device!");
return 0;
}
Stream f;
try
{
f = File.Open(F_NAME, FileMode.Open, FileAccess.Write);
}
catch (Exception ex)
{
Console.WriteLine($"Can't open file {F_NAME}!");
return 0;
}
byte[] status1 = new byte[4650];
byte[] status2 = new byte[4650];
// Offset detection
Console.WriteLine("Determining offset...\r");
ScsiPassThroughDirect SRB = new ScsiPassThroughDirect();
ReadSub(buffer, 0, f, offset, hDevice, SRB);
switch (buffer[8])
{
case 0x01:
offset = (byte)(75 - btoi(buffer[9]));
break;
case 0x02:
offset = (byte)(-btoi(buffer[9]));
break;
default:
Console.WriteLine("Can't determine offset!");
Console.WriteLine(BitConverter.ToString(buffer).Replace('-', ' '));
return 0;
}
sub[0] = buffer[0];
sub[1] = 0x01;
sub[2] = 0x01;
sub[6] = 0x00;
Console.WriteLine($"Subchannels offset correction: {offset}");
// Section 1) 02:58:00 - 03:69:74 -- status1
// Section 2) 08:58:00 - 09:69:74 -- status2
// Step 1
for (i = 0; i < CYCLES * 3; i++)
{
if (todo == 0)
goto end;
if (i % 3 == 0)
{
sector_start = 13350;
sector_end = 18000;
status = status1;
}
else if (i % 3 == 1)
{
sector_start = 40350;
sector_end = 45000;
status = status2;
}
else
{
Console.WriteLine($"Left: {todo:4} / Flushing cache... \r");
ClearCache(buffer2352, f, offset, hDevice, SRB);
continue;
}
for (sector = sector_start; sector < sector_end; sector++)
{
if (status[sector - sector_start] != 0)
continue;
ReadSub(buffer, sector, f, offset, hDevice, SRB);
Console.WriteLine("Left: %4u / Sector %u... \r", todo, sector);
// generating q-channel
sub[3] = itob((byte)(sector / 60 / 75));
sub[4] = itob((byte)((sector / 75) % 60));
sub[5] = itob((byte)(sector % 75));
sub[7] = itob((byte)((sector + 150) / 60 / 75));
sub[8] = itob((byte)(((sector + 150) / 75) % 60));
sub[9] = itob((byte)((sector + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
if (sub.SequenceEqual(buffer.Take(12)))
{
status[sector - sector_start] = 1;
todo--;
done++;
}
}
}
// Step 2
for (i = 0; i < 2; i++)
{
if (i == 0)
{
sector_start = 13350;
sector_end = 18000;
status = status1;
}
else
{
sector_start = 40350;
sector_end = 45000;
status = status2;
}
for (sector = sector_start; sector < sector_end; sector++)
{
if (status[sector - sector_start] != 0)
continue;
ReadSub(buffer, sector, f, offset, hDevice, SRB);
Console.WriteLine($"Left: {todo:4} / Sector {sector}... \r");
// generating q-channel
sub[3] = itob((byte)(sector / 60 / 75));
sub[4] = itob((byte)((sector / 75) % 60));
sub[5] = itob((byte)(sector % 75));
sub[7] = itob((byte)((sector + 150) / 60 / 75));
sub[8] = itob((byte)(((sector + 150) / 75) % 60));
sub[9] = itob((byte)((sector + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc ^ 0xFF);
if (sub.SequenceEqual(buffer.Take(12)))
{
Console.WriteLine($"Left: {todo:4} / Sector {sector}: flushing cache... \r");
do
{
ReadSub(buffer, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
ReadSub(buffer2, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
ReadSub(buffer3, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
} while (!buffer.SequenceEqual(buffer2) || !buffer.SequenceEqual(buffer3));
//} while (!matrix(buffer, buffer2, buffer3, buffer4, BUFFER_LEN));
if (buffer.SequenceEqual(sub))
{
byte[] buf = Encoding.ASCII.GetBytes($"MSF: {sub[7]:2x}:{sub[8]:2x}:{sub[9]:2x} Q-Data: {BitConverter.ToString(buffer.Take(12).ToArray()).Replace('-', ' ')}");
f.Write(buf, 0, buf.Length);
lcsectors++;
//fwrite(SRB.SRB_BufPointer, 1, SRB.SRB_BufLen - 4, f);
f.Flush();
}
}
todo--;
done++;
}
}
end:
Console.WriteLine($"Done! \nProtected sectors: {(lcsectors == 0 ? "None" : lcsectors.ToString())}");
f.Close();
return 1;
}
internal static int LibCryptDriveFast(string[] args)
{
Stream f;
Stream hDevice;
ScsiPassThroughDirect SRB;
s8 offset = 0, path[] = "\\\\.\\X:";
u8 buffer[BUFFER_LEN], buffer2352[23520], sub[12], lc1sectors = 0, lc2sectors = 0, othersectors = 0;
u16 crc;
if (argc != 1 || (argc == 1 && (args[0][1] != 0 && (args[0][1] != ':' || args[0][2] != 0))))
{
Console.WriteLine("LibCrypt drive detector (fast)\nUsage: psxt001z.exe --libcryptdrvfast <drive letter>\n");
return 0;
}
path[4] = args[0][0];
if ((hDevice = CreateFile(path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
{
Console.WriteLine("Can't open device!\n");
return 0;
}
if (fopen_s(&f, F_NAME, "wb") != 0)
{
Console.WriteLine("Can\'t open file %s!\n", F_NAME);
return 0;
}
// Offset detection
ReadSub(buffer, 0, f, offset, hDevice, SRB);
//if (buffer[5] != buffer[9]) {
// Console.WriteLine("Error determining offset!\nSector 0: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
//}
switch (buffer[8])
{
case 0x01:
offset = 75 - btoi(buffer[9]);
break;
case 0x02:
offset = -btoi(buffer[9]);
break;
default:
Console.WriteLine("Can't determine offset!\nSector 0: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
return 0;
}
Console.WriteLine("Subchannels offset correction: %d\n", offset);
sub[0] = buffer[0];
sub[1] = 0x01;
sub[2] = 0x01;
sub[6] = 0x00;
for (int i = 0; i < LIBCRYPT_NUM_SECTORS; i++)
{
Console.WriteLine("\nReading sector %u... ", lc_addresses[i]);
ReadSub(buffer, lc_addresses[i], f, offset, hDevice, SRB);
// generating q-channel
sub[3] = itob(lc_addresses[i] / 60 / 75);
sub[4] = itob((lc_addresses[i] / 75) % 60);
sub[5] = itob(lc_addresses[i] % 75);
sub[7] = itob((lc_addresses[i] + 150) / 60 / 75);
sub[8] = itob(((lc_addresses[i] + 150) / 75) % 60);
sub[9] = itob((lc_addresses[i] + 150) % 75);
crc = crc16(sub, 10);
sub[10] = HIbyte(crc);
sub[11] = LObyte(crc);
for (int a = 1; a <= READ_TIMES; a++)
{
if (!memcmp(sub, buffer, 12))
{
Console.WriteLine("original sector");
break;
}
else if (!memcmp(lc1_sectors_contents + (12 * i), buffer, 12))
{
Console.WriteLine("LibCrypt, LC1 sector");
fConsole.WriteLine(f, "MSF: %02x:%02x:%02x Q-Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", sub[7], sub[8], sub[9], buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
lc1sectors++;
break;
}
else
{
if (a < READ_TIMES)
{
ClearCache(buffer2352, 0, offset, hDevice, SRB);
continue;
}
else
{
Console.WriteLine("unknown");
fConsole.WriteLine(f, "MSF: %02x:%02x:%02x Q-Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", sub[7], sub[8], sub[9], buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
othersectors++;
}
}
}
}
Console.WriteLine("\n\nOriginal sectors: %u", LIBCRYPT_NUM_SECTORS - lc1sectors - lc2sectors - othersectors);
Console.WriteLine("\nLC1 sectors: %u", lc1sectors);
Console.WriteLine("\nLC2 sectors: %u", lc2sectors);
Console.WriteLine("\nOther sectors: %u", othersectors);
fConsole.WriteLine(f, "\nOriginal sectors: %u", LIBCRYPT_NUM_SECTORS - lc1sectors - lc2sectors - othersectors);
fConsole.WriteLine(f, "\nLC1 sectors: %u", lc1sectors);
fConsole.WriteLine(f, "\nLC2 sectors: %u", lc2sectors);
fConsole.WriteLine(f, "\nOther sectors: %u", othersectors);
fclose(f);
return 1;
}
internal static void ReadSub(byte[] buffer, uint sector, Stream f, byte offset, Stream hDevice, ScsiPassThroughDirect SRB)
{
uint returned;
ZeroMemory(&SRB, sizeof(ScsiPassThroughDirect));
SRB.Length = sizeof(ScsiPassThroughDirect);
SRB.CDBLength = 12;
SRB.DataIn = SCSI_IOCTL_DATA_IN;
SRB.DataTransferLength = BUFFER_LEN;
SRB.TimeOutValue = 30;
SRB.DataBuffer = buffer;
SRB.CDB[0] = RAW_READ_CMD;
SRB.CDB[2] = HIbyte(HIWORD(sector + offset));
SRB.CDB[3] = LObyte(HIWORD(sector + offset));
SRB.CDB[4] = HIbyte(LOWORD(sector + offset));
SRB.CDB[5] = LObyte(LOWORD(sector + offset));
SRB.CDB[8] = 1;
SRB.CDB[10] = 1;
if (!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0))
{
Console.WriteLine("\nError reading subchannel data!\n");
if (f != 0)
fConsole.WriteLine(f, "Error reading subchannel data!");
return 0;
}
Deinterleave(buffer);
return;
}
internal static void ClearCache(byte[] buffer, Stream f, byte offset, Stream hDevice, ScsiPassThroughDirect SRB)
{
static uint returned;
for (uint sector = 0; sector < 1000; sector += 10)
{
ZeroMemory(&SRB, sizeof(ScsiPassThroughDirect));
SRB.Length = sizeof(ScsiPassThroughDirect);
SRB.CDBLength = 12;
SRB.DataIn = SCSI_IOCTL_DATA_IN;
SRB.DataTransferLength = 23520;
SRB.TimeOutValue = 30;
SRB.DataBuffer = buffer;
SRB.CDB[0] = RAW_READ_CMD;
SRB.CDB[2] = HIbyte(HIWORD(sector + offset));
SRB.CDB[3] = LObyte(HIWORD(sector + offset));
SRB.CDB[4] = HIbyte(LOWORD(sector + offset));
SRB.CDB[5] = LObyte(LOWORD(sector + offset));
SRB.CDB[8] = 10;
SRB.CDB[9] = 0xF8;
DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0);
if (!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0))
{
Console.WriteLine("\nError clearing cache!\n");
if (f != 0)
fConsole.WriteLine(f, "Error clearing cache!");
exit(0);
}
}
return;
}
*/
internal static bool Matrix(byte[] buffer, byte[] buffer2, byte[] buffer3, byte[] buffer4, uint length)
{
for (int i = 0; i < length; i++)
{
if (buffer[i] == buffer2[i])
{
if (buffer[i] == buffer3[i])
continue;
if (buffer[i] == buffer4[i])
continue;
}
else if (buffer[i] == buffer3[i] && buffer[i] == buffer4[i])
{
continue;
}
else if (buffer2[i] == buffer3[i] && buffer2[i] == buffer4[i])
{
continue;
}
return false;
}
return true;
}
internal static void Deinterleave(byte[] buffer)
{
byte[] buffertmp = new byte[12];
for (int i = 0; i < 12; i++)
{
buffertmp[i] |= (byte)((buffer[i * 8] & 0x40) << 1);
buffertmp[i] |= (byte)((buffer[i * 8 + 1] & 0x40));
buffertmp[i] |= (byte)((buffer[i * 8 + 2] & 0x40) >> 1);
buffertmp[i] |= (byte)((buffer[i * 8 + 3] & 0x40) >> 2);
buffertmp[i] |= (byte)((buffer[i * 8 + 4] & 0x40) >> 3);
buffertmp[i] |= (byte)((buffer[i * 8 + 5] & 0x40) >> 4);
buffertmp[i] |= (byte)((buffer[i * 8 + 6] & 0x40) >> 5);
buffertmp[i] |= (byte)((buffer[i * 8 + 7] & 0x40) >> 6);
}
Array.Copy(buffertmp, buffer, 12);
return;
}
internal static bool LibCryptDetect(string subPath, string sbiPath)
{
if (string.IsNullOrWhiteSpace(subPath) || !File.Exists(subPath))
return false;
// Variables
byte[] buffer = new byte[16], sub = new byte[16];//, pregap = 0;
uint sector, psectors = 0, tpos = 0;
// Opening .sub
Stream subfile = File.OpenRead(subPath);
// checking extension
if (Path.GetExtension(subPath).TrimStart('.').ToLowerInvariant() != "sub")
{
Console.WriteLine($"{subPath}: unknown file extension");
return false;
}
// filesize
long size = subfile.Length;
if (size % 96 != 0)
{
Console.WriteLine($"{subfile}: wrong size");
return false;
}
// sbi
Stream sbi = null;
if (sbiPath != null)
{
sbi = File.OpenWrite(sbiPath);
sbi.Write(Encoding.ASCII.GetBytes("SBI\0"), 0, 4);
}
for (sector = 150; sector < ((size / 96) + 150); sector++)
{
subfile.Seek(12, SeekOrigin.Current);
if (subfile.Read(buffer, 0, 12) != 12)
return true;
subfile.Seek(72, SeekOrigin.Current);
// New track
if ((btoi(buffer[1]) == (btoi(sub[1]) + 1)) && (buffer[2] == 0 || buffer[2] == 1))
{
Array.Copy(buffer, sub, 6);
tpos = (uint)((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New index
else if (btoi(buffer[2]) == (btoi(sub[2]) + 1) && buffer[1] == sub[1])
{
Array.Copy(buffer, 2, sub, 2, 4);
tpos = (uint)((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// MSF1 [3-5]
else
{
if (sub[2] == 0)
tpos--;
else
tpos++;
sub[3] = itob((byte)(tpos / 60 / 75));
sub[4] = itob((byte)((tpos / 75) % 60));
sub[5] = itob((byte)(tpos % 75));
}
//MSF2 [7-9]
sub[7] = itob((byte)(sector / 60 / 75));
sub[8] = itob((byte)((sector / 75) % 60));
sub[9] = itob((byte)(sector % 75));
// CRC-16 [10-11]
ushort crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
//if (buffer[10] != sub[10] && buffer[11] != sub[11] && (buffer[3] != sub[3] || buffer[7] != sub[7] || buffer[4] != sub[4] || buffer[8] != sub[8] || buffer[5] != sub[5] || buffer[9] != sub[9])) {
//if (buffer[10] != sub[10] || buffer[11] != sub[11] || buffer[3] != sub[3] || buffer[7] != sub[7] || buffer[4] != sub[4] || buffer[8] != sub[8] || buffer[5] != sub[5] || buffer[9] != sub[9]) {
if (!buffer.Take(6).SequenceEqual(sub.Take(6)) || !buffer.Skip(7).Take(5).SequenceEqual(sub.Skip(7).Take(5)))
{
Console.WriteLine($"MSF: {sub[7]:2x}:{sub[8]:2x}:{sub[9]:2x} Q-Data: {buffer[0]:2x}{buffer[1]:2x}{buffer[2]:2x} {buffer[3]:2x}:{buffer[4]:2x}:{buffer[5]:2x} {buffer[6]:2x} {buffer[7]:2x}:{buffer[8]:2x}:{buffer[9]:2x} {buffer[10]:2x}{buffer[11]:2x} xor {crc ^ ((buffer[10] << 8) + buffer[11]):4x} {CRC16.Calculate(buffer, 0, 10) ^ ((buffer[10] << 8) + buffer[11]):4x}");
//Console.WriteLine("\nMSF: %02x:%02x:%02x Q-Data: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x", sub[7], sub[8], sub[9], sub[0], sub[1], sub[2], sub[3], sub[4], sub[5], sub[6], sub[7], sub[8], sub[9], sub[10], sub[11]);
if (buffer[3] != sub[3] && buffer[7] != sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.WriteLine($" P1 xor {buffer[3] ^ sub[3]:2x} {buffer[7] ^ sub[7]:2x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] != sub[4] && buffer[8] != sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.WriteLine($" P2 xor {buffer[4] ^ sub[4]:2x} {buffer[8] ^ sub[8]:2x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] != sub[5] && buffer[9] != sub[9])
Console.WriteLine($" P3 xor {buffer[5] ^ sub[5]:2x} {buffer[9] ^ sub[9]:2x}");
else
Console.WriteLine(" ?");
Console.WriteLine("\n");
psectors++;
if (sbi != null)
{
sbi.Write(sub, 7, 3);
sbi.Write(new byte[] { 0x01 }, 0, 1);
sbi.Write(buffer, 0, 10);
}
}
}
// }
Console.WriteLine($"Number of modified sectors: {psectors}");
return true;
}
internal static int XorLibCrypt()
{
sbyte b;
byte d;
byte i, a, x;
byte[] sub = new byte[12]
{
0x41, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
ushort crc;
for (i = 0; i < LIBCRYPT_NUM_SECTORS; i++)
{
sub[3] = itob((byte)(lc_addresses[i] / 60 / 75));
sub[4] = itob((byte)((lc_addresses[i] / 75) % 60));
sub[5] = itob((byte)(lc_addresses[i] % 75));
sub[7] = itob((byte)((lc_addresses[i] + 150) / 60 / 75));
sub[8] = itob((byte)(((lc_addresses[i] + 150) / 75) % 60));
sub[9] = itob((byte)((lc_addresses[i] + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
Console.WriteLine($"%u %02x:%02x:%02x", lc_addresses[i], sub[7], sub[8], sub[9]);
Console.WriteLine($" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x", sub[0], sub[1], sub[2], sub[3], sub[4], sub[5], sub[6], sub[7], sub[8], sub[9], sub[10], sub[11]);
Console.WriteLine($" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x", lc1_sectors_contents[i * 12], lc1_sectors_contents[(i * 12) + 1], lc1_sectors_contents[(i * 12) + 2], lc1_sectors_contents[(i * 12) + 3], lc1_sectors_contents[(i * 12) + 4], lc1_sectors_contents[(i * 12) + 5], lc1_sectors_contents[(i * 12) + 6], lc1_sectors_contents[(i * 12) + 7], lc1_sectors_contents[(i * 12) + 8], lc1_sectors_contents[(i * 12) + 9], lc1_sectors_contents[(i * 12) + 10], lc1_sectors_contents[(i * 12) + 11]);
d = 0;
for (a = 3; a < 12; a++)
{
x = (byte)(lc1_sectors_contents[(i * 12) + a] ^ sub[a]);
Console.WriteLine($" %x%x%x%x%x%x%x%x", (x >> 7) & 0x1, (x >> 6) & 0x1, (x >> 5) & 0x1, (x >> 4) & 0x1, (x >> 3) & 0x1, (x >> 2) & 0x1, (x >> 1) & 0x1, x & 0x1);
if (x == 0)
continue;
for (b = 7; b >= 0; b--)
{
if (((x >> b) & 0x1) != 0)
{
d = (byte)(d << 1);
d |= (byte)((sub[a] >> b) & 0x1);
}
}
}
Console.WriteLine($" {(d >> 3) & 0x1:x}{(d >> 2) & 0x1:x}{(d >> 1) & 0x1:x}{d & 0x1}");
}
return 1;
}
}
}

1004
BurnOutSharp/External/psxt001z/Main.cs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using static psxt001z.Common;
namespace psxt001z
{
public class Scramble
{
private static readonly byte[] sync = new byte[12] { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
public int __main(string[] args)
{
if (args.Length < 2 || args.Length > 3)
{
Console.WriteLine("Syntax: px_p8 [-t] filename");
return 1;
}
int sectors;
if (args.Length == 2 && args[0] == "-t")
{
args[0] = args[1];
sectors = 2352;
}
else
{
sectors = 4704;
}
Stream sector_file;
try
{
sector_file = File.OpenRead(args[1]);
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return 1;
}
byte[] sector = new byte[sectors];
if (args.Length == 2)
{
uint hex;
for (int i = 0; sector_file.Position < sector_file.Length && i < 3252; i++)
{
byte[] buf = new byte[2];
hex = uint.Parse(Encoding.ASCII.GetString(buf), NumberStyles.HexNumber);
sector[i] = (byte)hex;
}
}
else
{
sector_file.Read(sector, 0, sectors);
}
int offset = MemSearch(sector, sync, sectors, 12);
if (offset == -1)
{
Console.WriteLine("Error searching for sync!");
return 1;
}
Console.WriteLine($"MSF: {sector[offset + 12]:2x}:{sector[offset + 12 + 1]:2x}:{sector[offset + 12 + 2]:2x}");
int shiftRegister = 0x1;
for (int i = 0; i < 3; i++)
{
sector[offset + 12 + i] ^= (byte)(shiftRegister & 0xFF);
for (int j = 0; j < 8; j++)
{
int hibit = ((shiftRegister & 1) ^ ((shiftRegister & 2) >> 1)) << 15;
shiftRegister = (hibit | shiftRegister) >> 1;
}
}
int start_sector = (btoi(sector[offset + 12]) * 60 + btoi(sector[offset + 13])) * 75 + btoi(sector[offset + 14]) - 150;
Console.WriteLine($"MSF: {sector[offset + 12]:2x}:{sector[offset + 12 + 1]:2x}:{sector[offset + 12 + 2]:2x}");
offset -= start_sector * 2352;
Console.WriteLine($"Combined offset: {offset} bytes / {offset / 4} samples");
return 0;
}
/// <summary>
/// Search for a byte array in another
/// </summary>
private int MemSearch(in byte[] buf_where, in byte[] buf_search, int buf_where_len, int buf_search_len)
{
for (int i = 0; i <= buf_where_len - buf_search_len; i++)
{
for (int j = 0; j < buf_search_len; j++)
{
if (buf_where[i + j] != buf_search[j])
break;
if (j + 1 == buf_search_len)
return i;
}
}
return -1;
}
}
}

310
BurnOutSharp/External/psxt001z/Track.cs vendored Normal file
View File

@@ -0,0 +1,310 @@
using System;
using System.IO;
namespace psxt001z
{
internal class Track
{
#region Properties
/// <summary>
/// Original input path for the track
/// </summary>
private string InputPath { get; set; }
/// <summary>
/// Stream representing the track data
/// </summary>
private Stream InputStream { get; set; }
/// <summary>
/// Output for saving the track data
/// </summary>
private string OutputPath { get; set; }
/// <summary>
/// Starting offset within the file
/// </summary>
private int Start { get; set; }
/// <summary>
/// Size of the input file
/// </summary>
private int Size { get; set; }
/// <summary>
/// CRC-32 of the track data to compare against
/// </summary>
private uint CRC32 { get; set; }
/// <summary>
/// Audio data header
/// </summary>
private byte[] RiffData { get; set; } = new byte[44];
/// <summary>
/// True if the track is audio data
/// </summary>
private bool IsRiff { get; set; }
/// <summary>
/// True if the file is under ~100MB
/// </summary>
private bool SmallFile { get; set; } = false;
/// <summary>
/// True to write out the track data
/// </summary>
private bool SaveTrack { get; set; }
/// <summary>
/// True means '+' or 'p'
/// False means '-' or 'n'
/// Null means neither
/// </summary>
private bool? Mode { get; set; }
/// <summary>
/// Cache for small file data
/// </summary>
private byte[] FileContents { get; set; }
/// <summary>
/// Cached file offset
/// </summary>
private int Offset { get; set; } = 0;
/// <summary>
/// Current file offset
/// </summary>
private int Current { get; set; } = 0;
#endregion
#region Constructor
public Track(string filename, int start, int size, uint crc, bool isRiff = false, bool? mode = null, string output = null)
{
InputPath = filename;
InputStream = File.OpenRead(filename);
OutputPath = output;
Start = start;
Size = size;
CRC32 = crc;
Mode = mode;
IsRiff = isRiff;
SmallFile = Size <= 100_000_000;
SaveTrack = output != null;
Console.WriteLine($"File: {InputPath}\nStart: {Start}\nSize: {Size}\nCRC-32: {CRC32:8x}");
Console.WriteLine();
if (IsRiff)
PopulateRiffData();
if (SmallFile)
CacheFileData();
}
#endregion
#region Functions
public bool FindTrack()
{
// Positive mode
if (Mode == true)
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = Current;
Current += 4;
return MatchesCRC();
}
// Negative mode
else if (Mode == false)
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = -Current;
Current += 4;
return MatchesCRC();
}
// Neutral mode
else
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = Current;
if (MatchesCRC())
{
return true;
}
else
{
Offset = -Current;
Current += 4;
return MatchesCRC();
}
}
}
public bool MatchesCRC()
{
CRC32 calc = new CRC32();
if (SmallFile)
{
if (IsRiff)
calc.ProcessCRC(RiffData, 0, 44);
calc.ProcessCRC(FileContents, (int)(20000 + Offset), (int)Size);
}
else
{
InputStream.Seek(Start + Offset, SeekOrigin.Begin);
if (IsRiff)
calc.ProcessCRC(RiffData, 0, 44);
for (long i = 0; i < Size; i++)
{
byte[] buffer = new byte[1];
if (InputStream.Read(buffer, 0, 1) != 1)
{
buffer[0] = 0x00;
InputStream.Seek(Start + Offset + i + 1, SeekOrigin.Begin);
}
calc.ProcessCRC(buffer, 0, 1);
}
}
Console.Write($"Offset correction {Offset} bytes, {Offset / 4} samples, CRC-32 {calc.m_crc32:8x}");
return (calc.m_crc32 == CRC32);
}
public void Done()
{
if (SmallFile)
FileContents = null;
if (Mode == null)
{
Console.WriteLine();
Console.WriteLine("Can't find offset!");
return;
}
if (SaveTrack)
{
byte[] buffer = new byte[1];
Stream f2 = File.Open(OutputPath, FileMode.Create, FileAccess.ReadWrite);
if (IsRiff)
f2.Write(RiffData, 0, 44);
InputStream.Seek(Start + Offset, SeekOrigin.Begin);
for (long i = 0; i < Size; i++)
{
if (InputStream.Read(buffer, 0, 1) != 1)
{
buffer[0] = 0x00;
InputStream.Seek(Start + Offset + i + 1, SeekOrigin.Begin);
}
f2.Write(buffer, 0, 1);
}
}
Console.WriteLine();
Console.Write("DONE!");
Console.WriteLine();
Console.Write($"Offset correction: {Offset} bytes / {Offset / 4} samples");
}
#endregion
#region Utilities
// TODO: Figure out what this actually does
private void CacheFileData()
{
FileContents = new byte[Size + 40000];
InputStream.Seek(Start - 20000, SeekOrigin.Begin);
for (int i = 0; i < Size + 40000; i++)
{
if (Start + i <= 20000)
InputStream.Seek(Start + i - 20000, SeekOrigin.Begin);
if (InputStream.Read(new byte[1], 0, 1) != 1)
FileContents[i] = 0x00;
}
}
private void PopulateRiffData()
{
RiffData[0] = 0x52;
RiffData[1] = 0x49;
RiffData[2] = 0x46;
RiffData[3] = 0x46;
byte[] temp = BitConverter.GetBytes(Size - 8);
Array.Copy(temp, 0, RiffData, 4, 4);
RiffData[8] = 0x57;
RiffData[9] = 0x41;
RiffData[10] = 0x56;
RiffData[11] = 0x45;
RiffData[12] = 0x66;
RiffData[13] = 0x6D;
RiffData[14] = 0x74;
RiffData[15] = 0x20;
RiffData[16] = 0x10;
RiffData[17] = 0x00;
RiffData[18] = 0x00;
RiffData[19] = 0x00;
RiffData[20] = 0x01;
RiffData[21] = 0x00;
RiffData[22] = 0x02;
RiffData[23] = 0x00;
RiffData[24] = 0x44;
RiffData[25] = 0xAC;
RiffData[26] = 0x00;
RiffData[27] = 0x00;
RiffData[28] = 0x10;
RiffData[29] = 0xB1;
RiffData[30] = 0x02;
RiffData[31] = 0x00;
RiffData[32] = 0x04;
RiffData[33] = 0x00;
RiffData[34] = 0x10;
RiffData[35] = 0x00;
RiffData[36] = 0x64;
RiffData[37] = 0x61;
RiffData[38] = 0x74;
RiffData[39] = 0x61;
temp = BitConverter.GetBytes(Size - 44);
Array.Copy(temp, 0, RiffData, 40, 4);
Size -= 44;
}
#endregion
}
}

View File

@@ -1,26 +1,40 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Compressors;
using SharpCompress.Compressors.Deflate;
namespace BurnOutSharp.FileType
{
internal class BFPK
public class BFPK : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x42, 0x46, 0x50, 0x4b }))
if (magic.StartsWith(new byte?[] { 0x42, 0x46, 0x50, 0x4b }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the BFPK file itself fails
try
{
@@ -49,7 +63,7 @@ namespace BurnOutSharp.FileType
br.BaseStream.Seek(offset, SeekOrigin.Begin);
uint compressedSize = br.ReadUInt32();
// Some files can lack the length prefix
if (compressedSize > br.BaseStream.Length)
{
@@ -87,36 +101,40 @@ namespace BurnOutSharp.FileType
}
}
}
string protection = ProtectionFind.ScanContent(tempFile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempFile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add(tempFile);
}
catch { }
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
br.BaseStream.Seek(current, SeekOrigin.Begin);
}
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
}
catch { }
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return protections;
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,26 +1,40 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
namespace BurnOutSharp.FileType
{
internal class BZip2
public class BZip2 : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x42, 0x52, 0x68 }))
if (magic.StartsWith(new byte?[] { 0x42, 0x52, 0x68 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
if (!File.Exists(file))
return null;
// If the 7-zip file itself fails
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the BZip2 file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
@@ -31,37 +45,42 @@ namespace BurnOutSharp.FileType
// If an individual entry fails
try
{
string tempfile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempfile))
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempFile))
{
bz2File.CopyTo(fs);
}
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{protection}");
}
catch { }
// If temp directory cleanup fails
try
catch (Exception ex)
{
Directory.Delete(tempPath, true);
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,254 +1,193 @@
using System.Collections.Generic;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.ProtectionType;
using System.Threading.Tasks;
using BurnOutSharp.ExecutableType.Microsoft.NE;
using BurnOutSharp.ExecutableType.Microsoft.PE;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
namespace BurnOutSharp.FileType
{
internal class Executable
public class Executable : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// DOS MZ executable file format (and descendants)
if (magic.StartsWith(new byte[] { 0x4d, 0x5a }))
if (magic.StartsWith(new byte?[] { 0x4d, 0x5a }))
return true;
// Executable and Linkable Format
if (magic.StartsWith(new byte[] { 0x7f, 0x45, 0x4c, 0x46 }))
if (magic.StartsWith(new byte?[] { 0x7f, 0x45, 0x4c, 0x46 }))
return true;
// Mach-O binary (32-bit)
if (magic.StartsWith(new byte[] { 0xfe, 0xed, 0xfa, 0xce }))
if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xce }))
return true;
// Mach-O binary (32-bit, reverse byte ordering scheme)
if (magic.StartsWith(new byte[] { 0xce, 0xfa, 0xed, 0xfe }))
if (magic.StartsWith(new byte?[] { 0xce, 0xfa, 0xed, 0xfe }))
return true;
// Mach-O binary (64-bit)
if (magic.StartsWith(new byte[] { 0xfe, 0xed, 0xfa, 0xcf }))
if (magic.StartsWith(new byte?[] { 0xfe, 0xed, 0xfa, 0xcf }))
return true;
// Mach-O binary (64-bit, reverse byte ordering scheme)
if (magic.StartsWith(new byte[] { 0xcf, 0xfa, 0xed, 0xfe }))
if (magic.StartsWith(new byte?[] { 0xcf, 0xfa, 0xed, 0xfe }))
return true;
// Prefrred Executable File Format
if (magic.StartsWith(new byte[] { 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66 }))
if (magic.StartsWith(new byte?[] { 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, string file = null, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
// Load the current file content
byte[] fileContent = null;
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
fileContent = br.ReadBytes((int)stream.Length);
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Files can be protected in multiple ways
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
// Load the current file content for debug only
byte[] fileContent = null;
if (scanner.IncludeDebug)
{
try
{
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
{
fileContent = br.ReadBytes((int)stream.Length);
}
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
Utilities.AppendToDictionary(protections, file, "[Out of memory attempting to open]");
return protections;
}
}
// If we can, seek to the beginning of the stream
if (stream.CanSeek)
stream.Seek(0, SeekOrigin.Begin);
// Create PortableExecutable and NewExecutable objects for use in the checks
stream.Seek(0, SeekOrigin.Begin);
PortableExecutable pex = new PortableExecutable(stream);
stream.Seek(0, SeekOrigin.Begin);
NewExecutable nex = new NewExecutable(stream);
stream.Seek(0, SeekOrigin.Begin);
// Files can be protected in multiple ways
List<string> protections = new List<string>();
List<string> subProtections = new List<string>();
string protection;
// Iterate through all generic content checks
if (fileContent != null)
{
Parallel.ForEach(ScanningClasses.ContentCheckClasses, contentCheckClass =>
{
string protection = contentCheckClass.CheckContents(file, fileContent, scanner.IncludeDebug);
if (ShouldAddProtection(contentCheckClass, scanner.ScanPackers, protection))
Utilities.AppendToDictionary(protections, file, protection);
// 3PLock
protection = ThreePLock.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// If we have an IScannable implementation
if (contentCheckClass is IScannable scannable)
{
if (file != null && !string.IsNullOrEmpty(protection))
{
var subProtections = scannable.Scan(scanner, null, file);
Utilities.PrependToKeys(subProtections, file);
Utilities.AppendToDictionary(protections, subProtections);
}
}
});
}
// ActiveMARK
protection = ActiveMARK.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// If we have a NE executable, iterate through all NE content checks
if (nex?.Initialized == true)
{
Parallel.ForEach(ScanningClasses.NewExecutableCheckClasses, contentCheckClass =>
{
// Check using custom content checks first
string protection = contentCheckClass.CheckNewExecutable(file, nex, scanner.IncludeDebug);
if (ShouldAddProtection(contentCheckClass, scanner.ScanPackers, protection))
Utilities.AppendToDictionary(protections, file, protection);
// Alpha-ROM
protection = AlphaROM.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// If we have an IScannable implementation
if (contentCheckClass is IScannable scannable)
{
if (file != null && !string.IsNullOrEmpty(protection))
{
var subProtections = scannable.Scan(scanner, null, file);
Utilities.PrependToKeys(subProtections, file);
Utilities.AppendToDictionary(protections, subProtections);
}
}
});
}
// Armadillo
protection = Armadillo.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// If we have a PE executable, iterate through all PE content checks
if (pex?.Initialized == true)
{
// Print the section table for debug
if (scanner.IncludeDebug && pex.SectionTable != null)
pex.PrintAllSections();
// CD-Cops
protection = CDCops.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
Parallel.ForEach(ScanningClasses.PortableExecutableCheckClasses, contentCheckClass =>
{
// Check using custom content checks first
string protection = contentCheckClass.CheckPortableExecutable(file, pex, scanner.IncludeDebug);
if (ShouldAddProtection(contentCheckClass, scanner.ScanPackers, protection))
Utilities.AppendToDictionary(protections, file, protection);
// CD-Lock
protection = CDLock.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CDSHiELD SE
protection = CDSHiELDSE.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CD Check
protection = CDCheck.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Cenega ProtectDVD
protection = CengaProtectDVD.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Code Lock
protection = CodeLock.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// CopyKiller
protection = CopyKiller.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Cucko (EA Custom)
protection = Cucko.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// dotFuscator
protection = dotFuscator.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// DVD-Cops
protection = DVDCops.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// EA CdKey Registration Module
protection = EACdKey.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// EXE Stealth
protection = EXEStealth.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Games for Windows - Live
protection = GFWL.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Impulse Reactor
protection = ImpulseReactor.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Inno Setup
protection = InnoSetup.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// JoWooD X-Prot
protection = JoWooDXProt.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Key-Lock (Dongle)
protection = KeyLock.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// LaserLock
protection = LaserLock.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// PE Compact
protection = PECompact.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// ProtectDisc
protection = ProtectDisc.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Ring PROTECH
protection = RingPROTECH.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeDisc / SafeCast
protection = SafeDisc.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SafeLock
protection = SafeLock.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SecuROM
protection = SecuROM.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SmartE
protection = SmartE.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SolidShield
protection = SolidShield.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// StarForce
protection = StarForce.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// SVK Protector
protection = SVKProtector.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Sysiphus / Sysiphus DVD
protection = Sysiphus.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// TAGES
protection = Tages.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// VOB ProtectCD/DVD
protection = VOBProtectCDDVD.CheckContents(file, fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Wise Installer
subProtections = WiseInstaller.CheckContents(file, fileContent, includePosition);
if (subProtections != null && subProtections.Count > 0)
protections.AddRange(subProtections);
// WTM CD Protect
protection = WTMCDProtect.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// Xtreme-Protector
protection = XtremeProtector.CheckContents(fileContent, includePosition);
if (!string.IsNullOrWhiteSpace(protection))
protections.Add(protection);
// If we have an IScannable implementation
if (contentCheckClass is IScannable scannable)
{
if (file != null && !string.IsNullOrEmpty(protection))
{
var subProtections = scannable.Scan(scanner, null, file);
Utilities.PrependToKeys(subProtections, file);
Utilities.AppendToDictionary(protections, subProtections);
}
}
});
}
return protections;
}
#region Helpers
/// <summary>
/// Check to see if a protection should be added or not
/// </summary>
/// <param name="checkClass">Class that was last used to check</param>
/// <param name="scanPackers">Determines if packers should be included in the output</param>
/// <param name="protection">The protection result to be checked</param>
private bool ShouldAddProtection(object checkClass, bool scanPackers, string protection)
{
// If we have an invalid protection
if (string.IsNullOrWhiteSpace(protection))
return false;
// If we have a valid content check based on settings
if (scanPackers || !checkClass.GetType().Namespace.ToLowerInvariant().Contains("packertype"))
return true;
// Everything else fails
return false;
}
#endregion
}
}

View File

@@ -1,25 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Archives;
using SharpCompress.Archives.GZip;
namespace BurnOutSharp.FileType
{
internal class GZIP
public class GZIP : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x1f, 0x8b }))
if (magic.StartsWith(new byte?[] { 0x1f, 0x8b }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the gzip file itself fails
try
{
@@ -37,34 +51,40 @@ namespace BurnOutSharp.FileType
if (entry.IsDirectory)
continue;
string tempfile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempfile);
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{entry.Key} - {protection}");
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -0,0 +1,296 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace BurnOutSharp.FileType
{
public class IniFile : IDictionary<string, string>
{
private Dictionary<string, string> _keyValuePairs = new Dictionary<string, string>();
public string this[string key]
{
get
{
if (_keyValuePairs == null)
_keyValuePairs = new Dictionary<string, string>();
key = key.ToLowerInvariant();
if (_keyValuePairs.ContainsKey(key))
return _keyValuePairs[key];
return null;
}
set
{
if (_keyValuePairs == null)
_keyValuePairs = new Dictionary<string, string>();
key = key.ToLowerInvariant();
_keyValuePairs[key] = value;
}
}
/// <summary>
/// Create an empty INI file
/// </summary>
public IniFile()
{
}
/// <summary>
/// Populate an INI file from path
/// </summary>
public IniFile(string path)
{
this.Parse(path);
}
/// <summary>
/// Populate an INI file from stream
/// </summary>
public IniFile(Stream stream)
{
this.Parse(stream);
}
/// <summary>
/// Add or update a key and value to the INI file
/// </summary>
public void AddOrUpdate(string key, string value)
{
_keyValuePairs[key.ToLowerInvariant()] = value;
}
/// <summary>
/// Remove a key from the INI file
/// </summary>
public void Remove(string key)
{
_keyValuePairs.Remove(key.ToLowerInvariant());
}
/// <summary>
/// Read an INI file based on the path
/// </summary>
public bool Parse(string path)
{
// If we don't have a file, we can't read it
if (!File.Exists(path))
return false;
using (var fileStream = File.OpenRead(path))
{
return Parse(fileStream);
}
}
/// <summary>
/// Read an INI file from a stream
/// </summary>
public bool Parse(Stream stream)
{
// If the stream is invalid or unreadable, we can't process it
if (stream == null || !stream.CanRead || stream.Position >= stream.Length - 1)
return false;
// Keys are case-insensitive by default
try
{
using (StreamReader sr = new StreamReader(stream))
{
string section = string.Empty;
while (!sr.EndOfStream)
{
string line = sr.ReadLine().Trim();
// Comments start with ';'
if (line.StartsWith(";"))
{
// No-op, we don't process comments
}
// Section titles are surrounded by square brackets
else if (line.StartsWith("["))
{
section = line.TrimStart('[').TrimEnd(']');
}
// Valid INI lines are in the format key=value
else if (line.Contains("="))
{
// Split the line by '=' for key-value pairs
string[] data = line.Split('=');
// If the value field contains an '=', we need to put them back in
string key = data[0].Trim();
string value = string.Join("=", data.Skip(1)).Trim();
// Section names are prepended to the key with a '.' separating
if (!string.IsNullOrEmpty(section))
key = $"{section}.{key}";
// Set or overwrite keys in the returned dictionary
_keyValuePairs[key.ToLowerInvariant()] = value;
}
// All other lines are ignored
}
}
}
catch
{
// We don't care what the error was, just catch and return
return false;
}
return true;
}
/// <summary>
/// Write an INI file to a path
/// </summary>
public bool Write(string path)
{
// If we don't have a valid dictionary with values, we can't write out
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
return false;
using (var fileStream = File.OpenWrite(path))
{
return Write(fileStream);
}
}
/// <summary>
/// Write an INI file to a stream
/// </summary>
public bool Write(Stream stream)
{
// If we don't have a valid dictionary with values, we can't write out
if (_keyValuePairs == null || _keyValuePairs.Count == 0)
return false;
// If the stream is invalid or unwritable, we can't output to it
if (stream == null || !stream.CanWrite || stream.Position >= stream.Length - 1)
return false;
try
{
using (StreamWriter sw = new StreamWriter(stream))
{
// Order the dictionary by keys to link sections together
var orderedKeyValuePairs = _keyValuePairs.OrderBy(kvp => kvp.Key);
string section = string.Empty;
foreach (var keyValuePair in orderedKeyValuePairs)
{
// Extract the key and value
string key = keyValuePair.Key;
string value = keyValuePair.Value;
// We assume '.' is a section name separator
if (key.Contains('.'))
{
// Split the key by '.'
string[] data = keyValuePair.Key.Split('.');
// If the key contains an '.', we need to put them back in
string newSection = data[0].Trim();
key = string.Join(".", data.Skip(1)).Trim();
// If we have a new section, write it out
if (!string.Equals(newSection, section, StringComparison.OrdinalIgnoreCase))
{
sw.WriteLine($"[{newSection}]");
section = newSection;
}
}
// Now write out the key and value in a standardized way
sw.WriteLine($"{key}={value}");
}
}
}
catch
{
// We don't care what the error was, just catch and return
return false;
}
return true;
}
#region IDictionary Impelementations
public ICollection<string> Keys => ((IDictionary<string, string>)_keyValuePairs).Keys;
public ICollection<string> Values => ((IDictionary<string, string>)_keyValuePairs).Values;
public int Count => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Count;
public bool IsReadOnly => ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).IsReadOnly;
public void Add(string key, string value)
{
((IDictionary<string, string>)_keyValuePairs).Add(key.ToLowerInvariant(), value);
}
bool IDictionary<string, string>.Remove(string key)
{
return ((IDictionary<string, string>)_keyValuePairs).Remove(key.ToLowerInvariant());
}
public bool TryGetValue(string key, out string value)
{
return ((IDictionary<string, string>)_keyValuePairs).TryGetValue(key.ToLowerInvariant(), out value);
}
public void Add(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Add(newItem);
}
public void Clear()
{
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Clear();
}
public bool Contains(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Contains(newItem);
}
public bool ContainsKey(string key)
{
return _keyValuePairs.ContainsKey(key.ToLowerInvariant());
}
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, string>>)_keyValuePairs).CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<string, string> item)
{
var newItem = new KeyValuePair<string, string>(item.Key.ToLowerInvariant(), item.Value);
return ((ICollection<KeyValuePair<string, string>>)_keyValuePairs).Remove(newItem);
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return ((IEnumerable<KeyValuePair<string, string>>)_keyValuePairs).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_keyValuePairs).GetEnumerator();
}
#endregion
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using UnshieldSharp.Archive;
namespace BurnOutSharp.FileType
{
public class InstallShieldArchiveV3 : IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte?[] { 0x13, 0x5D, 0x65, 0x8C }))
return true;
return false;
}
/// <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);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Get the name of the first cabinet file or header
string directory = Path.GetDirectoryName(file);
string noExtension = Path.GetFileNameWithoutExtension(file);
string filenamePattern = Path.Combine(directory, noExtension);
filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty);
bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr"));
bool 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 the first file
if (shouldScanCabinet)
{
// If the cab file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
UnshieldSharp.Archive.InstallShieldArchiveV3 archive = new UnshieldSharp.Archive.InstallShieldArchiveV3(file);
foreach (CompressedFile cfile in archive.Files.Select(kvp => kvp.Value))
{
// If an individual entry fails
try
{
string tempFile = Path.Combine(tempPath, cfile.FullPath);
if (!Directory.Exists(Path.GetDirectoryName(tempFile)))
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
(byte[] fileContents, string error) = archive.Extract(cfile.FullPath);
if (!string.IsNullOrWhiteSpace(error))
continue;
using (FileStream fs = File.OpenWrite(tempFile))
{
fs.Write(fileContents, 0, fileContents.Length);
}
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
}
return null;
}
}
}

View File

@@ -1,26 +1,40 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text.RegularExpressions;
using UnshieldSharp;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using UnshieldSharp.Cabinet;
namespace BurnOutSharp.FileType
{
internal class InstallShieldCAB
public class InstallShieldCAB : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x49, 0x53, 0x63 }))
if (magic.StartsWith(new byte?[] { 0x49, 0x53, 0x63 }))
return true;
return false;
}
// TODO: Add stream opening support
public static List<string> Scan(string file, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// Get the name of the first cabinet file or header
string directory = Path.GetDirectoryName(file);
string noExtension = Path.GetFileNameWithoutExtension(file);
@@ -41,42 +55,56 @@ namespace BurnOutSharp.FileType
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
UnshieldCabinet cabfile = UnshieldCabinet.Open(file);
InstallShieldCabinet cabfile = InstallShieldCabinet.Open(file);
for (int i = 0; i < cabfile.FileCount; i++)
{
// If an individual entry fails
try
{
string tempFile = Path.Combine(tempPath, cabfile.FileName(i));
if (cabfile.FileSave(i, tempFile))
string filename = cabfile.FileName(i);
string tempFile;
try
{
string protection = ProtectionFind.ScanContent(tempFile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempFile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{cabfile.FileName(i)} - {protection}");
tempFile = Path.Combine(tempPath, filename);
}
catch
{
tempFile = Path.Combine(tempPath, $"BAD_FILENAME{i}");
}
cabfile.FileSave(i, tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
return protections;
return null;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,168 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using OpenMcdf;
namespace BurnOutSharp.FileType
{
public class MSI : IScannable
{
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte?[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }))
return true;
return false;
}
/// <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);
}
}
// TODO: Add stream opening support
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the MSI file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (CompoundFile msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default))
{
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())
{
decoded = decoded.Replace(c, '_');
}
string filename = Path.Combine(tempPath, decoded);
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(strData, 0, strData.Length);
}
}, 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
/// <remarks>Adapted from LibMSI</remarks>
private static string DecodeStreamName(string input)
{
if (input == null)
return null;
int count = 0;
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
int p = 0; // inputBytes[0]
byte[] output = new byte[inputBytes.Length + 1];
int q = 0; // output[0]
while (p < inputBytes.Length && inputBytes[p] != 0)
{
int ch = inputBytes[p];
if ((ch == 0xe3 && inputBytes[p + 1] >= 0xa0) || (ch == 0xe4 && inputBytes[p + 1] < 0xa0))
{
// UTF-8 encoding of 0x3800..0x47ff.
output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f);
output[q++] = (byte)Mime2Utf(inputBytes[p + 1] ^ 0xa0);
p += 3;
count += 2;
continue;
}
if (ch == 0xe4 && inputBytes[p + 1] == 0xa0)
{
// UTF-8 encoding of 0x4800..0x483f.
output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f);
p += 3;
count++;
continue;
}
output[q++] = inputBytes[p++];
if (ch >= 0xc1)
output[q++] = inputBytes[p++];
if (ch >= 0xe0)
output[q++] = inputBytes[p++];
if (ch >= 0xf0)
output[q++] = inputBytes[p++];
count++;
}
output[q] = 0;
return Encoding.ASCII.GetString(output);
}
/// <remarks>Adapted from LibMSI</remarks>
private static int Mime2Utf(int x)
{
if (x < 10)
return x + '0';
if (x < (10 + 26))
return x - 10 + 'A';
if (x < (10 + 26 + 26))
return x - 10 - 26 + 'a';
if (x == (10 + 26 + 26))
return '.';
return '_';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,52 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
namespace BurnOutSharp.FileType
{
internal class PKZIP
public class PKZIP : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// PKZIP (Unknown)
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x00, 0x00 }))
return true;
// PKZIP
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x03, 0x04 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x03, 0x04 }))
return true;
// PKZIP (Empty Archive)
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x05, 0x06 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x05, 0x06 }))
return true;
// PKZIP (Spanned Archive)
if (magic.StartsWith(new byte[] { 0x50, 0x4b, 0x07, 0x08 }))
if (magic.StartsWith(new byte?[] { 0x50, 0x4b, 0x07, 0x08 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the zip file itself fails
try
{
@@ -46,34 +64,41 @@ namespace BurnOutSharp.FileType
if (entry.IsDirectory)
continue;
string tempfile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempfile);
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{entry.Key} - {protection}");
string tempFile = Path.Combine(tempPath, entry.Key);
Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,30 +1,44 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
namespace BurnOutSharp.FileType
{
internal class RAR
public class RAR : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// RAR archive version 1.50 onwards
if (magic.StartsWith(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }))
return true;
// RAR archive version 5.0 onwards
if (magic.StartsWith(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the rar file itself fails
try
{
@@ -42,34 +56,40 @@ namespace BurnOutSharp.FileType
if (entry.IsDirectory)
continue;
string tempfile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempfile);
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{entry.Key} - {protection}");
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,25 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
namespace BurnOutSharp.FileType
{
internal class SevenZip
public class SevenZip : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))
if (magic.StartsWith(new byte?[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the 7-zip file itself fails
try
{
@@ -37,34 +51,40 @@ namespace BurnOutSharp.FileType
if (entry.IsDirectory)
continue;
string tempfile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempfile);
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{entry.Key} - {protection}");
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// Collect and format all found protections
var protections = scanner.GetProtections(tempPath);
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
// Remove temporary path references
Utilities.StripFromKeys(protections, tempPath);
return protections;
}
}
catch { }
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return protections;
return null;
}
}
}

View File

@@ -1,28 +1,42 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Archives;
using SharpCompress.Archives.Tar;
namespace BurnOutSharp.FileType
{
internal class TapeArchive
public class TapeArchive : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 }))
if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 }))
return true;
if (magic.StartsWith(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 }))
if (magic.StartsWith(new byte?[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// If the tar file itself fails
try
{
@@ -40,34 +54,40 @@ namespace BurnOutSharp.FileType
if (entry.IsDirectory)
continue;
string tempfile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempfile);
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{entry.Key} - {protection}");
string tempFile = Path.Combine(tempPath, entry.Key);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
// If temp directory cleanup fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,60 +1,144 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
namespace BurnOutSharp.FileType
{
internal class Textfile
public class Textfile : IScannable
{
public static bool ShouldScan(byte[] magic, string extension)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
return ShouldScan(magic, null);
}
/// <summary>
/// Determine if a file signature or extension matches one of the expected values
/// </summary>
/// <param name="magic">Byte array representing the file header</param>
/// <param name="extension">Extension for the file being checked</param>
/// <returns>True if the signature is valid, false otherwise</returns>
public bool ShouldScan(byte[] magic, string extension)
{
// Rich Text File
if (magic.StartsWith(new byte[] { 0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31 }))
if (magic.StartsWith(new byte?[] { 0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31 }))
return true;
// HTML
if (magic.StartsWith(new byte[] { 0x3c, 0x68, 0x74, 0x6d, 0x6c }))
if (magic.StartsWith(new byte?[] { 0x3c, 0x68, 0x74, 0x6d, 0x6c }))
return true;
// HTML and XML
if (magic.StartsWith(new byte[] { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45 }))
if (magic.StartsWith(new byte?[] { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45 }))
return true;
// Microsoft Office File (old)
if (magic.StartsWith(new byte[] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }))
if (magic.StartsWith(new byte?[] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }))
return true;
// InstallShield Compiled Rules
if (magic.StartsWith(new byte?[] { 0x61, 0x4C, 0x75, 0x5A }))
return true;
// InstallShield Script
if (string.Equals(extension?.TrimStart('.'), "ins", StringComparison.OrdinalIgnoreCase))
return true;
// Generic textfile (no header)
if (string.Equals(extension, "txt", StringComparison.OrdinalIgnoreCase))
if (string.Equals(extension?.TrimStart('.'), "txt", StringComparison.OrdinalIgnoreCase))
return true;
// XML (multiple headers possible)
if (string.Equals(extension?.TrimStart('.'), "xml", StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
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)
{
// Files can be protected in multiple ways
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
try
{
// Load the current file content
string fileContent = null;
using (StreamReader sr = new StreamReader(stream, Encoding.Default, false, 1024 * 1024, true))
using (var sr = new StreamReader(stream, Encoding.Default, true, 1024 * 1024, true))
{
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."))
Utilities.AppendToDictionary(protections, file, "AegiSoft License Manager");
// CD-Key
if (fileContent.Contains("a valid serial number is required")
|| fileContent.Contains("serial number is located"))
{
protections.Add("CD-Key / Serial");
}
if (fileContent.Contains("a valid serial number is required"))
Utilities.AppendToDictionary(protections, file, "CD-Key / Serial");
else if (fileContent.Contains("serial number is located"))
Utilities.AppendToDictionary(protections, file, "CD-Key / Serial");
// MediaCloQ
if (fileContent.Contains("SunnComm MediaCloQ"))
Utilities.AppendToDictionary(protections, file, "MediaCloQ");
else if (fileContent.Contains("http://download.mediacloq.com/"))
Utilities.AppendToDictionary(protections, file, "MediaCloQ");
else if (fileContent.Contains("http://www.sunncomm.com/mediacloq/"))
Utilities.AppendToDictionary(protections, file, "MediaCloQ");
// MediaMax
if (fileContent.Contains("MediaMax technology"))
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
else if (fileContent.Contains("exclusive Cd3 technology"))
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
else if (fileContent.Contains("<PROTECTION-VENDOR>MediaMAX</PROTECTION-VENDOR>"))
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
else if (fileContent.Contains("MediaMax(tm)"))
Utilities.AppendToDictionary(protections, file, "MediaMax CD-3");
// phenoProtect
if (fileContent.Contains("phenoProtect"))
Utilities.AppendToDictionary(protections, file, "phenoProtect");
// 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"))
Utilities.AppendToDictionary(protections, file, "SecuROM");
// Steam
if (fileContent.Contains("All use of the Program is governed by the terms of the Steam Agreement as described below."))
Utilities.AppendToDictionary(protections, file, "Steam");
// XCP
if (fileContent.Contains("http://cp.sonybmg.com/xcp/"))
Utilities.AppendToDictionary(protections, file, "XCP");
}
catch
catch (Exception ex)
{
// We don't care what the error was
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return protections;

View File

@@ -1,82 +1,89 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using HLExtract.Net;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using HLLib.Directory;
using HLLib.Packages;
namespace BurnOutSharp.FileType
{
internal class Valve
public class Valve : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
// GCF
if (magic.StartsWith(new byte[] { 0x01, 0x00, 0x00, 0x00 }))
return true;
return Package.GetPackageType(magic) != PackageType.HL_PACKAGE_NONE;
}
// PAK
if (magic.StartsWith(new byte[] { 0x50, 0x41, 0x43, 0x4b }))
return true;
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
// SGA
if (magic.StartsWith(new byte[] { 0x5f, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45 }))
return true;
// VPK
if (magic.StartsWith(new byte[] { 0x55, 0xaa, 0x12, 0x34 }))
return true;
// WAD
if (magic.StartsWith(new byte[] { 0x57, 0x41, 0x44, 0x33 }))
return true;
return false;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
// TODO: Add stream opening support
public static List<string> Scan(string file, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
List<string> protections = new List<string>();
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
string[] args = new string[]
{
"-p", file,
"-x", "root",
"-x", "'extract .'",
"-x", "exit",
"-d", tempPath,
};
HLExtractProgram.Process(args);
if (Directory.Exists(tempPath))
{
foreach (string tempFile in Directory.EnumerateFiles(tempPath, "*", SearchOption.AllDirectories))
{
string protection = ProtectionFind.ScanContent(tempFile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempFile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add(tempFile);
}
}
// If temp directory cleanup fails
// If the Valve archive itself fails
try
{
Directory.Delete(tempPath, true);
}
catch { }
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
return protections;
// Get the package type
byte[] magic = stream.ReadBytes(16);
PackageType packageType = Package.GetPackageType(magic);
if (packageType == PackageType.HL_PACKAGE_NONE)
return null;
// Create a new package from the file
var pkg = Package.CreatePackage(packageType);
FileModeFlags mode = FileModeFlags.HL_MODE_READ | FileModeFlags.HL_MODE_WRITE | FileModeFlags.HL_MODE_NO_FILEMAPPING | FileModeFlags.HL_MODE_VOLATILE;
bool opened = pkg.Open(file, mode, overwriteFiles: true);
if (!opened)
return null;
// Create the root directory
var rootDirectory = pkg.GetRoot();
// Extract all files
rootDirectory.Extract(tempPath, readEncrypted: true, overwrite: true);
// Close the package explicitly
pkg.Close();
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -1,25 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using SharpCompress.Compressors.Xz;
namespace BurnOutSharp.FileType
{
internal class XZ
public class XZ : IScannable
{
public static bool ShouldScan(byte[] magic)
/// <inheritdoc/>
public bool ShouldScan(byte[] magic)
{
if (magic.StartsWith(new byte[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 }))
if (magic.StartsWith(new byte?[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 }))
return true;
return false;
}
public static List<string> Scan(Stream stream, bool includePosition = false)
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
List<string> protections = new List<string>();
if (!File.Exists(file))
return null;
// If the 7-zip file itself fails
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
// If the xz file itself fails
try
{
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
@@ -30,37 +44,42 @@ namespace BurnOutSharp.FileType
// If an individual entry fails
try
{
string tempfile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempfile))
string tempFile = Path.Combine(tempPath, Guid.NewGuid().ToString());
using (FileStream fs = File.OpenWrite(tempFile))
{
xzFile.CopyTo(fs);
}
string protection = ProtectionFind.ScanContent(tempfile, includePosition);
// If tempfile cleanup fails
try
{
File.Delete(tempfile);
}
catch { }
if (!string.IsNullOrEmpty(protection))
protections.Add($"\r\n{protection}");
}
catch { }
// If temp directory cleanup fails
try
catch (Exception ex)
{
Directory.Delete(tempPath, true);
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
catch { }
}
}
catch { }
return protections;
// 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;
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

Binary file not shown.

Binary file not shown.

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