Skip to content

Commit 7c3deae

Browse files
committed
fix(core): address PR review follow-ups
1 parent 63f41d9 commit 7c3deae

7 files changed

Lines changed: 68 additions & 19 deletions

File tree

src/smda/common/SmdaBasicBlock.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def getPicBlockHash(self):
3535
return self.picblockhash
3636
picblockhash_sequence = self.getPicBlockHashSequence()
3737
if picblockhash_sequence is not None:
38-
self.picblockhash = struct.unpack("Q", hashlib.sha256(picblockhash_sequence).digest()[:8])[0]
38+
self.picblockhash = struct.unpack("<Q", hashlib.sha256(picblockhash_sequence).digest()[:8])[0]
3939
return self.picblockhash
4040

4141
def getPicBlockHashSequence(self):
@@ -66,7 +66,7 @@ def getOpcBlockHash(self):
6666
return self.opcblockhash
6767
opcblockhash_sequence = self.getOpcBlockHashSequence()
6868
if opcblockhash_sequence is not None:
69-
self.opcblockhash = struct.unpack("Q", hashlib.sha256(opcblockhash_sequence).digest()[:8])[0]
69+
self.opcblockhash = struct.unpack("<Q", hashlib.sha256(opcblockhash_sequence).digest()[:8])[0]
7070
return self.opcblockhash
7171

7272
def getOpcBlockHashSequence(self):
@@ -105,4 +105,6 @@ def __int__(self):
105105
return self.offset
106106

107107
def __str__(self):
108+
if self.offset is None:
109+
return f"0x????????: ({self.length:>4})"
108110
return f"0x{self.offset:08x}: ({self.length:>4})"

src/smda/common/SmdaFunction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def getPicHashAsLong(self):
144144
return self.pic_hash
145145

146146
def getPicHashAsHex(self):
147-
return struct.pack("Q", self.pic_hash).hex()
147+
return struct.pack("<Q", self.pic_hash).hex()
148148

149149
def getInstructions(self):
150150
for block in self.getBlocks():
@@ -186,7 +186,7 @@ def _calculateNestingDepth(self):
186186
return nesting_depth
187187

188188
def getPicHash(self, binary_info):
189-
return struct.unpack("Q", hashlib.sha256(self.getPicHashSequence(binary_info)).digest()[:8])[0]
189+
return struct.unpack("<Q", hashlib.sha256(self.getPicHashSequence(binary_info)).digest()[:8])[0]
190190

191191
def getPicHashSequence(self, binary_info):
192192
escaped_binary_seqs = []
@@ -203,7 +203,7 @@ def getPicHashSequence(self, binary_info):
203203
return bytes([ord(c) for c in "".join(escaped_binary_seqs)])
204204

205205
def getOpcHash(self):
206-
return struct.unpack("Q", hashlib.sha256(self.getOpcHashSequence()).digest()[:8])[0]
206+
return struct.unpack("<Q", hashlib.sha256(self.getOpcHashSequence()).digest()[:8])[0]
207207

208208
def getOpcHashSequence(self):
209209
escaped_binary_seqs = []

src/smda/common/labelprovider/CilSymbolProvider.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def decodeSymbolName(self, value):
3434
return value.encode("utf-8").decode("utf-8")
3535

3636
def update(self, binary_info):
37+
self._addr_to_func_symbols = {}
38+
self._func_symbol_to_addr = {}
3739
try:
3840
pe = dnfile.dnPE(data=binary_info.raw_data)
3941
except Exception as exc:

