Beispiel #1
0
ErrorCode PTrace::step(ProcessThreadId const &ptid, ProcessInfo const &pinfo,
                       int signal, Address const &address) {
  pid_t pid;

  if (!ptid.valid())
    return kErrorInvalidArgument;

  if (!(ptid.tid <= kAnyThreadId)) {
    pid = ptid.tid;
  } else {
    pid = ptid.pid;
  }

  //
  // Continuation from address?
  //
  if (address.valid()) {
    Architecture::CPUState state;
    ErrorCode error = readCPUState(ptid, pinfo, state);
    if (error != kSuccess)
      return error;

    state.setPC(address);

    error = writeCPUState(ptid, pinfo, state);
    if (error != kSuccess)
      return error;
  }

  // (caddr_t)1 indicate that execution is to pick up where it left off.
  if (wrapPtrace(PT_STEP, pid, (caddr_t)1, signal) < 0)
    return Platform::TranslateError();

  return kSuccess;
}
Beispiel #2
0
//
// Execute will execute the code in the target process/thread,
// the techinique for PTRACE is to read CPU state, rewrite the
// code portion pointed by PC with the code, resuming the process/thread,
// wait for the completion, read the CPU state back to grab return
// values, then restoring the previous code.
//
ErrorCode PTrace::execute(ProcessThreadId const &ptid, ProcessInfo const &pinfo,
                          void const *code, size_t length, uint64_t &result) {
  Architecture::CPUState savedState, resultState;
  std::string savedCode;

  if (!ptid.valid() || code == nullptr || length == 0)
    return kErrorInvalidArgument;

  // 1. Read and save the CPU state
  ErrorCode error = readCPUState(ptid, pinfo, savedState);
  if (error != kSuccess)
    return error;

  // 2. Copy the code at PC
  savedCode.resize(length);
  error = readMemory(ptid, savedState.pc(), &savedCode[0], length);
  if (error != kSuccess)
    return error;

  // 3. Write the code to execute at PC
  error = writeMemory(ptid, savedState.pc(), code, length);
  if (error != kSuccess)
    goto fail;

  // 3. Resume and wait
  error = resume(ptid, pinfo);
  if (error == kSuccess) {
    error = wait(ptid);
  }

  if (error == kSuccess) {
    // 4. Read back the CPU state
    error = readCPUState(ptid, pinfo, resultState);
    if (error == kSuccess) {
      // 5. Save the result
      result = resultState.retval();
    }
  }

  // 6. Write back the old code
  error = writeMemory(ptid, savedState.pc(), &savedCode[0], length);
  if (error != kSuccess)
    goto fail;

  // 7. Restore CPU state
  error = writeCPUState(ptid, pinfo, savedState);
  if (error != kSuccess)
    goto fail;

  // Success!! We injected and executed code!
  return kSuccess;

fail:
  return kill(ptid, SIGKILL); // we can't really do much at this point :(
}
Beispiel #3
0
ErrorCode Thread::step(int signal, Address const &address) {
  // Windows doesn't have a dedicated single-step call. We have to set
  // the single step flag in eflags and resume the thread.
  Architecture::CPUState state;
  ErrorCode error;

  error = readCPUState(state);
  if (error != kSuccess)
    return error;

  // TF (trap flag) is the 8th bit of eflags.
  state.gp.eflags |= (1 << 8);

  error = writeCPUState(state);
  if (error != kSuccess)
    return error;

  return resume(signal, address);
}
Beispiel #4
0
ErrorCode PTrace::prepareAddressForResume(ProcessThreadId const &ptid,
                                          ProcessInfo const &pinfo,
                                          Address const &address) {
  if (address.valid()) {
    Architecture::CPUState state;
    ErrorCode error = readCPUState(ptid, pinfo, state);
    if (error != kSuccess) {
      return error;
    }

    state.setPC(address);

    error = writeCPUState(ptid, pinfo, state);
    if (error != kSuccess) {
      return error;
    }
  }

  return kSuccess;
}