CAPE-parsers 0.1.42__tar.gz → 0.1.45__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.
Files changed (113) hide show
  1. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/PKG-INFO +2 -2
  2. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Lumma.py +38 -29
  3. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/pyproject.toml +2 -2
  4. cape_parsers-0.1.42/cape_parsers/CAPE/community/Amadey.py +0 -43
  5. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/LICENSE +0 -0
  6. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/README.md +0 -0
  7. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/__init__.py +0 -0
  8. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/AgentTesla.py +0 -0
  9. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Arkei.py +0 -0
  10. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/AsyncRAT.py +0 -0
  11. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/AuroraStealer.py +0 -0
  12. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/BackOffLoader.py +0 -0
  13. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/BackOffPOS.py +0 -0
  14. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/BlackNix.py +0 -0
  15. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Carbanak.py +0 -0
  16. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/CobaltStrikeBeacon.py +0 -0
  17. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/CobaltStrikeStager.py +0 -0
  18. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/DCRat.py +0 -0
  19. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Fareit.py +0 -0
  20. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Greame.py +0 -0
  21. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/KoiLoader.py +0 -0
  22. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/LokiBot.py +0 -0
  23. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/NanoCore.py +0 -0
  24. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Nighthawk.py +0 -0
  25. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Njrat.py +0 -0
  26. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Pandora.py +0 -0
  27. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/PhemedroneStealer.py +0 -0
  28. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/PoisonIvy.py +0 -0
  29. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Punisher.py +0 -0
  30. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/QuasarRAT.py +0 -0
  31. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/README.md +0 -0
  32. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/REvil.py +0 -0
  33. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Retefe.py +0 -0
  34. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Rozena.py +0 -0
  35. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/SmallNet.py +0 -0
  36. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Snake.py +0 -0
  37. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/SparkRAT.py +0 -0
  38. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/Stealc.py +0 -0
  39. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/TSCookie.py +0 -0
  40. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/TrickBot.py +0 -0
  41. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/VenomRAT.py +0 -0
  42. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/XWorm.py +0 -0
  43. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/XenoRAT.py +0 -0
  44. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/community/__init__.py +0 -0
  45. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/AdaptixBeacon.py +0 -0
  46. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Azorult.py +0 -0
  47. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/BitPaymer.py +0 -0
  48. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/BlackDropper.py +0 -0
  49. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Blister.py +0 -0
  50. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/BruteRatel.py +0 -0
  51. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/BuerLoader.py +0 -0
  52. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/BumbleBee.py +0 -0
  53. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/ChChes.py +0 -0
  54. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/DarkGate.py +0 -0
  55. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/DoppelPaymer.py +0 -0
  56. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/DridexLoader.py +0 -0
  57. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Emotet.py +0 -0
  58. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Enfal.py +0 -0
  59. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/EvilGrab.py +0 -0
  60. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Formbook.py +0 -0
  61. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/GuLoader.py +0 -0
  62. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/HttpBrowser.py +0 -0
  63. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/IcedID.py +0 -0
  64. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/IcedIDLoader.py +0 -0
  65. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Latrodectus.py +0 -0
  66. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Oyster.py +0 -0
  67. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/PikaBot.py +0 -0
  68. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/PlugX.py +0 -0
  69. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/QakBot.py +0 -0
  70. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Quickbind.py +0 -0
  71. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/RCSession.py +0 -0
  72. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/README.md +0 -0
  73. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/RedLeaf.py +0 -0
  74. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/RedLine.py +0 -0
  75. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Remcos.py +0 -0
  76. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Rhadamanthys.py +0 -0
  77. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/SmokeLoader.py +0 -0
  78. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Socks5Systemz.py +0 -0
  79. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/SquirrelWaffle.py +0 -0
  80. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Stealc.py +0 -0
  81. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Strrat.py +0 -0
  82. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/UrsnifV3.py +0 -0
  83. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/WarzoneRAT.py +0 -0
  84. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/Zloader.py +0 -0
  85. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/__init__.py +0 -0
  86. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/CAPE/core/test_cape.py +0 -0
  87. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/RATDecoders/README.md +0 -0
  88. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/RATDecoders/__init__.py +0 -0
  89. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/RATDecoders/test_rats.py +0 -0
  90. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/__init__.py +0 -0
  91. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/Hancitor.py +0 -0
  92. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/JavaDropper.py +0 -0
  93. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/Nymaim.py +0 -0
  94. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/PredatorPain.py +0 -0
  95. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/_ShadowTech.py +0 -0
  96. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/_VirusRat.py +0 -0
  97. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/_jRat.py +0 -0
  98. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/unrecom.py +0 -0
  99. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/deprecated/xRAT.py +0 -0
  100. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/malduck/LICENSE +0 -0
  101. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/malduck/README.md +0 -0
  102. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/malduck/__init__.py +0 -0
  103. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/malduck/test_malduck.py +0 -0
  104. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/mwcp/README.md +0 -0
  105. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/mwcp/__init__.py +0 -0
  106. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/mwcp/test_mwcp.py +0 -0
  107. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/__init__.py +0 -0
  108. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/aplib.py +0 -0
  109. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/blzpack.py +0 -0
  110. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/blzpack_lib.so +0 -0
  111. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/dotnet_utils.py +0 -0
  112. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/lznt1.py +0 -0
  113. {cape_parsers-0.1.42 → cape_parsers-0.1.45}/cape_parsers/utils/strings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: CAPE-parsers
