Why should I know this?

Ptrace로 rip를 변경시 0 ~ 2 를 더해야하는 이유. 본문

Technic

Ptrace로 rip를 변경시 0 ~ 2 를 더해야하는 이유.

die4taoam 2018. 7. 24. 16:47

regs.rip = addr;

[injected address] 0x400fb0


instead of expected SIGTRAP, target stopped with signal 11: Segmentation fault


(gdb) x/10i 0x400fae
[0x7f602fd0173c] [130037]                                                     │=> 0x400fae:    add    %al,(%rax)
[0x7f602fd0173c] [150037]                                                     │   0x400fb0:    push   %rsi
[0x7f602fd0173c] [110037]                                                     │   0x400fb1:    push   %rdx
[0x7f602fd0173c] [140037]                                                     │   0x400fb2:    push   %r9
[0x7f602fd0173c] [160038]                                                     │   0x400fb4:    mov    %rdi,%r9
[0x7f602fd0173c] [110038]                                                     │   0x400fb7:    mov    %rcx,%rdi



regs.rip = addr + 1;

[injected address] 0x400fb0


instead of expected SIGTRAP, target stopped with signal 11: Segmentation fault


(gdb) x/10i 0x400faf
[0x7f33db36c73c] [140013]                                                     │=> 0x400faf:    add    %dl,0x52(%rsi)
[0x7f33db36c73c] [160013]                                                     │   0x400fb2:    push   %r9
[0x7f33db36c73c] [110014]                                                     │   0x400fb4:    mov    %rdi,%r9
[0x7f33db36c73c] [140014]                                                     │   0x400fb7:    mov    %rcx,%rdi
[0x7f33db36c73c] [150014]                                                     │   0x400fba:    callq  *%r9
[0x7f33db36c73c] [130014]                                                     │   0x400fbd:    pop    %r9
[0x7f33db36c73c] [120014]                                                     │   0x400fbf:    int3
[0x7f33db36c73c] [160014]                                                     │   0x400fc0:    pop    %rdx
[0x7f33db36c73c] [110015]                                                     │   0x400fc1:    push   %r9
[0x7f33db36c73c] [140015]                                                     │   0x400fc3:    mov    %rdx,%r9



이유

"rip gets incremented by the size of the current instruction"

(뭔소린지 모르겟따.............;;;)


Ptrace는 User-level에서 CPU를 다룰 수 있는 막강한 API인데, 대부분의 기능 구현이 커널에 속해있다.

Register에 값을 대입하는 등의 행위가 CPU를 직접 제어해서 이뤄질 수 없기 때문에, Ptrace를 통해 Register를 변경하면,

해당 호출에 대응하는 Instruction으로 jmp하여 코드를 실행하는 방식으로 이뤄져있다.


소스는 이렇게 :


  51static __always_inline __must_check
  52int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
  53{
  54        int ret = 0;
  55
  56        if (!__builtin_constant_p(size))
  57                return copy_user_generic(dst, (__force void *)src, size);
  58        switch (size) {
  59        case 1:
  60                __uaccess_begin();
  61                __get_user_asm(*(u8 *)dst, (u8 __user *)src,
  62                              ret, "b", "b", "=q", 1);
  63                __uaccess_end();
  64                return ret;

( 출처 : https://lxr.missinglinkelectronics.com/linux+v4.6/arch/x86/include/asm/uaccess_64.h#L27 )


375#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ 376 asm volatile("\n" \ 377 "1: mov"itype" %2,%"rtype"1\n" \ 378 "2:\n" \ 379 ".section .fixup,\"ax\"\n" \ 380 "3: mov %3,%0\n" \ 381 " xor"itype" %"rtype"1,%"rtype"1\n" \ 382 " jmp 2b\n" \ 383 ".previous\n" \ 384 _ASM_EXTABLE(1b, 3b) \ 385 : "=r" (err), ltype(x) \ 386 : "m" (__m(addr)), "i" (errret), "0" (err))

( 출처 : https://lxr.missinglinkelectronics.com/linux+v4.6/arch/x86/include/asm/uaccess.h#L344 )


IP를 바꾸는 방식은 뭔가 다를까???




주석

now that we have an address to copy code to, set the target's rip to it. we have to
advance by 2 bytes here because rip gets incremented by the size of the current
instruction, and the instruction at the start of the function to inject always
happens to be 2 byte long.


Comments