Search code examples
linuxx86x86-64system-callsptrace

How to use ptrace in 64 bit process to modify registers in a 32-bit process and make it do a system-call?


I'm working on a program that needs to make a 32 bit process invoke a syscall. I wish to keep my program architecture independent, but the target will always be 32 bit.

To set the registers I'm using ptrace with PTRACE_SETREGS, which takes regs struct pointer as its data argument.

x86_64 and x86 have different definitions for struct user_regs_struct so I've tried simply using the x86_64 on, which passes the syscall number correctly but none of the arguments, I have verified this by passing 1 (__NR_exit on x86) as the syscall number and 21 as the first argument, but the process only exits with 0.

I have also tried copying the x86 definition for struct user_regs_struct with that only causing segfaults.

Since the two definitions of the struct use completely different data types (unsigned long long int on x86_64 and long int on x86) I doubt its implicitly accessing the right data, but it doesn't appear to be using the same registers as x86_64 does for arguments (rdi, rsi, rdx, r10, r8, and r9).


Solution

  • As luck would have it, I couldn't figure this out for days, but as soon as you ask the question you realize what you should be doing.

    You just have to use the x86_64 equivilant of the registers. So, for example eax, ebx, ecx, edx, esi, edi, edp becomes rax, rbx, rcx, rdx, rsi, rdi, rdp