├── .gitignore ├── LICENSE ├── README.md ├── dnbinaryformat └── __init__.py ├── scripts ├── extract_pe.py └── show_structure.py ├── setup.py └── tests ├── data └── dntojscript.bin ├── fixtures.py └── test_binary_format.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-dotnet-binaryformat 2 | Pure Python parser for data encoded by .NET's BinaryFormatter 3 | 4 | Structures implemented using the documentation available from Microsoft [here](https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-NRBF/%5bMS-NRBF%5d.pdf). Not all of these structures are implemented - just what I've seen in real-life so far. Please open issues against this repo if you encounter `NotImplementedError` and can provide a sample buffer. 5 | 6 | 7 | ## scripts 8 | 9 | ### extract_pe.py 10 | 11 | Searches for embedded byte arrays that begin with `MZ` and write them to a file named after their MD5 hash. 12 | 13 | 14 | Example:: 15 | 16 | ``` 17 | λ python scripts/extract_pe.py tests/data/dntojscript.bin -v 18 | INFO:__main__:record 32: found array 19 | INFO:__main__:record 32: found byte array 20 | INFO:__main__:record 32: found PE byte array 21 | INFO:__main__:writing PE to cd040cc16144ff4a91b333f3f0cb06ca.bin 22 | ``` 23 | 24 | 25 | ### show_structure.py 26 | 27 | Parse the serialized data and show its structure in a tree-like format. 28 | 29 | Example:: 30 | 31 | ``` 32 | λ python scripts/show_structure.py tests/data/dntojscript.bin -v 33 | 00000000 (6418) SerializedData: SerializedData 34 | 00000000 (17) 0: SerializationHeaderRecord 35 | 00000000 (01) RecordTypeEnum: SerializedStreamHeader (0x00000000) 36 | 00000001 (04) RootId: 0x00000001 (1) 37 | 00000005 (04) HeaderId: 0xffffffff (4294967295) 38 | 00000009 (04) MajorVersion: 0x00000001 (1) 39 | 0000000d (04) MinorVersion: 0x00000000 (0) 40 | 00000011 (204) 1: SystemClassWithMembersAndTypes 41 | 00000011 (01) RecordTypeEnum: SystemClassWithMembersAndTypes (0x00000004) 42 | 00000012 (68) ClassInfo: ClassInfo 43 | 00000012 (04) ObjectId: 0x00000001 (1) 44 | 00000016 (35) Name: LengthPrefixedString: System.DelegateSerializationHolder 45 | 00000039 (04) MemberCount: 0x00000003 (3) 46 | 0000003d (25) MemberNames: VArray 47 | 0000003d (09) 0: LengthPrefixedString: Delegate 48 | 00000046 (08) 1: LengthPrefixedString: target0 49 | 0000004e (08) 2: LengthPrefixedString: method0 50 | 00000056 (135) MemberTypeInfo: MemberTypeInfo 51 | 00000056 (03) BinaryTypeEnums: VArray 52 | 00000056 (01) 0: SystemClass (0x00000003) 53 | 00000057 (01) 1: SystemClass (0x00000003) 54 | 00000058 (01) 2: SystemClass (0x00000003) 55 | 00000059 (132) AdditionalInfos: VArray 56 | 00000059 (49) 0: LengthPrefixedString: System.DelegateSerializationHolder+DelegateEntry 57 | 0000008a (35) 1: LengthPrefixedString: System.DelegateSerializationHolder 58 | 000000ad (48) 2: LengthPrefixedString: System.Reflection.MemberInfoSerializationHolder 59 | 000000dd (05) 2: MemberReference 60 | 000000dd (01) RecordTypeEnum: MemberReference (0x00000009) 61 | 000000de (04) IdRef: 0x00000002 (2) 62 | 000000e2 (05) 3: MemberReference 63 | 000000e2 (01) RecordTypeEnum: MemberReference (0x00000009) 64 | 000000e3 (04) IdRef: 0x00000003 (3) 65 | 000000e7 (05) 4: MemberReference 66 | 000000e7 (01) RecordTypeEnum: MemberReference (0x00000009) 67 | 000000e8 (04) IdRef: 0x00000004 (4) 68 | 000000ec (194) 5: SystemClassWithMembersAndTypes 69 | 000000ec (01) RecordTypeEnum: SystemClassWithMembersAndTypes (0x00000004) 70 | 000000ed (137) ClassInfo: ClassInfo 71 | 000000ed (04) ObjectId: 0x00000002 (2) 72 | 000000f1 (49) Name: LengthPrefixedString: System.DelegateSerializationHolder+DelegateEntry 73 | 00000122 (04) MemberCount: 0x00000007 (7) 74 | 00000126 (80) MemberNames: VArray 75 | 00000126 (05) 0: LengthPrefixedString: type 76 | 0000012b (09) 1: LengthPrefixedString: assembly 77 | 00000134 (07) 2: LengthPrefixedString: target 78 | 0000013b (19) 3: LengthPrefixedString: targetTypeAssembly 79 | 0000014e (15) 4: LengthPrefixedString: targetTypeName 80 | 0000015d (11) 5: LengthPrefixedString: methodName 81 | 00000168 (14) 6: LengthPrefixedString: delegateEntry 82 | 00000176 (56) MemberTypeInfo: MemberTypeInfo 83 | 00000176 (07) BinaryTypeEnums: VArray 84 | 00000176 (01) 0: String (0x00000001) 85 | 00000177 (01) 1: String (0x00000001) 86 | 00000178 (01) 2: Object (0x00000002) 87 | 00000179 (01) 3: String (0x00000001) 88 | 0000017a (01) 4: String (0x00000001) 89 | 0000017b (01) 5: String (0x00000001) 90 | 0000017c (01) 6: SystemClass (0x00000003) 91 | 0000017d (49) AdditionalInfos: VArray 92 | 0000017d (49) 0: LengthPrefixedString: System.DelegateSerializationHolder+DelegateEntry 93 | 000001ae (53) 6: BinaryObjectString 94 | 000001ae (01) RecordTypeEnum: BinaryObjectString (0x00000006) 95 | 000001af (04) ObjectId: 0x00000005 (5) 96 | 000001b3 (48) Value: LengthPrefixedString: System.Runtime.Remoting.Messaging.HeaderHandler 97 | 000001e3 (81) 7: BinaryObjectString 98 | 000001e3 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 99 | 000001e4 (04) ObjectId: 0x00000006 (6) 100 | 000001e8 (76) Value: LengthPrefixedString: mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 101 | 00000234 (13) 8: BinaryObjectString 102 | 00000234 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 103 | 00000235 (04) ObjectId: 0x00000007 (7) 104 | 00000239 (08) Value: LengthPrefixedString: target0 105 | 00000241 (05) 9: MemberReference 106 | 00000241 (01) RecordTypeEnum: MemberReference (0x00000009) 107 | 00000242 (04) IdRef: 0x00000006 (6) 108 | 00000246 (21) 10: BinaryObjectString 109 | 00000246 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 110 | 00000247 (04) ObjectId: 0x00000009 (9) 111 | 0000024b (16) Value: LengthPrefixedString: System.Delegate 112 | 0000025b (19) 11: BinaryObjectString 113 | 0000025b (01) RecordTypeEnum: BinaryObjectString (0x00000006) 114 | 0000025c (04) ObjectId: 0x0000000a (10) 115 | 00000260 (14) Value: LengthPrefixedString: DynamicInvoke 116 | 0000026e (01) 12: ObjectNull 117 | 0000026e (01) RecordTypeEnum: ObjectNull (0x0000000a) 118 | 0000026f (170) 13: SystemClassWithMembersAndTypes 119 | 0000026f (01) RecordTypeEnum: SystemClassWithMembersAndTypes (0x00000004) 120 | 00000270 (68) ClassInfo: ClassInfo 121 | 00000270 (04) ObjectId: 0x00000003 (3) 122 | 00000274 (35) Name: LengthPrefixedString: System.DelegateSerializationHolder 123 | 00000297 (04) MemberCount: 0x00000003 (3) 124 | 0000029b (25) MemberNames: VArray 125 | 0000029b (09) 0: LengthPrefixedString: Delegate 126 | 000002a4 (08) 1: LengthPrefixedString: target0 127 | 000002ac (08) 2: LengthPrefixedString: method0 128 | 000002b4 (101) MemberTypeInfo: MemberTypeInfo 129 | 000002b4 (03) BinaryTypeEnums: VArray 130 | 000002b4 (01) 0: SystemClass (0x00000003) 131 | 000002b5 (01) 1: PrimitiveArray (0x00000007) 132 | 000002b6 (01) 2: SystemClass (0x00000003) 133 | 000002b7 (98) AdditionalInfos: VArray 134 | 000002b7 (49) 0: LengthPrefixedString: System.DelegateSerializationHolder+DelegateEntry 135 | 000002e8 (01) 1: Byte (0x00000002) 136 | 000002e9 (48) 2: LengthPrefixedString: System.Reflection.MemberInfoSerializationHolder 137 | 00000319 (05) 14: MemberReference 138 | 00000319 (01) RecordTypeEnum: MemberReference (0x00000009) 139 | 0000031a (04) IdRef: 0x0000000b (11) 140 | 0000031e (05) 15: MemberReference 141 | 0000031e (01) RecordTypeEnum: MemberReference (0x00000009) 142 | 0000031f (04) IdRef: 0x0000000c (12) 143 | 00000323 (05) 16: MemberReference 144 | 00000323 (01) RecordTypeEnum: MemberReference (0x00000009) 145 | 00000324 (04) IdRef: 0x0000000d (13) 146 | 00000328 (144) 17: SystemClassWithMembersAndTypes 147 | 00000328 (01) RecordTypeEnum: SystemClassWithMembersAndTypes (0x00000004) 148 | 00000329 (122) ClassInfo: ClassInfo 149 | 00000329 (04) ObjectId: 0x00000004 (4) 150 | 0000032d (48) Name: LengthPrefixedString: System.Reflection.MemberInfoSerializationHolder 151 | 0000035d (04) MemberCount: 0x00000006 (6) 152 | 00000361 (66) MemberNames: VArray 153 | 00000361 (05) 0: LengthPrefixedString: Name 154 | 00000366 (13) 1: LengthPrefixedString: AssemblyName 155 | 00000373 (10) 2: LengthPrefixedString: ClassName 156 | 0000037d (10) 3: LengthPrefixedString: Signature 157 | 00000387 (11) 4: LengthPrefixedString: MemberType 158 | 00000392 (17) 5: LengthPrefixedString: GenericArguments 159 | 000003a3 (21) MemberTypeInfo: MemberTypeInfo 160 | 000003a3 (06) BinaryTypeEnums: VArray 161 | 000003a3 (01) 0: String (0x00000001) 162 | 000003a4 (01) 1: String (0x00000001) 163 | 000003a5 (01) 2: String (0x00000001) 164 | 000003a6 (01) 3: String (0x00000001) 165 | 000003a7 (01) 4: Primitive (0x00000000) 166 | 000003a8 (01) 5: SystemClass (0x00000003) 167 | 000003a9 (15) AdditionalInfos: VArray 168 | 000003a9 (01) 0: Int32 (0x00000008) 169 | 000003aa (14) 1: LengthPrefixedString: System.Type[] 170 | 000003b8 (05) 18: MemberReference 171 | 000003b8 (01) RecordTypeEnum: MemberReference (0x00000009) 172 | 000003b9 (04) IdRef: 0x0000000a (10) 173 | 000003bd (05) 19: MemberReference 174 | 000003bd (01) RecordTypeEnum: MemberReference (0x00000009) 175 | 000003be (04) IdRef: 0x00000006 (6) 176 | 000003c2 (05) 20: MemberReference 177 | 000003c2 (01) RecordTypeEnum: MemberReference (0x00000009) 178 | 000003c3 (04) IdRef: 0x00000009 (9) 179 | 000003c7 (50) 21: BinaryObjectString 180 | 000003c7 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 181 | 000003c8 (04) ObjectId: 0x00000011 (17) 182 | 000003cc (45) Value: LengthPrefixedString: System.Object DynamicInvoke(System.Object[]) 183 | 000003f9 (04) 22: MemberPrimitiveTyped 184 | 000003f9 (01) RecordTypeEnum: MemberPrimitiveTyped (0x00000008) 185 | 000003fa (01) PrimitiveTypeEnum: 0 (0x00000000) 186 | 000003fb (02) Value: 0x00000000 (0) 187 | 000003fd (00) _eof: 188 | 000003fd (01) 23: ObjectNull 189 | 000003fd (01) RecordTypeEnum: ObjectNull (0x0000000a) 190 | 000003fe (09) 24: ClassWithId 191 | 000003fe (01) RecordTypeEnum: ClassWithId (0x00000001) 192 | 000003ff (04) ObjectId: 0x0000000b (11) 193 | 00000403 (04) MetadataId: 0x00000002 (2) 194 | 00000407 (38) 25: BinaryObjectString 195 | 00000407 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 196 | 00000408 (04) ObjectId: 0x00000012 (18) 197 | 0000040c (33) Value: LengthPrefixedString: System.Xml.Schema.XmlValueGetter 198 | 0000042d (83) 26: BinaryObjectString 199 | 0000042d (01) RecordTypeEnum: BinaryObjectString (0x00000006) 200 | 0000042e (04) ObjectId: 0x00000013 (19) 201 | 00000432 (78) Value: LengthPrefixedString: System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 202 | 00000480 (13) 27: BinaryObjectString 203 | 00000480 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 204 | 00000481 (04) ObjectId: 0x00000014 (20) 205 | 00000485 (08) Value: LengthPrefixedString: target0 206 | 0000048d (05) 28: MemberReference 207 | 0000048d (01) RecordTypeEnum: MemberReference (0x00000009) 208 | 0000048e (04) IdRef: 0x00000006 (6) 209 | 00000492 (32) 29: BinaryObjectString 210 | 00000492 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 211 | 00000493 (04) ObjectId: 0x00000016 (22) 212 | 00000497 (27) Value: LengthPrefixedString: System.Reflection.Assembly 213 | 000004b2 (10) 30: BinaryObjectString 214 | 000004b2 (01) RecordTypeEnum: BinaryObjectString (0x00000006) 215 | 000004b3 (04) ObjectId: 0x00000017 (23) 216 | 000004b7 (05) Value: LengthPrefixedString: Load 217 | 000004bc (01) 31: ObjectNull 218 | 000004bc (01) RecordTypeEnum: ObjectNull (0x0000000a) 219 | 000004bd (5130) 32: ArraySinglePrimitive 220 | 000004bd (01) RecordTypeEnum: ArraySinglePrimitive (0x0000000f) 221 | 000004be (08) ArrayInfo: ArrayInfo 222 | 000004be (04) ObjectId: 0x0000000c (12) 223 | 000004c2 (04) Length: 0x00001400 (5120) 224 | 000004c6 (01) PrimitiveTypeEnum: Byte (0x00000002) 225 | 000004c7 (5120) Value: 4d5a90000300000004000000ffff0000b80000000000000040... 226 | 000018c7 (00) _eof: 227 | 000018c7 (09) 33: ClassWithId 228 | 000018c7 (01) RecordTypeEnum: ClassWithId (0x00000001) 229 | 000018c8 (04) ObjectId: 0x0000000d (13) 230 | 000018cc (04) MetadataId: 0x00000004 (4) 231 | 000018d0 (05) 34: MemberReference 232 | 000018d0 (01) RecordTypeEnum: MemberReference (0x00000009) 233 | 000018d1 (04) IdRef: 0x00000017 (23) 234 | 000018d5 (05) 35: MemberReference 235 | 000018d5 (01) RecordTypeEnum: MemberReference (0x00000009) 236 | 000018d6 (04) IdRef: 0x00000006 (6) 237 | 000018da (05) 36: MemberReference 238 | 000018da (01) RecordTypeEnum: MemberReference (0x00000009) 239 | 000018db (04) IdRef: 0x00000016 (22) 240 | 000018df (45) 37: BinaryObjectString 241 | 000018df (01) RecordTypeEnum: BinaryObjectString (0x00000006) 242 | 000018e0 (04) ObjectId: 0x0000001a (26) 243 | 000018e4 (40) Value: LengthPrefixedString: System.Reflection.Assembly Load(Byte[]) 244 | 0000190c (04) 38: MemberPrimitiveTyped 245 | 0000190c (01) RecordTypeEnum: MemberPrimitiveTyped (0x00000008) 246 | 0000190d (01) PrimitiveTypeEnum: 0 (0x00000000) 247 | 0000190e (02) Value: 0x00000000 (0) 248 | 00001910 (00) _eof: 249 | 00001910 (01) 39: ObjectNull 250 | 00001910 (01) RecordTypeEnum: ObjectNull (0x0000000a) 251 | 00001911 (01) 40: MessageEnd 252 | 00001911 (01) RecordTypeEnum: MessageEnd (0x0000000b) 253 | ``` 254 | -------------------------------------------------------------------------------- /dnbinaryformat/__init__.py: -------------------------------------------------------------------------------- 1 | import hexdump 2 | import vstruct 3 | from vstruct.primitives import * 4 | 5 | 6 | 7 | 8 | 9 | 10 | RecordTypeEnumerator = v_enum() 11 | 12 | RecordTypeEnumerator.SerializedStreamHeader = 0 13 | RecordTypeEnumerator.ClassWithId = 1 14 | RecordTypeEnumerator.SystemClassWithMembers = 2 15 | RecordTypeEnumerator.ClassWithMembers = 3 16 | RecordTypeEnumerator.SystemClassWithMembersAndTypes = 4 17 | RecordTypeEnumerator.ClassWithMembersAndTypes = 5 18 | RecordTypeEnumerator.BinaryObjectString = 6 19 | RecordTypeEnumerator.BinaryArray = 7 20 | RecordTypeEnumerator.MemberPrimitiveTyped = 8 21 | RecordTypeEnumerator.MemberReference = 9 22 | RecordTypeEnumerator.ObjectNull = 10 23 | RecordTypeEnumerator.MessageEnd = 11 24 | RecordTypeEnumerator.BinaryLibrary = 12 25 | RecordTypeEnumerator.ObjectNullMultiple256 = 13 26 | RecordTypeEnumerator.ObjectNullMultiple = 14 27 | RecordTypeEnumerator.ArraySinglePrimitive = 15 28 | RecordTypeEnumerator.ArraySingleObject = 16 29 | RecordTypeEnumerator.ArraySingleString = 17 30 | RecordTypeEnumerator.MethodCall = 21 31 | RecordTypeEnumerator.MethodReturn = 22 32 | 33 | 34 | BinaryTypeEnumerator = v_enum() 35 | BinaryTypeEnumerator.Primitive = 0 36 | BinaryTypeEnumerator.String = 1 37 | BinaryTypeEnumerator.Object = 2 38 | BinaryTypeEnumerator.SystemClass = 3 39 | BinaryTypeEnumerator.Class = 4 40 | BinaryTypeEnumerator.ObjectArray = 5 41 | BinaryTypeEnumerator.StringArray = 6 42 | BinaryTypeEnumerator.PrimitiveArray = 7 43 | 44 | PrimitiveTypeEnumeration = v_enum() 45 | PrimitiveTypeEnumeration.Boolean = 1 46 | PrimitiveTypeEnumeration.Byte = 2 47 | PrimitiveTypeEnumeration.Char = 3 48 | PrimitiveTypeEnumeration.Unused = 4 49 | PrimitiveTypeEnumeration.Decimal = 5 50 | PrimitiveTypeEnumeration.Double = 6 51 | PrimitiveTypeEnumeration.Int16 = 7 52 | PrimitiveTypeEnumeration.Int32 = 8 53 | PrimitiveTypeEnumeration.Int64 = 9 54 | PrimitiveTypeEnumeration.SByte = 10 55 | PrimitiveTypeEnumeration.Single = 11 56 | PrimitiveTypeEnumeration.TimeSpan = 12 57 | PrimitiveTypeEnumeration.DateTime = 13 58 | PrimitiveTypeEnumeration.UInt16 = 14 59 | PrimitiveTypeEnumeration.UInt32 = 15 60 | PrimitiveTypeEnumeration.UInt64 = 16 61 | PrimitiveTypeEnumeration.Null = 17 62 | PrimitiveTypeEnumeration.String = 18 63 | 64 | MessageFlags = v_enum() 65 | MessageFlags.NoArgs = 0x00000001 66 | MessageFlags.ArgsInline = 0x00000002 67 | MessageFlags.ArgsIsArray = 0x00000004 68 | MessageFlags.ArgsInArray = 0x00000008 69 | MessageFlags.NoContext = 0x00000010 70 | MessageFlags.ContextInline = 0x00000020 71 | MessageFlags.ContextInArray = 0x00000040 72 | MessageFlags.MethodSignatureInArray = 0x00000080 73 | MessageFlags.PropertiesInArray = 0x00000100 74 | MessageFlags.NoReturnValue = 0x00000200 75 | MessageFlags.ReturnValueVoid = 0x00000400 76 | MessageFlags.ReturnValueInline = 0x00000800 77 | MessageFlags.ReturnValueInArray = 0x00001000 78 | MessageFlags.ExceptionInArray = 0x00002000 79 | MessageFlags.GenericMethod = 0x00008000 80 | 81 | 82 | class LengthPrefixedString(vstruct.VStruct): 83 | def __init__(self): 84 | vstruct.VStruct.__init__(self) 85 | self.Length = 0 86 | self.Value = '' 87 | 88 | def vsParse(self, bytez, offset=0, fast=False): 89 | length = bytez[offset + 0] & 0b01111111 90 | if bytez[offset + 0] & 0b10000000: 91 | # TODO: need an example of this to test against 92 | # don't want to code blind. 93 | raise NotImplementedError() 94 | 95 | value = bytez[offset + 1:offset + 1 + length].decode('utf-8') 96 | 97 | self.Length = length 98 | self.Value = value 99 | return offset + length + 1 100 | 101 | def __repr__(self): 102 | return 'LengthPrefixedString: %s' % (self.Value) 103 | 104 | def __len__(self): 105 | return self.Length + 1 106 | 107 | 108 | class ClassTypeInfo(vstruct.VStruct): 109 | def __init__(self): 110 | vstruct.VStruct.__init__(self) 111 | self.TypeName = LengthPrefixedString() 112 | self.LibraryId = v_int32() 113 | 114 | 115 | class SerializationHeaderRecord(vstruct.VStruct): 116 | def __init__(self): 117 | vstruct.VStruct.__init__(self) 118 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 119 | self.RootId = v_int32() 120 | self.HeaderId = v_int32() 121 | self.MajorVersion = v_int32() 122 | self.MinorVersion = v_int32() 123 | 124 | 125 | class ValueWithCode(vstruct.VStruct): 126 | def __init__(self): 127 | vstruct.VStruct.__init__(self) 128 | raise NotImplementedError() 129 | 130 | 131 | class StringWithCode(vstruct.VStruct): 132 | def __init__(self): 133 | vstruct.VStruct.__init__(self) 134 | self.PrimitiveTypeEnum = v_uint8(enum=PrimitiveTypeEnumeration) 135 | self.StringValue = LengthPrefixedString() 136 | 137 | def pcb_PrimitiveTypeEnum(self): 138 | assert self.PrimitiveTypeEnum == PrimitiveTypeEnumeration.String 139 | 140 | 141 | class ArrayOfValueWithCode(vstruct.VStruct): 142 | def __init__(self): 143 | vstruct.VStruct.__init__(self) 144 | self.Length = v_int32() 145 | self.ListOfValueWithCode = vstruct.VArray() 146 | 147 | def pcb_Length(self): 148 | for i in range(self.Length): 149 | self.ListOfValueWithCode.vsAddElement(ValueWithCode()) 150 | 151 | 152 | class BinaryMethodCall(vstruct.VStruct): 153 | def __init__(self): 154 | vstruct.VStruct.__init__(self) 155 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumeration) 156 | self.MessageEnum = v_uint32() # bitmask=MessageFlags 157 | self.MethodName = StringValueWithCode() 158 | self.TypeName = StringValueWithCode() 159 | raise NotImplementedError() 160 | # if self.MessageEnum & ContextInline 161 | self.CallContext = None # StringValueWithCode 162 | # if self.MessageEnum & ArgsInline 163 | self.Args = None # ArrayOfValueWithCode() 164 | 165 | 166 | def pcb_RecordTypeEnum(self): 167 | assert self.RecordTypeEnum == RecordTypeEnumeration.MethodCall 168 | 169 | 170 | 171 | # ... 172 | 173 | 174 | class ClassInfo(vstruct.VStruct): 175 | def __init__(self): 176 | vstruct.VStruct.__init__(self) 177 | self.ObjectId = v_int32() 178 | self.Name = LengthPrefixedString() 179 | self.MemberCount = v_int32() 180 | self.MemberNames = vstruct.VArray() 181 | 182 | def pcb_MemberCount(self): 183 | for i in range(self.MemberCount): 184 | self.MemberNames.vsAddElement(LengthPrefixedString()) 185 | 186 | 187 | class MemberTypeInfo(vstruct.VStruct): 188 | def __init__(self, member_count=0): 189 | vstruct.VStruct.__init__(self) 190 | self.member_count = member_count 191 | # not precisely correct: should be v_int8, but this has no `enum` kwarg at the moment 192 | self.BinaryTypeEnums = vstruct.VArray([v_uint8(enum=BinaryTypeEnumerator)] * member_count) 193 | self.AdditionalInfos = vstruct.VArray() 194 | 195 | def set_member_count(self, member_count): 196 | if self.member_count != 0: 197 | raise ValueError('cannot set member count after it is initialized') 198 | 199 | for i in range(member_count): 200 | self.BinaryTypeEnums.vsAddElement(v_uint8(enum=BinaryTypeEnumerator)) 201 | 202 | def pcb_BinaryTypeEnums(self): 203 | for (_, entry) in self.BinaryTypeEnums: 204 | if int(entry) == BinaryTypeEnumerator.Primitive: 205 | self.AdditionalInfos.vsAddElement(v_uint8(enum=PrimitiveTypeEnumeration)) 206 | elif int(entry) == BinaryTypeEnumerator.SystemClass: 207 | self.AdditionalInfos.vsAddElement(LengthPrefixedString()) 208 | elif int(entry) == BinaryTypeEnumerator.Class: 209 | self.AdditionalInfos.vsAddElement(ClassTypeInfo()) 210 | elif int(entry) == BinaryTypeEnumerator.PrimitiveArray: 211 | self.AdditionalInfos.vsAddElement(v_uint8(enum=PrimitiveTypeEnumeration)) 212 | else: 213 | continue 214 | 215 | 216 | class SystemClassWithMembersAndTypes(vstruct.VStruct): 217 | def __init__(self): 218 | vstruct.VStruct.__init__(self) 219 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 220 | self.ClassInfo = ClassInfo() 221 | self.MemberTypeInfo = MemberTypeInfo(member_count=0) 222 | 223 | def pcb_RecordTypeEnum(self): 224 | assert self.RecordTypeEnum == RecordTypeEnumerator.SystemClassWithMembersAndTypes 225 | 226 | def pcb_ClassInfo(self): 227 | self.MemberTypeInfo.set_member_count(self.ClassInfo.MemberCount) 228 | 229 | 230 | class MemberReference(vstruct.VStruct): 231 | def __init__(self): 232 | vstruct.VStruct.__init__(self) 233 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 234 | self.IdRef = v_int32() 235 | 236 | def pcb_RecordTypeEnum(self): 237 | assert self.RecordTypeEnum == RecordTypeEnumerator.MemberReference 238 | 239 | 240 | class BinaryObjectString(vstruct.VStruct): 241 | def __init__(self): 242 | vstruct.VStruct.__init__(self) 243 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 244 | self.ObjectId = v_int32() 245 | self.Value = LengthPrefixedString() 246 | 247 | def pcb_RecordTypeEnum(self): 248 | assert self.RecordTypeEnum == RecordTypeEnumerator.BinaryObjectString 249 | 250 | 251 | class ObjectNull(vstruct.VStruct): 252 | def __init__(self): 253 | vstruct.VStruct.__init__(self) 254 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 255 | 256 | def pcb_RecordTypeEnum(self): 257 | assert self.RecordTypeEnum == RecordTypeEnumerator.ObjectNull 258 | 259 | 260 | class MemberPrimitiveTyped(vstruct.VStruct): 261 | def __init__(self): 262 | vstruct.VStruct.__init__(self) 263 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 264 | self.PrimitiveTypeEnum = v_uint8(enum=PrimitiveTypeEnumeration) 265 | # self.Value = * 266 | self._eof = v_bytes() 267 | 268 | def pcb_RecordTypeEnum(self): 269 | assert self.RecordTypeEnum == RecordTypeEnumerator.MemberPrimitiveTyped 270 | 271 | def pcb_PrimitiveTypeEnum(self): 272 | if int(self.PrimitiveTypeEnum) == 0x0: 273 | # enum instance is not documented. seems to be | 00 00 | in practice? 274 | self.vsInsertField('Value', v_uint16(), '_eof') 275 | else: 276 | # trivial to implement, once we see sample data. 277 | raise NotImplementedError() 278 | 279 | 280 | class ClassWithId(vstruct.VStruct): 281 | def __init__(self): 282 | vstruct.VStruct.__init__(self) 283 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 284 | self.ObjectId = v_int32() 285 | self.MetadataId = v_int32() 286 | 287 | def pcb_RecordTypeEnum(self): 288 | assert self.RecordTypeEnum == RecordTypeEnumerator.ClassWithId 289 | 290 | 291 | class ArrayInfo(vstruct.VStruct): 292 | def __init__(self): 293 | vstruct.VStruct.__init__(self) 294 | self.ObjectId = v_int32() 295 | self.Length = v_int32() 296 | 297 | 298 | class ArraySinglePrimitive(vstruct.VStruct): 299 | def __init__(self): 300 | vstruct.VStruct.__init__(self) 301 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 302 | self.ArrayInfo = ArrayInfo() 303 | self.PrimitiveTypeEnum = v_uint8(enum=PrimitiveTypeEnumeration) 304 | # self.Value = * 305 | self._eof = v_bytes() 306 | 307 | def pcb_RecordTypeEnum(self): 308 | assert self.RecordTypeEnum == RecordTypeEnumerator.ArraySinglePrimitive 309 | 310 | def pcb_PrimitiveTypeEnum(self): 311 | if self.PrimitiveTypeEnum == PrimitiveTypeEnumeration.Byte: 312 | self.vsInsertField('Value', v_bytes(size=self.ArrayInfo.Length), '_eof') 313 | else: 314 | # trivial to implement, once we see sample data 315 | raise NotImplementedError() 316 | 317 | 318 | class MessageEnd(vstruct.VStruct): 319 | def __init__(self): 320 | vstruct.VStruct.__init__(self) 321 | self.RecordTypeEnum = v_uint8(enum=RecordTypeEnumerator) 322 | 323 | def pcb_RecordTypeEnum(self): 324 | assert self.RecordTypeEnum == RecordTypeEnumerator.MessageEnd 325 | 326 | 327 | class SerializedData(vstruct.VArray): 328 | def __init__(self): 329 | vstruct.VArray.__init__(self) 330 | self.count = 0 331 | 332 | def vsParse(self, bytez, offset=0, fast=False): 333 | while len(bytez) > offset: 334 | record_type = bytez[offset] 335 | 336 | if record_type == RecordTypeEnumerator.SerializedStreamHeader: 337 | record = SerializationHeaderRecord() 338 | elif record_type == RecordTypeEnumerator.SystemClassWithMembersAndTypes: 339 | record = SystemClassWithMembersAndTypes() 340 | elif record_type == RecordTypeEnumerator.ClassWithId: 341 | record = ClassWithId() 342 | elif record_type == RecordTypeEnumerator.MemberReference: 343 | record = MemberReference() 344 | elif record_type == RecordTypeEnumerator.BinaryObjectString: 345 | record = BinaryObjectString() 346 | elif record_type == RecordTypeEnumerator.ObjectNull: 347 | record = ObjectNull() 348 | elif record_type == RecordTypeEnumerator.MemberPrimitiveTyped: 349 | record = MemberPrimitiveTyped() 350 | elif record_type == RecordTypeEnumerator.ArraySinglePrimitive: 351 | record = ArraySinglePrimitive() 352 | elif record_type == RecordTypeEnumerator.MessageEnd: 353 | record = MessageEnd() 354 | else: 355 | # these other options are documented, just not implemented here yet 356 | raise NotImplementedError() 357 | 358 | record.vsParse(bytez, offset) 359 | self.vsAddElement(record) 360 | offset += len(record) 361 | self.count += 1 362 | 363 | if record_type == RecordTypeEnumerator.MessageEnd: 364 | break 365 | 366 | return offset 367 | 368 | 369 | def deserialize(buf): 370 | d = SerializedData() 371 | d.vsParse(buf) 372 | return d 373 | -------------------------------------------------------------------------------- /scripts/extract_pe.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ''' 3 | Extract byte arrays starting with an MZ header from .NET BinaryFormatter'd data. 4 | 5 | author: Willi Ballenthin 6 | email: william.ballenthin@fireeye.com 7 | ''' 8 | import sys 9 | import hashlib 10 | import logging 11 | 12 | import argparse 13 | 14 | import dnbinaryformat 15 | 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | def main(argv=None): 21 | if argv is None: 22 | argv = sys.argv[1:] 23 | 24 | parser = argparse.ArgumentParser(description="Extract byte arrays starting with an MZ header from .NET BinaryFormatter'd data.") 25 | parser.add_argument("input", type=str, 26 | help="Path to input file") 27 | parser.add_argument("-v", "--verbose", action="store_true", 28 | help="Enable debug logging") 29 | parser.add_argument("-q", "--quiet", action="store_true", 30 | help="Disable all output but errors") 31 | args = parser.parse_args(args=argv) 32 | 33 | if args.verbose: 34 | logging.basicConfig(level=logging.DEBUG) 35 | logging.getLogger().setLevel(logging.DEBUG) 36 | elif args.quiet: 37 | logging.basicConfig(level=logging.ERROR) 38 | logging.getLogger().setLevel(logging.ERROR) 39 | else: 40 | logging.basicConfig(level=logging.INFO) 41 | logging.getLogger().setLevel(logging.INFO) 42 | 43 | 44 | with open(args.input, 'rb') as f: 45 | buf = f.read() 46 | 47 | records = dnbinaryformat.deserialize(buf) 48 | for i, (_, record) in enumerate(records): 49 | if int(record.RecordTypeEnum) != dnbinaryformat.RecordTypeEnumerator.ArraySinglePrimitive: 50 | continue 51 | logger.info('record %d: found array', i) 52 | 53 | if record.PrimitiveTypeEnum != dnbinaryformat.PrimitiveTypeEnumeration.Byte: 54 | continue 55 | logger.info('record %d: found byte array', i) 56 | 57 | buf = bytes(record.Value) 58 | if not buf.startswith(b'MZ'): 59 | continue 60 | logger.info('record %d: found PE byte array', i) 61 | 62 | m = hashlib.md5() 63 | m.update(buf) 64 | filename = m.hexdigest() + '.bin' 65 | 66 | logger.info('writing PE to %s', filename) 67 | with open(filename, 'wb') as f: 68 | f.write(buf) 69 | 70 | return 0 71 | 72 | 73 | if __name__ == "__main__": 74 | sys.exit(main()) 75 | -------------------------------------------------------------------------------- /scripts/show_structure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ''' 3 | Extract byte arrays starting with an MZ header from .NET BinaryFormatter'd data. 4 | 5 | author: Willi Ballenthin 6 | email: william.ballenthin@fireeye.com 7 | ''' 8 | import sys 9 | import hashlib 10 | import logging 11 | 12 | import argparse 13 | 14 | import dnbinaryformat 15 | 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | def main(argv=None): 21 | if argv is None: 22 | argv = sys.argv[1:] 23 | 24 | parser = argparse.ArgumentParser(description="Extract byte arrays starting with an MZ header from .NET BinaryFormatter'd data.") 25 | parser.add_argument("input", type=str, 26 | help="Path to input file") 27 | parser.add_argument("-v", "--verbose", action="store_true", 28 | help="Enable debug logging") 29 | parser.add_argument("-q", "--quiet", action="store_true", 30 | help="Disable all output but errors") 31 | args = parser.parse_args(args=argv) 32 | 33 | if args.verbose: 34 | logging.basicConfig(level=logging.DEBUG) 35 | logging.getLogger().setLevel(logging.DEBUG) 36 | elif args.quiet: 37 | logging.basicConfig(level=logging.ERROR) 38 | logging.getLogger().setLevel(logging.ERROR) 39 | else: 40 | logging.basicConfig(level=logging.INFO) 41 | logging.getLogger().setLevel(logging.INFO) 42 | 43 | 44 | with open(args.input, 'rb') as f: 45 | buf = f.read() 46 | 47 | print(dnbinaryformat.deserialize(buf).tree()) 48 | 49 | return 0 50 | 51 | 52 | if __name__ == "__main__": 53 | sys.exit(main()) 54 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import setuptools 4 | 5 | 6 | description = "Pure Python parser for .NET BinaryFormatter serialized data." 7 | setuptools.setup(name="python-dotnet-binaryformat", 8 | version="0.1", 9 | description=description, 10 | long_description=description, 11 | author="Willi Ballenthin", 12 | author_email="william.ballenthin@fireeye.com", 13 | url="https://github.com/williballenthin/python-dotnet-binaryformat", 14 | license="Apache 2.0 License", 15 | install_requires=[ 16 | "pytest", 17 | "hexdump", 18 | "vivisect-vstruct-wb", 19 | ], 20 | packages=setuptools.find_packages()) 21 | -------------------------------------------------------------------------------- /tests/data/dntojscript.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williballenthin/python-dotnet-binaryformat/34eb3956ce10a1165dc6334257de2c4ac3f22d86/tests/data/dntojscript.bin -------------------------------------------------------------------------------- /tests/fixtures.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def dntojscript(): 8 | # via: https://gist.github.com/caseysmithrc/b752447067b6f099f08baefe00978fad 9 | cd = os.path.dirname(os.path.abspath(__file__)) 10 | with open(os.path.join(cd, 'data', 'dntojscript.bin'), 'rb') as f: 11 | return f.read() 12 | -------------------------------------------------------------------------------- /tests/test_binary_format.py: -------------------------------------------------------------------------------- 1 | import dnbinaryformat 2 | 3 | from fixtures import * 4 | 5 | 6 | def test_subtee_dntojscript(dntojscript): 7 | record_types = [] 8 | for (_, record) in dnbinaryformat.deserialize(dntojscript): 9 | record_types.append(type(record)) 10 | 11 | assert record_types == [ 12 | dnbinaryformat.SerializationHeaderRecord, 13 | dnbinaryformat.SystemClassWithMembersAndTypes, 14 | dnbinaryformat.MemberReference, 15 | dnbinaryformat.MemberReference, 16 | dnbinaryformat.MemberReference, 17 | dnbinaryformat.SystemClassWithMembersAndTypes, 18 | dnbinaryformat.BinaryObjectString, 19 | dnbinaryformat.BinaryObjectString, 20 | dnbinaryformat.BinaryObjectString, 21 | dnbinaryformat.MemberReference, 22 | dnbinaryformat.BinaryObjectString, 23 | dnbinaryformat.BinaryObjectString, 24 | dnbinaryformat.ObjectNull, 25 | dnbinaryformat.SystemClassWithMembersAndTypes, 26 | dnbinaryformat.MemberReference, 27 | dnbinaryformat.MemberReference, 28 | dnbinaryformat.MemberReference, 29 | dnbinaryformat.SystemClassWithMembersAndTypes, 30 | dnbinaryformat.MemberReference, 31 | dnbinaryformat.MemberReference, 32 | dnbinaryformat.MemberReference, 33 | dnbinaryformat.BinaryObjectString, 34 | dnbinaryformat.MemberPrimitiveTyped, 35 | dnbinaryformat.ObjectNull, 36 | dnbinaryformat.ClassWithId, 37 | dnbinaryformat.BinaryObjectString, 38 | dnbinaryformat.BinaryObjectString, 39 | dnbinaryformat.BinaryObjectString, 40 | dnbinaryformat.MemberReference, 41 | dnbinaryformat.BinaryObjectString, 42 | dnbinaryformat.BinaryObjectString, 43 | dnbinaryformat.ObjectNull, 44 | dnbinaryformat.ArraySinglePrimitive, 45 | dnbinaryformat.ClassWithId, 46 | dnbinaryformat.MemberReference, 47 | dnbinaryformat.MemberReference, 48 | dnbinaryformat.MemberReference, 49 | dnbinaryformat.BinaryObjectString, 50 | dnbinaryformat.MemberPrimitiveTyped, 51 | dnbinaryformat.ObjectNull, 52 | dnbinaryformat.MessageEnd, 53 | ] 54 | --------------------------------------------------------------------------------