20#include "KittyUtils.hpp"
21#include "KittyMemoryEx.hpp"
24#define KT_PTRACE_GETREG_REQ PTRACE_GETREGSET
25#define KT_PTRACE_SETREG_REQ PTRACE_SETREGSET
27#define KT_PTRACE_GETREG_REQ PTRACE_GETREGS
28#define KT_PTRACE_SETREG_REQ PTRACE_SETREGS
32#define user_regs_struct user_regs
36#define KT_CPSR_T_MASK (1u << 5)
39#if defined(__aarch64__)
40#define KT_CPSR_SS_MASK (1ULL << 21)
41#define KT_CPSR_D_MASK (1ULL << 9)
42#define KT_CPSR_BTYPE_MASK (3ULL << 10)
50#define KT_REG_SYSNR eax
51#define KT_REG_ARGS_NUM 0
53#elif defined(__x86_64__)
58#define KT_REG_SYSNR rax
59#define KT_REG_ARGS_NUM 6
61#elif defined(__aarch64__)
62#define KT_REG_RET regs[0]
66#define KT_REG_SYSNR regs[8]
67#define KT_REG_LR regs[30]
68#define KT_REG_CPSR pstate
69#define KT_REG_ARGS_NUM 8
72#define KT_REG_RET uregs[0]
73#define KT_REG_PC uregs[15]
74#define KT_REG_IP uregs[15]
75#define KT_REG_SP uregs[13]
76#define KT_REG_SYSNR uregs[7]
77#define KT_REG_LR uregs[14]
78#define KT_REG_CPSR uregs[16]
79#define KT_REG_ARGS_NUM 4
92 KT_RP_CALL_CONT_FAILED,
93 KT_RP_CALL_REGS_FAILED,
94 KT_RP_CALL_WAIT_FAILED,
95 KT_RP_CALL_MEM_FAILED,
96 KT_RP_CALL_STEP_FAILED,
97 KT_RP_CALL_NOT_STOPPED,
98 KT_RP_CALL_MISMATCH_STOP,
99 KT_RP_CALL_INVALID_NARGS,
107 KT_HW_BP_EXECUTE = 0,
118 KT_HW_BP_SIZE_EXEC = 0,
152#if defined(__aarch64__)
153 static constexpr int EXEC_SIZE = 4;
154 static constexpr uint8_t BRKP[] = {0x00, 0x00, 0x20, 0xd4};
155 static constexpr uint8_t SYSCALL[] = {0x01, 0x00, 0x00, 0xd4};
156 static constexpr uint8_t NOP[] = {0x1f, 0x20, 0x03, 0xd5};
157#elif defined(__arm__)
158 static constexpr int THUMB_EXEC_SIZE = 2;
159 static constexpr uint8_t THUMB_BRKP[] = {0x00, 0xbe};
160 static constexpr uint8_t THUMB_SYSCALL[] = {0x00, 0xdf};
161 static constexpr uint8_t THUMB_NOP[] = {0x00, 0xbf};
163 static constexpr int EXEC_SIZE = 4;
164 static constexpr uint8_t BRKP[] = {0x70, 0x00, 0x20, 0xe1};
165 static constexpr uint8_t SYSCALL[] = {0x00, 0x00, 0x00, 0xef};
166 static constexpr uint8_t NOP[] = {0x00, 0xf0, 0x20, 0xe3};
167#elif defined(__x86_64__)
168 static constexpr int EXEC_SIZE = 1;
169 static constexpr uint8_t BRKP[] = {0xcc};
170 static constexpr uint8_t SYSCALL[] = {0x0f, 0x05};
171 static constexpr uint8_t NOP[] = {0x90};
172#elif defined(__i386__)
173 static constexpr int EXEC_SIZE = 1;
174 static constexpr uint8_t BRKP[] = {0xcc};
175 static constexpr uint8_t SYSCALL[] = {0xcd, 0x80};
176 static constexpr uint8_t NOP[] = {0x90};
180#define KT_REGS_ALIGN_STACK(regs) \
183 regs.KT_REG_SP = uintptr_t(intptr_t(intptr_t(regs.KT_REG_SP) & intptr_t(~0xF))); \
185#define KT_REGS_ALIGN_STACK_N(regs, n) \
188 regs.KT_REG_SP = uintptr_t(intptr_t((intptr_t(regs.KT_REG_SP) - intptr_t(n)) & intptr_t(~0xF))); \
190#define KT_ALIGN_STACK(s) \
193 s = uintptr_t(intptr_t(intptr_t(s) & intptr_t(~0xF))); \
195#define KT_ALIGN_STACK_N(s, n) \
198 s = uintptr_t(intptr_t((intptr_t(s) - intptr_t(n)) & intptr_t(~0xF))); \
206 KT_RP_CALL_STATUS status = KT_RP_CALL_FAILED;
221 uintptr_t _defaultCaller;
222 bool _attached, _seized, _autoRestoreRegs;
223 int _remoteCallTimeout;
224 uintptr_t _syscallGadget;
227 static inline uintptr_t _toRemoteArg(T &&v)
229 using DecayedType = std::decay_t<T>;
230 static_assert(std::is_integral_v<DecayedType> || std::is_enum_v<DecayedType> ||
231 std::is_pointer_v<DecayedType> || std::is_null_pointer_v<DecayedType>,
232 "remote call arguments must be integers, enums or pointers");
233 return static_cast<uintptr_t
>(v);
236 kitty_rp_call_t _callFunctionFrom(uintptr_t callerAddress, uintptr_t functionAddress,
int nargs, ...);
241 : _pid(0), _defaultCaller(0), _attached(
false), _seized(
false), _autoRestoreRegs(
true), _remoteCallTimeout(0),
277 return _pid >= 0 ? kill(_pid, 0) == 0 :
false;
286 KittyMemoryEx::ProcStatus::parse(_pid, &pstatus);
287 int tracerPID = pstatus.
getInt(
"TracerPid");
288 return _pid >= 0 && getpid() == tracerPID;
347 pid_t
wait(
int *status,
int options,
int timeout_ms = 0)
const;
360 bool step(
int steps = 1)
const;
376 if (!si || !_pid || !_attached)
378 return ptrace(PTRACE_GETSIGINFO, _pid, 0, si) == 0;
402#if defined(__x86_64__) || defined(__i386__)
404 peekMem(regs->KT_REG_SP, &ret,
sizeof(uintptr_t));
407#elif defined(__aarch64__) || defined(__arm__)
408 return regs->KT_REG_LR;
420 template <
typename T>
423 static_assert(std::is_arithmetic<T>::value,
"T must be a numeric type!");
425#if defined(__x86_64__)
445 peekMem(regs->KT_REG_SP + 8 + (arg_num - 6) * 8, &arg,
sizeof(uintptr_t));
448#elif defined(__i386__)
450 peekMem(regs->KT_REG_SP + 4 + (arg_num * 4), &arg,
sizeof(uintptr_t));
453#elif defined(__aarch64__)
455 return regs->regs[arg_num];
458 peekMem(regs->KT_REG_SP + (arg_num - 8) * 8, &arg,
sizeof(uintptr_t));
461#elif defined(__arm__)
463 return regs->uregs[arg_num];
466 peekMem(regs->KT_REG_SP + (arg_num - 4) * 4, &arg,
sizeof(uintptr_t));
482 size_t peekMem(uintptr_t addr,
void *buf,
size_t size)
const;
495 size_t pokeMem(uintptr_t addr,
const void *buf,
size_t size)
const;
502 return _defaultCaller;
511 _defaultCaller = caller;
519 return _autoRestoreRegs;
528 _autoRestoreRegs = flag;
536 return _remoteCallTimeout;
545 _remoteCallTimeout = ms > 0 ? ms : 0;
553 return _syscallGadget;
562 _syscallGadget = address;
572 template <
class... Args>
575 return _callFunctionFrom(callerAddress, functionAddress,
sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
584 template <
class... Args>
587 return _callFunctionFrom(_defaultCaller, functionAddress,
sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
597 template <
class... Args>
600 return _callSyscall(sysnr,
sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
613 const std::function<
bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
630 const std::function<
bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
642 const std::function<
bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
654 bool setHwBreakpoint(uintptr_t address, KT_HW_BP_TYPE type, KT_HW_BP_SIZE size,
int slot);
Class to retrieve process status information.
Definition KittyMemoryEx.hpp:145
long long getInt(const std::string &key) const
Retrieves the integer value associated with a key.
Definition KittyMemoryEx.hpp:235
uintptr_t syscallGadget() const
Returns the syscall gadget address for remote syscalls.
Definition KittyTrace.hpp:551
bool cont(int sig=0)
Continue the traced process thread.
void setAutoRestoreRegs(bool flag)
Sets the automatic registers restore flag for remote function calls.
Definition KittyTrace.hpp:526
KT_BP_RESULT setHardBreakpointAndWait(uintptr_t address, KT_HW_BP_TYPE type, KT_HW_BP_SIZE size, int slot, const std::function< bool(uintptr_t bp_addr, user_regs_struct regs)> &cb, int timeout_ms)
Set and wait for a hardware breakpoint/watchpoint at a single address.
uintptr_t defaultCaller() const
Returns the default caller address for remote function calls.
Definition KittyTrace.hpp:500
bool stop()
Stop the traced process thread.
bool getSignalInfo(siginfo_t *si) const
Get the signal information of the process.
Definition KittyTrace.hpp:374
bool waitSyscall() const
Wait for the process to enter or exit a syscall.
bool waitStep(int steps=1) const
Single-step and wait the process.
bool seize(int options=0)
Seize the process.
bool autoRestoreRegs() const
Returns true if automatic registers restore for remote function calls is enabled, false otherwise.
Definition KittyTrace.hpp:517
bool detach()
Detach from the process.
pid_t pid() const
Returns the PID of the process being traced.
Definition KittyTrace.hpp:267
bool getRegs(user_regs_struct *regs) const
Get the current registers of the process.
void setRemoteCallTimeout(int ms)
Sets the default remote function call timeout in milliseconds.
Definition KittyTrace.hpp:543
bool setOptions(int options)
Set options for the process being traced.
std::vector< pid_t > threads() const
Get a list of all threads in the traced process.
Definition KittyTrace.hpp:295
KT_BP_RESULT setSoftBreakpointAndWait(uintptr_t address, const std::function< bool(uintptr_t bp_addr, user_regs_struct regs)> &cb, int timeout_ms)
Sets and wait for software breakpoint at a given address.
void setDefaultCaller(uintptr_t caller)
Sets the default caller address for remote function calls.
Definition KittyTrace.hpp:509
void setSyscallGadget(uintptr_t address)
Sets the syscall gadget address for remote syscalls.
Definition KittyTrace.hpp:560
kitty_rp_call_t callSyscall(long sysnr, Args &&...a)
Call a syscall in the remote process.
Definition KittyTrace.hpp:598
bool clearHwBreakpoint(KT_HW_BP_TYPE type, int slot)
Clears a hardware breakpoint on a specified address for traced thread.
T getArgFromRegs(user_regs_struct *regs, uint32_t arg_num)
Get the n-th argument value from registers.
Definition KittyTrace.hpp:421
bool step(int steps=1) const
Single-step the process.
bool setRegs(user_regs_struct *regs) const
Set the current registers of the process.
kitty_rp_call_t callFunction(uintptr_t functionAddress, Args &&...a)
Call a function in the remote process.
Definition KittyTrace.hpp:585
size_t pokeMem(uintptr_t addr, const void *buf, size_t size) const
Writes memory from a traced process using PTRACE_POKETEXT. Works around ptrace's word-sized limitatio...
uintptr_t getReturnAddressFromRegs(user_regs_struct *regs)
Get the return address value from registers.
Definition KittyTrace.hpp:400
size_t peekMem(uintptr_t addr, void *buf, size_t size) const
Reads memory from a traced process using PTRACE_PEEKTEXT. Works around ptrace's word-sized limitation...
bool isAttached() const
Check if the process is currently attached.
Definition KittyTrace.hpp:283
bool isAlive() const
Check if the process is alive.
Definition KittyTrace.hpp:275
kitty_rp_call_t callFunctionFrom(uintptr_t callerAddress, uintptr_t functionAddress, Args &&...a)
Call a function in the remote process and spoof return address.
Definition KittyTrace.hpp:573
bool setHwBreakpoint(uintptr_t address, KT_HW_BP_TYPE type, KT_HW_BP_SIZE size, int slot)
Sets a hardware breakpoint on a specified address for traced thread.
KT_BP_RESULT setHardExecBreakpointsAndWait(const std::vector< uintptr_t > &addresses, const std::function< bool(uintptr_t bp_addr, user_regs_struct regs)> &cb, int timeout_ms)
Set hardware execute breakpoints on several addresses (one per debug slot) and wait for whichever is ...
bool attach(int options=0)
Attach to the process.
int remoteCallTimeout() const
Returns the default timeout (ms) for remote function calls.
Definition KittyTrace.hpp:534
KittyTraceMgr(pid_t pid, uintptr_t defaultCaller=0, bool autoRestoreRegs=true, int remoteCallTimeout=0, uintptr_t syscallGadget=0)
Constructs a new KittyTraceMgr object.
Definition KittyTrace.hpp:254
pid_t wait(int *status, int options, int timeout_ms=0) const
Wait for the process.
std::vector< pid_t > getAllThreads(pid_t pid)
Retrieves a list of thread IDs for a given process ID.
Provides some asm instructions that are useful for KittyTrace class.
Definition KittyTrace.hpp:151
A structure to hold result data of a remote process function call.
Definition KittyTrace.hpp:205