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