Session Control

What are Sessions?

A session refers to an automation-enabled running instance of x64dbg.

Each instance of the debugger you launch or attach to has a session ID allocated to it. The automation client relies on sessions to know which debugger instance to communicate with. For all intents and purposes the session ID is equivalent to the debugger PID.

After launching x64dbg with the plugin installed its session ID and port binds can be seen in the startup log:

[x64dbg-automate] Allocated session ID: 12584
[x64dbg-automate] Allocated PUB/SUB port: 49759
[x64dbg-automate] Allocated REQ/REP port: 52085

Sessions can also be discovered programmatically - with PIDs, command lines, working directories, and window titles provided for disambiguation.

Example: Sessions

"""
Example: Session Control (32/64 bit)
"""
import subprocess
import sys
from x64dbg_automate import X64DbgClient

if len(sys.argv) != 2:
    print("Usage: python sessions.py <x64dbg_path>")
    quit(1)

print('[+] Creating an x64dbg Automate session using start_session')
client1 = X64DbgClient(x64dbg_path=sys.argv[1])
client1.start_session(r'c:\Windows\system32\winver.exe')

print('[+] Starting an unconnected session using subprocess.Popen')
client2 = X64DbgClient(x64dbg_path=sys.argv[1])
proc = subprocess.Popen([sys.argv[1]], executable=sys.argv[1])

print('[+] Waiting for the unconnected session to start')
X64DbgClient.wait_for_session(proc.pid)

print('[+] Listing running sessions')
sessions = X64DbgClient.list_sessions()
print(sessions)

print('[+] Terminating the first session')
client1.terminate_session()

print('[+] Listing running sessions')
sessions = X64DbgClient.list_sessions()
print(sessions)

print('[+] Attaching to the second session')
client2.attach_session(sessions[0].pid)

print('[+] Detaching from the second session')
client2.detach_session()

print('[+] Re-attaching to the second session')
client2.attach_session(sessions[0].pid)

print('[+] Terminating the second session')
client2.terminate_session()
[+] Creating an x64dbg Automate session using start_session
[+] Starting an unconnected session using subprocess.Popen
[+] Waiting for the unconnected session to start
[+] Listing running sessions
[DebugSession(pid=11396, lockfile_path='C:\\Users\\dariu\\AppData\\Local\\Temp\\xauto_session.11396.lock', cmdline=['C:\\re\\x64dbg_dev\\release\\x64\\x64dbg.exe'], cwd='C:\\re\\x64dbg_dev\\release\\x64', window_title='winver.exe - PID: 30944 - Module: ntdll.dll - Thread: Main Thread 20648 - x64dbg', sess_req_rep_port=54561, sess_pub_sub_port=60710), DebugSession(pid=26000, lockfile_path='C:\\Users\\dariu\\AppData\\Local\\Temp\\xauto_session.26000.lock', cmdline=['C:\\re\\x64dbg_dev\\release\\x64\\x64dbg.exe'], cwd='C:\\re\\x64dbg_dev\\release\\x64', window_title='x64dbg', sess_req_rep_port=53337, sess_pub_sub_port=61219)]
[+] Terminating the first session
[+] Listing running sessions
[DebugSession(pid=26000, lockfile_path='C:\\Users\\dariu\\AppData\\Local\\Temp\\xauto_session.26000.lock', cmdline=['C:\\re\\x64dbg_dev\\release\\x64\\x64dbg.exe'], cwd='C:\\re\\x64dbg_dev\\release\\x64', window_title='x64dbg', sess_req_rep_port=53337, sess_pub_sub_port=61219)]   
[+] Attaching to the second session
[+] Detaching from the second session
[+] Re-attaching to the second session
[+] Terminating the second session

API Method Reference

start_session(target_exe='', cmdline='', current_dir='')

Start a new x64dbg session and optionally load an executable into it. If target_exe is not provided, the debugger starts without any executable. This is useful for performing configuration before the debuggee is loaded.

Parameters:

Name Type Description Default
target_exe str

The path to the target executable (optional)

''
cmdline str

The command line arguments to pass to the executable (optional)

''
current_dir str

The current working directory to set for the executable (optional)

''

Returns:

Type Description
int

The debug session ID

Source code in x64dbg_automate/__init__.py
def start_session(self, target_exe: str = "", cmdline: str = "", current_dir: str = "") -> int:
    """
    Start a new x64dbg session and optionally load an executable into it. If target_exe is not provided,
    the debugger starts without any executable. This is useful for performing configuration before the debuggee is loaded.

    Args:
        target_exe: The path to the target executable (optional)
        cmdline: The command line arguments to pass to the executable (optional)
        current_dir: The current working directory to set for the executable (optional)

    Returns:
        The debug session ID
    """
    if len(target_exe.strip()) == 0 and (len(cmdline) > 0 or len(current_dir) > 0):
        raise ValueError("cmdline and current_dir cannot be provided without target_exe")

    self.proc = subprocess.Popen([self.x64dbg_path], executable=self.x64dbg_path)
    self.session_pid = self.proc.pid
    self.attach_session(self.session_pid)

    if target_exe.strip() != "":
        if not self.load_executable(target_exe.strip(), cmdline, current_dir):
            self.terminate_session()
            raise RuntimeError("Failed to load executable")
        self.wait_cmd_ready()
    return self.session_pid

start_session_attach(pid)

Start a new x64dbg session and attach to an existing process identified by pid.

Parameters:

Name Type Description Default
pid int

Process Identifier (PID) of the process to attach to.

required

