2011-03-31 113 views
4

嘿:) 我目前正在爲x86/x64 Linux開發一個內存查找庫。我奮鬥的一點是實現某種遠程系統調用執行。Linux:通過ptrace()執行系統調用()

這是我的代碼,當我嘗試執行有效的系統調用時,它只是崩潰了其他進程。

(所有的代碼中使用我的功能都是圍繞ptrace的包裝) 你可以在這裏找到完整的代碼: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; 
} 

是任何人都能夠檢測我的錯誤?謝謝:) Regards, Florian

回答

0

只是一個瘋狂的猜測,你確定任何內存地址作爲與系統調用參數傳遞有效嗎?

3

當系統調用發生時,您是否知道%rip是否已遞增到下一條指令?通常在e8或e9(調用/ jmp)之後,並且可能在0f05系統調用之後,%rip指向調用後的地址,而不是直接指向地址。使用%rip - 2可能會修復它。