3
- Version: 0.1.42
3
+ Version: 0.1.45
4
4
  Summary: CAPE: Malware Configuration Extraction
5
5
  License: MIT
6
6
  Keywords: cape,parsers,malware,configuration
@@ -23,7 +23,7 @@ Requires-Dist: pefile
23
23
  Requires-Dist: pycryptodomex (>=3.20.0)
24
24
  Requires-Dist: rat-king-parser (>=4.1.0)
25
25
  Requires-Dist: ruff (>=0.7.2)
26
- Requires-Dist: unicorn (==2.1.1)
26
+ Requires-Dist: unicorn (>=2.1.1)
27
27
  Requires-Dist: yara-python (>=4.5.1)
28
28
  Description-Content-Type: text/markdown
29
29
 
@@ -75,7 +75,6 @@ RULE_SOURCE_LUMMA_NEW_ENCRYPTED_C2 = """rule LummaConfigNewEncryptedStrings
75
75
  }"""
76
76
 
77
77
 
78
-
79
78
  def yara_scan_generator(raw_data, rule_source):
80
79
  yara_rules = yara.compile(source=rule_source)
81
80
  matches = yara_rules.match(data=raw_data)
@@ -198,10 +197,22 @@ def chacha20_block(key, nonce, blocknum):
198
197
  nonce_words = words_from_bytes(nonce)
199
198
 
200
199
  original_block = [
201
- constant_words[0], constant_words[1], constant_words[2], constant_words[3],
202
- key_words[0], key_words[1], key_words[2], key_words[3],
203
- key_words[4], key_words[5], key_words[6], key_words[7],
204
- mask32(blocknum), nonce_words[0], nonce_words[1], nonce_words[2],
200
+ constant_words[0],
201
+ constant_words[1],
202
+ constant_words[2],
203
+ constant_words[3],
204
+ key_words[0],
205
+ key_words[1],
206
+ key_words[2],
207
+ key_words[3],
208
+ key_words[4],
209
+ key_words[5],
210
+ key_words[6],
211
+ key_words[7],
212
+ mask32(blocknum),
213
+ nonce_words[0],
214
+ nonce_words[1],
215
+ nonce_words[2],
205
216
  ]
206
217
 
207
218
  permuted_block = list(original_block)
@@ -241,7 +252,7 @@ def extract_c2_domain(data):
241
252
 
242
253
 
243
254
  def find_encrypted_c2_blocks(data):
244
- pattern = rb'(.{128})\x00'
255
+ pattern = rb"(.{128})\x00"
245
256
  for match in re.findall(pattern, data, re.DOTALL):
246
257
  yield match
247
258
 
@@ -251,9 +262,9 @@ def get_build_id(pe, data):
251
262
  image_base = pe.OPTIONAL_HEADER.ImageBase
252
263
  for offset in yara_scan_generator(data, RULE_SOURCE_BUILD_ID):
253
264
  try:
254
- build_id_data_rva = struct.unpack('i', data[offset + 2 : offset + 6])[0]
265
+ build_id_data_rva = struct.unpack("i", data[offset + 2 : offset + 6])[0]
255
266
  build_id_dword_offset = pe.get_offset_from_rva(build_id_data_rva - image_base)
