fork()로 프로세스를 복제해 부모와 자식으로 나눈다
execve() 기존 프로세스를 덮고 새 프로그램 실행
syscall 26(32bit)
tracer가 tracee를 제어하고 관찰하게 해준다
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
long value = 10;
int main(void)
{
int status;
pid_t pid = fork();
if (pid == 0) {
ptrace(PTRACE_TRACEME, 0, 0, 0);
raise(SIGSTOP);
printf("value = %ld\n", value);
_exit(0);
}
waitpid(pid, &status, 0);
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
printf("RIP = %llx\n", regs.rip);
printf("old = %ld\n", ptrace(PTRACE_PEEKDATA, pid, &value, 0));
ptrace(PTRACE_POKEDATA, pid, &value, 99);
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
waitpid(pid, &status, 0);
ptrace(PTRACE_CONT, pid, 0, 0);
waitpid(pid, &status, 0);
}
PTRACE_TRACEME
Indicate that this process is to be traced by its parent.
A process probably shouldn't make this operation if its
parent isn't expecting to trace it. (pid, addr, and data
are ignored.)
The PTRACE_TRACEME operation is used only by the tracee;
the remaining operations are used only by the tracer. In
the following operations, pid specifies the thread ID of
the tracee to be acted on. For operations other than
PTRACE_ATTACH, PTRACE_SEIZE, PTRACE_INTERRUPT, and
PTRACE_KILL, the tracee must be stopped.
PTRACE_GETFPREGS
Copy the tracee's general-purpose or floating-point
registers, respectively, to the address data in the tracer.
See <sys/user.h> for information on the format of this
data. (addr is ignored.) Note that SPARC systems have the
meaning of data and addr reversed; that is, data is ignored
and the registers are copied to the address addr.
PTRACE_GETREGS and PTRACE_GETFPREGS are not present on all
architectures.
PTRACE_PEEKDATA
Read a word at the address addr in the tracee's memory,
returning the word as the result of the ptrace() call.
Linux does not have separate text and data address spaces,
so these two operations are currently equivalent. (data is
ignored; but see NOTES.)
PTRACE_POKEDATA
Copy the word data to the address addr in the tracee's
memory. As for PTRACE_PEEKTEXT and PTRACE_PEEKDATA, these
two operations are currently equivalent.
PTRACE_SINGLESTEP
Restart the stopped tracee as for PTRACE_CONT, but arrange
for the tracee to be stopped at the next entry to or exit
from a system call, or after execution of a single
instruction, respectively. (The tracee will also, as
usual, be stopped upon receipt of a signal.) From the
tracer's perspective, the tracee will appear to have been
stopped by receipt of a SIGTRAP. So, for PTRACE_SYSCALL,
for example, the idea is to inspect the arguments to the
system call at the first stop, then do another
PTRACE_SYSCALL and inspect the return value of the system
call at the second stop. The data argument is treated as
for PTRACE_CONT. (addr is ignored.)
자식프로세스가 부모프로세스가 자신을 추적하기를 커널에 요청한다
자식프로세스 레지스터값을 읽어온다
자식프로세스 가상공간의 값을 변경
싱글스텝(명령하나)실행한다
재개한다
ptrace(op , pid , addr , data )
인자값들
자식 프로세스가 부모 프로세스를 tracer로 지정해
부모가 자식을 제어가능하게한다
게임치트나 소프트웨어 무단 배포 방지 등을 위해 debugging을 어렵게 만드는 기법
대표적으로
int is_debugger_attached(void)
{ return traer_pid != 0;
}
로 존재여부를 확인한다
하지만 gdb로 반환값을 0으로 바꾼다면 우회가 가능하다
break *0x10 => 0x10 int3
break는 코드를 덮어써서 중단하는 것이므로 .text섹션 변조를 확인해 탐지한다
break *0x10 => 0x10 mov rbx,2 //변경되지 않는다
hbreak 코드를 덮어쓰지 않고 주소를 기억해 중단하여 우회가 가능하다
in3 = 프로그램 일시중단
디버거를 사용하면 실행시간이 수상하게 길어지므로 시간끌기 전력으로 난독화해 공격자가 공격하는 것을 무의미하게 만든다
