Skip to content

Commit

Permalink
attach: Change continue opt to stop
Browse files Browse the repository at this point in the history
Also research that lead nowhere
  • Loading branch information
dd86k committed Jan 11, 2024
1 parent 745e42d commit 3ce1960
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 97 deletions.
8 changes: 4 additions & 4 deletions src/adbg/include/windows/ntdll.d
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
/// Command shell and interface to debugger.
/// ntdll bindings.
///
/// Authors: dd86k <dd@dax.moe>
/// Copyright: © dd86k <dd@dax.moe>
/// License: BSD-3-Clause
module adbg.include.windows.ntdll;

version (Windows):
extern(C):

import core.sys.windows.windef;
import core.stdc.config : c_long;
import core.sys.windows.ntdef; // NTSTATUS
import core.sys.windows.ntdll;
import adbg.v2.object.symbols;
import adbg.error;

alias NTSTATUS = c_long;
extern(C):

alias MEMORY_INFORMATION_CLASS = int;
enum
Expand Down
8 changes: 8 additions & 0 deletions src/adbg/include/windows/winnt.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@
/// License: BSD-3-Clause
module adbg.include.windows.winnt;

version (Windows):

public import core.sys.windows.winnt;

extern (Windows):

alias ULONGLONG = ulong;
alias DWORD = uint;

enum PROCESS_SUSPEND_RESUME = 0x0800;

