smda 2.2.2__tar.gz → 2.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {smda-2.2.2/smda.egg-info → smda-2.3.1}/PKG-INFO +57 -41
- {smda-2.2.2 → smda-2.3.1}/README.md +56 -40
- smda-2.3.1/pyproject.toml +78 -0
- {smda-2.2.2 → smda-2.3.1}/setup.py +11 -18
- {smda-2.2.2 → smda-2.3.1}/smda/Disassembler.py +27 -20
- {smda-2.2.2 → smda-2.3.1}/smda/DisassemblyResult.py +36 -37
- {smda-2.2.2 → smda-2.3.1}/smda/DisassemblyStatistics.py +2 -5
- {smda-2.2.2 → smda-2.3.1}/smda/SmdaConfig.py +3 -4
- {smda-2.2.2 → smda-2.3.1}/smda/cil/CilDisassembler.py +57 -33
- smda-2.3.1/smda/cil/CilInstructionEscaper.py +473 -0
- {smda-2.2.2 → smda-2.3.1}/smda/cil/FunctionAnalysisState.py +32 -23
- smda-2.3.1/smda/common/BasicBlock.py +14 -0
- {smda-2.2.2 → smda-2.3.1}/smda/common/BinaryInfo.py +18 -7
- {smda-2.2.2 → smda-2.3.1}/smda/common/BlockLocator.py +15 -15
- {smda-2.2.2 → smda-2.3.1}/smda/common/CodeXref.py +3 -6
- {smda-2.2.2 → smda-2.3.1}/smda/common/DominatorTree.py +41 -17
- {smda-2.2.2 → smda-2.3.1}/smda/common/SmdaBasicBlock.py +26 -15
- {smda-2.2.2 → smda-2.3.1}/smda/common/SmdaFunction.py +46 -37
- {smda-2.2.2 → smda-2.3.1}/smda/common/SmdaInstruction.py +22 -10
- {smda-2.2.2 → smda-2.3.1}/smda/common/SmdaReport.py +47 -50
- {smda-2.2.2 → smda-2.3.1}/smda/common/TailcallAnalyzer.py +42 -28
- {smda-2.2.2 → smda-2.3.1}/smda/common/Tarjan.py +12 -11
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/AbstractLabelProvider.py +3 -4
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/CilSymbolProvider.py +4 -5
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/DelphiKbSymbolProvider.py +23 -22
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/ElfApiResolver.py +4 -5
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/ElfSymbolProvider.py +15 -20
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/GoLabelProvider.py +51 -37
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/OrdinalHelper.py +2 -2
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/PdbSymbolProvider.py +13 -6
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/PeSymbolProvider.py +25 -25
- {smda-2.2.2 → smda-2.3.1}/smda/common/labelprovider/WinApiResolver.py +29 -15
- smda-2.3.1/smda/common/labelprovider/__init__.py +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda/ida/BackendInterface.py +1 -2
- {smda-2.2.2 → smda-2.3.1}/smda/ida/IdaExporter.py +19 -9
- {smda-2.2.2 → smda-2.3.1}/smda/ida/IdaInterface.py +27 -39
- smda-2.3.1/smda/ida/__init__.py +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda/intel/BitnessAnalyzer.py +6 -7
- {smda-2.2.2 → smda-2.3.1}/smda/intel/FunctionAnalysisState.py +46 -29
- {smda-2.2.2 → smda-2.3.1}/smda/intel/FunctionCandidate.py +35 -22
- {smda-2.2.2 → smda-2.3.1}/smda/intel/FunctionCandidateManager.py +151 -70
- {smda-2.2.2 → smda-2.3.1}/smda/intel/IndirectCallAnalyzer.py +119 -38
- {smda-2.2.2 → smda-2.3.1}/smda/intel/IntelDisassembler.py +150 -52
- smda-2.3.1/smda/intel/IntelInstructionEscaper.py +2354 -0
- {smda-2.2.2 → smda-2.3.1}/smda/intel/JumpTableAnalyzer.py +59 -43
- {smda-2.2.2 → smda-2.3.1}/smda/intel/LanguageAnalyzer.py +68 -50
- {smda-2.2.2 → smda-2.3.1}/smda/intel/MnemonicTfIdf.py +417 -6
- smda-2.3.1/smda/intel/__init__.py +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda/intel/definitions.py +70 -35
- {smda-2.2.2 → smda-2.3.1}/smda/utility/BracketQueue.py +10 -8
- {smda-2.2.2 → smda-2.3.1}/smda/utility/DelphiKbFileLoader.py +1 -2
- {smda-2.2.2 → smda-2.3.1}/smda/utility/ElfFileLoader.py +55 -29
- {smda-2.2.2 → smda-2.3.1}/smda/utility/FileLoader.py +4 -3
- {smda-2.2.2 → smda-2.3.1}/smda/utility/MachoFileLoader.py +41 -17
- {smda-2.2.2 → smda-2.3.1}/smda/utility/MemoryFileLoader.py +0 -1
- {smda-2.2.2 → smda-2.3.1}/smda/utility/PeFileLoader.py +49 -33
- {smda-2.2.2 → smda-2.3.1}/smda/utility/PriorityQueue.py +3 -2
- {smda-2.2.2 → smda-2.3.1}/smda/utility/StringExtractor.py +21 -10
- smda-2.3.1/smda/utility/__init__.py +0 -0
- {smda-2.2.2 → smda-2.3.1/smda.egg-info}/PKG-INFO +57 -41
- {smda-2.2.2 → smda-2.3.1}/smda.egg-info/SOURCES.txt +1 -0
- {smda-2.2.2 → smda-2.3.1}/tests/testBracketQueue.py +34 -36
- smda-2.3.1/tests/testEscaper.py +248 -0
- {smda-2.2.2 → smda-2.3.1}/tests/testFileFormatParsers.py +12 -13
- {smda-2.2.2 → smda-2.3.1}/tests/testIntegration.py +33 -27
- {smda-2.2.2 → smda-2.3.1}/tests/testTarjan.py +1 -4
- smda-2.2.2/smda/__init__.py +0 -1
- smda-2.2.2/smda/cil/CilInstructionEscaper.py +0 -259
- smda-2.2.2/smda/common/BasicBlock.py +0 -12
- smda-2.2.2/smda/common/__init__.py +0 -1
- smda-2.2.2/smda/intel/IntelInstructionEscaper.py +0 -580
- smda-2.2.2/smda/intel/__init__.py +0 -1
- smda-2.2.2/smda/utility/__init__.py +0 -1
- smda-2.2.2/tests/testEscaper.py +0 -86
- {smda-2.2.2 → smda-2.3.1}/LICENSE +0 -0
- {smda-2.2.2 → smda-2.3.1}/setup.cfg +0 -0
- {smda-2.2.2/smda/cil → smda-2.3.1/smda}/__init__.py +0 -0
- {smda-2.2.2/smda/common/labelprovider → smda-2.3.1/smda/cil}/__init__.py +0 -0
- {smda-2.2.2/smda/ida → smda-2.3.1/smda/common}/__init__.py +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda.egg-info/dependency_links.txt +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda.egg-info/requires.txt +0 -0
- {smda-2.2.2 → smda-2.3.1}/smda.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: smda
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: A recursive disassmbler optimized for CFG recovery from memory dumps. Based on capstone.
|
|
5
5
|
Home-page: https://github.com/danielplohmann/smda
|
|
6
6
|
Author: Daniel Plohmann
|
|
@@ -27,7 +27,7 @@ Optionally, references to the Windows API can be inferred by using the ApiScout
|
|
|
27
27
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
|
-
With version 1.2.0, we have finally simplified things by moving to [PyPI](https://pypi.org/project/smda/)!
|
|
30
|
+
With version 1.2.0, we have finally simplified things by moving to [PyPI](https://pypi.org/project/smda/)!
|
|
31
31
|
So installation now is as easy as:
|
|
32
32
|
|
|
33
33
|
```
|
|
@@ -56,11 +56,11 @@ A typical workflow using SMDA could like this:
|
|
|
56
56
|
0x0000172e: ( 7402) - je 0x1732
|
|
57
57
|
0x00001730: ( ffd0) - call rax
|
|
58
58
|
0x00001732: ( 4883c408) - add rsp, 8
|
|
59
|
-
0x00001736: ( c3) - ret
|
|
59
|
+
0x00001736: ( c3) - ret
|
|
60
60
|
0x00001ad0: (-> 1, 4->) 1 blocks, 12 instructions.
|
|
61
61
|
[...]
|
|
62
62
|
>>> json_report = report.toDict()
|
|
63
|
-
```
|
|
63
|
+
```
|
|
64
64
|
|
|
65
65
|
There is also a demo script:
|
|
66
66
|
|
|
@@ -70,50 +70,65 @@ The code should be fully compatible with Python 3.8+.
|
|
|
70
70
|
Further explanation on the innerworkings follow in separate publications but will be referenced here.
|
|
71
71
|
|
|
72
72
|
To take full advantage of SMDA's capabilities, make sure to (optionally) install:
|
|
73
|
-
* lief
|
|
73
|
+
* lief
|
|
74
74
|
* pdbparse (currently as fork from https://github.com/VPaulV/pdbparse to support Python3)
|
|
75
75
|
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
### Code Quality
|
|
79
|
+
|
|
80
|
+
This project uses [Ruff](https://docs.astral.sh/ruff/) for linting and code formatting. To set up the development environment:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Install development dependencies
|
|
84
|
+
pip install -r requirements.txt
|
|
85
|
+
|
|
86
|
+
# Install pre-commit hooks (optional but recommended)
|
|
87
|
+
make init
|
|
88
|
+
|
|
89
|
+
# Run linting
|
|
90
|
+
make lint
|
|
91
|
+
# or
|
|
92
|
+
ruff check .
|
|
93
|
+
|
|
94
|
+
# Run formatting
|
|
95
|
+
make format
|
|
96
|
+
# or
|
|
97
|
+
ruff format .
|
|
98
|
+
|
|
99
|
+
# Fix auto-fixable issues
|
|
100
|
+
make ruff-fix
|
|
101
|
+
# or
|
|
102
|
+
ruff check . --fix
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Pre-commit Hooks
|
|
106
|
+
|
|
107
|
+
Pre-commit hooks are configured to run ruff automatically on commit. Install them with:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pre-commit install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Testing
|
|
114
|
+
|
|
115
|
+
Run tests with:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
make test
|
|
119
|
+
```
|
|
120
|
+
|
|
76
121
|
## Version History
|
|
77
|
-
* 2025-
|
|
122
|
+
* 2025-10-21: v2.3.1 - Fixed lief error for section/segment flags in ELF files crashing file loading. Now properly parsing and providing symbol info for PEs in their own xmetadata section.
|
|
123
|
+
* 2025-10-21: v2.3.0 - Major code refactor and cleanup, with many thanks to the contribution @r0ny123!!
|
|
124
|
+
* 2025-07-25: v2.2.3 - Minor bugfixes.
|
|
78
125
|
* 2025-07-23: v2.2.1 - Added xmetadata field to SmdaReport, with information about imports and exports. Improved string extraction from Go binaries.
|
|
79
126
|
* 2025-06-13: v2.1.0 - Support for export from IDA 9.0+ (THX to @jershmagersh for the update!).
|
|
80
127
|
* 2025-02-26: v2.0.2 - Adjusting relative import, adding init file.
|
|
81
128
|
* 2025-02-25: v2.0.0 - Initial experimental support for CIL (.NET) disassembly.
|
|
82
|
-
* 2025-02-24: v1.14.3 - PicHashing can now be disabled via SmdaConfig to save some processing time. (THX to @Nalexander-hanel!)
|
|
83
|
-
* 2025-02-24: v1.14.2 - We are Python 3.8+ compatible again (changed UTC usage) and (DWARF) PE symbols for PE files should be extracted again (THX to @N0fix for the update!)
|
|
84
|
-
* 2025-02-21: v1.14.1 - Fixed changed field names in LIEF usage that broke ELF parsing, added tests for ELF+macOS parsing (THX to @N0fix for the update!)
|
|
85
129
|
* 2025-01-29: v1.14.0 - Bump to LIEF 0.16.0+ (THX to @huettenhain for the ping!). Migrated tests to `pytest`, UTC datetime handling fixes.
|
|
86
|
-
* 2025-01-26: v1.13.24 - Added functionality to import and export SMDA reports as JSON. Fixed byte patterns matching special regex chars (THX to @alexander-hanel!).
|
|
87
|
-
* 2024-07-26: v1.13.23 - Now using OEP as symbol function candidate when available (THX to @alexander-hanel for reporting!).
|
|
88
|
-
* 2024-05-10: v1.13.22 - Handled odd case where disassembly with capstone and IDA would return different results (THX to @r0ny123 for reporting!).
|
|
89
|
-
* 2024-04-17: v1.13.21 - Fixed handling of Go binaries for version 1.20+ (THX to @Manny684!).
|
|
90
|
-
* 2024-04-08: v1.13.20 - Fixed handling of bnd prefix in CFG instructions to help with parsing PLT (THX to @Manny684!).
|
|
91
|
-
* 2024-04-02: v1.13.19 - Fixed bug in string parsing, added tests, strings now no longer are hex-encoded as they are always printable anyway.
|
|
92
|
-
* 2024-03-12: v1.13.18 - Added functionality to extract and store all referenced strings along SmdaFunctions (has to be enabled via SmdaConfig).
|
|
93
|
-
* 2024-03-12: v1.13.17 - Extended disassembleBuffer() to now take additional arguments `code_areas` and `oep`.
|
|
94
|
-
* 2024-02-21: v1.13.16 - BREAKING IntelInstructionEscaper.escapeMnemonic: Escaper now handles another 200 instruction names found in other capstone source files (THX for reporting @malwarefrank!).
|
|
95
|
-
* 2024-02-15: v1.13.15 - Fixed issues with version recognition in SmdaFunction which cause issues in MCRIT (THX to @
|
|
96
|
-
malwarefrank!)
|
|
97
|
-
* 2024-02-02: v1.13.12 - Versions might be non-numerical, addressed that in SmdaFunction.
|
|
98
|
-
* 2024-01-23: v1.13.11 - Introduced indicator in SmdaConfig for compatibility of instruction escaping.
|
|
99
|
-
* 2024-01-23: v1.13.10 - Parsing of PE files should work again with lief >=0.14.0.
|
|
100
|
-
* 2024-01-23: v1.13.9 - Improved parsing robustness for section/segment tables in ELF files, also now padding with zeroes when finding less content than expected physical size in a segment (THX for reporting @schrodyn!).
|
|
101
|
-
* 2024-01-23: v1.13.8 - BREAKING adjustments to IntelInstructionEscaper.escapeMnemonic: Escaper now is capable of handling all known x86/x64 instructions in capstone (THX for reporting @schrodyn!).
|
|
102
|
-
* 2023-12-01: v1.13.7 - Skip processing of Delphi structs for large files, workaround until this is properly reimplemented.
|
|
103
|
-
* 2023-11-29: v1.13.6 - Made OpcodeHash an attribute with on-demand calculation to save processing time.
|
|
104
|
-
* 2023-11-29: v1.13.3 - Implemented an alternative queue working with reference count based brackets in pursuit of accelerated processing.
|
|
105
|
-
* 2023-11-28: v1.13.2 - IndirectCallAnalyzer will now analyze at most a configurable amount of calls per basic block, default 50.
|
|
106
|
-
* 2023-11-21: v1.13.1 - SmdaBasicBlock now has `getPredecessors()` and `getSuccessors()`.
|
|
107
130
|
* 2023-11-21: v1.13.0 - BREAKING adjustments to PicHashing (now wildcarding intraprocedural jumps in functions, additionally more immediates if within address space). Introduction of OpcodeHash (OpcHash), which wildcards all but prefixes and opcode bytes.
|
|
108
|
-
* 2023-10-12: v1.12.7 - Bugfix for parsing Delphi structs.
|
|
109
|
-
* 2023-09-15: v1.12.6 - Bugfix in BlockLocator (THX to @cccs-ay!).
|
|
110
|
-
* 2023-08-28: v1.12.5 - Bugfix for address dereferencing where buffer sizes were not properly checked (THX to @yankovs!).
|
|
111
|
-
* 2023-08-08: v1.12.4 - SmdaBasicBlock can now do getPicBlockHash().
|
|
112
|
-
* 2023-05-23: v1.12.3 - Fixed bugs in PE parser and Go parser.
|
|
113
|
-
* 2023-05-08: v1.12.1 - Get rid of deprecation warning in IDA 8.0+.
|
|
114
131
|
* 2023-03-24: v1.12.0 - SMDA now parses PE export directories for symbols, as well as MinGW DWARF information if available.
|
|
115
|
-
* 2023-03-14: v1.11.2 - SMDA report now also contains SHA1 and MD5.
|
|
116
|
-
* 2023-03-14: v1.11.1 - rendering dotGraph can now include API references instead of plain calls.
|
|
117
132
|
* 2023-02-06: v1.11.0 - SmdaReport now has functionality to find a function/block by a given offset contained within in (THX to @cccs-ay!).
|
|
118
133
|
* 2023-02-06: v1.10.0 - Adjusted to LIEF 0.12.3 API for binary parsing (THX to @lainswork!).
|
|
119
134
|
* 2022-08-12: v1.9.1 - Added support for parsing intel MachO files, including Go parsing.
|
|
@@ -122,21 +137,22 @@ malwarefrank!)
|
|
|
122
137
|
* 2021-08-20: v1.6.0 - Bugfix for alignment calculation of binary mappings. (THX: @williballenthin)
|
|
123
138
|
* 2021-08-19: v1.6.0 - Bugfix for truncation during ELF segment/section loading. API usage in ELF files is now resolved as well! (THX: @williballenthin)
|
|
124
139
|
* 2020-10-30: v1.5.0 - PE section table now contained in SmdaReport and added `SmdaReport.getSection(offset)`.
|
|
125
|
-
* 2020-10-26: v1.4.0 - Adding SmdaBasicBlock. Some convenience code to ease intgration with capa. (GeekWeek edition!)
|
|
140
|
+
* 2020-10-26: v1.4.0 - Adding SmdaBasicBlock. Some convenience code to ease intgration with capa. (GeekWeek edition!)
|
|
126
141
|
* 2020-06-22: v1.3.0 - Added DominatorTree (Implementation by Armin Rigo) to calculate function nesting depth, shortened PIC hash to 8 byte, added some missing instructions for the InstructionEscaper, IdaInterface now demangles names.
|
|
127
142
|
* 2020-04-29: v1.2.0 - Restructured config.py into smda/SmdaConfig.py to similfy usage and now available via PyPI! The smda/Disassembler.py now emits a report object (smda.common.SmdaReport) that allows direct (pythonic) interaction with the results - a JSON can still be easily generated by using toDict() on the report.
|
|
128
143
|
* 2020-04-28: v1.1.0 - Several improvements, including: x64 jump table handling, better data flow handling for calls using registers and tailcalls, extended list of common prologues based on much more groundtruth data, extended padding instruction list for gap function discovery, adjusted weights in candidate priority score, filtering code areas based on section tables, using exported symbols as candidates, new function output metadata: confidence score based on instruction mnemonic histogram, PIC hash based on escaped binary instruction sequence
|
|
129
144
|
* 2018-07-01: v1.0.0 - Initial Release.
|
|
130
145
|
|
|
146
|
+
For full earlier history, check `version_history.md`.
|
|
131
147
|
|
|
132
148
|
## Credits
|
|
133
149
|
|
|
134
150
|
Thanks to Steffen Enders for his extensive contributions to this project!
|
|
135
151
|
Thanks to Paul Hordiienko for adding symbol parsing support (ELF+PDB)!
|
|
136
152
|
Thanks to Jonathan Crussell for helping me to beef up SMDA enough to make it a disassembler backend in capa!
|
|
137
|
-
Thanks to Willi Ballenthin for improving handling of ELF files, including properly handling API usage!
|
|
153
|
+
Thanks to Willi Ballenthin for improving the handling of ELF files, including properly handling API usage!
|
|
138
154
|
Thanks to Daniel Enders for his contributions to the parsing of the Golang function registry and label information!
|
|
139
155
|
The project uses the implementation of Tarjan's Algorithm by Bas Westerbaan and the implementation of Lengauer-Tarjan's Algorithm for the DominatorTree by Armin Rigo.
|
|
156
|
+
Thanks to r0ny123 for his major code quality improvements added via ruff to this project!
|
|
140
157
|
|
|
141
158
|
Pull requests welcome! :)
|
|
142
|
-
|
|
@@ -9,7 +9,7 @@ Optionally, references to the Windows API can be inferred by using the ApiScout
|
|
|
9
9
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
|
-
With version 1.2.0, we have finally simplified things by moving to [PyPI](https://pypi.org/project/smda/)!
|
|
12
|
+
With version 1.2.0, we have finally simplified things by moving to [PyPI](https://pypi.org/project/smda/)!
|
|
13
13
|
So installation now is as easy as:
|
|
14
14
|
|
|
15
15
|
```
|
|
@@ -38,11 +38,11 @@ A typical workflow using SMDA could like this:
|
|
|
38
38
|
0x0000172e: ( 7402) - je 0x1732
|
|
39
39
|
0x00001730: ( ffd0) - call rax
|
|
40
40
|
0x00001732: ( 4883c408) - add rsp, 8
|
|
41
|
-
0x00001736: ( c3) - ret
|
|
41
|
+
0x00001736: ( c3) - ret
|
|
42
42
|
0x00001ad0: (-> 1, 4->) 1 blocks, 12 instructions.
|
|
43
43
|
[...]
|
|
44
44
|
>>> json_report = report.toDict()
|
|
45
|
-
```
|
|
45
|
+
```
|
|
46
46
|
|
|
47
47
|
There is also a demo script:
|
|
48
48
|
|
|
@@ -52,50 +52,65 @@ The code should be fully compatible with Python 3.8+.
|
|
|
52
52
|
Further explanation on the innerworkings follow in separate publications but will be referenced here.
|
|
53
53
|
|
|
54
54
|
To take full advantage of SMDA's capabilities, make sure to (optionally) install:
|
|
55
|
-
* lief
|
|
55
|
+
* lief
|
|
56
56
|
* pdbparse (currently as fork from https://github.com/VPaulV/pdbparse to support Python3)
|
|
57
57
|
|
|
58
|
+
## Development
|
|
59
|
+
|
|
60
|
+
### Code Quality
|
|
61
|
+
|
|
62
|
+
This project uses [Ruff](https://docs.astral.sh/ruff/) for linting and code formatting. To set up the development environment:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Install development dependencies
|
|
66
|
+
pip install -r requirements.txt
|
|
67
|
+
|
|
68
|
+
# Install pre-commit hooks (optional but recommended)
|
|
69
|
+
make init
|
|
70
|
+
|
|
71
|
+
# Run linting
|
|
72
|
+
make lint
|
|
73
|
+
# or
|
|
74
|
+
ruff check .
|
|
75
|
+
|
|
76
|
+
# Run formatting
|
|
77
|
+
make format
|
|
78
|
+
# or
|
|
79
|
+
ruff format .
|
|
80
|
+
|
|
81
|
+
# Fix auto-fixable issues
|
|
82
|
+
make ruff-fix
|
|
83
|
+
# or
|
|
84
|
+
ruff check . --fix
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Pre-commit Hooks
|
|
88
|
+
|
|
89
|
+
Pre-commit hooks are configured to run ruff automatically on commit. Install them with:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pre-commit install
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Testing
|
|
96
|
+
|
|
97
|
+
Run tests with:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
make test
|
|
101
|
+
```
|
|
102
|
+
|
|
58
103
|
## Version History
|
|
59
|
-
* 2025-
|
|
104
|
+
* 2025-10-21: v2.3.1 - Fixed lief error for section/segment flags in ELF files crashing file loading. Now properly parsing and providing symbol info for PEs in their own xmetadata section.
|
|
105
|
+
* 2025-10-21: v2.3.0 - Major code refactor and cleanup, with many thanks to the contribution @r0ny123!!
|
|
106
|
+
* 2025-07-25: v2.2.3 - Minor bugfixes.
|
|
60
107
|
* 2025-07-23: v2.2.1 - Added xmetadata field to SmdaReport, with information about imports and exports. Improved string extraction from Go binaries.
|
|
61
108
|
* 2025-06-13: v2.1.0 - Support for export from IDA 9.0+ (THX to @jershmagersh for the update!).
|
|
62
109
|
* 2025-02-26: v2.0.2 - Adjusting relative import, adding init file.
|
|
63
110
|
* 2025-02-25: v2.0.0 - Initial experimental support for CIL (.NET) disassembly.
|
|
64
|
-
* 2025-02-24: v1.14.3 - PicHashing can now be disabled via SmdaConfig to save some processing time. (THX to @Nalexander-hanel!)
|
|
65
|
-
* 2025-02-24: v1.14.2 - We are Python 3.8+ compatible again (changed UTC usage) and (DWARF) PE symbols for PE files should be extracted again (THX to @N0fix for the update!)
|
|
66
|
-
* 2025-02-21: v1.14.1 - Fixed changed field names in LIEF usage that broke ELF parsing, added tests for ELF+macOS parsing (THX to @N0fix for the update!)
|
|
67
111
|
* 2025-01-29: v1.14.0 - Bump to LIEF 0.16.0+ (THX to @huettenhain for the ping!). Migrated tests to `pytest`, UTC datetime handling fixes.
|
|
68
|
-
* 2025-01-26: v1.13.24 - Added functionality to import and export SMDA reports as JSON. Fixed byte patterns matching special regex chars (THX to @alexander-hanel!).
|
|
69
|
-
* 2024-07-26: v1.13.23 - Now using OEP as symbol function candidate when available (THX to @alexander-hanel for reporting!).
|
|
70
|
-
* 2024-05-10: v1.13.22 - Handled odd case where disassembly with capstone and IDA would return different results (THX to @r0ny123 for reporting!).
|
|
71
|
-
* 2024-04-17: v1.13.21 - Fixed handling of Go binaries for version 1.20+ (THX to @Manny684!).
|
|
72
|
-
* 2024-04-08: v1.13.20 - Fixed handling of bnd prefix in CFG instructions to help with parsing PLT (THX to @Manny684!).
|
|
73
|
-
* 2024-04-02: v1.13.19 - Fixed bug in string parsing, added tests, strings now no longer are hex-encoded as they are always printable anyway.
|
|
74
|
-
* 2024-03-12: v1.13.18 - Added functionality to extract and store all referenced strings along SmdaFunctions (has to be enabled via SmdaConfig).
|
|
75
|
-
* 2024-03-12: v1.13.17 - Extended disassembleBuffer() to now take additional arguments `code_areas` and `oep`.
|
|
76
|
-
* 2024-02-21: v1.13.16 - BREAKING IntelInstructionEscaper.escapeMnemonic: Escaper now handles another 200 instruction names found in other capstone source files (THX for reporting @malwarefrank!).
|
|
77
|
-
* 2024-02-15: v1.13.15 - Fixed issues with version recognition in SmdaFunction which cause issues in MCRIT (THX to @
|
|
78
|
-
malwarefrank!)
|
|
79
|
-
* 2024-02-02: v1.13.12 - Versions might be non-numerical, addressed that in SmdaFunction.
|
|
80
|
-
* 2024-01-23: v1.13.11 - Introduced indicator in SmdaConfig for compatibility of instruction escaping.
|
|
81
|
-
* 2024-01-23: v1.13.10 - Parsing of PE files should work again with lief >=0.14.0.
|
|
82
|
-
* 2024-01-23: v1.13.9 - Improved parsing robustness for section/segment tables in ELF files, also now padding with zeroes when finding less content than expected physical size in a segment (THX for reporting @schrodyn!).
|
|
83
|
-
* 2024-01-23: v1.13.8 - BREAKING adjustments to IntelInstructionEscaper.escapeMnemonic: Escaper now is capable of handling all known x86/x64 instructions in capstone (THX for reporting @schrodyn!).
|
|
84
|
-
* 2023-12-01: v1.13.7 - Skip processing of Delphi structs for large files, workaround until this is properly reimplemented.
|
|
85
|
-
* 2023-11-29: v1.13.6 - Made OpcodeHash an attribute with on-demand calculation to save processing time.
|
|
86
|
-
* 2023-11-29: v1.13.3 - Implemented an alternative queue working with reference count based brackets in pursuit of accelerated processing.
|
|
87
|
-
* 2023-11-28: v1.13.2 - IndirectCallAnalyzer will now analyze at most a configurable amount of calls per basic block, default 50.
|
|
88
|
-
* 2023-11-21: v1.13.1 - SmdaBasicBlock now has `getPredecessors()` and `getSuccessors()`.
|
|
89
112
|
* 2023-11-21: v1.13.0 - BREAKING adjustments to PicHashing (now wildcarding intraprocedural jumps in functions, additionally more immediates if within address space). Introduction of OpcodeHash (OpcHash), which wildcards all but prefixes and opcode bytes.
|
|
90
|
-
* 2023-10-12: v1.12.7 - Bugfix for parsing Delphi structs.
|
|
91
|
-
* 2023-09-15: v1.12.6 - Bugfix in BlockLocator (THX to @cccs-ay!).
|
|
92
|
-
* 2023-08-28: v1.12.5 - Bugfix for address dereferencing where buffer sizes were not properly checked (THX to @yankovs!).
|
|
93
|
-
* 2023-08-08: v1.12.4 - SmdaBasicBlock can now do getPicBlockHash().
|
|
94
|
-
* 2023-05-23: v1.12.3 - Fixed bugs in PE parser and Go parser.
|
|
95
|
-
* 2023-05-08: v1.12.1 - Get rid of deprecation warning in IDA 8.0+.
|
|
96
113
|
* 2023-03-24: v1.12.0 - SMDA now parses PE export directories for symbols, as well as MinGW DWARF information if available.
|
|
97
|
-
* 2023-03-14: v1.11.2 - SMDA report now also contains SHA1 and MD5.
|
|
98
|
-
* 2023-03-14: v1.11.1 - rendering dotGraph can now include API references instead of plain calls.
|
|
99
114
|
* 2023-02-06: v1.11.0 - SmdaReport now has functionality to find a function/block by a given offset contained within in (THX to @cccs-ay!).
|
|
100
115
|
* 2023-02-06: v1.10.0 - Adjusted to LIEF 0.12.3 API for binary parsing (THX to @lainswork!).
|
|
101
116
|
* 2022-08-12: v1.9.1 - Added support for parsing intel MachO files, including Go parsing.
|
|
@@ -104,21 +119,22 @@ malwarefrank!)
|
|
|
104
119
|
* 2021-08-20: v1.6.0 - Bugfix for alignment calculation of binary mappings. (THX: @williballenthin)
|
|
105
120
|
* 2021-08-19: v1.6.0 - Bugfix for truncation during ELF segment/section loading. API usage in ELF files is now resolved as well! (THX: @williballenthin)
|
|
106
121
|
* 2020-10-30: v1.5.0 - PE section table now contained in SmdaReport and added `SmdaReport.getSection(offset)`.
|
|
107
|
-
* 2020-10-26: v1.4.0 - Adding SmdaBasicBlock. Some convenience code to ease intgration with capa. (GeekWeek edition!)
|
|
122
|
+
* 2020-10-26: v1.4.0 - Adding SmdaBasicBlock. Some convenience code to ease intgration with capa. (GeekWeek edition!)
|
|
108
123
|
* 2020-06-22: v1.3.0 - Added DominatorTree (Implementation by Armin Rigo) to calculate function nesting depth, shortened PIC hash to 8 byte, added some missing instructions for the InstructionEscaper, IdaInterface now demangles names.
|
|
109
124
|
* 2020-04-29: v1.2.0 - Restructured config.py into smda/SmdaConfig.py to similfy usage and now available via PyPI! The smda/Disassembler.py now emits a report object (smda.common.SmdaReport) that allows direct (pythonic) interaction with the results - a JSON can still be easily generated by using toDict() on the report.
|
|
110
125
|
* 2020-04-28: v1.1.0 - Several improvements, including: x64 jump table handling, better data flow handling for calls using registers and tailcalls, extended list of common prologues based on much more groundtruth data, extended padding instruction list for gap function discovery, adjusted weights in candidate priority score, filtering code areas based on section tables, using exported symbols as candidates, new function output metadata: confidence score based on instruction mnemonic histogram, PIC hash based on escaped binary instruction sequence
|
|
111
126
|
* 2018-07-01: v1.0.0 - Initial Release.
|
|
112
127
|
|
|
128
|
+
For full earlier history, check `version_history.md`.
|
|
113
129
|
|
|
114
130
|
## Credits
|
|
115
131
|
|
|
116
132
|
Thanks to Steffen Enders for his extensive contributions to this project!
|
|
117
133
|
Thanks to Paul Hordiienko for adding symbol parsing support (ELF+PDB)!
|
|
118
134
|
Thanks to Jonathan Crussell for helping me to beef up SMDA enough to make it a disassembler backend in capa!
|
|
119
|
-
Thanks to Willi Ballenthin for improving handling of ELF files, including properly handling API usage!
|
|
135
|
+
Thanks to Willi Ballenthin for improving the handling of ELF files, including properly handling API usage!
|
|
120
136
|
Thanks to Daniel Enders for his contributions to the parsing of the Golang function registry and label information!
|
|
121
137
|
The project uses the implementation of Tarjan's Algorithm by Bas Westerbaan and the implementation of Lengauer-Tarjan's Algorithm for the DominatorTree by Armin Rigo.
|
|
138
|
+
Thanks to r0ny123 for his major code quality improvements added via ruff to this project!
|
|
122
139
|
|
|
123
140
|
Pull requests welcome! :)
|
|
124
|
-
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.ruff]
|
|
6
|
+
# Exclude a variety of commonly ignored directories.
|
|
7
|
+
exclude = [
|
|
8
|
+
".bzr",
|
|
9
|
+
".direnv",
|
|
10
|
+
".eggs",
|
|
11
|
+
".git",
|
|
12
|
+
".git-rewrite",
|
|
13
|
+
".hg",
|
|
14
|
+
".mypy_cache",
|
|
15
|
+
".nox",
|
|
16
|
+
".pants.d",
|
|
17
|
+
".pytype",
|
|
18
|
+
".ruff_cache",
|
|
19
|
+
".svn",
|
|
20
|
+
".tox",
|
|
21
|
+
".venv",
|
|
22
|
+
"__pypackages__",
|
|
23
|
+
"_build",
|
|
24
|
+
"buck-out",
|
|
25
|
+
"build",
|
|
26
|
+
"dist",
|
|
27
|
+
"node_modules",
|
|
28
|
+
"venv",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# Same as Black.
|
|
32
|
+
line-length = 120
|
|
33
|
+
indent-width = 4
|
|
34
|
+
|
|
35
|
+
# Assume Python 3.8+
|
|
36
|
+
target-version = "py38"
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
|
40
|
+
select = [
|
|
41
|
+
"E4",
|
|
42
|
+
"E7",
|
|
43
|
+
"E9",
|
|
44
|
+
"F",
|
|
45
|
+
"W",
|
|
46
|
+
"I", # isort
|
|
47
|
+
"UP", # pyupgrade
|
|
48
|
+
"B", # flake8-bugbear
|
|
49
|
+
"C4", # flake8-comprehensions
|
|
50
|
+
"PIE", # flake8-pie
|
|
51
|
+
"SIM", # flake8-simplify
|
|
52
|
+
]
|
|
53
|
+
ignore = [
|
|
54
|
+
"E501", # Line too long (handled by formatter)
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
# Allow fix for all enabled rules (when `--fix`) is provided.
|
|
58
|
+
fixable = ["ALL"]
|
|
59
|
+
unfixable = []
|
|
60
|
+
|
|
61
|
+
# Allow unused variables when underscore-prefixed.
|
|
62
|
+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
63
|
+
|
|
64
|
+
[tool.ruff.format]
|
|
65
|
+
# Like Black, use double quotes for strings.
|
|
66
|
+
quote-style = "double"
|
|
67
|
+
|
|
68
|
+
# Like Black, indent with spaces, rather than tabs.
|
|
69
|
+
indent-style = "space"
|
|
70
|
+
|
|
71
|
+
# Like Black, respect magic trailing commas.
|
|
72
|
+
skip-magic-trailing-comma = false
|
|
73
|
+
|
|
74
|
+
# Like Black, automatically detect the appropriate line ending.
|
|
75
|
+
line-ending = "auto"
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint.isort]
|
|
78
|
+
known-first-party = ["smda"]
|
|
@@ -1,36 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
import sys
|
|
3
|
-
from setuptools import setup, find_packages
|
|
1
|
+
from setuptools import find_packages, setup
|
|
4
2
|
|
|
5
|
-
with open("README.md"
|
|
3
|
+
with open("README.md") as fh:
|
|
6
4
|
long_description = fh.read()
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
requirements = ["capstone", "dncil", "dnfile"]
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
# py3
|
|
13
|
-
requirements.append("lief>=0.16.0")
|
|
14
|
-
else:
|
|
15
|
-
# py2 - newer LIEF is Python3 only
|
|
16
|
-
requirements.append("lief==0.9.0")
|
|
9
|
+
requirements.append("lief>=0.16.0")
|
|
17
10
|
|
|
18
11
|
|
|
19
12
|
setup(
|
|
20
|
-
name=
|
|
13
|
+
name="smda",
|
|
21
14
|
# note to self: always change this in config as well.
|
|
22
|
-
version=
|
|
23
|
-
description=
|
|
15
|
+
version="2.3.1",
|
|
16
|
+
description="A recursive disassmbler optimized for CFG recovery from memory dumps. Based on capstone.",
|
|
24
17
|
long_description_content_type="text/markdown",
|
|
25
18
|
long_description=long_description,
|
|
26
|
-
author=
|
|
27
|
-
author_email=
|
|
28
|
-
url=
|
|
19
|
+
author="Daniel Plohmann",
|
|
20
|
+
author_email="daniel.plohmann@mailbox.org",
|
|
21
|
+
url="https://github.com/danielplohmann/smda",
|
|
29
22
|
license="BSD 2-Clause",
|
|
30
|
-
packages=find_packages(exclude=(
|
|
23
|
+
packages=find_packages(exclude=("tests", "docs")),
|
|
31
24
|
install_requires=requirements,
|
|
32
25
|
data_files=[
|
|
33
|
-
(
|
|
26
|
+
("", ["LICENSE"]),
|
|
34
27
|
],
|
|
35
28
|
classifiers=[
|
|
36
29
|
"Development Status :: 4 - Beta",
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import hashlib
|
|
2
1
|
import datetime
|
|
3
|
-
import
|
|
4
|
-
import os
|
|
5
|
-
import traceback
|
|
2
|
+
import hashlib
|
|
6
3
|
import logging
|
|
4
|
+
import traceback
|
|
7
5
|
|
|
8
|
-
from smda.
|
|
9
|
-
from smda.utility.MemoryFileLoader import MemoryFileLoader
|
|
10
|
-
from smda.utility.StringExtractor import extract_strings
|
|
11
|
-
from smda.SmdaConfig import SmdaConfig
|
|
6
|
+
from smda.cil.CilDisassembler import CilDisassembler
|
|
12
7
|
from smda.common.BinaryInfo import BinaryInfo
|
|
13
8
|
from smda.common.labelprovider.GoLabelProvider import GoSymbolProvider
|
|
14
9
|
from smda.common.SmdaReport import SmdaReport
|
|
15
|
-
from smda.intel.IntelDisassembler import IntelDisassembler
|
|
16
|
-
from smda.cil.CilDisassembler import CilDisassembler
|
|
17
10
|
from smda.ida.IdaExporter import IdaExporter
|
|
11
|
+
from smda.intel.IntelDisassembler import IntelDisassembler
|
|
12
|
+
from smda.SmdaConfig import SmdaConfig
|
|
13
|
+
from smda.utility.FileLoader import FileLoader
|
|
14
|
+
from smda.utility.MemoryFileLoader import MemoryFileLoader
|
|
15
|
+
from smda.utility.StringExtractor import extract_strings
|
|
18
16
|
|
|
19
17
|
LOGGER = logging.getLogger(__name__)
|
|
20
18
|
|
|
21
19
|
|
|
22
|
-
class Disassembler
|
|
23
|
-
|
|
20
|
+
class Disassembler:
|
|
24
21
|
def __init__(self, config=None, backend=None):
|
|
25
22
|
if config is None:
|
|
26
23
|
config = SmdaConfig()
|
|
@@ -38,7 +35,7 @@ class Disassembler(object):
|
|
|
38
35
|
self.disassembly = None
|
|
39
36
|
|
|
40
37
|
def initDisassembler(self, architecture="intel"):
|
|
41
|
-
"""
|
|
38
|
+
"""Initialize disassembler backend to given architecture, if not initialized yet, default: intel"""
|
|
42
39
|
if self.disassembler is None:
|
|
43
40
|
if architecture == "intel":
|
|
44
41
|
self.disassembler = IntelDisassembler(self.config)
|
|
@@ -61,12 +58,14 @@ class Disassembler(object):
|
|
|
61
58
|
function_strings = []
|
|
62
59
|
for string_result in extract_strings(smda_function, mode=mode):
|
|
63
60
|
string, referencing_addr, string_addr, string_type = string_result
|
|
64
|
-
function_strings.append(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
function_strings.append(
|
|
62
|
+
{
|
|
63
|
+
"string": string,
|
|
64
|
+
"ins_addr": referencing_addr,
|
|
65
|
+
"data_addr": string_addr,
|
|
66
|
+
"type": string_type,
|
|
67
|
+
}
|
|
68
|
+
)
|
|
70
69
|
smda_function.stringrefs = function_strings
|
|
71
70
|
|
|
72
71
|
def disassembleFile(self, file_path, pdb_path=""):
|
|
@@ -130,7 +129,15 @@ class Disassembler(object):
|
|
|
130
129
|
smda_report = self._createErrorReport(start, exc)
|
|
131
130
|
return smda_report
|
|
132
131
|
|
|
133
|
-
def disassembleBuffer(
|
|
132
|
+
def disassembleBuffer(
|
|
133
|
+
self,
|
|
134
|
+
file_content,
|
|
135
|
+
base_addr,
|
|
136
|
+
bitness=None,
|
|
137
|
+
code_areas=None,
|
|
138
|
+
oep=None,
|
|
139
|
+
architecture="intel",
|
|
140
|
+
):
|
|
134
141
|
"""
|
|
135
142
|
Disassemble a given buffer (file_content), with given base_addr.
|
|
136
143
|
Optionally specify bitness, the areas to which disassembly should be limited to (code_areas) and an entry point (oep)
|