
рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░
рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдореЗрдВ, рд╣рдордиреЗ Sega Mega Drive
/ Genesis
рдкрд░ рдЧреЗрдо рдПрдореБрд▓реЗрдЯрд░ рдХреЗ рдХреЛрд░ рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдпрд╛, рдЗрд╕рдореЗрдВ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреНрд╖рдорддрд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рд╛ред рдЕрдм IDA Pro
, рд╕рдВрд╕реНрдХрд░рдг 7.0
рд▓рд┐рдП рдбрд┐рдмрдЧрд░ рдкреНрд▓рдЧрдЗрди рд▓рд┐рдЦрдиреЗ рдХреА рдмрд╛рд░реА рд╣реИред рдЪрд▓рд┐рдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
рднрд╛рдЧ рджреЛ: рдбреАрдмрдЧрд░ рдкреНрд▓рдЧрд┐рди
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рдирдпрд╛ рдЦрд╛рд▓реА DLL
рдкреНрд░реЛрдЬреЗрдХреНрдЯ DLL
: File
-> New
-> Project
-> Windows Desktop Wizard
-> Dynamic link library (.dll)
, Empty Project
рдмреЙрдХреНрд╕ рдХреЛ рднреА рдЪреЗрдХ рдХрд░реЗрдВ рдФрд░ рдмрд╛рдХреА рдХреЛ рдЕрдирдЪреЗрдХ рдХрд░реЗрдВред

IDA SDK
рдЕрдирдкреИрдХ рдХрд░реЗрдВ, рдФрд░ рдЗрд╕реЗ Visual Studio
рдореИрдХреНрд░реЛрдЬрд╝ (рдореИрдВ 2017 Community
рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛) рдореЗрдВ рд▓рд┐рдЦреВрдВрдЧрд╛ рддрд╛рдХрд┐ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЖрдк рдЗрд╕реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░ рд╕рдХреЗрдВред рдЙрд╕реА рд╕рдордп, рд╣рдо IDA Pro
рдХреЗ рдкрде рдХреЗ рд▓рд┐рдП рдПрдХ рдореИрдХреНрд░реЛ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗред
View
-> Other Windows
-> Property Manager
:

рдХреНрдпреЛрдВрдХрд┐ рд╣рдо SDK 7.0
рд╕рдВрд╕реНрдХрд░рдг SDK 7.0
рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рд╕рдВрдХрд▓рди x64
рд╕рдВрдХрд▓рдХ рджреНрд╡рд╛рд░рд╛ рд╣реЛрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, Debug | x64
рдЪрдпрди Debug | x64
Debug | x64
-> Microsoft.Cpp.x64.user
-> Properties
:

User Macros
рдЕрдиреБрднрд╛рдЧ рдореЗрдВ Add Macro
рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ, рдФрд░ IDA_SDK
рдореИрдХреНрд░реЛ рдХреЛ рдЙрд╕ рдкрде рдХреЗ рд╕рд╛рде рд▓рд┐рдЦреЗрдВ рдЬрд╣рд╛рдВ рдЖрдкрдиреЗ SDK
рдЕрдирдкреИрдХ рдХрд┐рдпрд╛ рдерд╛:

рд╣рдо IDA_DIR
(рдЖрдкрдХреЗ IDA Pro
рдХрд╛ рдкрде) рдХреЗ рд╕рд╛рде рднреА рдРрд╕рд╛ рд╣реА рдХрд░рддреЗ рд╣реИрдВ:

рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ IDA
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ %Program Files%
рд╕реЗрдЯ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдЕрдзрд┐рдХрд╛рд░реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рдЖрдЗрдП Win32
рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рднреА рд╣рдЯрд╛ рджреЗрдВ (рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдПрдХ x86
рд╕рд┐рд╕реНрдЯрдо рдкрд░ рд╕рдВрдХрд▓рди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛), рдХреЗрд╡рд▓ x64
рд╡рд┐рдХрд▓реНрдк рдХреЛ рдЫреЛрдбрд╝рдХрд░ред
рдЕрдм рдбрд┐рдмрдЧрд░ рдИрд╡реЗрдВрдЯ рдХрддрд╛рд░ рд╡рд░реНрдЧ рдЯреЗрдореНрдкрд▓реЗрдЯ рд▓реЗрдВ:
рдбрд╛рдЙрдирд▓реЛрдб рд╕реЛрд░реНрд╕ рдкреИрдХреЗрдЬ ida_debmod.h #pragma once #include <deque> #include <ida.hpp> #include <idd.hpp> //-------------------------------------------------------------------------- // Very simple class to store pending events enum queue_pos_t { IN_FRONT, IN_BACK }; struct eventlist_t : public std::deque<debug_event_t> { private: bool synced; public: // save a pending event void enqueue(const debug_event_t &ev, queue_pos_t pos) { if (pos != IN_BACK) push_front(ev); else push_back(ev); } // retrieve a pending event bool retrieve(debug_event_t *event) { if (empty()) return false; // get the first event and return it *event = front(); pop_front(); return true; } };
рдЕрдм рд╕реНрдЯреВрдбрд┐рдпреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рд╕рдВрдХрд▓рдХ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:
__NT__ __IDP__ __X64__
рдПрдХ рдирдпрд╛ рдЦрд╛рд▓реА ida_debug.cpp
рдлрд╝рд╛рдЗрд▓ рдЬреЛрдбрд╝реЗрдВ рдФрд░ ida_debug.cpp
рдирд┐рдореНрди рдЯреЗрдореНрдкрд▓реЗрдЯ рдЪрд┐рдкрдХрд╛рдПрдБ:
рд╕реНрд░реЛрдд рдкреИрдХреЗрдЬ ida_debug.cpp рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ #include <ida.hpp> #include <idd.hpp> #include <auto.hpp> #include <funcs.hpp> #include <idp.hpp> #include <dbg.hpp> #include "ida_debmod.h" #include "debug_wrap.h" static dbg_request_t *dbg_req = NULL; static void pause_execution() { send_dbg_request(dbg_req, REQ_PAUSE); } static void continue_execution() { send_dbg_request(dbg_req, REQ_RESUME); } static void stop_debugging() { send_dbg_request(dbg_req, REQ_STOP); } eventlist_t g_events; static qthread_t events_thread = NULL; // TODO: Implement status register bits mask static const char *const SRReg[] = { }; #define RC_GENERAL (1 << 0) // TODO: define different register types register_info_t registers[] = { // TODO: Implement registers description }; static const char *register_classes[] = { "General Registers", // TODO: Add other register group names NULL }; static void finish_execution() { if (events_thread != NULL) { qthread_join(events_thread); qthread_free(events_thread); qthread_kill(events_thread); events_thread = NULL; } } static bool idaapi init_debugger(const char *hostname, int portnum, const char *password) { set_processor_type(ph.psnames[0], SETPROC_LOADER); // reset proc to "M68000" return true; } static bool idaapi term_debugger(void) { dbg_req->is_ida = 0; close_shared_mem(&dbg_req); return true; } static int idaapi process_get_info(procinfo_vec_t *procs) { return 0; } static int idaapi check_debugger_events(void *ud) { while (dbg_req->dbg_active || dbg_req->dbg_events_count) { dbg_req->is_ida = 1; int event_index = recv_dbg_event(dbg_req, 0); if (event_index == -1) { qsleep(10); continue; } debugger_event_t *dbg_event = &dbg_req->dbg_events[event_index]; debug_event_t ev; switch (dbg_event->type) { case DBG_EVT_STARTED: ev.eid = PROCESS_START; ev.pid = 1; ev.tid = 1; ev.ea = BADADDR; ev.handled = true; ev.modinfo.name[0] = 'E'; ev.modinfo.name[1] = 'M'; ev.modinfo.name[2] = 'U'; ev.modinfo.name[3] = 'L'; ev.modinfo.name[4] = '\0'; ev.modinfo.base = 0; ev.modinfo.size = 0; ev.modinfo.rebase_to = BADADDR; g_events.enqueue(ev, IN_FRONT); break; case DBG_EVT_PAUSED: ev.pid = 1; ev.tid = 1; ev.ea = dbg_event->pc; ev.handled = true; ev.eid = PROCESS_SUSPEND; g_events.enqueue(ev, IN_BACK); break; case DBG_EVT_BREAK: ev.pid = 1; ev.tid = 1; ev.ea = dbg_event->pc; ev.handled = true; ev.eid = BREAKPOINT; ev.bpt.hea = ev.bpt.kea = ev.ea; g_events.enqueue(ev, IN_BACK); break; case DBG_EVT_STEP: ev.pid = 1; ev.tid = 1; ev.ea = dbg_event->pc; ev.handled = true; ev.eid = STEP; g_events.enqueue(ev, IN_BACK); break; case DBG_EVT_STOPPED: ev.eid = PROCESS_EXIT; ev.pid = 1; ev.handled = true; ev.exit_code = 0; g_events.enqueue(ev, IN_BACK); break; default: break; } dbg_event->type = DBG_EVT_NO_EVENT; qsleep(10); } return 0; } static int idaapi start_process(const char *path, const char *args, const char *startdir, int dbg_proc_flags, const char *input_path, uint32 input_file_crc32) { g_events.clear(); dbg_req = open_shared_mem(); if (!dbg_req) { show_wait_box("HIDECANCEL\nWaiting for connection to plugin..."); while (!dbg_req) { dbg_req = open_shared_mem(); } hide_wait_box(); } events_thread = qthread_create(check_debugger_events, NULL); send_dbg_request(dbg_req, REQ_ATTACH); return 1; } static void idaapi rebase_if_required_to(ea_t new_base) { } static int idaapi prepare_to_pause_process(void) { pause_execution(); return 1; } static int idaapi emul_exit_process(void) { stop_debugging(); finish_execution(); return 1; } static gdecode_t idaapi get_debug_event(debug_event_t *event, int timeout_ms) { while (true) { // are there any pending events? if (g_events.retrieve(event)) { return g_events.empty() ? GDE_ONE_EVENT : GDE_MANY_EVENTS; } if (g_events.empty()) break; } return GDE_NO_EVENT; } static int idaapi continue_after_event(const debug_event_t *event) { dbg_notification_t req = get_running_notification(); switch (event->eid) { case STEP: case BREAKPOINT: case PROCESS_SUSPEND: if (req == dbg_null || req == dbg_run_to) continue_execution(); break; } return 1; } static void idaapi stopped_at_debug_event(bool dlls_added) { } static int idaapi thread_suspend(thid_t tid) // Suspend a running thread { return 0; } static int idaapi thread_continue(thid_t tid) // Resume a suspended thread { return 0; } static int idaapi set_step_mode(thid_t tid, resume_mode_t resmod) // Run one instruction in the thread { switch (resmod) { case RESMOD_INTO: ///< step into call (the most typical single stepping) send_dbg_request(dbg_req, REQ_STEP_INTO); break; case RESMOD_OVER: ///< step over call send_dbg_request(dbg_req, REQ_STEP_OVER); break; } return 1; } static int idaapi read_registers(thid_t tid, int clsmask, regval_t *values) { if (!dbg_req) return 0; if (clsmask & RC_GENERAL) { dbg_req->regs_data.type = REG_TYPE_M68K; send_dbg_request(dbg_req, REQ_GET_REGS); // TODO: Set register values for IDA } // TODO: Implement other registers reading return 1; } static void set_reg(register_type_t type, int reg_index, unsigned int value) { dbg_req->regs_data.type = type; dbg_req->regs_data.any_reg.index = reg_index; dbg_req->regs_data.any_reg.val = value; send_dbg_request(dbg_req, REQ_SET_REG); } static int idaapi write_register(thid_t tid, int regidx, const regval_t *value) { // TODO: Implement set registers for emulator return 1; } static int idaapi get_memory_info(meminfo_vec_t &areas) { memory_info_t info; // Don't remove this loop for (int i = 0; i < get_segm_qty(); ++i) { segment_t *segm = getnseg(i); info.start_ea = segm->start_ea; info.end_ea = segm->end_ea; qstring buf; get_segm_name(&buf, segm); info.name = buf; get_segm_class(&buf, segm); info.sclass = buf; info.sbase = 0; info.perm = SEGPERM_READ | SEGPERM_WRITE; info.bitness = 1; areas.push_back(info); } // Don't remove this loop return 1; } static ssize_t idaapi read_memory(ea_t ea, void *buffer, size_t size) { // TODO: Implement memory regions reading return size; } static ssize_t idaapi write_memory(ea_t ea, const void *buffer, size_t size) { return 0; } static int idaapi is_ok_bpt(bpttype_t type, ea_t ea, int len) { switch (type) { //case BPT_SOFT: case BPT_EXEC: case BPT_READ: // there is no such constant in sdk61 case BPT_WRITE: case BPT_RDWR: return BPT_OK; } return BPT_BAD_TYPE; } static int idaapi update_bpts(update_bpt_info_t *bpts, int nadd, int ndel) { for (int i = 0; i < nadd; ++i) { ea_t start = bpts[i].ea; ea_t end = bpts[i].ea + bpts[i].size - 1; bpt_data_t *bpt_data = &dbg_req->bpt_data; switch (bpts[i].type) { case BPT_EXEC: bpt_data->type = BPT_M68K_E; break; case BPT_READ: bpt_data->type = BPT_M68K_R; break; case BPT_WRITE: bpt_data->type = BPT_M68K_W; break; case BPT_RDWR: bpt_data->type = BPT_M68K_RW; break; } bpt_data->address = start; bpt_data->width = bpts[i].size; send_dbg_request(dbg_req, REQ_ADD_BREAK); bpts[i].code = BPT_OK; } for (int i = 0; i < ndel; ++i) { ea_t start = bpts[nadd + i].ea; ea_t end = bpts[nadd + i].ea + bpts[nadd + i].size - 1; bpt_data_t *bpt_data = &dbg_req->bpt_data; switch (bpts[nadd + i].type) { case BPT_EXEC: bpt_data->type = BPT_M68K_E; break; case BPT_READ: bpt_data->type = BPT_M68K_R; break; case BPT_WRITE: bpt_data->type = BPT_M68K_W; break; case BPT_RDWR: bpt_data->type = BPT_M68K_RW; break; } bpt_data->address = start; send_dbg_request(dbg_req, REQ_DEL_BREAK); bpts[nadd + i].code = BPT_OK; } return (ndel + nadd); } //-------------------------------------------------------------------------- // // DEBUGGER DESCRIPTION BLOCK // //-------------------------------------------------------------------------- debugger_t debugger = { IDD_INTERFACE_VERSION, "DBGNAME", 0x8000 + 1, "m68k", DBG_FLAG_NOHOST | DBG_FLAG_CAN_CONT_BPT | DBG_FLAG_FAKE_ATTACH | DBG_FLAG_SAFE | DBG_FLAG_NOPASSWORD | DBG_FLAG_NOSTARTDIR | DBG_FLAG_CONNSTRING | DBG_FLAG_ANYSIZE_HWBPT | DBG_FLAG_DEBTHREAD, register_classes, RC_GENERAL, registers, qnumber(registers), 0x1000, NULL, NULL, 0, DBG_RESMOD_STEP_INTO | DBG_RESMOD_STEP_OVER, init_debugger, term_debugger, process_get_info, start_process, NULL, NULL, rebase_if_required_to, prepare_to_pause_process, emul_exit_process, get_debug_event, continue_after_event, NULL, stopped_at_debug_event, thread_suspend, thread_continue, set_step_mode, read_registers, write_register, NULL, get_memory_info, read_memory, write_memory, is_ok_bpt, update_bpts, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, };
рдЕрдЧрд▓рд╛, рдПрдХ рдФрд░ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдВ, рдЗрд╕реЗ ida_plugin.cpp
рдХреЙрд▓ рдХрд░реЗрдВ рдФрд░ рдЗрд╕рдореЗрдВ рдирд┐рдореНрди рдХреЛрдб рдкреЗрд╕реНрдЯ рдХрд░реЗрдВ:
рд╕реНрд░реЛрдд рдкреИрдХреЗрдЬ ida_plugin.cpp рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ #include <ida.hpp> #include <dbg.hpp> #include <idd.hpp> #include <loader.hpp> #include <idp.hpp> #include <offset.hpp> #include <kernwin.hpp> #include "ida_plugin.h" #include "ida_debmod.h" extern debugger_t debugger; static bool plugin_inited; static bool my_dbg; static int idaapi idp_to_dbg_reg(int idp_reg) { int reg_idx = idp_reg; if (idp_reg >= 0 && idp_reg <= 7) reg_idx = 0 + idp_reg; else if (idp_reg >= 8 && idp_reg <= 39) reg_idx = 8 + (idp_reg % 8); else if (idp_reg == 91) reg_idx = 16; else if (idp_reg == 92 || idp_reg == 93) reg_idx = 17; else if (idp_reg == 94) reg_idx = 15; else { char buf[MAXSTR]; ::qsnprintf(buf, MAXSTR, "reg: %d\n", idp_reg); warning("SEND THIS MESSAGE TO you@mail.com:\n%s\n", buf); return 0; } return reg_idx; } #ifdef _DEBUG static const char* const optype_names[] = { "o_void", "o_reg", "o_mem", "o_phrase", "o_displ", "o_imm", "o_far", "o_near", "o_idpspec0", "o_idpspec1", "o_idpspec2", "o_idpspec3", "o_idpspec4", "o_idpspec5", }; static const char* const dtyp_names[] = { "dt_byte", "dt_word", "dt_dword", "dt_float", "dt_double", "dt_tbyte", "dt_packreal", "dt_qword", "dt_byte16", "dt_code", "dt_void", "dt_fword", "dt_bitfild", "dt_string", "dt_unicode", "dt_3byte", "dt_ldbl", "dt_byte32", "dt_byte64", }; static void print_insn(insn_t *insn) { if (my_dbg) { msg("cs=%x, ", insn->cs); msg("ip=%x, ", insn->ip); msg("ea=%x, ", insn->ea); msg("itype=%x, ", insn->itype); msg("size=%x, ", insn->size); msg("auxpref=%x, ", insn->auxpref); msg("segpref=%x, ", insn->segpref); msg("insnpref=%x, ", insn->insnpref); msg("insnpref=%x, ", insn->insnpref); msg("flags["); if (insn->flags & INSN_MACRO) msg("INSN_MACRO|"); if (insn->flags & INSN_MODMAC) msg("OF_OUTER_DISP"); msg("]\n"); } } static void print_op(ea_t ea, op_t *op) { if (my_dbg) { msg("type[%s], ", optype_names[op->type]); msg("flags["); if (op->flags & OF_NO_BASE_DISP) msg("OF_NO_BASE_DISP|"); if (op->flags & OF_OUTER_DISP) msg("OF_OUTER_DISP|"); if (op->flags & PACK_FORM_DEF) msg("PACK_FORM_DEF|"); if (op->flags & OF_NUMBER) msg("OF_NUMBER|"); if (op->flags & OF_SHOW) msg("OF_SHOW"); msg("], "); msg("dtyp[%s], ", dtyp_names[op->dtype]); if (op->type == o_reg) msg("reg=%x, ", op->reg); else if (op->type == o_displ || op->type == o_phrase) msg("phrase=%x, ", op->phrase); else msg("reg_phrase=%x, ", op->phrase); msg("addr=%x, ", op->addr); msg("value=%x, ", op->value); msg("specval=%x, ", op->specval); msg("specflag1=%x, ", op->specflag1); msg("specflag2=%x, ", op->specflag2); msg("specflag3=%x, ", op->specflag3); msg("specflag4=%x, ", op->specflag4); msg("refinfo["); opinfo_t buf; if (get_opinfo(&buf, ea, op->n, op->flags)) { msg("target=%x, ", buf.ri.target); msg("base=%x, ", buf.ri.base); msg("tdelta=%x, ", buf.ri.tdelta); msg("flags["); if (buf.ri.flags & REFINFO_TYPE) msg("REFINFO_TYPE|"); if (buf.ri.flags & REFINFO_RVAOFF) msg("REFINFO_RVAOFF|"); if (buf.ri.flags & REFINFO_PASTEND) msg("REFINFO_PASTEND|"); if (buf.ri.flags & REFINFO_CUSTOM) msg("REFINFO_CUSTOM|"); if (buf.ri.flags & REFINFO_NOBASE) msg("REFINFO_NOBASE|"); if (buf.ri.flags & REFINFO_SUBTRACT) msg("REFINFO_SUBTRACT|"); if (buf.ri.flags & REFINFO_SIGNEDOP) msg("REFINFO_SIGNEDOP"); msg("]"); } msg("]\n"); } } #endif typedef const regval_t &(idaapi *getreg_func_t)(const char *name, const regval_t *regvalues); static ssize_t idaapi hook_idp(void *user_data, int notification_code, va_list va) { switch (notification_code) { case processor_t::ev_get_idd_opinfo: { idd_opinfo_t * opinf = va_arg(va, idd_opinfo_t *); ea_t ea = va_arg(va, ea_t); int n = va_arg(va, int); int thread_id = va_arg(va, int); getreg_func_t getreg = va_arg(va, getreg_func_t); const regval_t *regvalues = va_arg(va, const regval_t *); opinf->ea = BADADDR; opinf->debregidx = 0; opinf->modified = false; opinf->value.ival = 0; opinf->value_size = 4; insn_t out; if (decode_insn(&out, ea)) { op_t op = out.ops[n]; #ifdef _DEBUG print_insn(&out); #endif int size = 0; switch (op.dtype) { case dt_byte: size = 1; break; case dt_word: size = 2; break; default: size = 4; break; } opinf->value_size = size; switch (op.type) { case o_mem: case o_near: case o_imm: { flags_t flags; switch (n) { case 0: flags = get_optype_flags0(get_flags(ea)); break; case 1: flags = get_optype_flags1(get_flags(ea)); break; default: flags = 0; break; } switch (op.type) { case o_mem: case o_near: opinf->ea = op.addr; break; case o_imm: opinf->ea = op.value; break; } opinfo_t info; if (get_opinfo(&info, ea, n, flags) != NULL) { opinf->ea += info.ri.base; } } break; case o_phrase: case o_reg: { int reg_idx = idp_to_dbg_reg(op.reg); regval_t reg = getreg(dbg->registers(reg_idx).name, regvalues); if (op.phrase >= 0x10 && op.phrase <= 0x1F || // (A0)..(A7), (A0)+..(A7)+ op.phrase >= 0x20 && op.phrase <= 0x27) // -(A0)..-(A7) { if (op.phrase >= 0x20 && op.phrase <= 0x27) reg.ival -= size; opinf->ea = (ea_t)reg.ival; switch (size) { case 1: { uint8_t b = 0; dbg->read_memory((ea_t)reg.ival, &b, 1); opinf->value.ival = b; } break; case 2: { uint16_t w = 0; dbg->read_memory((ea_t)reg.ival, &w, 2); w = swap16(w); opinf->value.ival = w; } break; default: { uint32_t l = 0; dbg->read_memory((ea_t)reg.ival, &l, 4); l = swap32(l); opinf->value.ival = l; } break; } } else opinf->value = reg; opinf->debregidx = reg_idx; } break; case o_displ: { regval_t main_reg, add_reg; int main_reg_idx = idp_to_dbg_reg(op.reg); int add_reg_idx = idp_to_dbg_reg(op.specflag1 & 0xF); main_reg.ival = 0; add_reg.ival = 0; if (op.specflag2 & 0x10) { add_reg = getreg(dbg->registers(add_reg_idx).name, regvalues); if (op.specflag1 & 0x10) { add_reg.ival &= 0xFFFF; add_reg.ival = (uint64)((int16_t)add_reg.ival); } } if (main_reg_idx != 16) main_reg = getreg(dbg->registers(main_reg_idx).name, regvalues); ea_t addr = (ea_t)main_reg.ival + op.addr + (ea_t)add_reg.ival; opinf->ea = addr; switch (size) { case 1: { uint8_t b = 0; dbg->read_memory(addr, &b, 1); opinf->value.ival = b; } break; case 2: { uint16_t w = 0; dbg->read_memory(addr, &w, 2); w = swap16(w); opinf->value.ival = w; } break; default: { uint32_t l = 0; dbg->read_memory(addr, &l, 4); l = swap32(l); opinf->value.ival = l; } break; } } break; } opinf->ea &= 0xFFFFFF; return 1; } } break; default: { #ifdef _DEBUG if (my_dbg) { msg("msg = %d\n", notification_code); } #endif } break; } return 0; } //-------------------------------------------------------------------------- static void print_version() { static const char format[] = NAME " debugger plugin v%s;\nAuthor: Dr. MefistO."; info(format, VERSION); msg(format, VERSION); } //-------------------------------------------------------------------------- // Initialize debugger plugin static int idaapi init(void) { if (ph.id == PLFM_68K) { dbg = &debugger; plugin_inited = true; my_dbg = false; hook_to_notification_point(HT_IDP, hook_idp, NULL); print_version(); return PLUGIN_KEEP; } return PLUGIN_SKIP; } //-------------------------------------------------------------------------- // Terminate debugger plugin static void idaapi term(void) { if (plugin_inited) { unhook_from_notification_point(HT_IDP, hook_idp); plugin_inited = false; } } //-------------------------------------------------------------------------- // The plugin method - usually is not used for debugger plugins static bool idaapi run(size_t arg) { return false; } //-------------------------------------------------------------------------- char comment[] = NAME " debugger plugin by Dr. MefistO."; char help[] = NAME " debugger plugin by Dr. MefistO.\n" "\n" "This module lets you debug Genesis roms in IDA.\n"; //-------------------------------------------------------------------------- // // PLUGIN DESCRIPTION BLOCK // //-------------------------------------------------------------------------- plugin_t PLUGIN = { IDP_INTERFACE_VERSION, PLUGIN_PROC | PLUGIN_DBG | PLUGIN_MOD, // plugin flags init, // initialize term, // terminate. this pointer may be NULL. run, // invoke plugin comment, // long comment about the plugin // it could appear in the status line // or as a hint help, // multiline help about the plugin NAME " debugger plugin", // the preferred short name of the plugin "" // the preferred hotkey to run the plugin };
рдЕрдм рд╕рдордЭрддреЗ рд╣реИрдВ, рдФрд░ рдЙрд╕реА рд╕рдордп рдХреЛрдб рд▓рд┐рдЦрддреЗ рд╣реИрдВред
рдбрд┐рдмрдЧрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
dbg_req
рдЪрд░ рдбрд┐рдмрдЧрд░ рдХреА рдХрд░реНрдиреЗрд▓ рдХреЗ рд╕рд╛рде рд╕рд╛рдЭрд╛ рдХреА рдЧрдИ рдореЗрдореЛрд░реА рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЙрдЗрдВрдЯрд░ рдХреЛ рд╕рдВрдЪрд┐рдд рдХрд░реЗрдЧрд╛ред рдпрд╣ рдЗрд╕рдореЗрдВ рд╣реИ рдХрд┐ рд╣рдо рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВрдЧреЗ, рдФрд░ рдЗрд╕рд╕реЗ рдЙрддреНрддрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗред
рдбреАрдмрдЧрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди pause_execution()
, pause_execution()
рдФрд░ stop_debugging()
рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
eventlist_t g_events
рдбрд┐рдмрдЧрд░ рдШрдЯрдирд╛рдУрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ рдЬреЛ IDA
рд╣рдорд╛рд░реЗ рдХреБрдЫ рдХрд╛рд░реНрдпреЛрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкреНрд░рд╛рд░рдВрдн / рд░реЛрдХрдирд╛ рдЕрдиреБрдХрд░рдг, рдЯреНрд░рд┐рдЧрд░ рд╡рд┐рд░рд╛рдо) рдХреЗ рдЬрд╡рд╛рдм рдореЗрдВ рдЙрдореНрдореАрдж рдХрд░реЗрдЧреАред
рдЦреИрд░, events_thread
рдЗрд╕ рд╕реВрдЪреА рдХреЛ рдлрд┐рд░ рд╕реЗ рднрд░ рджреЗрдЧрд╛, рдЬреЛ рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рдореЗрдВ рдбреАрдмрдЧрд░ рдШрдЯрдирд╛рдУрдВ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░реЗрдЧрд╛, рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕рдВрдмрдВрдзрд┐рдд IDA
рдШрдЯрдирд╛рдУрдВ рдореЗрдВ рдмрджрд▓ рджреЗрдЧрд╛ред
рд╣рдо finish_execution()
рдлрд╝рдВрдХреНрд╢рди finish_execution()
, рдЬреЛ рдХреЗрд╡рд▓ рдбреАрдмрдЧрд┐рдВрдЧ рдЗрд╡реЗрдВрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдереНрд░реЗрдб рд╕рдорд╛рдкреНрдд рдХрд░реЗрдЧрд╛:
static void finish_execution() { if (events_thread != NULL) { qthread_join(events_thread); qthread_free(events_thread); qthread_kill(events_thread); events_thread = NULL; } }
рдЗрд╕рд▓рд┐рдП, рд╣рдордиреЗ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ред рдЕрдм рд╡рд░реНрдгрди рджрд░реНрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЖрддреЗ рд╣реИрдВред
рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдлреЙрд░реНрдо рдХреА рдПрдХ рд╕рдВрд░рдЪрдирд╛ рд╣реИ:
struct register_info_t { const char *name; uint32 flags; register_class_t register_class; op_dtype_t dtype; const char *const *bit_strings; uval_t default_bit_strings_mask; };
name
рдлрд╝реАрд▓реНрдб рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд╛ рдкрд╛рда рдирд╛рдо рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рд╕рдореВрд╣реЛрдВ рдореЗрдВ рдПрдХ рд╣реА рдирд╛рдо рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдк рджреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реЗ PC
рд░рдЬрд┐рд╕реНрдЯрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ (рдФрд░ Sega Mega Drive
рдореЗрдВ рдЙрдирдореЗрдВ рд╕реЗ рджреЛ рд╣реИрдВ: Motorola 68000
рдФрд░ Z80
), рддреЛ рдЖрдкрдХреЛ рдЗрд╕рдХрд╛ рдирд╛рдо рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛ред
flags
рдореИрджрд╛рди рдореЗрдВ рдирд┐рдореНрди рдореЗрдВ рд╕реЗ рдПрдХ рдпрд╛ рдЕрдзрд┐рдХ flags
рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:
#define REGISTER_READONLY 0x0001
рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ рдХрд┐ рдЖрдк REGISTER_IP
рдФрд░ REGISTER SP
рд╕рдВрдпреЛрдЬрд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЖрдк рдпрд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдлрд╝реАрд▓реНрдб рдореЗрдВ REGISTER_ADDRESS
рдзреНрд╡рдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдкрддрд╛ рд╣реИред
register_class
рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рд▓рд╛рдЧреВ рдХрд┐рдП рдЧрдП рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдХреЗ рд╕рдореВрд╣ рдХреА рдореБрдЦреМрдЯрд╛ рд╕рдВрдЦреНрдпрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддреАрди рдЬреЛрдбрд╝реЗ рд╣реИрдВ:
#define RC_GENERAL (1 << 0) #define RC_VDP (1 << 1) #define RC_Z80 (1 << 2)
dtype
рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рдЖрдХрд╛рд░ рдХрд╛ рдПрдХ рд╕рдВрдХреЗрдд рд╣реИред рд╡рд┐рдХрд▓реНрдк рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИрдВ:
#define dt_byte 0
рджрд░рдЕрд╕рд▓, рдореБрдЭреЗ рдХреЗрд╡рд▓ dt_word
, dt_dword
ред
bit_strings
рдлрд╝реАрд▓реНрдб bit_strings
рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЗрд╕рдХреЗ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдмрд┐рдЯреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдХреБрдЫ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд░рдЬрд┐рд╕реНрдЯрд░ рдЭрдВрдбреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: Negative
, Overflow
, Zero
, Carry
, рдЖрджрд┐ред рдПрдХ рдЙрджрд╛рд╣рд░рдг:
static const char *const SRReg[] = { "C", "V", "Z", "N", "X", NULL, NULL, NULL, "I", "I", "I", NULL, NULL, "S", NULL, "T" };
рдмрд┐рдЯреНрд╕ рдКрдкрд░ рд╕реЗ рдиреАрдЪреЗ (рдХрдо рд╕реЗ рдЙрдЪреНрдЪ рддрдХ) рд╕реЗ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИрдВред рдпрджрд┐ рдЖрдкрдХреЛ рдмрд┐рдЯ рдорд╛рди рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдирд╛рдо рдХреЗ рдмрдЬрд╛рдп NULL
рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВред рдпрджрд┐ рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдХрдИ рдмрд┐рдЯреНрд╕ рдПрдХ рдЭрдВрдбреЗ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рд╣реА рдирд╛рдо рдХреЛ рдХрдИ рдмрд╛рд░ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрдЦреНрдпрд╛ рджрд░реНрд╢рд╛рддреЗ рд╣реИрдВред
рдЦреИрд░, рдЕрдВрддрд┐рдо default_bit_strings_mask
рдлрд╝реАрд▓реНрдб рдПрдХ рдмрд┐рдЯрдорд╛рд╕реНрдХ рд╣реИ рдЬрд┐рд╕реЗ рд░рдЬрд┐рд╕реНрдЯрд░ рдмрд┐рдЯ рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдпрд╣рд╛рдБ Sega Mega Drive
рд▓рд┐рдП рд░рдЬрд┐рд╕реНрдЯрд░ рд╕реВрдЪреА рдХреЗ рдореЗрд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ (рдореИрдВрдиреЗ M68K, Z80 рдФрд░ VDP рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдХреЛ рдЪрд╛рд▓реВ рдХрд┐рдпрд╛, рд╕рд╛рде рд╣реА рд╕рд╛рде рдХрд╕реНрдЯрдо рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рднреА):
рдбрд┐рдмрдЧрд░ рдХреЗ рд▓рд┐рдП рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдХрд╛ рд╡рд┐рд╡рд░рдг register_info_t registers[] = { { "D0", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D1", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D2", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D3", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D4", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D5", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D6", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "D7", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A0", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A1", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A2", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A3", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A4", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A5", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A6", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "A7", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "PC", REGISTER_ADDRESS | REGISTER_IP, RC_GENERAL, dt_dword, NULL, 0 }, { "SR", NULL, RC_GENERAL, dt_word, SRReg, 0xFFFF }, { "SP", REGISTER_ADDRESS | REGISTER_SP, RC_GENERAL, dt_dword, NULL, 0 }, { "USP", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "ISP", REGISTER_ADDRESS, RC_GENERAL, dt_dword, NULL, 0 }, { "PPC", REGISTER_ADDRESS | REGISTER_READONLY, RC_GENERAL, dt_dword, NULL, 0 }, { "IR", NULL, RC_GENERAL, dt_dword, NULL, 0 },
рдЗрд╕рдХреЗ рдмрд╛рдж register_classes[]
рд╕реВрдЪреА рдЖрддреА рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╣рдореЗрдВ рд░рдЬрд┐рд╕реНрдЯрд░ рд╕рдореВрд╣реЛрдВ рдХреЗ рдкрд╛рда рдирд╛рдореЛрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдЙрдиреНрд╣реЗрдВ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЦрд┐рдбрд╝рдХрд┐рдпреЛрдВ рдореЗрдВ рдЦреЛрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдпрд╣рд╛рдБ рдореЗрд░рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ (рдЕрдВрддрд┐рдо рддрддреНрд╡ NULL
рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП):
static const char *register_classes[] = { "General Registers", "VDP Registers", "Z80 Registers", NULL };
рдЖрдИрдбреАрдП рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рдХреЙрд▓рдмреИрдХ
init_debugger ()
static bool idaapi init_debugger(const char *hostname, int portnum, const char *password) { set_processor_type(ph.psnames[0], SETPROC_LOADER);
рдЪреВрдВрдХрд┐ IDA
рдореЛрдЯреЛрд░реЛрд▓рд╛ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреЗ рдХрдИ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЗрд╕реЗ рд╕реВрдЪреА рдореЗрдВ рдкрд╣рд▓реЗ рд╕реНрдерд╛рди рдкрд░ рдЬрдмрд░рди рд░реАрд╕реЗрдЯ рдХрд░ рджреЗрддрд╛ рд╣реВрдВред
term_debugger ()
static bool idaapi term_debugger(void) { dbg_req->is_ida = 0; close_shared_mem(&dbg_req); return true; }
рдордЬреЗрджрд╛рд░ рддрдереНрдп : init_debugger()
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкреНрд░рддрд┐ рд╕рддреНрд░ рдЗрдореНрдпреВрд▓реЗрд╢рди рдХреА рдкрд╣рд▓реА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдПрдХ рдмрд╛рд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ term_debugger()
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╣рд░ рдмрд╛рд░ рдбрд┐рдмрдЧрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреВрд░реА рд╣реЛрдиреЗ рдкрд░ term_debugger()
рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдпрд╣рд╛рдВ рдЦреБрд▓реА рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рдХреЛ рдмрдВрдж рдХрд░рддрд╛ рд╣реВрдВред
рд╕рдлрд▓ рд╣реЛрдиреЗ рдкрд░ рджреЛрдиреЛрдВ рдХрд╛рд░реНрдп true
рдЪрд╛рд╣рд┐рдПред
process_get_info ()
static int idaapi process_get_info(procinfo_vec_t *procs) { return 0; }
рдпрджрд┐ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдЖрдк рдХрдИ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕ рдХреЙрд▓рдмреИрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рдЙрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рд▓рд┐рдП IDA
рдЬрд╛рдирдХрд╛рд░реА рдХреА рд╕реВрдЪрдирд╛ рджреЗрдЧрд╛, рдЕрд░реНрдерд╛рддреН PID
рдФрд░ рдирд╛рдоред
рдореБрдЭреЗ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ 0
рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реВрдВред
check_debugger_events () - рдХреЙрд▓рдмреИрдХ рдирд╣реАрдВ, рд▓реЗрдХрд┐рди рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдбрд┐рдмрдЧрд┐рдВрдЧ рдШрдЯрдирд╛рдУрдВ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рдПрдХ рдзрд╛рдЧрд╛ рд╣реИред рдпрд╣рд╛рдБ рдкрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдмрддрд╛рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред
рдЬрдм рдбреАрдмрдЧ рдХрд░рдирд╛ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ IDA
рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░рдиреЗ рд╡рд╛рд▓реА рдкрд╣рд▓реА рдШрдЯрдирд╛ PROCESS_START
рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рдкрд╣рд▓реЗ рдПрдХ рдЖрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рд░рд╛рдо рдЕрдиреБрдХрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд╕рдВрджреЗрд╢, IDA
рдмрд╕ рдЧрд┐рд░ рдЬрд╛рдПрдЧрд╛ред
рдЙрд╕рдХреЗ рдмрд╛рдж, рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдиреНрдп рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдореБрдЦреНрдп рд╣реИрдВ:
PROCESS_SUSPEND
тАФ , , .BREAKPOINT
тАФ IDA
, тАФ , , . ? PROCESS_SUSPEND
, , IDA
STEP
тАФ , IDA
, Step Into
Step Over
, , , PROCESS_SUSPEND
PROCESS_EXIT
тАФ IDA
, . Stop
, IDA
, , , .
:
struct debug_event_t { event_id_t eid;
eid
тАФ ,
pid
, tid
тАФ , Process ID Thread ID ,
ea
тАФ ,
handled
тАФ , , IDA SDK
, , ( ?). true
, .
PROCESS_START
( ), ImageBase
, , , ImageBase
, , IDB
. , , BADADDR
:
case DBG_EVT_STARTED: ev.eid = PROCESS_START; ev.pid = 1; ev.tid = 1; ev.ea = BADADDR; ev.handled = true; ev.modinfo.name[0] = 'G'; ev.modinfo.name[1] = 'P'; ev.modinfo.name[2] = 'G'; ev.modinfo.name[3] = 'X'; ev.modinfo.name[4] = '\0'; ev.modinfo.base = 0; ev.modinfo.size = 0; ev.modinfo.rebase_to = BADADDR; g_events.enqueue(ev, IN_FRONT); break;
BREAKPOINT
bpt
hardware
тАФ kernel
- . , IDA
, .
case DBG_EVT_BREAK: ev.pid = 1; ev.tid = 1; ev.ea = dbg_event->pc; ev.handled = true; ev.eid = BREAKPOINT; ev.bpt.hea = ev.bpt.kea = ev.ea; g_events.enqueue(ev, IN_BACK); break;
PROCESS_EXIT
exit_code
.
start_process()
, , , .
, ( ), , .
1
.
rebase_if_required_to()
, .. , , :
rebase_if_required_to static void idaapi rebase_if_required_to(ea_t new_base) { ea_t currentbase = new_base; ea_t imagebase = inf.startIP; if (imagebase != currentbase) { adiff_t delta = currentbase - imagebase; int code = rebase_program(delta, MSF_FIXONCE); if (code != MOVE_SEGM_OK) { msg("Failed to rebase program, error code %d\n", code); warning("IDA failed to rebase the program.\n" "Most likely it happened because of the debugger\n" "segments created to reflect the real memory state.\n\n" "Please stop the debugger and rebase the program manually.\n" "For that, please select the whole program and\n" "use Edit, Segments, Rebase program with delta 0x%08a", delta); } } }
prepare_to_pause_process()
Pause
IDA
, .
1
.
get_debug_event()
, IDA
, . (?) . , debug_event_t
*event
, :
GDE_ONE_EVENT
, ,GDE_MANY_EVENTS
, ,GDE_NO_EVENT
,
static gdecode_t idaapi get_debug_event(debug_event_t *event, int timeout_ms) { while (true) {
continue_after_event()
, - IDA
. .
, , , - . :
STEP
IDA
, ..- , ,
Step In
continue_after_event()
, . тАФ STEP
IDA
STEP
, , , , !
, , 3
Step Into
, Step Over
, F9
, .
STEP
, BREAKPOINT
PROCESS_SUSPEND
, F9
, continue_execution()
. F9
Run to
:
dbg_notification_t req = get_running_notification(); if (req == dbg_null || req == dbg_run_to) continue_execution();
stopped_at_debug_event()
, . .
thread_suspend(), thread_continue()
, / , . , , 0
. , .
set_step_mode()
, Step Into
, Step Over
, Step Out
. ( debugger_t
, ).
1
.
static int idaapi set_step_mode(thid_t tid, resume_mode_t resmod) { switch (resmod) { case RESMOD_INTO: send_dbg_request(dbg_req, REQ_STEP_INTO); break; case RESMOD_OVER: send_dbg_request(dbg_req, REQ_STEP_OVER); break; } return 1; }
read_registers()
IDA
STEP
, BREAKPOINT
PROCESS_SUSPEND
(.. , ), , .
:
clsmask
тАФ ? .values
тАФ , . registers[]
.
:
read_registers() static int idaapi read_registers(thid_t tid, int clsmask, regval_t *values) { if (!dbg_req) return 0; if (clsmask & RC_GENERAL) { dbg_req->regs_data.type = REG_TYPE_M68K; send_dbg_request(dbg_req, REQ_GET_REGS); regs_68k_data_t *reg_vals = &dbg_req->regs_data.regs_68k; values[REG_68K_D0].ival = reg_vals->d0; values[REG_68K_D1].ival = reg_vals->d1; values[REG_68K_D2].ival = reg_vals->d2; values[REG_68K_D3].ival = reg_vals->d3; values[REG_68K_D4].ival = reg_vals->d4; values[REG_68K_D5].ival = reg_vals->d5; values[REG_68K_D6].ival = reg_vals->d6; values[REG_68K_D7].ival = reg_vals->d7; values[REG_68K_A0].ival = reg_vals->a0; values[REG_68K_A1].ival = reg_vals->a1; values[REG_68K_A2].ival = reg_vals->a2; values[REG_68K_A3].ival = reg_vals->a3; values[REG_68K_A4].ival = reg_vals->a4; values[REG_68K_A5].ival = reg_vals->a5; values[REG_68K_A6].ival = reg_vals->a6; values[REG_68K_A7].ival = reg_vals->a7; values[REG_68K_PC].ival = reg_vals->pc & 0xFFFFFF; values[REG_68K_SR].ival = reg_vals->sr; values[REG_68K_SP].ival = reg_vals->sp & 0xFFFFFF; values[REG_68K_PPC].ival = reg_vals->ppc & 0xFFFFFF; values[REG_68K_IR].ival = reg_vals->ir; } if (clsmask & RC_VDP) { dbg_req->regs_data.type = REG_TYPE_VDP; send_dbg_request(dbg_req, REQ_GET_REGS); vdp_regs_t *vdp_regs = &dbg_req->regs_data.vdp_regs; for (int i = 0; i < sizeof(vdp_regs->regs_vdp) / sizeof(vdp_regs->regs_vdp[0]); ++i) { values[REG_VDP_00 + i].ival = vdp_regs->regs_vdp[i]; } values[REG_VDP_DMA_LEN].ival = vdp_regs->dma_len; values[REG_VDP_DMA_SRC].ival = vdp_regs->dma_src; values[REG_VDP_DMA_DST].ival = vdp_regs->dma_dst; } if (clsmask & RC_Z80) { dbg_req->regs_data.type = REG_TYPE_Z80; send_dbg_request(dbg_req, REQ_GET_REGS); regs_z80_data_t *z80_regs = &dbg_req->regs_data.regs_z80; for (int i = 0; i < (REG_Z80_I - REG_Z80_PC + 1); ++i) { if (i >= 0 && i <= 12)
1
.
write_register()
тАФ . .
:
write_register() static int idaapi write_register(thid_t tid, int regidx, const regval_t *value) { if (regidx >= REG_68K_D0 && regidx <= REG_68K_D7) { set_reg(REG_TYPE_M68K, regidx - REG_68K_D0, (uint32)value->ival); } else if (regidx >= REG_68K_A0 && regidx <= REG_68K_A7) { set_reg(REG_TYPE_M68K, regidx - REG_68K_A0, (uint32)value->ival); } else if (regidx == REG_68K_PC) { set_reg(REG_TYPE_M68K, REG_68K_PC, (uint32)value->ival & 0xFFFFFF); } else if (regidx == REG_68K_SR) { set_reg(REG_TYPE_M68K, REG_68K_SR, (uint16)value->ival); } else if (regidx == REG_68K_SP) { set_reg(REG_TYPE_M68K, REG_68K_SP, (uint32)value->ival & 0xFFFFFF); } else if (regidx == REG_68K_USP) { set_reg(REG_TYPE_M68K, REG_68K_USP, (uint32)value->ival & 0xFFFFFF); } else if (regidx == REG_68K_ISP) { set_reg(REG_TYPE_M68K, REG_68K_ISP, (uint32)value->ival & 0xFFFFFF); } else if (regidx >= REG_VDP_00 && regidx <= REG_VDP_1F) { set_reg(REG_TYPE_VDP, regidx - REG_VDP_00, value->ival & 0xFF); } else if (regidx >= REG_Z80_PC && regidx <= REG_Z80_I) { set_reg(REG_TYPE_Z80, regidx - REG_Z80_PC, value->ival); } return 1; }
1
.
get_memory_info()
, . : IDB
- , . .
- , , . :
info.name = "DBG_VDP_VRAM"; info.start_ea = 0xD00000; info.end_ea = info.start_ea + 0x10000; info.bitness = 1; areas.push_back(info); info.name = "DBG_VDP_CRAM"; info.start_ea = info.end_ea; info.end_ea = info.start_ea + 0x10000; info.bitness = 1; areas.push_back(info); info.name = "DBG_VDP_VSRAM"; info.start_ea = info.end_ea; info.end_ea = info.start_ea + 0x10000; info.bitness = 1; areas.push_back(info);
1
.
read_memory()
. , , XTRN
, IDA
.
ea
, , size
, , buffer
, .
read_memory() static ssize_t idaapi read_memory(ea_t ea, void *buffer, size_t size) { if ((ea >= 0xA00000 && ea < 0xA0FFFF)) { dbg_req->mem_data.address = ea; dbg_req->mem_data.size = size; send_dbg_request(dbg_req, REQ_READ_Z80); memcpy(buffer, &dbg_req->mem_data.z80_ram[ea & 0x1FFF], size);
write_memory()
, - : , RAM, , .
, 0
. 1
.
, , , buffer
тАФ , .
is_ok_bpt()
len
type
ea
.
, BPT_OK
, тАФ BPT_BAD_TYPE
.
update_bpts()
, IDA
. , , . F9
( Continue ).
:
bpts
, , : , , , nadd
ndel
, .- , ,
bpts[i].code
BPT_OK
.
+ . nadd + ndel
.
update_bpts() static int idaapi update_bpts(update_bpt_info_t *bpts, int nadd, int ndel) { for (int i = 0; i < nadd; ++i) { ea_t start = bpts[i].ea; ea_t end = bpts[i].ea + bpts[i].size - 1; bpt_data_t *bpt_data = &dbg_req->bpt_data; switch (bpts[i].type) { case BPT_EXEC: bpt_data->type = BPT_M68K_E; break; case BPT_READ: bpt_data->type = BPT_M68K_R; break; case BPT_WRITE: bpt_data->type = BPT_M68K_W; break; case BPT_RDWR: bpt_data->type = BPT_M68K_RW; break; } bpt_data->address = start; bpt_data->width = bpts[i].size; send_dbg_request(dbg_req, REQ_ADD_BREAK); bpts[i].code = BPT_OK; } for (int i = 0; i < ndel; ++i) { ea_t start = bpts[nadd + i].ea; ea_t end = bpts[nadd + i].ea + bpts[nadd + i].size - 1; bpt_data_t *bpt_data = &dbg_req->bpt_data; switch (bpts[nadd + i].type) { case BPT_EXEC: bpt_data->type = BPT_M68K_E; break; case BPT_READ: bpt_data->type = BPT_M68K_R; break; case BPT_WRITE: bpt_data->type = BPT_M68K_W; break; case BPT_RDWR: bpt_data->type = BPT_M68K_RW; break; } bpt_data->address = start; send_dbg_request(dbg_req, REQ_DEL_BREAK); bpts[nadd + i].code = BPT_OK; } return (ndel + nadd); }
debugger_t
, (, , IDA
, , , , ).
:
debugger_t struct debugger_t { int version;
, , , .
рд╣рд╛рдБ, рд╣рд╛рдБред ida_plugin.cpp
. , .
idp_to_dbg_reg()
( ) .
static int idaapi idp_to_dbg_reg(int idp_reg) { int reg_idx = idp_reg; if (idp_reg >= 0 && idp_reg <= 7) reg_idx = 0 + idp_reg; else if (idp_reg >= 8 && idp_reg <= 39) reg_idx = 8 + (idp_reg % 8); else if (idp_reg == 91) reg_idx = 16; else if (idp_reg == 92 || idp_reg == 93) reg_idx = 17; else if (idp_reg == 94) reg_idx = 15; else { char buf[MAXSTR]; ::qsnprintf(buf, MAXSTR, "reg: %d\n", idp_reg); warning("SEND THIS MESSAGE TO you@mail.com:\n%s\n", buf); return 0; } return reg_idx; }
hook_idp()
hook_to_notification_point()
:
hook_to_notification_point(HT_IDP, hook_idp, NULL);
unhook_from_notification_point()
:
unhook_from_notification_point(HT_IDP, hook_idp);
: debugger hints . "":

, , - , . , , IDA
, . .
notification_code
ev_get_idd_opinfo
. , , , , , .
case processor_t::ev_get_idd_opinfo: { idd_opinfo_t * opinf = va_arg(va, idd_opinfo_t *); ea_t ea = va_arg(va, ea_t); int n = va_arg(va, int); int thread_id = va_arg(va, int); getreg_func_t getreg = va_arg(va, getreg_func_t); const regval_t *regvalues = va_arg(va, const regval_t *); opinf->ea = BADADDR; opinf->debregidx = 0; opinf->modified = false; opinf->value.ival = 0; opinf->value_size = 4; insn_t out; if (decode_insn(&out, ea)) { op_t op = out.ops[n]; #ifdef _DEBUG print_insn(&out); #endif int size = 0; switch (op.dtype) { case dt_byte: size = 1; break; case dt_word: size = 2; break; default: size = 4; break; } opinf->value_size = size; switch (op.type) { case o_mem: case o_near: case o_imm: { flags_t flags; switch (n) { case 0: flags = get_optype_flags0(get_flags(ea)); break; case 1: flags = get_optype_flags1(get_flags(ea)); break; default: flags = 0; break; } switch (op.type) { case o_mem: case o_near: opinf->ea = op.addr; break; case o_imm: opinf->ea = op.value; break; } opinfo_t info; if (get_opinfo(&info, ea, n, flags) != NULL) { opinf->ea += info.ri.base; } } break; case o_phrase: case o_reg: { int reg_idx = idp_to_dbg_reg(op.reg); regval_t reg = getreg(dbg->registers(reg_idx).name, regvalues); if (op.phrase >= 0x10 && op.phrase <= 0x1F || // (A0)..(A7), (A0)+..(A7)+ op.phrase >= 0x20 && op.phrase <= 0x27) // -(A0)..-(A7) { if (op.phrase >= 0x20 && op.phrase <= 0x27) reg.ival -= size; opinf->ea = (ea_t)reg.ival; switch (size) { case 1: { uint8_t b = 0; dbg->read_memory((ea_t)reg.ival, &b, 1); opinf->value.ival = b; } break; case 2: { uint16_t w = 0; dbg->read_memory((ea_t)reg.ival, &w, 2); w = swap16(w); opinf->value.ival = w; } break; default: { uint32_t l = 0; dbg->read_memory((ea_t)reg.ival, &l, 4); l = swap32(l); opinf->value.ival = l; } break; } } else opinf->value = reg; opinf->debregidx = reg_idx; } break; case o_displ: { regval_t main_reg, add_reg; int main_reg_idx = idp_to_dbg_reg(op.reg); int add_reg_idx = idp_to_dbg_reg(op.specflag1 & 0xF); main_reg.ival = 0; add_reg.ival = 0; if (op.specflag2 & 0x10) { add_reg = getreg(dbg->registers(add_reg_idx).name, regvalues); if (op.specflag1 & 0x10) { add_reg.ival &= 0xFFFF; add_reg.ival = (uint64)((int16_t)add_reg.ival); } } if (main_reg_idx != 16) main_reg = getreg(dbg->registers(main_reg_idx).name, regvalues); ea_t addr = (ea_t)main_reg.ival + op.addr + (ea_t)add_reg.ival; opinf->ea = addr; switch (size) { case 1: { uint8_t b = 0; dbg->read_memory(addr, &b, 1); opinf->value.ival = b; } break; case 2: { uint16_t w = 0; dbg->read_memory(addr, &w, 2); w = swap16(w); opinf->value.ival = w; } break; default: { uint32_t l = 0; dbg->read_memory(addr, &l, 4); l = swap32(l); opinf->value.ival = l; } break; } } break; } opinf->ea &= 0xFFFFFF; return 1; } } break;
, .
init()
, .
, id
ph
.
PLFM_68K
. dbg
debugger_t
.
HT_IDP
, PLUGIN_KEEP
. , , PLUGIN_SKIP
.
static int idaapi init(void) { if (ph.id == PLFM_68K) { dbg = &debugger; plugin_inited = true; my_dbg = false; hook_to_notification_point(HT_IDP, hook_idp, NULL); print_version(); return PLUGIN_KEEP; } return PLUGIN_SKIP; }
term()
IDB
-. , init()
.
static void idaapi term(void) { if (plugin_inited) { unhook_from_notification_point(HT_IDP, hook_idp); plugin_inited = false; } }
run()
- . false
.
plugin_t
: , , , , :
plugin_t class plugin_t { public: int version;
рд╢рд╛рдпрдж рдпрд╣реА рд╕рдм рд╣реИред , , . , IDA
, .
, :
GPGX Debugger
Smd IDA Tools