示例#1
0
//--------------------------------------------------------------------------
bool debmod_t::restore_broken_breakpoints(void)
{
  debmodbpt_map_t::const_iterator p;
  for ( p = bpts.begin(); p != bpts.end(); ++p )
  {
    const debmod_bpt_t &bpt = p->second;
    if ( !dbg_write_memory(bpt.ea, bpt.saved, bpt.nsaved) )
      msg("Failed to restore broken breakpoint at 0x%a\n", bpt.ea);
  }
  bpts.clear();
  return true;
}
示例#2
0
文件: dbggw.c 项目: HarryR/sanos
void write_memory(struct drpc_packet *pkt, char *buf)
{
  void *addr;
  int size;
  int rc;

  addr = *(void **) (buf + 8);
  size = *(int *) (buf + 16);

  rc = dbg_write_memory(session, addr, size, buf + 20);
  if (rc < 0) pkt->result = E_FAIL;
  *(int *) buf = size;
}
示例#3
0
文件: memory.c 项目: howard5888/wineT
/***********************************************************************
 *           memory_write_value
 *
 * Store a value in memory.
 */
BOOL memory_write_value(const struct dbg_lvalue* lvalue, DWORD size, void* value)
{
    BOOL        ret = TRUE;
    DWORD64     os;

    os = ~(DWORD64)size;
    types_get_info(&lvalue->type, TI_GET_LENGTH, &os);
    assert(size == os);

    /* FIXME: only works on little endian systems */
    if (lvalue->cookie == DLV_TARGET)
    {
        void*       linear = memory_to_linear_addr(&lvalue->addr);
        if (!(ret = dbg_write_memory(linear, value, size)))
            memory_report_invalid_addr(linear);
    }
    else 
    {
        memcpy((void*)(DWORD_PTR)lvalue->addr.Offset, value, size);
    }
    return ret;
}
示例#4
0
文件: debmod.cpp 项目: nealey/vera
//--------------------------------------------------------------------------
ea_t idaapi debmod_t::dbg_appcall(
  ea_t func_ea,
  thid_t tid,
  const struct func_type_info_t *fti,
  int /*nargs*/,
  const struct regobjs_t *regargs,
  struct relobj_t *stkargs,
  struct regobjs_t *retregs,
  qstring *errbuf,
  debug_event_t *event,
  int options)
{
  enum
  {
    E_OK,          // Success
    E_READREGS,    // Failed to read registers
    E_REG_USED,    // The calling convention refers to reserved registers
    E_ARG_ALLOC,   // Failed to allocate memory for stack arguments
    E_WRITE_ARGS,  // Failed to setup stack arguments
    E_WRITE_REGS,  // Failed to setup register arguments
    E_HANDLE_EVENT,// Failed to handle debug event
    E_DEBUG_EVENT, // Could not get debug events
    E_QUIT,        // Program exited
    E_RESUME,      // Failed to resume the application
    E_EXCEPTION,   // An exception has occured
    E_APPCALL_FROM_EXC, // Cannot issue an AppCall if last event was an exception
    E_TIMEOUT,     // Timeout
  };

  static const char *const errstrs[] =
  {
    "success",
    "failed to read registers",
    "the calling convention refers to reserved registers",
    "failed to allocate memory for stack arguments",
    "failed to setup stack arguments",
    "failed to setup register arguments",
    "failed to handle debug event",
    "could not get debug events",
    "program exited",
    "failed to resume the application",
    "an exception has occured",
    "last event was an exception, cannot perform an appcall",
    "timeout",
  };

  // Save registers
  regval_t rv;

  bool brk = false;
  int err = E_OK;

  call_context_t &ctx = appcalls[tid].push_back();

  regval_map_t call_regs;
  ea_t args_sp = BADADDR;
  do
  {
    // In Win32, when WaitForDebugEvent() returns an exception
    // it seems that the OS remembers the exception context so that
    // the next call to ContinueDebugEvent() will work with the last exception context.
    // Now if we carry an AppCall when an exception was just reported:
    // - Appcall will change context
    // - Appcall's control bpt will generate an exception thus overriding the last exception context saved by the OS
    // - After Appcall, IDA kernel cannot really continue from the first exception because it was overwritten
    // Currently we will disallow Appcalls if last event is an exception
    if ( last_event.eid == EXCEPTION )
    {
      err = E_APPCALL_FROM_EXC;
      break;
    }
    // Save registers
    ctx.saved_regs.resize(nregs);
    if ( dbg_read_registers(tid, -1, ctx.saved_regs.begin()) != 1 )
    {
      err = E_READREGS;
      break;
    }

    // Get SP value
    ea_t org_sp = ea_t(ctx.saved_regs[sp_idx].ival);

    // Stack contents
    bytevec_t stk;

    // Prepare control address
    // We will generate a BP code ptrsz aligned and push unto the stack
    // as the first argument. This is where we will set the control bpt.
    // Since the bpt is on the stack, two possible scenarios:
    // - BPT exception
    // - Access violation: trying to execute from NX page
    // In both cases we will catch an exception and learn what address was
    // involved.

    // - Save the ctrl address
    ea_t ctrl_ea = org_sp - addrsize;

    // - Compute the pointer where arguments will be allocated on the stack
    size_t stkargs_size = align_up(stkargs->size(), addrsize);
    args_sp = ctrl_ea - stkargs_size;

    // align the stack pointer to 16 byte boundary (gcc compiled programs require it)
    args_sp &= ~15;
    ctx.ctrl_ea = args_sp + stkargs_size;

    // Relocate the stack arguments
    if ( !stkargs->relocate(args_sp, false) )
    {
      err = E_ARG_ALLOC;
      break;
    }

    // Prepare the stack.
    // The memory layout @SP before transfering to the function:
    // R = ret addr
    // A = args

    // - Append the return address (its value is the value of the ctrl code address)
    stk.append(&ctx.ctrl_ea, addrsize);

    // - Append the stack args
    stk.append(stkargs->begin(), stkargs->size());
    stk.resize(addrsize+stkargs_size); // align up
    ctx.sp = args_sp - addrsize;

    int delta = finalize_appcall_stack(ctx, call_regs, stk);
    ctx.sp += delta;

    // Write the stack
    int nwrite = stk.size() - delta;
    if ( nwrite > 0 )
    {
      if ( dbg_write_memory(ctx.sp, stk.begin()+delta, nwrite) != nwrite )
      {
        err = E_WRITE_ARGS;
        break;
      }
      //show_hex(stk.begin()+delta, nwrite, "Written stack bytes to %a:\n", ctx.sp);
    }

    // ask the debugger to set a breakpoint
    dbg_add_bpt(BPT_SOFT, ctx.ctrl_ea, -1);

    // Copy arg registers to call_regs
    for ( size_t i=0; i < regargs->size(); i++ )
    {
      const regobj_t &ri = regargs->at(i);
      int reg_idx = ri.regidx;
      if ( reg_idx == sp_idx || reg_idx == pc_idx )
      {
        brk = true;
        err = E_REG_USED;
        break;
      }

      // Copy the register value
      if ( ri.size() <= sizeof(rv.fval) )
      {
        rv.clear();
        memcpy(rv.fval, ri.value.begin(), ri.size());
        if ( ri.relocate )
          rv.ival += args_sp;
      }
      else
      {
        bytevec_t &b = rv.set_bytes();
        b.resize(ri.size());
        memcpy(b.begin(), ri.value.begin(), ri.size());
        rv.rvtype = 0; // custom data format
      }
      call_regs[reg_idx] = rv;
    }
    if ( brk )
      break;

    // Set the stack pointer
    rv.clear();
    rv.ival = ctx.sp;
    call_regs[sp_idx] = rv;

    // Set the instruction pointer
    rv.ival = func_ea;
    call_regs[pc_idx] = rv;

    // Change all the registers in question
    for ( regval_map_t::iterator it = call_regs.begin();
          it != call_regs.end();
          ++it )
    {
      if ( dbg_write_register(tid, it->first, &it->second) != 1 )
      {
        err = E_WRITE_REGS;
        brk = true;
        break;
      }
      // Mark that we changed the regs already
      ctx.regs_spoiled = true;
    }
    if ( brk )
      break;

    // For manual appcall, we have done everything, just return now
    if ( (options & APPCALL_MANUAL) != 0 )
      break;

    // Resume the application
    // Since no* exception last occured**, we can safely say that the
    // debugger actually handled the exception.
    // * : We disallow appcalls if an exception last occured
    // **: Actually if an AppCall was issued then last event is an exception
    //     but we will mask it by calling continue_after_event(handled_by_debugger = true)
    if ( !continue_after_last_event(true) )
    {
      err = E_RESUME;
      break;
    }

    // We use this list to accumulate the events
    // We will give back the events at the end of the loop
    debug_event_t tmp;
    if ( event == NULL )
      event = &tmp;

    // Determine timeout for get_debug_event()
    uint64 endtime = 0;
    int recalc_timeout = 0; // never recalc timeout
    int timeout_ms = TIMEOUT;
    if ( (options & APPCALL_TIMEOUT) != 0 )
    {
      timeout_ms = GET_APPCALL_TIMEOUT(options);
      if ( timeout_ms > 0 )
      {
        get_nsec_stamp(&endtime);
        endtime += timeout_ms * uint64(1000 * 1000);
      }
      recalc_timeout = 1; // recalc timeout after the first pass
    }

    while ( true )
    {
      if ( recalc_timeout )
      {
        if ( recalc_timeout != 2 )
        { // we will recalc timeout at the next iteration
          recalc_timeout = 2;
        }
        else
        {
          if ( timeout_ms > 0 )
          {
            // calculate the remaining timeout
            uint64 now;
            get_nsec_stamp(&now);
            timeout_ms = int64(endtime - now) / int64(1000 * 1000);
          }
          if ( timeout_ms <= 0 )
          { // timeout out waiting for the appcall to finish
            err = E_TIMEOUT;
            if ( dbg_prepare_to_pause_process() <= 0 )
              break; // could not even prepare to pause, nothing we can do :(
          }
        }
      }
      // Wait for debug events
      gdecode_t r = dbg_get_debug_event(event, timeout_ms);
      if ( r == GDE_NO_EVENT )
        continue;
      if ( r == GDE_ERROR )
      { // error getting debug event (network error, etc)
        err = E_DEBUG_EVENT;
        break;
      }

      // We may get three possible events related to our control breakpoint:
      // - Access violation type: because we try to execute non-executable code
      // - Or a BPT exception if the stack page happens to be executable
      // - Process exit
      bool hit_ctrl_bpt = false;
      if ( event->eid == PROCESS_EXIT
        || (hit_ctrl_bpt=should_stop_appcall(tid, event, ctx.ctrl_ea)) != false
        || err == E_TIMEOUT )
      {
        if ( !hit_ctrl_bpt )
        {
          send_debug_event_to_ida(event, RQ_SILENT|RQ_SUSPEND);
          event->eid = NO_EVENT;
        }
        last_event.eid = NO_EVENT;
        break;
      }
      // Any other exception?
      else if ( event->eid == EXCEPTION )
      {
        if ( (options & APPCALL_DEBEV) == 0 )
          *errbuf = event->exc.info; // Copy exception text to the user
        err = E_EXCEPTION;
        // When an exception happens during the appcall, we want to mask
        // the exception, because:
        // 1. we reset the EIP to its original location
        // 2. there is no exception handler for the appcall so we cannot really pass as unhandled
        // FIXME
        last_event.eid = NO_EVENT;
        last_event.handled = true;
        brk = true;
        break;
      }

      if ( send_debug_event_to_ida(event, RQ_SILENT|RQ_SUSPEND) != 0 )
      {
        err = E_HANDLE_EVENT;
        break;
      }
      dbg_continue_after_event(event);
      event->eid = NO_EVENT;
    }

    if ( brk || err != E_OK )
      break;

    // write the argument vector back because it could be spoiled by the application
    size_t nbytes = fti->stkargs;
    if ( nbytes > 0
      && dbg_write_memory(args_sp, stkargs->begin(), nbytes) != ssize_t(nbytes) )
    {
      err = E_WRITE_ARGS;
      break;
    }

    // Retrieve the return value
    if ( retregs != NULL && !retregs->empty() )
    {
      regvals_t retr;
      retr.resize(nregs);
      if ( dbg_read_registers(tid, -1, retr.begin()) <= 0 )
      {
        err = E_READREGS;
        break;
      }
      for ( size_t i=0; i < retregs->size(); i++ )
      {
        regobj_t &r = retregs->at(i);
        regval_t &v = retr[r.regidx];
        memcpy(r.value.begin(), v.get_data(), r.value.size());
        r.relocate = false;
      }
    }
  } while ( false );

  if ( err != E_OK )
  {
    if ( err != E_EXCEPTION )
      *errbuf = errstrs[err];
    dbg_cleanup_appcall(tid);
    args_sp = BADADDR;
  }

  return args_sp;
}