1. ptrace(PTRACE_ATTACH, pid, NULL, NULL)
- process에 attach 한다.
2. wait(&status)
- 대기
3. orgcode = ptrace(PTRACE_PEEKTEXT, pid, address, NULL)
- 특정 address의 코드(기계어)를 얻어온다. (address는 symbol의 시작주소를 통해 얻어온다.)
- 원본 orgcode는 backup 용도
4. ptrace(PTRACE_POKETEXT, pid, address, trap)
- trap = (orig & ~0xff) | 0xcc <signal 발생 기계어>
- trap(2byte)을 설치한다. trap이 실제로 breakpoint를 심는 과정이다.
5. ptrace(PTRACE_CONT, pid, NULL, NULL)
- trap 설치 후 attach되어 멈춰있는 프로세스를 다시 run 상태로 돌려놓는다.
6. wait(&status)
- attach된 프로세스로부터 특정 signal이 발생할때까지 대기한다.
7-1-1. if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
- trap을 설치한 address에 attach한 프로세스가 진입한 경우로 성공적으로 breakpoint가 작동한 case
7-1-2. ptrace(PTRACE_GETREGS, pid, NULL &pt_reg)
- pt_reg(struct user_regs_struct) 구조체에 현재 register 정보를 받아온다.
7-1-3. ptrace(PTRACE_POKETEXT, pid, address, orgcode)
- trap 을 설치한 곳을 원래 code로 돌려놓는다.
7-1-3. pt_reg.rip = pkt_reg.rip - 1
- 현재 명령을 실행할 주소가 저장되어있는 rip register 값을 -1을 하여 trap이 실행되었던 명령어 주소로 이동시킨다.
7-1-4. ptrace(PTRACE_SETREGS, pid, NULL, &pt_reg)
- 변경된 register를 setting 한다.
7-1-5. ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL)
- asm 명령어 하나를 실행한다 (trap으로 인해 실행 못한 orgcode)
7-1-6. wait(NULL)
- (orgcode) asm 명령 실행을 위해 대기한다.
7-1-7. ptrace(PTRACE_PKETEXT, pid, address, trap)
- 다시 trap을 설치한다. ㅎㅎ
- 위의 과정 loop도 가능하며, trap 설치 없이 끝내도 상관없다.
7-2. else if(WIFEXITED(status))
- attach한 process가 trap을 거치지 않고 종료한 경우
8. usleep(10)
- 어떤 글에서 봤는데 attach후 이것저것하다가 바로 detach 하는 경우 process의 thread가 깨어나지 않는 경우가 있다고 한다.
- 따라서 usleep()를 통해 thread를 각성(?) 시킨후 detach를 하면 잘 된다고 한다.
** usleep 없이 했다가 한번인가 멈춤 현상을 겪은뒤로 usleep을 넣었는데 그 뒤로 매우 잘되고있다.
9. ptrace(PTRACE_DETACH, pid, NULL, NULL)
- detach한다.
** trap은 제거하고 detach ㅎㅎ
*** 실제 코드에서 추가할 부분은 프로세스에 attach해서 이것저것 장난(?)치다가 signal이 수도 없이 발생하는데 이때 signal handler를 통해 detach를 하지 않으면 target process는 stop상태로 남아있어서 kill을 해줘야하는 상황이 나온다. 따라서 signal handler로 언제든지 안전하게 detach를 시켜주도록 한다.
댓글 없음:
댓글 쓰기