Linux: Running syscall via ptrace ()

Hey :) I am currently developing a memory library for x86 / x64 Linux. The thing is, I am doing some kind of remote syscall execution.

Here is my code that just crashes another process when I try to execute a valid syscall.

(All of my functions used in the code are wrappers around ptrace) You can find the full code here: http://code.google.com/p/ethonmem/source/browse/

long Debugger::executeSyscall( unsigned long code, std::vector<unsigned long> const& args) const { // Backup registers. Registers buRegs = getRegisters(buRegs); FpuRegisters buFregs = getFpuRegisters(buFregs); // Get register set to modify. Registers regs = buRegs; #if __WORDSIZE == 32 // EAX stores the syscall code. regs.eax = code; // If less than 7 args exist, they are stored in registers. size_t argCount = args.size(); if(argCount < 7) { while(argCount) { switch(argCount) { case 1: regs.ebx = args[0]; break; case 2: regs.ecx = args[1]; break; case 3: regs.edx = args[2]; break; case 4: regs.esi = args[3]; break; case 5: regs.edi = args[4]; break; case 6: regs.ebp = args[5]; break; } --argCount; } } // Otherwise we have to use memory. else { // Get stack space. regs.esp -= argCount * sizeof(unsigned long); // Write arguments to stack. for(size_t i = 0; i < argCount; ++i) writeWord(regs.esp + i * sizeof(unsigned long), args[i]); // EBX stores the address. regs.ebx = regs.esp; } // Write INT 0x80-instruction to current instruction pointer position. unsigned long const oldInstruction = readWord(regs.eip); uint8_t newInstruction[sizeof(long)] = { 0xCD, 0x80, 0xCC, 0xCC }; writeWord(regs.eip, *reinterpret_cast<unsigned long*>(&newInstruction[0])); #elif __WORDSIZE == 64 // RAX stores the syscall code. regs.rax = code; // If less than 7 args exist, they are stored in registers. size_t argCount = args.size(); if(argCount < 7) { while(argCount) { switch(argCount) { case 1: regs.rdi = args[0]; break; case 2: regs.rsi = args[1]; break; case 3: regs.rdx = args[2]; break; case 4: regs.r10 = args[3]; // Or RCX ??? break; case 5: regs.r8 = args[4]; break; case 6: regs.r9 = args[5]; break; } --argCount; } } // Otherwise this fails. else { BOOST_THROW_EXCEPTION(EthonError() << ErrorString("More than 6 arguments passed to a 64bit syscall")); } // Write SYSCALL-instruction to current instruction pointer position. unsigned long const oldInstruction = readWord(regs.rip); uint8_t newInstruction[sizeof(long)] = { 0x0F, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }; writeWord(regs.rip, *reinterpret_cast<unsigned long*>(&newInstruction[0])); #endif // Apply new registers. setRegisters(regs); // Step to begin of syscall. stepSyscall(); // Step to end of syscall. stepSyscall(); // Fetch return value and restore patched word getRegisters(regs); long returnValue; #if __WORDSIZE == 32 returnValue = regs.eax; writeWord(regs.eip, oldInstruction); #elif __WORDSIZE == 64 returnValue = regs.rax; writeWord(regs.rip, oldInstruction); #endif // Restore registers. setRegisters(buRegs); setFpuRegisters(buFregs); return returnValue; } 

Can anyone find my mistake? Thanks :) Regards, Florian

+4
source share
2 answers

Do you know if% rip has increased to the next instruction when syscall happens? Usually after e8 or e9 (call / jmp), and possibly after syscall 0f05,% rip points to the address after the call, and not to it directly. Using% rip-2 can fix it.

+3
source

Just a wild hunch, are you sure that all memory addresses passed as an argument with syscall are valid?

0
source

Source: https://habr.com/ru/post/1346035/


All Articles