Skip to content

Commit 245bed8

Browse files
committed
Merge branch 'master' into staging
2 parents 747a069 + 22992be commit 245bed8

File tree

104 files changed

+2221
-1038
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+2221
-1038
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,4 @@ If you use CAPEv2 in your work, please cite it as specified in the "Cite this re
228228

229229
### Docs
230230
* [ReadTheDocs](https://capev2.readthedocs.io/en/latest/#)
231+
* [DeepWiki](https://deepwiki.com/kevoreilly/CAPEv2/1-overview) - AI generated, some might be wrong but generally pretty accurate.

agent/agent.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import http.server
1010
import ipaddress
1111
import json
12-
import multiprocessing
1312
import os
1413
import platform
1514
import random
@@ -25,9 +24,8 @@
2524
import time
2625
import traceback
2726
from io import StringIO
28-
from multiprocessing.synchronize import Event as EventClass
2927
from threading import Lock
30-
from typing import Iterable, Optional
28+
from typing import Iterable
3129
from zipfile import ZipFile
3230

3331
try:
@@ -45,7 +43,7 @@
4543
if sys.maxsize > 2**32 and sys.platform == "win32":
4644
sys.exit("You should install python3 x86! not x64")
4745

48-
AGENT_VERSION = "0.18"
46+
AGENT_VERSION = "0.19"
4947
AGENT_FEATURES = [
5048
"execpy",
5149
"execute",
@@ -97,7 +95,7 @@ def _missing_(cls, value):
9795
AGENT_BROWSER_EXT_PATH = ""
9896
AGENT_BROWSER_LOCK = Lock()
9997
ANALYZER_FOLDER = ""
100-
agent_mutexes: dict[str, str] = {}
98+
agent_mutexes: dict = {}
10199
"""Holds handles of mutexes held by the agent."""
102100
state = {
103101
"status": Status.INIT,
@@ -180,7 +178,7 @@ def run(
180178
self,
181179
host: ipaddress.IPv4Address = ipaddress.IPv4Address("0.0.0.0"),
182180
port: int = 8000,
183-
event: Optional[EventClass] = None,
181+
event = None,
184182
):
185183
socketserver.ThreadingTCPServer.allow_reuse_address = True
186184
self.s = socketserver.ThreadingTCPServer((str(host), port), self.handler)
@@ -324,8 +322,8 @@ def headers(self, obj):
324322

325323

326324
class request:
327-
form: dict[str, str] = {}
328-
files: dict[str, str] = {}
325+
form: dict = {}
326+
files: dict = {}
329327
client_ip = None
330328
client_port = None
331329
method = None
@@ -378,7 +376,7 @@ def get_subprocess_status():
378376
"""Return the subprocess status."""
379377
async_subprocess = state.get("async_subprocess")
380378
message = "Analysis status"
381-
exitcode = async_subprocess.exitcode
379+
exitcode = async_subprocess.poll()
382380
if exitcode is None or (sys.platform == "win32" and exitcode == 259):
383381
# Process is still running.
384382
state["status"] = Status.RUNNING
@@ -713,9 +711,7 @@ def background_subprocess(command_args, cwd, base64_encode, shell=False):
713711

714712
def spawn(args, cwd, base64_encode, shell=False):
715713
"""Kick off a subprocess in the background."""
716-
run_subprocess_args = [args, cwd, base64_encode, shell]
717-
proc = multiprocessing.Process(target=background_subprocess, name=f"child process {args[1]}", args=run_subprocess_args)
718-
proc.start()
714+
proc = subprocess.Popen(args, cwd=cwd, shell=shell)
719715
state["status"] = Status.RUNNING
720716
state["description"] = ""
721717
state["async_subprocess"] = proc
@@ -799,7 +795,6 @@ def do_kill():
799795

800796

801797
if __name__ == "__main__":
802-
multiprocessing.set_start_method("spawn")
803798
parser = argparse.ArgumentParser()
804799
parser.add_argument("host", nargs="?", default="0.0.0.0")
805800
parser.add_argument("port", type=int, nargs="?", default=8000)

agent/test_agent.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pathlib
1010
import random
1111
import shutil
12+
import subprocess
1213
import sys
1314
import tempfile
1415
import time
@@ -39,8 +40,8 @@ class TestAgentFunctions:
3940
@mock.patch("sys.platform", "win32")
4041
def test_get_subprocess_259(self):
4142
mock_process_id = 999998
42-
mock_subprocess = mock.Mock(spec=multiprocessing.Process)
43-
mock_subprocess.exitcode = 259
43+
mock_subprocess = mock.Mock(spec=subprocess.Popen)
44+
mock_subprocess.poll = mock.Mock(return_value=259)
4445
mock_subprocess.pid = mock_process_id
4546
with mock.patch.dict(agent.state, {"async_subprocess": mock_subprocess}):
4647
actual = agent.get_subprocess_status()

analyzer/windows/bin/PPLinject.exe

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

analyzer/windows/bin/loader.exe

6 KB
Binary file not shown.
-6.5 KB
Binary file not shown.

analyzer/windows/data/yara/DarkGateLoader.yar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ rule DarkGateLoader
66
cape_options = "bp0=$decrypt1+30,bp0=$decrypt2+29,action0=dump:eax::ebx,bp1=$decrypt3+80,action1=dumpsize:eax,bp2=$decrypt3+124,hc2=1,action2=dump:eax,count=0"
77
packed = "b15e4b4fcd9f0d23d902d91af9cc4e01417c426e55f6e0b4ad7256f72ac0231a"
88
strings:
9-
$loader = {6C 6F 61 64 65 72}
9+
$loader = "loader"
1010
$decrypt1 = {B? 01 00 00 00 8B [3] E8 [4] 8B D7 32 54 [4] 88 54 18 FF 4? 4? 75}
1111
$decrypt2 = {B? 01 00 00 00 8B [2] E8 [4] 8B D7 2B D3 [4] 88 54 18 FF 4? 4? 75}
1212
$decrypt3 = {89 85 [4] 8B 85 [4] 8B F0 8D BD [4] B? 10 [3] F3 A5 8B 85 [4] 33 D2 [2] 8B 85 [4] 99}

analyzer/windows/data/yara/Socks5Systemz.yar

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ rule Socks5Systemz
33
meta:
44
author = "kevoreilly"
55
description = "Socks5Systemz config extraction"
6-
cape_options = "br0=user32::wsprintfA,action1=string:[esp],count=0,typestring=Socks5Systemz Config"
6+
cape_options = "br0=user32::wsprintfA,br1=ntdll::sprintf,action2=string:[esp],action3=string:[esp],count=0,typestring=Socks5Systemz Config"
77
packed = "9b997d0de3fe83091726919a0dc653e22f8f8b20b1bb7d0b8485652e88396f29"
88
strings:
99
$chunk1 = {0F B6 84 8A [4] E9 [3] (00|FF)}
1010
$chunk2 = {0F B6 04 8D [4] E9 [3] (00|FF)}
11-
$chunk3 = {0F B6 04 8D [4] E9 [3] (00|FF)}
12-
$chunk4 = {0F B6 04 8D [4] E9 [3] (00|FF)}
13-
$chunk5 = {66 0F 6F 05 [4] E9 [3] (00|FF)}
14-
$chunk6 = {F0 0F B1 95 [4] E9 [3] (00|FF)}
15-
$chunk7 = {83 FA 04 E9 [3] (00|FF)}
11+
$chunk3 = {66 0F 6F 05 [4] E9 [3] (00|FF)}
12+
$chunk4 = {F0 0F B1 95 [4] E9 [3] (00|FF)}
13+
$chunk5 = {83 FA 04 E9 [3] (00|FF)}
14+
$chunk6 = {8A 04 8D [4] E9 [3] (00|FF)}
15+
$chunk7 = {83 C4 04 83 C4 04 E9}
16+
$chunk8 = {83 C2 04 87 14 24 5C E9}
1617
condition:
17-
uint16(0) == 0x5A4D and 6 of them
18+
uint16(0) == 0x5A4D and 5 of them
1819
}

analyzer/windows/dll/capemon.dll

11.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)