256
- build_id_dword_rva = struct.unpack('i', data[build_id_dword_offset : build_id_dword_offset + 4])[0]
267
+ build_id_dword_rva = struct.unpack("i", data[build_id_dword_offset : build_id_dword_offset + 4])[0]
257
268
  build_id_offset = pe.get_offset_from_rva(build_id_dword_rva - image_base)
258
269
  build_id = pe.get_string_from_data(build_id_offset, data)
259
270
  if not contains_non_printable(build_id):
@@ -263,18 +274,20 @@ def get_build_id(pe, data):
263
274
  continue
264
275
  return build_id
265
276
 
277
+
266
278
  def get_build_id_new(data):
267
279
  build_id = ""
268
- pattern = b'123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\x00'
280
+ pattern = b"123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\x00"
269
281
  offset = data.find(pattern)
270
282
  if offset != -1:
271
- build_id = data[offset + len(pattern):].split(b'\x00', 1)[0]
283
+ build_id = data[offset + len(pattern) :].split(b"\x00", 1)[0]
272
284
  build_id = build_id.decode()
273
285
 
274
286
  return build_id
275
287
 
288
+
276
289
  def extract_config(data):
277
- config_dict = {"C2": []}
290
+ config_dict = {}
278
291
 
279
292
  # try to load as a PE
280
293
  pe = None
@@ -287,37 +300,36 @@ def extract_config(data):
287
300
  key = None
288
301
  nonce = None
289
302
  for offset in yara_scan_generator(data, RULE_SOURCE_LUMMA_NEW_KEYS):
290
- key_rva = struct.unpack('i', data[offset + 1 : offset + 5])[0]
303
+ key_rva = struct.unpack("i", data[offset + 1 : offset + 5])[0]
291
304
  key_offset = pe.get_offset_from_rva(key_rva - image_base)
292
305
  key = data[key_offset : key_offset + 32]
293
- nonce_rva = struct.unpack('i', data[offset + 20 : offset + 24])[0]
306
+ nonce_rva = struct.unpack("i", data[offset + 20 : offset + 24])[0]
294
307
  nonce_offset = pe.get_offset_from_rva(nonce_rva - image_base)
295
- nonce = b'\x00\x00\x00\x00' + data[nonce_offset : nonce_offset + 8]
308
+ nonce = b"\x00\x00\x00\x00" + data[nonce_offset : nonce_offset + 8]
296
309
 
297
310
  if key and nonce:
298
311
  for offset in yara_scan_generator(data, RULE_SOURCE_LUMMA_NEW_ENCRYPTED_C2):
299
- encrypted_strings_rva = struct.unpack('i', data[offset + 5 : offset + 9])[0]
312
+ encrypted_strings_rva = struct.unpack("i", data[offset + 5 : offset + 9])[0]
300
313
  encrypted_strings_offset = pe.get_offset_from_rva(encrypted_strings_rva - image_base)
301
314
  step_size = 0x80
302
315
  counter = 2
303
316
  for i in range(12):
304
- encrypted_string = data[encrypted_strings_offset:encrypted_strings_offset+40]
305
- decoded_c2 = chacha20_xor(encrypted_string, key, nonce, counter).split(b'\x00', 1)[0]
317
+ encrypted_string = data[encrypted_strings_offset : encrypted_strings_offset + 40]
318
+ decoded_c2 = chacha20_xor(encrypted_string, key, nonce, counter).split(b"\x00", 1)[0]
306
319
  if contains_non_printable(decoded_c2):
307
320
  break
308
- config_dict["C2"].append(decoded_c2.decode())
321
+ config_dict.setdefault("C2", []).append(decoded_c2.decode())
309
322
  encrypted_strings_offset = encrypted_strings_offset + step_size
310
323
  counter += 2
311
324
 
312
- if config_dict["C2"]:
325
+ if config_dict.get("C2"):
313
326
  # If found C2 servers try to find build ID
314
327
  build_id = get_build_id_new(data)
315
328
  if build_id:
316
329
  config_dict["Build ID"] = build_id
317
330
 
318
-
319
331
  # If no C2s try with the version after Jan 21, 2025
320
- if not config_dict["C2"]:
332
+ if "C2" not in config_dict:
321
333
  offset = yara_scan(data, RULE_SOURCE_LUMMA)
322
334
  if offset:
323
335
  key = data[offset + 16 : offset + 48]
@@ -327,7 +339,7 @@ def extract_config(data):
327
339
  try:
328
340
  start_offset = offset + 56 + (i * 4)
329
341
  end_offset = start_offset + 4
