// create the mapping table static void create_mappings(void) { free_mappings(); for ( int i=0; i < numports; i++ ) { const char *name = ports[i].name; ea_t nameea = get_name_ea(BADADDR, name); if ( nameea != BADADDR && nameea > dataseg) add_mapping(ports[i].address, nameea-dataseg); } }
ea_t find_import_loc(const char *name) { for (int i = 0; i < get_segm_qty(); i++) { segment_t *seg = getnseg(i); //msg("segment[%d] %a %a\n", i, seg->startEA, seg->endEA); if (seg->type == SEG_XTRN) { //msg("segment[%d] == SEG_XTRN\n", i); ea_t loc = get_name_ea(seg->startEA, name); if (loc != BADADDR) { return loc; } } } return BADADDR; }
static int notify(processor_t::idp_notify msgid, ...) // Various messages { va_list va; va_start(va, msgid); // A well behaving processor module should call invoke_callbacks() // in his notify() function. If this function returns 0, then // the processor module should process the notification itself // Otherwise the code should be returned to the caller: int code = invoke_callbacks(HT_IDP, msgid, va); if ( code ) return code; switch ( msgid ) { case processor_t::newfile: { // ig: вообще у меня теперь такая точка зрения: // не надо в коде задавать вид имен. // при желании это можно сделать в ida.cfg: // #ifdef __80196__ // DUMMY_NAMES_TYPE = NM_SHORT // #endif segment_t *sptr = get_first_seg(); if( sptr != NULL ) set_segm_class( sptr, "CODE" ); ea_t ea, ea1; for( int i = 0; i < qnumber(entries); i++ ) { ea = toEA( inf.baseaddr, entries[i].off ); if( isEnabled(ea) ) { switch( entries[i].type ) { case I196F_BTS: doByte( ea, entries[i+1].off-entries[i].off ); set_cmt( ea, entries[i].cmt, 0 ); break; case I196F_CMT: if( entries[i].cmt ) add_long_cmt( ea, 1, "%s", entries[i].cmt ); else describe( ea, 1, "" ); break; case I196F_OFF: doWord( ea, 2 ); set_offset( ea, 0, toEA( inf.baseaddr, 0 ) ); ea1 = toEA( inf.baseaddr, get_word( ea ) ); auto_make_proc( ea1 ); //dash: long_cmt здесь не смотрится, так как рисуется до заголовка // хорошо бы поставить func_cmt, но к этому моменту функций еще нет // как быть? //ig: воспользоваться простым комментарием // при создании функции комментарий перетащится set_cmt( ea1, entries[i].cmt, 1 ); } set_name( ea, entries[i].name ); } } ea = toEA( inf.baseaddr, 0x2080 ); if( isEnabled( ea ) ) { inf.beginEA = ea; inf.startIP = 0x2080; } segment_t s; s.startEA = toEA( inf.baseaddr, 0 ); s.endEA = toEA( inf.baseaddr, 0x400 ); s.sel = inf.baseaddr; s.type = SEG_IMEM; // internal memory // ig: лучше искать дырку не от нуля, а от базы загрузки // ea_t bottom = toEA( inf.baseaddr, 0 ); // intmem = s.startEA = freechunk( bottom, 1024, 0xF ); // s.endEA = s.startEA + 1024; // s.sel = ushort(s.startEA >> 4); // dash: дырку искать не пришлось, но я оставил это как пример на будущее add_segm_ex( &s, "INTMEM", NULL, ADDSEG_OR_DIE); predefined_t *ptr; for( ptr = iregs; ptr->name != NULL; ptr++ ) { ea_t ea = toEA( inf.baseaddr, ptr->addr ); ea_t oldea = get_name_ea( BADADDR, ptr->name ); if( oldea != ea ) { if( oldea != BADADDR ) set_name( oldea, NULL ); do_unknown( ea, DOUNK_EXPAND ); set_name( ea, ptr->name ); } if( ptr->cmt != NULL ) set_cmt( ea, ptr->cmt, 1 ); } } // do16bit( 0x18, 2 ); // SP always word break; case processor_t::oldfile: for ( segment_t *s=get_first_seg(); s != NULL; s=get_next_seg(s->startEA) ) { if ( getSRarea(s->startEA) == NULL ) { segreg_t sr; sr.startEA = s->startEA; sr.endEA = s->endEA; sr.reg(WSR) = 0; sr.reg(WSR1) = 0; sr.reg(rVds) = inf.baseaddr; sr.settags(SR_autostart); SRareas.create_area(&sr); } } break; case processor_t::newseg: // default DS is equal to Base Address (va_arg(va, segment_t *))->defsr[rVds-ph.regFirstSreg] = inf.baseaddr; break; case processor_t::newprc: extended = va_arg(va,int) != 0; if ( !extended ) ph.flag &= ~PR_SEGS; else ph.flag |= PR_SEGS; default: break; } va_end(va); return(1); }
//-------------------------------------------------------------------------- static int idaapi callback( void * /*user_data*/, int notification_code, va_list va) { static int stage = 0; static bool is_dll; static char needed_file[QMAXPATH]; switch ( notification_code ) { case dbg_process_start: case dbg_process_attach: get_input_file_path(needed_file, sizeof(needed_file)); // no break case dbg_library_load: if ( stage == 0 ) { const debug_event_t *pev = va_arg(va, const debug_event_t *); if ( !strieq(pev->modinfo.name, needed_file) ) break; if ( notification_code == dbg_library_load ) is_dll = true; // remember the current module bounds if ( pev->modinfo.rebase_to != BADADDR ) curmod.startEA = pev->modinfo.rebase_to; else curmod.startEA = pev->modinfo.base; curmod.endEA = curmod.startEA + pev->modinfo.size; deb(IDA_DEBUG_PLUGIN, "UUNP: module space %a-%a\n", curmod.startEA, curmod.endEA); ++stage; } break; case dbg_library_unload: if ( stage != 0 && is_dll ) { const debug_event_t *pev = va_arg(va, const debug_event_t *); if ( curmod.startEA == pev->modinfo.base || curmod.startEA == pev->modinfo.rebase_to ) { deb(IDA_DEBUG_PLUGIN, "UUNP: unload unpacked module\n"); if ( stage > 2 ) enable_step_trace(false); stage = 0; curmod.startEA = 0; curmod.endEA = 0; _hide_wait_box(); } } break; case dbg_run_to: // Parameters: const debug_event_t *event dbg->stopped_at_debug_event(true); bp_gpa = get_name_ea(BADADDR, "kernel32_GetProcAddress"); #ifndef __X64__ if( (LONG)GetVersion() < 0 ) // win9x mode -- use thunk's { is_9x = true; win9x_resolve_gpa_thunk(); } #endif if ( bp_gpa == BADADDR ) { bring_debugger_to_front(); warning("Sorry, could not find kernel32.GetProcAddress"); FORCE_STOP: stage = 4; // last stage clear_requests_queue(); request_exit_process(); run_requests(); break; } else if( !my_add_bpt(bp_gpa) ) { bring_debugger_to_front(); warning("Sorry, can not set bpt to kernel32.GetProcAddress"); goto FORCE_STOP; } else { ++stage; set_wait_box("Waiting for a call to GetProcAddress()"); } continue_process(); break; case dbg_bpt: // A user defined breakpoint was reached. // Parameters: thid_t tid // ea_t breakpoint_ea // int *warn = -1 // Return (in *warn): // -1 - to display a breakpoint warning dialog // if the process is suspended. // 0 - to never display a breakpoint warning dialog. // 1 - to always display a breakpoint warning dialog. { thid_t tid = va_arg(va, thid_t); qnotused(tid); ea_t ea = va_arg(va, ea_t); //int *warn = va_arg(va, int*); if ( stage == 2 ) { if ( ea == bp_gpa ) { regval_t rv; if ( get_reg_val(REGNAME_ESP, &rv) ) { ea_t esp = ea_t(rv.ival); invalidate_dbgmem_contents(esp, 1024); ea_t gpa_caller = getPtr(esp); if ( !is_library_entry(gpa_caller) ) { ea_t nameaddr; if ( ptrSz == 4 ) { nameaddr = get_long(esp+8); } else { get_reg_val(REGNAME_ECX, &rv); nameaddr = ea_t(rv.ival); } invalidate_dbgmem_contents(nameaddr, 1024); char name[MAXSTR]; size_t len = get_max_ascii_length(nameaddr, ASCSTR_C, ALOPT_IGNHEADS); name[0] = '\0'; get_ascii_contents2(nameaddr, len, ASCSTR_C, name, sizeof(name)); if ( !ignore_win32_api(name) ) { deb(IDA_DEBUG_PLUGIN, "%a: found a call to GetProcAddress(%s)\n", gpa_caller, name); if ( !my_del_bpt(bp_gpa) || !my_add_bpt(gpa_caller) ) error("Can not modify breakpoint"); } } } } else if ( ea == bpt_ea ) { my_del_bpt(ea); if ( !is_library_entry(ea) ) { msg("Uunp: reached unpacker code at %a, switching to trace mode\n", ea); enable_step_trace(true); ++stage; uint64 eax; if ( get_reg_val(REGNAME_EAX, &eax) ) an_imported_func = ea_t(eax); set_wait_box("Waiting for the unpacker to finish"); } else { warning("%a: bpt in library code", ea); // how can it be? my_add_bpt(bp_gpa); } } // not our bpt? skip it else { // hide the wait box to allow others plugins to properly stop _hide_wait_box(); break; } } } // while continue_process() would work here too, request+run is more universal // because they do not ignore the request queue request_continue_process(); run_requests(); break; case dbg_trace: // A step occured (one instruction was executed). This event // notification is only generated if step tracing is enabled. // Parameter: none if ( stage == 3 ) { thid_t tid = va_arg(va, thid_t); qnotused(tid); ea_t ip = va_arg(va, ea_t); // ip reached the OEP range? if ( oep_area.contains(ip) ) { // stop the trace mode enable_step_trace(false); msg("Uunp: reached OEP %a\n", ip); set_wait_box("Reanalyzing the unpacked code"); // reanalyze the unpacked code do_unknown_range(oep_area.startEA, oep_area.size(), DOUNK_EXPAND); auto_make_code(ip); // plan to make code noUsed(oep_area.startEA, oep_area.endEA); // plan to reanalyze auto_mark_range(oep_area.startEA, oep_area.endEA, AU_FINAL); // plan to analyze move_entry(ip); // mark the program's entry point _hide_wait_box(); // inform the user bring_debugger_to_front(); if ( askyn_c(1, "HIDECANCEL\n" "The universal unpacker has finished its work.\n" "Do you want to take a memory snapshot and stop now?\n" "(you can do it yourself if you want)\n") > 0 ) { set_wait_box("Recreating the import table"); invalidate_dbgmem_config(); if ( is_9x ) find_thunked_imports(); create_impdir(); set_wait_box("Storing resources to 'resource.res'"); if ( resfile[0] != '\0' ) extract_resource(resfile); _hide_wait_box(); if ( take_memory_snapshot(true) ) goto FORCE_STOP; } suspend_process(); unhook_from_notification_point(HT_DBG, callback, NULL); } } break; case dbg_process_exit: { stage = 0; // stop the tracing _hide_wait_box(); unhook_from_notification_point(HT_DBG, callback, NULL); if ( success ) jumpto(inf.beginEA, -1); else tell_about_failure(); } break; case dbg_exception:// Parameters: const debug_event_t *event // int *warn = -1 // Return (in *warn): // -1 - to display an exception warning dialog // if the process is suspended. // 0 - to never display an exception warning dialog. // 1 - to always display an exception warning dialog. { // const debug_event_t *event = va_arg(va, const debug_event_t *); // int *warn = va_arg(va, int *); // FIXME: handle code which uses SEH to unpack itself if ( askyn_c(1, "AUTOHIDE DATABASE\n" "HIDECANCEL\n" "An exception occurred in the program.\n" "UUNP does not support exceptions yet.\n" "The execution has been suspended.\n" "Do you want to continue the unpacking?") <= 0 ) { _hide_wait_box(); stage = 0; enable_step_trace(false); // stop the trace mode suspend_process(); } else { continue_process(); } } break; case dbg_request_error: // An error occured during the processing of a request. // Parameters: ui_notification_t failed_command // dbg_notification_t failed_dbg_notification { ui_notification_t failed_cmd = va_arg(va, ui_notification_t); dbg_notification_t failed_dbg_notification = va_arg(va, dbg_notification_t); _hide_wait_box(); stage = 0; warning("dbg request error: command: %d notification: %d", failed_cmd, failed_dbg_notification); } break; } return 0; }
int RP_mapping::process_string(char *str, int ln) { char *arg1, *arg2; for ( arg1 = arg2 = str; !isspace( *arg2) && *arg2; arg2++ ) ; if ( !*arg2 ) return 0; *arg2++ = 0x0; if ( !*arg2) return 0; for ( ; *arg2 && isspace(*arg2); arg2++ ) ; if ( !*arg2 ) return 0; // next - just trim all spaces at end char *ptr = arg2 + 1; for ( ; !isspace(*ptr) && *ptr; ptr++ ) ; *ptr = 0x0; /* O`k, now arg1 contains address or name and arg2 contains name of struct */ // first check for struct presence tid_t tid = get_struc_id(arg2); if ( BADADDR == tid ) { if ( verbose ) msg("Cannot find struct '%s'\n", arg2); return 0; } // next try to resolve first arg as name ea_t ea = get_name_ea(BADADDR, arg1); if ( ea != BADADDR ) { /* first check for already presenting */ dnode_t *again = is_presented(ea); if ( NULL != again ) { if ( verbose ) msg("Warning, address %X already in dictionary, overwrite\n", ea); dnode_put(again, (void *)tid); } else { /* place to dict new mapping name -> tid_t */ dict_alloc_insert(mapping, (const void *)ea, (void *)tid); } #ifdef RP_DEBUG msg("Mapping %X (%s) -> %s (%X) \n", ea, arg1, arg2, tid); #endif return 1; } /* well may be we shold add yet one underscore at begin of name ? */ { int len = strlen(arg1); char *dup = (char *)qalloc(len + 2); *dup = '_'; strcpy(dup + 1, arg1); ea = get_name_ea(BADADDR, dup); if ( BADADDR != ea ) { dnode_t *again = is_presented(ea); if ( NULL != again ) { if ( verbose ) msg("Warning, address %X already in dictionary, overwrite\n", ea); dnode_put(again, (void *)tid); } else { dict_alloc_insert(mapping, (const void *)ea, (void *)tid); } #ifdef RP_DEBUG msg("Mapping %X (%s) -> %s (%X) \n", ea, dup, arg2, tid); #endif qfree(dup); return 1; } qfree(dup); } /* well - may be we has address ? */ if ( *arg1 == '0' && ( arg1[1] == 'x' || arg1[1] == 'X' ) ) { arg1 += 2; if ( ! *arg1 ) { if ( verbose ) msg("Line %d. Bad address '%s'\n", ln, arg1 - 2); return 0; } } char *notused; ea = strtol(arg1, ¬used, 0x10); if ( !ea ) { if ( verbose ) msg("Line %d. Bad address '%s'\n", ln, arg1); return 0; } // O`k it seems that we really has some address. Lets check it if ( NULL == getseg(ea) ) { if ( verbose ) msg("Line %d. Address %X is not in your file\n", ln, ea); return 0; } dnode_t *again = is_presented(ea); if ( NULL != again ) { if ( verbose ) msg("Warning, address %X already in dictionary, overwrite\n", ea); dnode_put(again, (void *)tid); } else { dict_alloc_insert(mapping, (const void *)ea, (void *)tid); } #ifdef RP_DEBUG msg("Mapping %X -> %s (%X) \n", ea, arg2, tid); #endif return 1; }
static int notify(processor_t::idp_notify msgid, ...) { // Various messages: va_list va; va_start(va, msgid); // A well behaving processor module should call invoke_callbacks() // in his notify() function. If this function returns 0, then // the processor module should process the notification itself // Otherwise the code should be returned to the caller: int code = invoke_callbacks(HT_IDP, msgid, va); if ( code ) return code; switch(msgid) { case processor_t::init: inf.mf = 1; // MSB first default: break; case processor_t::newfile: { segment_t *sptr = get_first_seg(); if( sptr != NULL ) { if( sptr->startEA - get_segm_base( sptr ) == 0 ) { inf.beginEA = sptr->startEA + 0xC; inf.startIP = 0xC; for( int i = 0; i < qnumber(entries); i++ ) { ea_t ea = sptr->startEA + entries[i].off; if( isEnabled(ea) ) { doWord( ea, 2 ); // ig: set_op_type - внутренняя функция, ее нельзя использовать // set_op_type( ea, offflag(), 0 ); set_offset( ea, 0, sptr->startEA ); ea_t ea1 = sptr->startEA + get_word( ea ); auto_make_proc( ea1 ); set_name( ea, entries[i].name ); // ig: так получше будет? set_cmt( sptr->startEA+get_word(ea), entries[i].cmt, 1 ); } } } set_segm_class( sptr, "CODE" ); } segment_t s; ea_t bottom = toEA( inf.baseaddr, 0 ); intmem = s.startEA = freechunk( bottom, 256, 0xF ); s.endEA = s.startEA + 256; s.sel = allocate_selector( s.startEA >> 4 ); s.type = SEG_IMEM; // internal memory add_segm_ex( &s, "INTMEM", NULL, ADDSEG_OR_DIE); const predefined_t *ptr; for( ptr = iregs; ptr->name != NULL; ptr++ ) { ea_t ea = intmem + ptr->addr; ea_t oldea = get_name_ea( BADADDR, ptr->name ); if( oldea != ea ) { if( oldea != BADADDR ) set_name( oldea, NULL ); do_unknown( ea, DOUNK_EXPAND ); set_name( ea, ptr->name ); } if( ptr->cmt != NULL ) set_cmt( ea, ptr->cmt, 1 ); } } break; case processor_t::oldfile: sel_t sel; if( atos( "INTMEM", &sel) ) intmem = specialSeg(sel); break; case processor_t::newseg: { // default DS is equal to CS segment_t *sptr = va_arg(va, segment_t *); sptr->defsr[rVds-ph.regFirstSreg] = sptr->sel; } } va_end(va); return(1); }
void idaapi PIC_run(int arg) { ea_t curr_addr; int n_funcz, i; func_t *curr_func; if ( is_first ) { got_addr = get_name_ea(BADADDR, got_name); if ( BADADDR == got_addr ) { got_addr = get_name_ea(BADADDR,got_name1); if ( BADADDR != got_addr ) { got_addr = get_long(got_addr); } else { got_addr = get_name_ea(BADADDR, got_name2); } } is_first = false; // 2 Nov 2005: dirty hack, bcs get_name_ea("_got") return BADADDR segment_t *s; if ( BADADDR == got_addr ) { s = get_segm_by_name(".got"); if ( s != NULL ) got_addr = s->startEA; } // 14 oct 2009 s = get_segm_by_name(".got.plt"); if ( s != NULL ) got_plt_addr = s->startEA; } if ( BADADDR == got_addr ) { msg("Cannot resolve _got address. Bad plugin initialization"); return; } #ifdef PIC_DEBUG RP_TRACE1( "got_addr %X\n", got_addr ); #endif switch (arg) { case 0: /* only function under current EA */ curr_addr = get_screen_ea(); #ifdef PIC_DEBUG RP_TRACE1( "curr_addr %X\n", curr_addr ); #endif /* next I had to resolve function */ curr_func = get_func(curr_addr); if ( NULL == curr_func ) { warning("Cannot operate not on function, address %X\n", curr_addr); return; } #if defined(PIC_DEBUG) || defined(PIC_SHOW) rp_log_fp = fopen(log_filename, "w+t"); #endif process_PIC(curr_func->startEA, curr_func->endEA); #if defined(PIC_DEBUG) || defined(PIC_SHOW) if ( NULL != rp_log_fp ) { fclose(rp_log_fp); rp_log_fp = NULL; } #endif break; case 1: /* process all defined functions */ #if defined(PIC_DEBUG) || defined(PIC_SHOW) rp_log_fp = fopen(log_filename, "w+t"); #endif n_funcz = get_func_qty(); if ( !n_funcz ) { warning("No functions defined!"); return; } for ( i = 0; i < n_funcz; i++ ) { curr_func = getn_func(i); if ( NULL == curr_func ) { RP_TRACE1("PIC: cannot get func N %d\n", i); continue; } process_PIC(curr_func->startEA, curr_func->endEA); } #if defined(PIC_DEBUG) || defined(PIC_SHOW) if ( NULL != rp_log_fp ) { fclose(rp_log_fp); rp_log_fp = NULL; } #endif break; default: warning("PIC: Unknown arg %d", arg); break; } /* switch */ }