diff options
Diffstat (limited to 'tests/analysis/scan/pyapi.py')
| -rw-r--r-- | tests/analysis/scan/pyapi.py | 209 |
1 files changed, 208 insertions, 1 deletions
diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py index 4b066f3..7a697b3 100644 --- a/tests/analysis/scan/pyapi.py +++ b/tests/analysis/scan/pyapi.py @@ -1,5 +1,6 @@ import binascii +import struct from chrysacase import ChrysalideTestCase from gi._constants import TYPE_INVALID @@ -34,7 +35,7 @@ class TestRostPythonAPI(ChrysalideTestCase): class StrLenExpr(ScanExpression): def __init__(self, value): - super().__init__(ScanExpression.ExprValueType.STRING) + super().__init__(ScanExpression.ScanReductionState.REDUCED) self._value = value def _cmp_rich(self, other, op): @@ -73,6 +74,7 @@ class TestRostPythonAPI(ChrysalideTestCase): self.assertEqual(source, transformed[0]) + mod = find_token_modifiers_for_name('hex') self.assertIsNotNone(mod) @@ -81,6 +83,7 @@ class TestRostPythonAPI(ChrysalideTestCase): self.assertEqual(binascii.hexlify(source), transformed[0]) + mod = find_token_modifiers_for_name('rev') self.assertIsNotNone(mod) @@ -88,3 +91,207 @@ class TestRostPythonAPI(ChrysalideTestCase): transformed = mod.transform(source) self.assertEqual(source[::-1], transformed[0]) + + + mod = find_token_modifiers_for_name('lower') + self.assertIsNotNone(mod) + + source = b'AbC' + transformed = mod.transform(source) + + self.assertEqual(source.lower(), transformed[0]) + + + mod = find_token_modifiers_for_name('upper') + self.assertIsNotNone(mod) + + source = b'AbC' + transformed = mod.transform(source) + + self.assertEqual(source.upper(), transformed[0]) + + + mod = find_token_modifiers_for_name('wide') + self.assertIsNotNone(mod) + + source = b'ABC' + transformed = mod.transform(source) + + self.assertEqual(source.decode('ascii'), transformed[0].decode('utf-16-le')) + + + mod = find_token_modifiers_for_name('base64') + self.assertIsNotNone(mod) + + source = b'ABC' + transformed = mod.transform(source) + + self.assertEqual(len(transformed), 3) + self.assertEqual(transformed[0], b'QUJD') + self.assertEqual(transformed[1], b'FCQ') + self.assertEqual(transformed[2], b'BQk') + + + def testClassicalAPIHashing(self): + """Reproduce classical API Hashing results.""" + + def b2i(t): + return struct.unpack('<I', t)[0] + + + # Example: + # - PlugX (2020) - https://vms.drweb.fr/virus/?i=21512304 + + mod = find_token_modifiers_for_name('crc32') + self.assertIsNotNone(mod) + + source = b'GetCurrentProcess\x00' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x3690e66) + + + # Example: + # - GuLoader (2020) - https://www.crowdstrike.com/blog/guloader-malware-analysis/ + + mod = find_token_modifiers_for_name('djb2') + self.assertIsNotNone(mod) + + source = b'GetProcAddress' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0xcf31bb1f) + + + def testCustomAPIHashing(self): + """Reproduce custom API Hashing results.""" + + def b2i(t): + return struct.unpack('<I', t)[0] + + + # Example: + # Underminer Exploit Kit (2019) - https://jsac.jpcert.or.jp/archive/2019/pdf/JSAC2019_1_koike-nakajima_jp.pdf + + mod = find_token_modifiers_for_name('add1505-shl5') + self.assertIsNotNone(mod) + + source = b'LoadLibraryA' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x5fbff0fb) + + + # Example: + # Enigma Stealer (2023) https://www.trendmicro.com/es_mx/research/23/b/enigma-stealer-targets-cryptocurrency-industry-with-fake-jobs.html + + mod = find_token_modifiers_for_name('enigma-murmur') + self.assertIsNotNone(mod) + + source = b'CreateMutexW' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0xfd43765a) + + + # Examples: + # - ShadowHammer (2019) - https://blog.f-secure.com/analysis-shadowhammer-asus-attack-first-stage-payload/ + # - ShadowHammer (2019) - https://securelist.com/operation-shadowhammer-a-high-profile-supply-chain-attack/90380/ + + mod = find_token_modifiers_for_name('imul21-add') + self.assertIsNotNone(mod) + + source = b'VirtualAlloc' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0xdf894b12) + + + # Examples: + # - Bottle Exploit Kit (2019) - https://nao-sec.org/2019/12/say-hello-to-bottle-exploit-kit.html + # - ShadowHammer (2019) - https://securelist.com/operation-shadowhammer-a-high-profile-supply-chain-attack/90380/ + + mod = find_token_modifiers_for_name('imul83-add') + self.assertIsNotNone(mod) + + source = b'GetProcAddress' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x9ab9b854) + + + # Examples: + # - ?? (2021) - https://www.threatspike.com/blogs/reflective-dll-injection + # - Mustang Panda (2022) - https://blog.talosintelligence.com/mustang-panda-targets-europe/ + + mod = find_token_modifiers_for_name('ror13') + self.assertIsNotNone(mod) + + source = b'GetProcAddress' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x7c0dfcaa) + + source = b'VirtualAlloc' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x91afca54) + + + # Example: + # - Energetic Bear (2019) - https://insights.sei.cmu.edu/blog/api-hashing-tool-imagine-that/ + + mod = find_token_modifiers_for_name('sll1-add-hash32') + self.assertIsNotNone(mod) + + source = b'LoadLibraryA' + transformed = mod.transform(source) + + self.assertEqual(b2i(transformed[0]), 0x000d5786) + + + # Example: + # - SideWinder/WarHawk (2022) - https://www.zscaler.com/blogs/security-research/warhawk-new-backdoor-arsenal-sidewinder-apt-group + + mod = find_token_modifiers_for_name('sub42') + self.assertIsNotNone(mod) + + source = b'LoadLibraryA' + transformed = mod.transform(source) + + self.assertEqual(transformed[0], b'\x8e\xb1\xa3\xa6\x8e\xab\xa4\xb4\xa3\xb4\xbb\x83') + + + # Example: + # - TrickBot (2021) - https://medium.com/walmartglobaltech/trickbot-crews-new-cobaltstrike-loader-32c72b78e81c + + mod = find_token_modifiers_for_name('sub-index1') + self.assertIsNotNone(mod) + + source = b'raw.githubusercontent.com' + transformed = mod.transform(source) + + self.assertEqual(transformed[0], b'\x73\x63\x7a\x32\x6c\x6f\x7b\x70\x7e\x6c\x80\x7f\x72\x80\x72\x7f\x7f\x86\x78\x82\x89\x44\x7a\x87\x86') + + + def testBytePatternModifiersAPI(self): + """Validate the API for pattern modifiers.""" + + mod = find_token_modifiers_for_name('plain') + self.assertIsNotNone(mod) + + source = [ b'ABC', b'01234' ] + transformed = mod.transform(source) + + self.assertEqual(len(source), len(transformed)) + self.assertEqual(source[0], transformed[0]) + self.assertEqual(source[1], transformed[1]) + + + mod = find_token_modifiers_for_name('xor') + self.assertIsNotNone(mod) + + source = [ b'ABC' ] + transformed = mod.transform(source, 0x20) + + self.assertEqual(transformed[0], b'abc') |
