Files
sigmaker-ida/idasdk76/plugins/uunp/uunp.idc
2021-10-31 21:20:46 +02:00

114 lines
3.5 KiB
C

/*
This is a reimplementation of the uunp universal unpacker in IDC.
It illustrates the use of the new debugger functions in IDA v5.2
*/
#include <idc.idc>
//--------------------------------------------------------------------------
static main()
{
auto ea, bptea, tea1, tea2, code, minea, maxea, r_esp, r_eip, caller, funcname;
// Calculate the target IP range. It is the first segment.
// As soon as the EIP register points to this range, we assume that
// the unpacker has finished its work.
tea1 = get_first_seg();
tea2 = get_segm_end(tea1);
// Calculate the current module boundaries. Any calls to GetProcAddress
// outside of these boundaries will be ignored.
minea = get_inf_attr(INF_MIN_EA);
maxea = get_inf_attr(INF_MAX_EA);
// Use win32 local debugger
load_debugger("win32", 0);
// Launch the debugger and run until the entry point
if ( !run_to(get_inf_attr(INF_START_EA)) )
return Failed(-10);
// Wait for the process to stop at the entry point
code = wait_for_next_event(WFNE_SUSP, -1);
if ( code <= 0 )
return Failed(code);
// Set a breakpoint at GetProcAddress
bptea = get_name_ea_simple("kernel32_GetProcAddress");
if ( bptea == BADADDR )
return warning("Could not locate GetProcAddress");
add_bpt(bptea);
while ( 1 )
{
// resume the execution and wait until the unpacker calls GetProcAddress
code = wait_for_next_event(WFNE_SUSP|WFNE_CONT, -1); // CONT means resume
if ( code <= 0 )
return Failed(code);
// check the caller, it must be from our module
r_esp = get_reg_value("ESP");
caller = get_wide_dword(r_esp);
if ( caller < minea || caller >= maxea )
continue;
// if the function name passed to GetProcAddress is not in the ignore-list,
// then switch to the trace mode
funcname = get_strlit_contents(get_wide_dword(r_esp+8), -1, STRTYPE_C);
// ignore some api calls because they might be used by the unpacker
if ( funcname == "VirtualAlloc" )
continue;
if ( funcname == "VirtualFree" )
continue;
// A call to GetProcAddress() probably means that the program has been
// unpacked in the memory and now is setting up its import table
break;
}
// trace the program in the single step mode until we jump to
// the area with the original entry point.
del_bpt(bptea);
enable_tracing(TRACE_STEP, 1);
for ( code = wait_for_next_event(WFNE_ANY|WFNE_CONT, -1); // resume
code > 0;
code = wait_for_next_event(WFNE_ANY, -1) )
{
r_eip = get_event_ea();
if ( r_eip >= tea1 && r_eip < tea2 )
break;
}
if ( code <= 0 )
return Failed(code);
// as soon as the current ip belongs OEP area, suspend the execution and
// inform the user
suspend_process();
code = wait_for_next_event(WFNE_SUSP, -1);
if ( code <= 0 )
return Failed(code);
enable_tracing(TRACE_STEP, 0);
// Clean up the disassembly so it looks nicer
del_items(tea1, DELIT_EXPAND|DELIT_DELNAMES, tea2-tea1);
create_insn(r_eip);
auto_mark_range(tea1, tea2, AU_USED);
auto_mark_range(tea1, tea2, AU_FINAL);
take_memory_snapshot(1);
set_name(r_eip, "real_start");
warning("Successfully traced to the completion of the unpacker code\n"
"Please rebuild the import table using renimp.idc\n"
"before stopping the debugger");
}
//--------------------------------------------------------------------------
// Print an failure message
static Failed(code)
{
warning("Failed to unpack the file, sorry (code %d)", code);
return 0;
}