src/smda/common/labelprovider/ElfApiResolver.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,7 @@ def getApi(self, to_addr, absolute_addr=None):
6666
May return None for the `dll` if it cannot be determined.
6767
When it can be determined for ELF files, the `dll` field should be interpreted as the API version rather than shared library name.
6868
For example: "GLIBC_2.2.5".
69+
`absolute_addr` is part of the label-provider API but intentionally unused here:
70+
ELF lookups are keyed by relocation slot address (`to_addr`) in `_api_map["lief"]`.
6971
"""
7072
return self._api_map["lief"].get(to_addr, (None, None))

src/smda/intel/JumpTableAnalyzer.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,22 +142,21 @@ def _resolveExplicitTable(self, jump_instruction_address, state, jumptable_addre
142142
jumptable_size = jumptable_size if jumptable_size is not None else 0xFF
143143
jumptable_addresses = []
144144
bitness = self.disassembly.binary_info.bitness
145-
entry_size = 4 if bitness == 32 else 8
145+
if bitness == 32:
146+
entry_size = 4
147+
entry_format = "I"
148+
elif bitness == 64:
149+
entry_size = 8
150+
entry_format = "Q"
151+
else:
152+
LOGGER.warning("Unsupported %s-bit jump table analysis", bitness)
153+
return jumptable_addresses
146154
if self.disassembly.isAddrWithinMemoryImage(jumptable_address):
147155
for i in range(jumptable_size):
148-
if bitness == 32:
149-
table_entry = struct.unpack(
150-
"I",
151-
self.disassembly.getBytes(jumptable_address + i * entry_size, entry_size),
152-
)[0]
153-
elif bitness == 64:
154-
table_entry = struct.unpack(
155-
"Q",
156-
self.disassembly.getBytes(jumptable_address + i * entry_size, entry_size),
157-
)[0]
158-
else:
159-
LOGGER.warning("Unsupported bitness for jump table analysis: %s", bitness)
160-
break
156+
table_entry = struct.unpack(
157+
entry_format,
158+
self.disassembly.getBytes(jumptable_address + i * entry_size, entry_size),
159+
)[0]
161160
if not self.disassembly.isAddrWithinMemoryImage(table_entry):
162161
break
163162
state.addDataRef(

tests/testCommonModels.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import hashlib
2+
import struct
3+
import unittest
4+
5+
from smda.common.SmdaBasicBlock import SmdaBasicBlock
6+
from smda.common.SmdaFunction import SmdaFunction
7+
8+
9+
class TestCommonModels(unittest.TestCase):
10+
def test_empty_basic_block_string_is_safe(self):
11+
self.assertEqual(str(SmdaBasicBlock([])), "0x????????: ( 0)")
12+
13+
def test_function_hash_helpers_use_little_endian(self):
14+
function = SmdaFunction()
15+
function.pic_hash = 0x0102030405060708
16+
function.getPicHashSequence = lambda binary_info: b"pic-sequence"
17+
function.getOpcHashSequence = lambda: b"opc-sequence"
18+
19+
self.assertEqual(function.getPicHashAsHex(), struct.pack("<Q", function.pic_hash).hex())
20+
self.assertEqual(
21+
function.getPicHash(None),
22+
struct.unpack("<Q", hashlib.sha256(b"pic-sequence").digest()[:8])[0],
23+
)
24+
self.assertEqual(
25+
function.getOpcHash(),
26+
struct.unpack("<Q", hashlib.sha256(b"opc-sequence").digest()[:8])[0],
27+
)
28+
29+
30+
if __name__ == "__main__":
31+
unittest.main()

tests/testFileFormatParsers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from smda.cil.CilDisassembler import CilDisassembler
1212
from smda.common.BinaryInfo import BinaryInfo
13+
from smda.common.labelprovider.CilSymbolProvider import CilSymbolProvider
1314
from smda.common.labelprovider.ElfApiResolver import ElfApiResolver
1415
from smda.common.labelprovider.GoLabelProvider import GoSymbolProvider
1516
from smda.common.labelprovider.PeSymbolProvider import PeSymbolProvider
@@ -204,6 +205,18 @@ def test_elf_api_resolver_uses_relocation_slot_address(self):
204205
self.assertEqual(resolver.getApi(0x4018, absolute_addr=0x1000), ("GLIBC_2.2.5", "puts"))
205206
self.assertEqual(resolver.getApi(0x1000, absolute_addr=0x4018), (None, None))
206207

208+
def test_cil_symbol_provider_clears_symbols_before_parse(self):
209+
provider = CilSymbolProvider(None)
210+
provider._addr_to_func_symbols[0x1000] = "stale"
211+
provider._func_symbol_to_addr["stale"] = 0x1000
212+
binary_info = BinaryInfo(b"not a dotnet file")
213+
214+
with mock.patch("smda.common.labelprovider.CilSymbolProvider.dnfile.dnPE", side_effect=ValueError("bad pe")):
215+
provider.update(binary_info)
216+
217+
self.assertEqual(provider.getFunctionSymbols(), {})
218+
self.assertIsNone(provider.getAddress("stale"))
219+
207220

208221
if __name__ == "__main__":
209222
unittest.main()

0 commit comments

Comments
 (0)