Returns:

Name Type Description
int int

The debug session ID (the PID of the x64dbg process).

Raises:

Type Description
RuntimeError

If attaching to the process fails.

Source code in x64dbg_automate/__init__.py
def start_session_attach(self, pid: int) -> int:
    """
    Start a new x64dbg session and attach to an existing process identified by pid.

    Args:
        pid (int): Process Identifier (PID) of the process to attach to.

    Returns:
        int: The debug session ID (the PID of the x64dbg process).

    Raises:
        RuntimeError: If attaching to the process fails.
    """
    self.proc = subprocess.Popen([self.x64dbg_path], executable=self.x64dbg_path)
    self.session_pid = self.proc.pid
    self.attach_session(self.session_pid)

    if not self.attach(pid):
        self.terminate_session()
        raise RuntimeError("Failed to attach to process")

    self.wait_until_debugging()
    return self.session_pid

attach_session(session_pid)

Attach to an existing x64dbg session

Parameters:

Name Type Description Default
session_pid int

The session ID to attach to (debugger PID)

required
Source code in x64dbg_automate/__init__.py
def attach_session(self, session_pid: int) -> None:
    """
    Attach to an existing x64dbg session

    Args:
        session_pid: The session ID to attach to (debugger PID)
    """
    session = X64DbgClient.wait_for_session(session_pid)
    self.sess_req_rep_port = session.sess_req_rep_port
    self.sess_pub_sub_port = session.sess_pub_sub_port
    self._init_connection()
    self._assert_connection_compat()

detach_session()

Detach from the current x64dbg session, leaving the debugger process running.

Source code in x64dbg_automate/__init__.py
def detach_session(self) -> None:
    """
    Detach from the current x64dbg session, leaving the debugger process running.
    """
    self._close_connection()

terminate_session()

End the current x64dbg session, terminating the debugger process.

Source code in x64dbg_automate/__init__.py
def terminate_session(self) -> None:
    """
    End the current x64dbg session, terminating the debugger process.
    """
    sid = self.session_pid
    self._xauto_terminate_session()
    self._close_connection()
    for _ in range(100):
        time.sleep(0.2)
        if sid not in [p.pid for p in self.list_sessions()]:
            return
    raise TimeoutError("Session did not terminate in a reasonable amount of time")

list_sessions() staticmethod

Lists all active x64dbg sessions

Returns:

Type Description
list[DebugSession]

A list of sessions

Source code in x64dbg_automate/__init__.py
@staticmethod
def list_sessions() -> list[DebugSession]:
    """
    Lists all active x64dbg sessions

    Returns:
        A list of sessions
    """
    sessions: list[DebugSession] = []
    temp_path_cstr = ctypes.create_unicode_buffer(1024)
    if GetTempPathW(1024, temp_path_cstr) == 0:
        temp_path = "c:\\windows\\temp\\"
    else:
        temp_path = temp_path_cstr.value

    locks = glob.glob(f'{temp_path}xauto_session.*.lock')
    for lock in locks:
        while True:
            try:
                with open(lock, 'r') as f:
                    sess_req_rep_port = int(f.readline().strip())
                    sess_pub_sub_port = int(f.readline().strip())

                pid = int(lock.split('.')[-2])
                if psutil.pid_exists(pid):
                    process = psutil.Process(pid)
                    sessions.append(DebugSession(
                        pid=pid,
                        lockfile_path=lock,
                        cmdline=process.cmdline(),
                        cwd=process.cwd(),
                        window_title=X64DbgClient._window_title_for_pid(pid),
                        sess_req_rep_port=sess_req_rep_port,
                        sess_pub_sub_port=sess_pub_sub_port
                    ))
                    break
                else:
                    if time.time() - os.path.getctime(lock) > 10.0:
                        logger.warning(f"Stale lockfile {lock}, removing")
                        os.unlink(lock)
                        break
            except FileNotFoundError:
                # The process exited between the glob and the open
                break

    return sessions

wait_for_session(session_pid, timeout=10) staticmethod

Wait for an x64dbg session to start

Parameters:

Name Type Description Default
session_pid int

The session ID to wait for (debugger PID)

required
timeout int

The maximum time to wait in seconds

10

Returns:

Type Description
DebugSession

The awaited debug session object

Source code in x64dbg_automate/__init__.py
@staticmethod
def wait_for_session(session_pid: int, timeout: int = 10) -> DebugSession:
    """
    Wait for an x64dbg session to start

    Args:
        session_pid: The session ID to wait for (debugger PID)
        timeout: The maximum time to wait in seconds

    Returns:
        The awaited debug session object
    """
    while timeout > 0:
        sessions = X64DbgClient.list_sessions()
        sessions = [s for s in sessions if s.pid == session_pid]
        if session_pid in [s.pid for s in sessions]:
            return sessions[0]
        time.sleep(0.2)
        timeout -= 0.2
    raise TimeoutError("Session did not appear in a reasonable amount of time")

API Model Reference

DebugSession

Represents a debug session in x64dbg Automate

Source code in x64dbg_automate/models.py
class DebugSession(BaseModel):
    """
    Represents a debug session in x64dbg Automate
    """
    pid: int # The process ID of the debugger
    lockfile_path: str # The path to the lockfile for the session
    cmdline: list[str] # The command line arguments used to start the session
    cwd: str # The current working directory of the session
    window_title: str # The title of the x64dbg window
    sess_req_rep_port: int # The port used for zmq request/reply communication
    sess_pub_sub_port: int # The port used for zmq publish/subscribe communication