-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ [performance] Compile regular expressions in IndirectCallAnalyzer #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
42e7c5e
ab72d23
fccaccc
d729a39
8670707
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import unittest | ||
| from unittest.mock import MagicMock | ||
|
|
||
| from smda.intel.IndirectCallAnalyzer import IndirectCallAnalyzer | ||
|
|
||
|
|
||
| class IndirectCallAnalyzerTestSuite(unittest.TestCase): | ||
| """Basic tests for IndirectCallAnalyzer regex and logic""" | ||
|
|
||
| def test_regex_matching(self): | ||
| analyzer = IndirectCallAnalyzer(MagicMock()) | ||
|
|
||
| # Test mov <reg>, <reg> | ||
| match = analyzer.RE_MOV_REG_REG.match("eax, ebx") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg1"), "eax") | ||
| self.assertEqual(match.group("reg2"), "ebx") | ||
| match = analyzer.RE_MOV_REG_REG.match("r8, r9") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg1"), "r8") | ||
| self.assertEqual(match.group("reg2"), "r9") | ||
|
|
||
| # Test mov <reg>, <const> | ||
| match = analyzer.RE_MOV_REG_CONST.match("ecx, 0x12345678") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg"), "ecx") | ||
| self.assertEqual(match.group("val"), "0x12345678") | ||
| match = analyzer.RE_MOV_REG_CONST.match("r10, 0x1122334455667788") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg"), "r10") | ||
| self.assertEqual(match.group("val"), "0x1122334455667788") | ||
|
|
||
| # Test mov <reg>, dword ptr [<addr>] | ||
| match = analyzer.RE_REG_DWORD_PTR_ADDR.match("edx, dword ptr [0x8048000]") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg"), "edx") | ||
| self.assertEqual(match.group("addr"), "0x8048000") | ||
|
|
||
| # Test mov <reg>, qword ptr [rip + <addr>] | ||
| match = analyzer.RE_REG_QWORD_PTR_RIP_ADDR.match("rax, qword ptr [rip + 0x1234]") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg"), "rax") | ||
| self.assertEqual(match.group("addr"), "0x1234") | ||
|
|
||
| # Test lea <reg>, [<addr>] | ||
| match = analyzer.RE_REG_ADDR.match("rsi, [0x400000]") | ||
| self.assertIsNotNone(match) | ||
| self.assertEqual(match.group("reg"), "rsi") | ||
| self.assertEqual(match.group("addr"), "0x400000") | ||
|
Comment on lines
+10
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's great that you've added tests for the regexes! To make them more comprehensive, I suggest adding cases for 64-bit architecture. This would include registers with names that are not 3 characters long (e.g., def test_regex_matching(self):
analyzer = IndirectCallAnalyzer(MagicMock())
# Test mov <reg>, <reg>
match = analyzer.RE_MOV_REG_REG.match("eax, ebx")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg1"), "eax")
self.assertEqual(match.group("reg2"), "ebx")
match = analyzer.RE_MOV_REG_REG.match("r8, r9")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg1"), "r8")
self.assertEqual(match.group("reg2"), "r9")
# Test mov <reg>, <const>
match = analyzer.RE_MOV_REG_CONST.match("ecx, 0x12345678")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg"), "ecx")
self.assertEqual(match.group("val"), "0x12345678")
match = analyzer.RE_MOV_REG_CONST.match("r10, 0x1122334455667788")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg"), "r10")
self.assertEqual(match.group("val"), "0x1122334455667788")
# Test mov <reg>, dword ptr [<addr>]
match = analyzer.RE_REG_DWORD_PTR_ADDR.match("edx, dword ptr [0x8048000]")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg"), "edx")
self.assertEqual(match.group("addr"), "0x8048000")
# Test mov <reg>, qword ptr [rip + <addr>]
match = analyzer.RE_REG_QWORD_PTR_RIP_ADDR.match("rax, qword ptr [rip + 0x1234]")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg"), "rax")
self.assertEqual(match.group("addr"), "0x1234")
# Test lea <reg>, [<addr>]
match = analyzer.RE_REG_ADDR.match("rsi, [0x400000]")
self.assertIsNotNone(match)
self.assertEqual(match.group("reg"), "rsi")
self.assertEqual(match.group("addr"), "0x400000") |
||
| def test_processBlock_logic(self): | ||
| disassembler = MagicMock() | ||
| disassembler.resolveApi.return_value = (None, None) | ||
| analyzer = IndirectCallAnalyzer(disassembler) | ||
| analyzer.getDword = MagicMock(return_value=0x12345678) | ||
|
|
||
| analysis_state = MagicMock() | ||
| analyzer.state = analysis_state | ||
| # block is a list of [address, size, mnemonic, op_str] | ||
| block = [[0x401000, 5, "mov", "eax, 0x402000"], [0x401005, 2, "mov", "ebx, eax"]] | ||
| registers = {} | ||
| register_name = "ebx" | ||
| processed = [] | ||
| depth = 1 | ||
|
|
||
| # Mock disassembly | ||
| analyzer.disassembly = MagicMock() | ||
| analyzer.disassembly.isAddrWithinMemoryImage.return_value = True | ||
|
|
||
| result = analyzer.processBlock(analysis_state, block, registers, register_name, processed, depth) | ||
|
|
||
| # result should be True because we found an absolute value for the register we were looking for | ||
| self.assertTrue(result) | ||
| # eax should have 0x402000 | ||
| self.assertEqual(registers.get("eax"), 0x402000) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() | ||
Uh oh!
There was an error while loading. Please reload this page.