KittyMemoryEx 1.0.0
Dedicated library for runtime code patching, memory scanning, tracing, injection and some more useful memory utilities. works for both Android and Linux
Loading...
Searching...
No Matches
KittyTrace.hpp
1#pragma once
2
3#include <cstdarg>
4#include <cstddef>
5#include <cstdint>
6#include <csignal>
7#include <cstring>
8#include <sys/mman.h>
9#include <sys/ptrace.h>
10#include <sys/wait.h>
11#include <sys/user.h>
12#include <csignal>
13#include <cstring>
14#include <cerrno>
15#include <functional>
16#include <type_traits>
17#include <utility>
18#include <vector>
19
20#include "KittyUtils.hpp"
21#include "KittyMemoryEx.hpp"
22
23#if defined(__LP64__)
24#define KT_PTRACE_GETREG_REQ PTRACE_GETREGSET
25#define KT_PTRACE_SETREG_REQ PTRACE_SETREGSET
26#else
27#define KT_PTRACE_GETREG_REQ PTRACE_GETREGS
28#define KT_PTRACE_SETREG_REQ PTRACE_SETREGS
29#endif
30
31#if defined(__arm__)
32#define user_regs_struct user_regs
33#endif
34
35#if defined(__arm__)
36#define KT_CPSR_T_MASK (1u << 5) // Thumb bit (Bit 5)
37#endif
38
39#if defined(__aarch64__)
40#define KT_CPSR_SS_MASK (1ULL << 21) // Single-step bit (Bit 21)
41#define KT_CPSR_D_MASK (1ULL << 9) // Debug bit (Bit 9)
42#define KT_CPSR_BTYPE_MASK (3ULL << 10) // BTYPE bits (Bits 10 & 11)
43#endif
44
45#if defined(__i386__)
46#define KT_REG_RET eax
47#define KT_REG_PC eip
48#define KT_REG_IP eip
49#define KT_REG_SP esp
50#define KT_REG_SYSNR eax
51#define KT_REG_ARGS_NUM 0
52
53#elif defined(__x86_64__)
54#define KT_REG_RET rax
55#define KT_REG_PC rip
56#define KT_REG_IP rip
57#define KT_REG_SP rsp
58#define KT_REG_SYSNR rax
59#define KT_REG_ARGS_NUM 6
60
61#elif defined(__aarch64__)
62#define KT_REG_RET regs[0]
63#define KT_REG_PC pc
64#define KT_REG_IP pc
65#define KT_REG_SP sp
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
70
71#elif defined(__arm__)
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
80
81#endif
82
86enum KT_RP_CALL_STATUS
87{
88 KT_RP_CALL_FAILED,
89 KT_RP_CALL_SUCCESS,
90 KT_RP_CALL_TIMEOUT,
91 KT_RP_CALL_EXITED,
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,
100};
101
105enum KT_HW_BP_TYPE
106{
107 KT_HW_BP_EXECUTE = 0,
108 KT_HW_BP_READ,
109 KT_HW_BP_WRITE,
110 KT_HW_BP_ACCESS
111};
112
116enum KT_HW_BP_SIZE
117{
118 KT_HW_BP_SIZE_EXEC = 0,
119 KT_HW_BP_SIZE_1 = 1,
120 KT_HW_BP_SIZE_2 = 2,
121 KT_HW_BP_SIZE_3 = 3,
122 KT_HW_BP_SIZE_4 = 4,
123 KT_HW_BP_SIZE_5 = 5,
124 KT_HW_BP_SIZE_6 = 6,
125 KT_HW_BP_SIZE_7 = 7,
126 KT_HW_BP_SIZE_8 = 8,
127};
128
132enum KT_BP_RESULT
133{
134 KT_BP_FAILED,
135 KT_BP_SUCCESS,
136 KT_BP_TIMEOUT,
137 KT_BP_EXITED,
138 KT_BP_CONT_FAILED,
139 KT_BP_STEP_FAILED,
140 KT_BP_REGS_FAILED,
141 KT_BP_WAIT_FAILED,
142 KT_BP_MEM_FAILED,
143 KT_BP_NOT_STOPPED,
144 KT_BP_MISMATCH_STOP,
145};
146
151{
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};
162
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};
177#endif
178} // namespace KittyTraceInsns
179
180#define KT_REGS_ALIGN_STACK(regs) \
181 do \
182 { \
183 regs.KT_REG_SP = uintptr_t(intptr_t(intptr_t(regs.KT_REG_SP) & intptr_t(~0xF))); \
184 } while (false)
185#define KT_REGS_ALIGN_STACK_N(regs, n) \
186 do \
187 { \
188 regs.KT_REG_SP = uintptr_t(intptr_t((intptr_t(regs.KT_REG_SP) - intptr_t(n)) & intptr_t(~0xF))); \
189 } while (false)
190#define KT_ALIGN_STACK(s) \
191 do \
192 { \
193 s = uintptr_t(intptr_t(intptr_t(s) & intptr_t(~0xF))); \
194 } while (false)
195#define KT_ALIGN_STACK_N(s, n) \
196 do \
197 { \
198 s = uintptr_t(intptr_t((intptr_t(s) - intptr_t(n)) & intptr_t(~0xF))); \
199 } while (false)
200
205{
206 KT_RP_CALL_STATUS status = KT_RP_CALL_FAILED;
207 union
208 {
209 intptr_t val = 0;
210 uintptr_t ptr;
211 } result;
212};
213
217class KittyTraceMgr
218{
219private:
220 pid_t _pid;
221 uintptr_t _defaultCaller;
222 bool _attached, _seized, _autoRestoreRegs;
223 int _remoteCallTimeout;
224 uintptr_t _syscallGadget;
225
226 template <class T>
227 static inline uintptr_t _toRemoteArg(T &&v)
228 {
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);
234 }
235
236 kitty_rp_call_t _callFunctionFrom(uintptr_t callerAddress, uintptr_t functionAddress, int nargs, ...);
237 kitty_rp_call_t _callSyscall(long sysnr, int nargs, ...);
238
239public:
240 KittyTraceMgr()
241 : _pid(0), _defaultCaller(0), _attached(false), _seized(false), _autoRestoreRegs(true), _remoteCallTimeout(0),
242 _syscallGadget(0)
243 {
244 }
245
255 uintptr_t defaultCaller = 0,
256 bool autoRestoreRegs = true,
257 int remoteCallTimeout = 0,
258 uintptr_t syscallGadget = 0)
259 : _pid(pid), _defaultCaller(defaultCaller), _attached(isAttached()), _seized(false),
260 _autoRestoreRegs(autoRestoreRegs), _remoteCallTimeout(remoteCallTimeout), _syscallGadget(syscallGadget)
261 {
262 }
263
267 inline pid_t pid() const
268 {
269 return _pid;
270 }
271
275 inline bool isAlive() const
276 {
277 return _pid >= 0 ? kill(_pid, 0) == 0 : false;
278 }
279
283 inline bool isAttached() const
284 {
286 KittyMemoryEx::ProcStatus::parse(_pid, &pstatus);
287 int tracerPID = pstatus.getInt("TracerPid");
288 return _pid >= 0 && getpid() == tracerPID;
289 }
290
295 inline std::vector<pid_t> threads() const
296 {
297 return KittyMemoryEx::getAllThreads(_pid);
298 }
299
305 bool attach(int options = 0);
306
312 bool seize(int options = 0);
313
319 bool setOptions(int options);
320
325 bool detach();
326
331 bool stop();
332
338 bool cont(int sig = 0);
339
347 pid_t wait(int *status, int options, int timeout_ms = 0) const;
348
353 bool waitSyscall() const;
354
360 bool step(int steps = 1) const;
361
367 bool waitStep(int steps = 1) const;
368
374 inline bool getSignalInfo(siginfo_t *si) const
375 {
376 if (!si || !_pid || !_attached)
377 return false;
378 return ptrace(PTRACE_GETSIGINFO, _pid, 0, si) == 0;
379 }
380
386 bool getRegs(user_regs_struct *regs) const;
387
393 bool setRegs(user_regs_struct *regs) const;
394
400 uintptr_t getReturnAddressFromRegs(user_regs_struct *regs)
401 {
402#if defined(__x86_64__) || defined(__i386__)
403 uintptr_t ret = 0;
404 peekMem(regs->KT_REG_SP, &ret, sizeof(uintptr_t));
405 return ret;
406
407#elif defined(__aarch64__) || defined(__arm__)
408 return regs->KT_REG_LR;
409#endif
410 }
411
420 template <typename T>
421 T getArgFromRegs(user_regs_struct *regs, uint32_t arg_num)
422 {
423 static_assert(std::is_arithmetic<T>::value, "T must be a numeric type!");
424
425#if defined(__x86_64__)
426 switch (arg_num)
427 {
428 case 0:
429 return regs->rdi;
430 case 1:
431 return regs->rsi;
432 case 2:
433 return regs->rdx;
434 case 3:
435 return regs->rcx;
436 case 4:
437 return regs->r8;
438 case 5:
439 return regs->r9;
440 default:
441 break;
442 }
443
444 uintptr_t arg = 0;
445 peekMem(regs->KT_REG_SP + 8 + (arg_num - 6) * 8, &arg, sizeof(uintptr_t));
446 return arg;
447
448#elif defined(__i386__)
449 uintptr_t arg = 0;
450 peekMem(regs->KT_REG_SP + 4 + (arg_num * 4), &arg, sizeof(uintptr_t));
451 return arg;
452
453#elif defined(__aarch64__)
454 if (arg_num < 8)
455 return regs->regs[arg_num];
456
457 uintptr_t arg = 0;
458 peekMem(regs->KT_REG_SP + (arg_num - 8) * 8, &arg, sizeof(uintptr_t));
459 return arg;
460
461#elif defined(__arm__)
462 if (arg_num < 4)
463 return regs->uregs[arg_num];
464
465 uintptr_t arg = 0;
466 peekMem(regs->KT_REG_SP + (arg_num - 4) * 4, &arg, sizeof(uintptr_t));
467 return arg;
468#endif
469 }
470
482 size_t peekMem(uintptr_t addr, void *buf, size_t size) const;
483
495 size_t pokeMem(uintptr_t addr, const void *buf, size_t size) const;
496
500 inline uintptr_t defaultCaller() const
501 {
502 return _defaultCaller;
503 }
504
509 inline void setDefaultCaller(uintptr_t caller)
510 {
511 _defaultCaller = caller;
512 }
513
517 inline bool autoRestoreRegs() const
518 {
519 return _autoRestoreRegs;
520 }
521
526 inline void setAutoRestoreRegs(bool flag)
527 {
528 _autoRestoreRegs = flag;
529 }
530
534 inline int remoteCallTimeout() const
535 {
536 return _remoteCallTimeout;
537 }
538
543 inline void setRemoteCallTimeout(int ms)
544 {
545 _remoteCallTimeout = ms > 0 ? ms : 0;
546 }
547
551 inline uintptr_t syscallGadget() const
552 {
553 return _syscallGadget;
554 }
555
560 inline void setSyscallGadget(uintptr_t address)
561 {
562 _syscallGadget = address;
563 }
564
572 template <class... Args>
573 kitty_rp_call_t callFunctionFrom(uintptr_t callerAddress, uintptr_t functionAddress, Args &&...a)
574 {
575 return _callFunctionFrom(callerAddress, functionAddress, sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
576 }
577
584 template <class... Args>
585 kitty_rp_call_t callFunction(uintptr_t functionAddress, Args &&...a)
586 {
587 return _callFunctionFrom(_defaultCaller, functionAddress, sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
588 }
589
597 template <class... Args>
598 kitty_rp_call_t callSyscall(long sysnr, Args &&...a)
599 {
600 return _callSyscall(sysnr, sizeof...(a), _toRemoteArg(std::forward<Args>(a))...);
601 }
602
612 KT_BP_RESULT setSoftBreakpointAndWait(uintptr_t address,
613 const std::function<bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
614 int timeout_ms);
615
626 KT_BP_RESULT setHardBreakpointAndWait(uintptr_t address,
627 KT_HW_BP_TYPE type,
628 KT_HW_BP_SIZE size,
629 int slot,
630 const std::function<bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
631 int timeout_ms);
632
641 KT_BP_RESULT setHardExecBreakpointsAndWait(const std::vector<uintptr_t> &addresses,
642 const std::function<bool(uintptr_t bp_addr, user_regs_struct regs)> &cb,
643 int timeout_ms);
644
654 bool setHwBreakpoint(uintptr_t address, KT_HW_BP_TYPE type, KT_HW_BP_SIZE size, int slot);
655
663 bool clearHwBreakpoint(KT_HW_BP_TYPE type, int slot);
664};
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