330
- c2_dword_rva = struct.unpack('i', data[start_offset : end_offset])[0]
342
+ c2_dword_rva = struct.unpack("i", data[start_offset:end_offset])[0]
331
343
  if pe:
332
344
  c2_dword_offset = pe.get_offset_from_rva(c2_dword_rva - image_base)
333
345
  else:
@@ -345,16 +357,14 @@ def extract_config(data):
345
357
  except Exception:
346
358
  continue
347
359
 
348
- if config_dict["C2"] and pe is not None:
360
+ if "C2" in config_dict and config_dict["C2"] and pe is not None:
349
361
  # If found C2 servers try to find build ID
350
362
  build_id = get_build_id(pe, data)
351
363
  if build_id:
352
364
  config_dict["Build ID"] = build_id
353
365
 
354
-
355
366
  # If no C2s try with version prior to Jan 21, 2025
356
- if not config_dict["C2"]:
357
-
367
+ if "C2" not in config_dict:
358
368
  try:
359
369
  if pe is not None:
360
370
  rdata = get_rdata(pe, data)
@@ -374,20 +384,19 @@ def extract_config(data):
374
384
  decoded_c2 = xor_data(encoded_c2, xor_key)
375
385
 
376
386
  if not contains_non_printable(decoded_c2):
377
- config_dict["C2"].append(decoded_c2.decode())
387
+ config_dict.setdefault("C2", []).append(decoded_c2.decode())
378
388
  except Exception:
379
389
  continue
380
390
 
381
391
  except Exception:
382
392
  return
383
393
 
384
- if config_dict["C2"] and pe is not None:
394
+ if "C2" in config_dict and pe is not None:
385
395
  # If found C2 servers try to find build ID
386
396
  build_id = get_build_id(pe, data)
387
397
  if build_id:
388
398
  config_dict["Build ID"] = build_id
389
399
 
390
-
391
400
  return config_dict
392
401
 
393
402
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "CAPE-parsers"
3
- version = "0.1.42"
3
+ version = "0.1.45"
4
4
  description = "CAPE: Malware Configuration Extraction"
5
5
  authors = ["Kevin O'Reilly <kev@capesandbox.com>", "doomedraven <doomedraven@capesandbox.com>"]
6
6
  license = "MIT"
@@ -23,7 +23,7 @@ maco = "1.1.8"
23
23
  yara-python = ">=4.5.1"
24
24
  dnfile = ">=0.15.1"
25
25
  dncil = ">=1.0.2"
26
- unicorn = "2.1.1"
26
+ unicorn = ">=2.1.1"
27
27
  rat-king-parser = ">=4.1.0"
28
28
 
29
29
  ruff = ">=0.7.2"
@@ -1,43 +0,0 @@
1
- import base64
2
- import re
3
-
4
- str_hash_data = 'd6052c4fe86a6346964a6bbbe2423e20'
5
- str_alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '
6
-
7
- def is_ascii(s):
8
- return all(c < 128 or c == 0 for c in s)
9
-
10
- def decrypt(str_data, str_hash_data, str_alphabet):
11
- str_hash = ''
12
-
13
- for i in range(len(str_data)):
14
- str_hash += str_hash_data[i % len(str_hash_data)]
15
-
16
- out = ''
17
-
18
- for i in range(len(str_data)):
19
- if str_data[i] not in str_alphabet:
20
- out += str_data[i]
21
- continue
22
- alphabet_count = str_alphabet.find(str_data[i])
23
- hash_count = str_alphabet.find(str_hash[i])
24
- index_calc = (alphabet_count + len(str_alphabet) - hash_count) % len(str_alphabet)
25
- out += str_alphabet[index_calc]
26
-
27
- return base64.b64decode(out)
28
-
29
- file_data = open('/tmp/amadey.bin','rb').read()
30
-
31
- strings = []
32
- for m in re.finditer(rb'[a-zA-Z =0-9]{4,}',file_data):
33
- strings.append(m.group().decode('utf-8'))
34
-
35
- for s in strings:
36
- try:
37
- temp = decrypt(s, str_hash_data, str_alphabet)
38
- if is_ascii(temp) and len(temp) > 3:
39
- print(temp.decode('utf-8'))
40
- except:
41
- continue
42
-
43
- decrypt('1RydQIOr3Zcp6emn RYv8IGzgUKS6r5ThSdqDVBERAP2Ir 0JQ1=', str_hash_data, str_alphabet)
File without changes
File without changes