//
// Process specific MEMORY_BASIC_INFORMATION, useful for WoW processes.
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
Expand Down
2 changes: 1 addition & 1 deletion src/adbg/v1/debugger/debugger.d
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ struct adbg_mm_map {
int adbg_mm_maps(adbg_mm_map **mmaps, size_t *mcount, ...) {
version (Windows) {
if (__dynlib_psapi_load())
return adbg_oops(AdbgError.libLoader);
return adbg_errno();

if (g_debuggee.pid == 0) {
return adbg_oops(AdbgError.notAttached);
Expand Down
17 changes: 7 additions & 10 deletions src/adbg/v2/debugger/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ import core.stdc.config : c_long;
import adbg.error;
import adbg.utils.math;

//TODO: uint adbg_memory_pagesize() (0 on error)
// Windows: GetSystemInfo + SYSTEM_INFO.dwPageSize
// Linux: sysconf(_SC_PAGESIZE)

version (Windows) {
import core.sys.windows.winbase; // WriteProcessMemory
import core.sys.windows.winnt;
Expand Down Expand Up @@ -112,18 +108,15 @@ int adbg_memory_read(adbg_process_t *tracee, size_t addr, void *data, uint size)
/// size = Size of data.
/// Returns: Error code.
int adbg_memory_write(adbg_process_t *tracee, size_t addr, void *data, uint size) {
if (tracee == null || data == null) {
if (tracee == null || data == null)
return adbg_oops(AdbgError.nullArgument);
}

//TODO: FreeBSD/NetBSD/OpenBSD: PT_IO
version (Windows) {
if (WriteProcessMemory(tracee.hpid, cast(void*)addr, data, size, null) == 0)
return adbg_oops(AdbgError.os);
return 0;
} else version (linux) { // Based on https://www.linuxjournal.com/article/6100
import core.stdc.errno : errno;

c_long *user = cast(c_long*)data; /// user data pointer
int i; /// offset index
int j = size / c_long.sizeof; /// number of "blocks" to process
Expand All @@ -134,6 +127,7 @@ int adbg_memory_write(adbg_process_t *tracee, size_t addr, void *data, uint size
return adbg_oops(AdbgError.os);
}

//TODO: Save remainder before writing
j = size % c_long.sizeof;
if (j) {
if (ptrace(PT_POKEDATA, tracee.pid,
Expand Down Expand Up @@ -171,6 +165,7 @@ enum AdbgPageUse : ubyte {
}

private enum MEM_MAP_NAME_LEN = 512;
//TODO: Map groups
/// Represents a mapped memory region.
struct adbg_memory_map_t {
//TODO: type (file, free, commited, etc.)
Expand All @@ -184,12 +179,14 @@ struct adbg_memory_map_t {
ubyte type;
/// Page attributes (large, etc.)
ubyte attributes;
//TODO: Should take this out into its own function
// e.g., adbg_memory_get_map_name()
/// Module name or mapped file.
char[MEM_MAP_NAME_LEN] name;
}

//TODO: Options for process modules and process memory regions separatively
//TODO: Option to include free memory regions (linux: ---p)
//TODO: Option to include free/reserved memory regions (linux: ---p)
// Memory options for adbg_memory_maps.
/*enum AdbgMapOpt {
// Only get the memory regions for this process.
Expand Down Expand Up @@ -239,7 +236,7 @@ L_OPTION:

version (Windows) {
if (__dynlib_psapi_load()) // EnumProcessModules, QueryWorkingSet
return adbg_oops(AdbgError.libLoader);
return adbg_errno();

size_t uindex; /// (user) map index

Expand Down
146 changes: 64 additions & 82 deletions src/adbg/v2/debugger/process.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,39 @@ module adbg.v2.debugger.process;
// Linux: Send SIGSTOP/SIGCONT signals via kill(2)
//TODO: List threads of process

import adbg.include.c.stdlib : malloc, calloc, free;
import adbg.include.c.stdio : snprintf;
import adbg.include.c.stdlib; // malloc, calloc, free, exit;
import adbg.include.c.stdio; // snprintf;
import adbg.include.c.stdarg;
import core.stdc.string : memset;
import adbg.platform, adbg.error;
import adbg.platform;
import adbg.error;
import adbg.utils.strings : adbg_util_argv_flatten;
import adbg.v2.debugger.exception : adbg_exception_t, adbg_exception_translate;
import adbg.v2.debugger.breakpoint : adbg_breakpoint_t;
import adbg.v2.object.machines;
import core.stdc.string : memset;

version (Windows) {
import core.sys.windows.windows;
import adbg.include.windows.wow64;
import adbg.include.windows.psapi_dyn : __dynlib_psapi_load,
EnumProcesses, EnumProcessModules,
GetModuleBaseNameA;
import adbg.include.windows.psapi_dyn;
import adbg.include.windows.winnt;
import core.sys.windows.basetsd;
import core.sys.windows.winbase;
import core.sys.windows.tlhelp32;
} else version (Posix) {
import adbg.include.posix.mann;
import adbg.include.posix.ptrace;
import adbg.include.posix.unistd : clone, CLONE_PTRACE;
import core.sys.posix.sys.stat;
import core.sys.posix.sys.wait : waitpid, SIGCONT, WUNTRACED;
import core.sys.posix.signal;
import core.sys.posix.sys.uio;
import core.sys.posix.fcntl : open, O_RDONLY;
import core.sys.posix.unistd : read, close, execve;
import core.stdc.stdlib : exit, malloc, free;
import adbg.include.posix.mann;
import adbg.include.posix.ptrace;
import adbg.include.posix.unistd : clone, CLONE_PTRACE;
import adbg.include.linux.user;
private enum __WALL = 0x40000000;

version (linux) {
import adbg.include.linux.user;
private enum __WALL = 0x40000000;
}
}

version (linux)
Expand Down Expand Up @@ -385,11 +389,12 @@ private int adbg_linux_child(void* arg) {
}

enum AdbgAttachOpt {
/// Continue execution when attached.
/// When set, stop execution when attached.
/// Note: Currently not supported on Windows. Will always stop.
/// Type: int
/// Default: 0
continue_ = 1,
/// Kill tracee when debugger exits.
stop = 1,
/// When set, kill tracee when debugger exits.
/// Type: int
/// Default: 0
exitkill = 2,
Expand All @@ -403,23 +408,22 @@ enum AdbgAttachOpt {
/// tracee = Tracee reference.
/// pid = Process ID.
/// ... = Options. Pass 0 for none or to end list.
///
/// Returns: Error code.
int adbg_attach(adbg_process_t *tracee, int pid, ...) {
if (tracee == null)
return adbg_oops(AdbgError.nullArgument);

int continue_; // continue execution after attaching
int exitkill; // kill child if debugger quits
return adbg_oops(AdbgError.invalidArgument);
if (pid <= 0)
return adbg_oops(AdbgError.invalidArgument);

va_list list = void;
va_start(list, pid);

int stop;
int exitkill;
L_OPTION:
switch (va_arg!int(list)) {
case 0: break;
case AdbgAttachOpt.continue_:
continue_ = va_arg!int(list);
case AdbgAttachOpt.stop:
stop = va_arg!int(list);
goto L_OPTION;
case AdbgAttachOpt.exitkill:
exitkill = va_arg!int(list);
Expand All @@ -428,70 +432,46 @@ L_OPTION:
return adbg_oops(AdbgError.invalidOption);
}

version (Trace) trace("pid=%d stop=%d exitkill=%d", pid, stop, exitkill);

tracee.creation = AdbgCreation.attached;

version (Windows) {
// Creates events:
// - CREATE_PROCESS_DEBUG_EVENT
// - CREATE_THREAD_DEBUG_EVENT
if (DebugActiveProcess(pid) == FALSE)
return adbg_oops(AdbgError.os);
//TODO: Integrate ObRegisterCallbacks?
// https://blog.xpnsec.com/anti-debug-openprocess/

// NOTE: Emulate ProcessIdToHandle
// Uses NtOpenProcess with ClientId.UniqueProcess=PID
// Uses PROCESS_ALL_ACCESS, but let's start with the basics
tracee.pid = cast(DWORD)pid;
tracee.hpid = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ |
PROCESS_SUSPEND_RESUME |
PROCESS_QUERY_INFORMATION,
FALSE,
cast(DWORD)pid);
if (tracee.hpid == null)
return adbg_oops(AdbgError.os);

// Default is TRUE on Windows
// Check if process already has an attached debugger
BOOL dbgpresent = void;
if (CheckRemoteDebuggerPresent(tracee.hpid, &dbgpresent) == FALSE)
return adbg_oops(AdbgError.os);
if (dbgpresent)
return adbg_oops(AdbgError.debuggerPresent);

// Breaks into remote process and initiates break-in
if (DebugActiveProcess(tracee.pid) == FALSE)
return adbg_oops(AdbgError.os);

// DebugActiveProcess, by default, kills the process on exit.
if (exitkill == false)
DebugSetProcessKillOnExit(FALSE);

// DebugActiveProcess stops debuggee when attached
if (continue_) {
DEBUG_EVENT e = void;

wait: while (WaitForDebugEvent(&e, 100)) {
switch (e.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT:
case CREATE_THREAD_DEBUG_EVENT:
continue;
case EXCEPTION_DEBUG_EVENT:
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_CONTINUE);
continue;
default:
break wait;
}
}

// This was my second attempt, but, could be useful later...
/*import core.sys.windows.tlhelp32 :
CreateToolhelp32Snapshot, Thread32First, Thread32Next,
THREADENTRY32, TH32CS_SNAPTHREAD;
// CreateToolhelp32Snapshot ignores th32ProcessID for TH32CS_SNAPTHREAD
HANDLE h_thread_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (h_thread_snapshot == INVALID_HANDLE_VALUE)
return adbg_oops(AdbgError.os);
THREADENTRY32 te32 = void;
te32.dwSize = THREADENTRY32.sizeof;
// If the first fails, all successive ones will fail
if (Thread32First(h_thread_snapshot, &te32) == FALSE)
{
CloseHandle(h_thread_snapshot);
return adbg_oops(AdbgError.os);
}
do {
if (te32.th32OwnerProcessID == pid) {
ContinueDebugEvent(pid, te32.th32ThreadID, DBG_CONTINUE);
}
} while (Thread32Next(h_thread_snapshot, &te32));*/
}
} else version (Posix) {
if (ptrace(continue_ ? PT_SEIZE : PT_ATTACH, pid, null, null) < 0)
version (Trace) if (stop) trace("Sending break...");
if (ptrace(stop ? PT_ATTACH : PT_SEIZE, pid, null, null) < 0)
return adbg_oops(AdbgError.os);

tracee.pid = cast(pid_t)pid;
Expand All @@ -501,7 +481,7 @@ L_OPTION:
}

tracee.creation = AdbgCreation.attached;
tracee.status = continue_ ? AdbgStatus.running : AdbgStatus.paused;
tracee.status = stop ? AdbgStatus.paused : AdbgStatus.running;
return 0;
}

Expand Down Expand Up @@ -690,6 +670,7 @@ L_DEBUG_LOOP:
// - First SIGTRAP does NOT contain int3
// - Windows does, though, and points to it
// - gdbserver and lldb never attempt to do such thing anyway
// - RIP-1 (x86) could *maybe* point to int3 or similar.
// NOTE: Newer D compilers fixed siginfo_t as a whole
// for version (linux). Noticed on DMD 2.103.1.
// Old glibc: ._sifields._sigfault.si_addr
Expand Down Expand Up @@ -961,8 +942,9 @@ struct adbg_process_list_t {
}

//TODO: Redo adbg_process_enumerate
// 1. List of PIDs instead, use adbg_process_get_name for file path.
// 2. Allocate structure with count + items
// int adbg_process_list(adbg_process_list_t*)
// - List of PIDs instead, use adbg_process_get_name for file path.

// NOTE: For the C vararg to work, list is a parameter instead of a return value.
/// Enumerate running processes.
///
Expand Down Expand Up @@ -1006,7 +988,7 @@ L_OPTION:
version (Windows) {
if (__dynlib_psapi_load()) {
free(list.processes);
return adbg_oops(AdbgError.libLoader);
return adbg_errno();
}

// Allocate temp PID buffer
Expand Down Expand Up @@ -1038,8 +1020,8 @@ L_OPTION:

adbg_process_t *proc = &list.processes[count++];
proc.pid = pid;
proc.hpid = procHandle;
proc.tid = 0;
proc.htid = procHandle;

//TODO: Is EnumProcessModules really necessary?
HMODULE hmod = void;
Expand Down

0 comments on commit 3ce1960

Please sign in to comment.