IDC examples
IDC examples
The following examples demonstrate the usage of native IDA scripting language in more complex scripts. Our selection illustrates how IDC can help you automate everyday tasks and speed up your learning efforts while learning IDC scripting.
Where can I find all the examples?
The full library of our examples is shipped with your IDA instance in the idc
folder.
Before you start
Some of the examples shows below used an imports another scripts, like idc.idc
: the file that contains IDA built-in function declarations and internal bit definitions. It is recommend to check the idc
folder for all sample scripts.
How to run the examples?
Load the script via File Loader
Navigate to File -> Script file...
In the new dialog, select the
.idc
script you want to run and click Open.
Load the script via Script command
Navigate to File -> Script command....
Change the scripting language to IDC.
Paste the code into Please enter script body field and click Run.
Sample scripts
You can also find the scripts below in the idc
folder inside your IDA directory.
analysis
Sample IDC program to automate IDA.
//
// Sample IDC program to automate IDA.
//
// IDA can be run from the command line in the batch (non-interactive) mode.
//
// If IDA is started with
//
// ida -A -Sanalysis.idc file
//
// then this IDC file will be executed. It performs the following:
//
// - analyzes the input file
// - creates the output file
// - exits to the operating system
//
// Feel free to modify this file as you wish
// (or write your own script/plugin to automate IDA)
//
// Since the script calls the qexit() function at the end,
// it can be used in the batch files (use text mode idat)
//
// NB: "ida -B file" is a shortcut for the command line above
//
#include <idc.idc>
static main()
{
// turn on coagulation of data in the final pass of analysis
set_inf_attr(INF_AF, get_inf_attr(INF_AF) | AF_DODATA | AF_FINAL);
// .. and plan the entire address space for the final pass
auto_mark_range(0, BADADDR, AU_FINAL);
msg("Waiting for the end of the auto analysis...\n");
auto_wait();
msg("\n\n------ Creating the output file.... --------\n");
auto file = get_idb_path()[0:-4] + ".asm";
auto fhandle = fopen(file, "w");
gen_file(OFILE_ASM, fhandle, 0, BADADDR, 0); // create the assembler file
msg("All done, exiting...\n");
// the following line instructs IDA to quit without saving the database
// process_config_directive("ABANDON_DATABASE=YES");
qexit(0); // exit to OS, error code 0 - success
}
arraytst
Sample demonstration on how to use array manipulation functions.
//
// This example shows how to use array manipulation functions.
//
#include <idc.idc>
#define MAXIDX 100
static main() {
auto id,idx,code;
id = create_array("my array");
if ( id == -1 ) {
warning("Can't create array!");
} else {
msg("Filling array of longs...\n");
for ( idx=0; idx < MAXIDX; idx=idx+10 )
set_array_long(id,idx,2*idx);
msg("Displaying array of longs...\n");
for ( idx=get_first_index(AR_LONG,id);
idx != -1;
idx=get_next_index(AR_LONG,id,idx) )
msg("%d: %d\n",idx,get_array_element(AR_LONG,id,idx));
msg("Filling array of strings...\n");
for ( idx=0; idx < MAXIDX; idx=idx+10 )
set_array_string(id, idx, sprintf("This is %d-th element of array", idx));
msg("Displaying array of strings...\n");
for ( idx=0; idx < MAXIDX; idx=idx+10 )
msg("%d: %s\n",idx,get_array_element(AR_STR,id,idx));
}
}
bds
Sample executed when IDA detects Delphi 6-7 or BDS.
//
// This file is executed when IDA detects Delphi6-7 or BDS2005-BDS2006
// invoked from pe_bds.pat
//
// Feel free to modify this file as you wish.
//
#include <idc.idc>
static main()
{
// Set Delphi-Style string
//set_inf_attr(INF_STRTYPE,STRTYPE_LEN4);
// Set demangled names to display
//set_inf_attr(INF_DEMNAMES,DEMNAM_NAME);
// Set compiler to Borland
set_inf_attr(INF_COMPILER, COMP_BC);
}
// Add old borland signatures
static bor32(ea)
{
AddPlannedSig("bh32rw32");
AddPlannedSig("b32vcl");
SetOptionalSigs("bdsext/bh32cls/bh32owl/bh32ocf/b5132mfc/bh32dbe/b532cgw");
return ea;
}
// Add latest version of Borland Cbuilder (Embarcadero)
static emb(ea)
{
AddPlannedSig("bds8rw32");
AddPlannedSig("bds8vcl");
SetOptionalSigs("bdsboost/bds8ext");
return ea;
}
static has_Emb(ea)
{
ea = ea & 0xFFFFFFFF;
return ea+2 < 0xFFFFFFFF
&& get_wide_byte(ea ) == 'E'
&& get_wide_byte(ea + 1) == 'm'
&& get_wide_byte(ea + 2) == 'b';
}
// Detect the latest version of Borland Cbuilder (Embarcadero)
static detect(ea)
{
// Use version string to detect which signatures to use. Both bds08
// and bds10 (up to xe10) have two null bytes after the string we are
// testing for, which comes immediately before the argument ea.
//
// bds06: Borland C++ - Copyright 2005 Borland Corporation
// bds08: CodeGear C++ - Copyright 2008 Embarcadero Technologies
// bds10: Embarcadero RAD Studio - Copyright 2009 Embarcadero Technologies, Inc.
if ( has_Emb(ea-0x1A) || has_Emb(ea-0x20) )
{
ResetPlannedSigs();
emb(ea);
}
return ea;
}
biosdata
Sample that makes comments to BIOS data area.
//
// This script creates a segment at paragraph 0x40 and
// makes comments to BIOS data area. To see mnemonical names of
// BIOS data area variables, please use this file:
//
// - press F2 when running IDA
// - select this file
//
#include <idc.idc>
//-------------------------------------------------------------------------
static CW(off,name,cmt) {
auto x;
x = 0x400 + off;
create_word(x);
set_name(x,name);
set_cmt(x,cmt, 1);
}
//-------------------------------------------------------------------------
static CD(off,name,cmt) {
auto x;
x = 0x400 + off;
create_dword(x);
set_name(x,name);
set_cmt(x,cmt, 1);
}
//-------------------------------------------------------------------------
static CB(off,name,cmt) {
auto x;
x = 0x400 + off;
create_byte(x);
set_name(x,name);
set_cmt(x,cmt, 1);
}
//-------------------------------------------------------------------------
static CmtBdata() {
CW(0x000,"com_port_1","Base I/O address of 1st serial I/O port");
CW(0x002,"com_port_2","Base I/O address of 2nd serial I/O port");
CW(0x004,"com_port_3","Base I/O address of 3rd serial I/O port");
CW(0x006,"com_port_4","Base I/O address of 4th serial I/O port");
CW(0x008,"prn_port_1","Base I/O address of 1st parallel I/O port");
CW(0x00A,"prn_port_2","Base I/O address of 2nd parallel I/O port");
CW(0x00C,"prn_port_3","Base I/O address of 3rd parallel I/O port");
CW(0x00E,"prn_port_4","Base I/O address of 4th parallel I/O port");
CW(0x010,"equip_bits", "Equipment installed info bits\n"
"15 14 13 12 11 10 9 8\n"
"\\ / game \\ /\n"
"# of print port # of RS-232\n"
"ports 0-3 used ports 0-4\n"
"\n"
"7 6 5 4 3 2 1 0\n"
"\\ / \\ / \\ / Math |\n"
"# of video mode RAM uP no\n"
"disk- at boot up 00=16K dsk\n"
"ettes 00=EGA/VGA 01=32K driv\n"
" 1-4 01=CGA-40 10=48K if 0\n"
"if bit 10=CGA-80 11=64K\n"
"0 = 1 11=MDA-80 (old PCs)\n"
"\n"
"Note: bit 13=modem on PC lap-tops\n"
" bit 2=mouse on MCA & others");
CB(0x012,"manufactr_test", "Manufacturing Test get_wide_byte\n"
"bit 0 = 1 while in test mode\n"
"MCA systems use other bits\n"
" during POST operations");
CW(0x013,"base_ram_size", "Base memory size in KBytes (0-640)");
CB(0x015,"mtest_scratchpad", "[AT] {Manufacturing test scratch pad}\n"
"[Compaq Deskpro 386] previous scan code");
CB(0x016,"error_codes", "[AT] {Manufacturing test scratch pad}\n"
"[PS/2 Mod 30] {BIOS control flags}\n"
"[Compaq Deskpro 386] keyclick loudness (00h-7Fh)");
CB(0x017,"keybd_flags_1", "Keyboard flag bits\n"
" 7 6 5 4 3 2 1 0\n"
"ins- cap num scrl alt ctl lef rig\n"
"sert --toggles--- --shifts down--");
CB(0x018,"keybd_flags_2", "Keyboard flag bits\n"
" 7 6 5 4 \n"
"insert caps num scroll\n"
"------now depressed------\n"
"\n"
" 3 2 1 0\n"
" pause sys left right\n"
" lock request -alt-down-");
CB(0x019,"keybd_alt_num", "Alt-nnn keypad workspace");
CW(0x01A,"keybd_q_head", "pointer to next character in keyboard buffer");
CW(0x01C,"keybd_q_tail", "pointer to first free slot in keyboard buffer");
CW(0x01E,"keybd_queue", "Keyboard circular buffer");
make_array(0x41E, 16 );
CB(0x03E,"dsk_recal_stat", "Recalibrate floppy drive bits\n"
" 3 2 1 0\n"
"drive-3 drive-2 drive-1 drive-0\n"
"\n"
"bit 7 = interrupt flag");
CB(0x03F,"dsk_motor_stat", "Motor running status & disk write\n"
" bit 7=1 disk write in progress\n"
" bits 6&5 = drive selected 0 to 3\n"
" 3 2 1 0\n"
" drive-3 drive-2 drive-1 drive-0\n"
" --------- 1=motor on-----------");
CB(0x040,"dsk_motor_timer", "Motor timer, at 0, turn off motor");
CB(0x041,"dsk_ret_code", "Controller return code\n"
" 00h = ok\n"
" 01h = bad command or parameter\n"
" 02h = can't find address mark\n"
" 03h = can't write, protected dsk\n"
" 04h = sector not found\n"
" 08h = DMA overrun\n"
" 09h = DMA attempt over 64K bound\n"
" 10h = bad CRC on disk read\n"
" 20h = controller failure\n"
" 40h = seek failure\n"
" 80h = timeout, no response");
CB(0x042,"dsk_status_1", "Status bytes-disk controller chip\n"
" Note: 7 info bytes returned from\n"
" controller are saved here. Refer\n"
" to the NEC uPD 765 chip manual\n"
" for the specific info, depending\n"
" on the previous command issued.");
CB(0x043,"dsk_status_2", "");
CB(0x044,"dsk_status_3", "");
CB(0x045,"dsk_status_4", "");
CB(0x046,"dsk_status_5", "");
CB(0x047,"dsk_status_6", "");
CB(0x048,"dsk_status_7", "");
CB(0x049,"video_mode", "Present display mode");
CW(0x04A,"video_columns", "Number of columns");
CW(0x04C,"video_buf_size", "Video buffer size in bytes\n"
" Note: size may be rounded up to\n"
" the nearest 2K boundary. For\n"
" example, 80x25 mode=4000 bytes,\n"
" but value may be 4096.");
CW(0x04E,"video_pageoff", "Video page offset of the active\n"
" page, from start of current \n"
" video segment.");
CW(0x050,"vid_curs_pos0", "Cursor position page 0\n"
" bits 15-8=row, bits 7-0=column");
CW(0x052,"vid_curs_pos1", "Cursor position page 1\n"
" bits 15-8=row, bits 7-0=column");
CW(0x054,"vid_curs_pos2", "Cursor position page 2\n"
" bits 15-8=row, bits 7-0=column");
CW(0x056,"vid_curs_pos3", "Cursor position page 3\n"
" bits 15-8=row, bits 7-0=column");
CW(0x058,"vid_curs_pos4", "Cursor position page 4\n"
" bits 15-8=row, bits 7-0=column");
CW(0x05A,"vid_curs_pos5", "Cursor position page 5\n"
" bits 15-8=row, bits 7-0=column");
CW(0x05C,"vid_curs_pos6", "Cursor position page 6\n"
" bits 15-8=row, bits 7-0=column");
CW(0x05E,"vid_curs_pos7", "Cursor position page 7\n"
" bits 15-8=row, bits 7-0=column");
CW(0x060,"vid_curs_mode", "Active cursor, start & end lines \n"
" bits 12 to 8 for starting line\n"
" bits 4 to 0 for ending line");
CB(0x062,"video_page", "Present page");
CW(0x063,"video_port", "Video controller base I/O address");
CB(0x065,"video_mode_reg", "Hardware mode register bits");
CB(0x066,"video_color", "Color set in CGA modes");
CW(0x067,"gen_use_ptr", "General use offset pointer");
CW(0x069,"gen_use_seg", "General use segment pointer");
CB(0x06B,"gen_int_occurd", "Unused interrupt occurred\n"
" value holds the IRQ bit 7-0 of\n"
" the interrupt that occurred");
CW(0x06C,"timer_low", "Timer, low word, cnts every 55 ms");
CW(0x06E,"timer_high", "Timer, high word");
CB(0x070,"timer_rolled", "Timer overflowed, set to 1 when\n"
" more than 24 hours have elapsed");
CB(0x071,"keybd_break", "Bit 7 set if break key depressed");
CW(0x072,"warm_boot_flag", "Boot (reset) type\n"
" 1234h=warm boot, no memory test \n"
" 4321h=boot & save memory");
CB(0x074,"hdsk_status_1", "Hard disk status\n"
" 00h = ok\n"
" 01h = bad command or parameter\n"
" 02h = can't find address mark\n"
" 03h = can't write, protected dsk\n"
" 04h = sector not found\n"
" 05h = reset failure\n"
" 07h = activity failure\n"
" 08h = DMA overrun\n"
" 09h = DMA attempt over 64K bound\n"
" 0Ah = bad sector flag\n"
" 0Bh = removed bad track\n"
" 0Dh = wrong # of sectors, format\n"
" 0Eh = removed control data addr\n"
" mark\n"
" 0Fh = out of limit DMA\n"
" arbitration level\n"
" 10h = bad CRC or ECC, disk read\n"
" 11h = bad ECC corrected data\n"
" 20h = controller failure\n"
" 40h = seek failure\n"
" 80h = timeout, no response\n"
" AAh = not ready\n"
" BBh = error occurred, undefined\n"
" CCh = write error, selected dsk\n"
" E0h = error register = 0\n"
" FFh = disk sense failure");
CB(0x075,"hdsk_count", "Number of hard disk drives");
CB(0x076,"hdsk_head_ctrl", "Head control (XT only)");
CB(0x077,"hdsk_ctrl_port", "Hard disk control port (XT only)");
CB(0x078,"prn_timeout_1", "Countdown timer waits for printer\n"
" to respond (printer 1)");
CB(0x079,"prn_timeout_2", "Countdown timer waits for printer\n"
" to respond (printer 2)");
CB(0x07A,"prn_timeout_3", "Countdown timer waits for printer\n"
" to respond (printer 3)");
CB(0x07B,"prn_timeout_4", "Countdown timer waits for printer\n"
" to respond (printer 4)");
CB(0x07C,"rs232_timeout_1", "Countdown timer waits for RS-232 (1)");
CB(0x07D,"rs232_timeout_2", "Countdown timer waits for RS-232 (2)");
CB(0x07E,"rs232_timeout_3", "Countdown timer waits for RS-232 (3)");
CB(0x07F,"rs232_timeout_4", "Countdown timer waits for RS-232 (4)");
CW(0x080,"keybd_begin", "Ptr to beginning of keybd queue");
CW(0x082,"keybd_end", "Ptr to end of keyboard queue");
CB(0x084,"video_rows", "Rows of characters on display - 1");
CW(0x085,"video_pixels", "Number of pixels per charactr * 8");
CB(0x087,"video_options", "Display adapter options\n"
" bit 7 = clear RAM\n"
" bits 6,5 = memory on adapter\n"
" 00 - 64K\n"
" 01 - 128K\n"
" 10 - 192K\n"
" 11 - 256K\n"
" bit 4 = unused\n"
" bit 3 = 0 if EGA/VGA active\n"
" bit 2 = wait for display enable\n"
" bit 1 = 1 - mono monitor\n"
" = 0 - color monitor\n"
" bit 0 = 0 - handle cursor, CGA");
CB(0x088,"video_switches", "Switch setting bits from adapter\n"
" bits 7-4 = feature connector\n"
" bits 3-0 = option switches");
CB(0x089,"video_1_save", "Video save area 1-EGA/VGA control\n"
" bit 7 = 200 line mode\n"
" bits 6,5 = unused\n"
" bit 4 = 400 line mode\n"
" bit 3 = no palette load\n"
" bit 2 = mono monitor\n"
" bit 1 = gray scale\n"
" bit 0 = unused");
CB(0x08A,"video_2_save", "Video save area 2");
CB(0x08B,"dsk_data_rate", "Last data rate for diskette\n"
" bits 7 & 6 = 00 for 500K bit/sec\n"
" = 01 for 300K bit/sec\n"
" = 10 for 250K bit/sec\n"
" = 11 for 1M bit/sec\n"
" bits 5 & 4 = step rate"
"Rate at start of operation\n"
" bits 3 & 2 = 00 for 500K bit/sec\n"
" = 01 for 300K bit/sec\n"
" = 10 for 250K bit/sec\n"
" = 11 for 1M bit/sec");
CB(0x08C,"hdsk_status_2", "Hard disk status");
CB(0x08D,"hdsk_error", "Hard disk error");
CB(0x08E,"hdsk_complete", "When the hard disk controller's\n"
" task is complete, this byte is\n"
" set to FFh (from interrupt 76h)");
CB(0x08F,"dsk_options", "Diskette controller information\n"
" bit 6 = 1 Drv 1 type determined\n"
" 5 = 1 Drv 1 is multi-rate\n"
" 4 = 1 Drv 1 change detect\n"
" 2 = 1 Drv 0 type determined\n"
" 1 = 1 Drv 0 is multi-rate\n"
" 0 = 1 Drv 0 change detect");
CB(0x090,"dsk0_media_st", "Media state for diskette drive 0\n"
" 7 6 5 4\n"
" data xfer rate two media\n"
" 00=500K bit/s step known\n"
" 01=300K bit/s\n"
" 10=250K bit/s\n"
" 11=1M bit/sec\n"
" 3 2 1 0\n"
" unused -----state of drive-----\n"
" bits floppy drive state\n"
" 000= 360K in 360K, ?\n"
" 001= 360K in 1.2M, ?\n"
" 010= 1.2M in 1.2M, ?\n"
" 011= 360K in 360K, ok\n"
" 100= 360K in 1.2M, ok\n"
" 101= 1.2M in 1.2M, ok\n"
" 111= 720K in 720K, ok\n"
" or 1.44M in 1.44M\n"
" (state not used for 2.88)");
CB(0x091,"dsk1_media_st", "Media state for diskette drive 1\n"
" (see dsk0_media_st)");
CB(0x092,"dsk0_start_st", "Starting state for drive 0");
CB(0x093,"dsk1_start_st", "Starting state for drive 1");
CB(0x094,"dsk0_cylinder", "Current track number for drive 0");
CB(0x095,"dsk1_cylinder", "Current track number for drive 1");
CB(0x096,"keybd_flags_3", "Special keyboard type and mode\n"
" bit 7 Reading ID of keyboard\n"
" 6 last char is 1st ID char\n"
" 5 force num lock\n"
" 4 101/102 key keyboard\n"
" 3 right alt key down\n"
" 2 right ctrl key down\n"
" 1 E0h hidden code last\n"
" 0 E1h hidden code last");
CB(0x097,"keybd_flags_4", "Keyboard Flags (advanced keybd)\n"
" 7 6 5 4 3 2 1 0\n"
"xmit char Resend Ack \ /\n"
"error was ID Rec'd Rec'd LEDs");
CW(0x098,"timer_waitoff", "Ptr offset to wait done flag");
CW(0x09A,"timer_waitseg", "Ptr segment to wait done flag");
CW(0x09C,"timer_clk_low", "Timer low word, 1 microsecond clk");
CW(0x09E,"timer_clk_high", "Timer high word");
CB(0x0A0,"timer_clk_flag", "Timer flag 00h = post acknowledgd\n"
" 01h = busy\n"
" 80h = posted");
CB(0x0A1,"lan_bytes", "Local area network bytes (7)");
make_array(0x4A1, 7);
CD(0x0A8,"video_sav_tbl", "Pointer to a save table of more\n"
"pointers for the video system \n"
" SAVE TABLE\n"
" offset type pointer to\n"
" ------ ---- --------------------\n"
" 0 dd Video parameters\n"
" 4 dd Parms save area\n"
" 8 dd Alpha char set\n"
" 0Ch dd Graphics char set\n"
" 10h dd 2nd save ptr table\n"
" 14h dd reserved (0:0)\n"
" 18h dd reserved (0:0)\n"
" \n"
" 2ND SAVE TABLE (from ptr above)\n"
" offset type functions & pointers\n"
" ------ ---- --------------------\n"
" 0 dw Bytes in this table\n"
" 2 dd Combination code tbl\n"
" 6 dd 2nd alpha char set\n"
" 0Ah dd user palette tbl\n"
" 0Eh dd reserved (0:0)\n"
" 12h dd reserved (0:0)\n"
" 16h dd reserved (0:0)");
CW(0x0CE,"days_since1_80", "Days since 1-Jan-1980 counter");
make_array(0x4AC,0xCE-0xAC);
}
//-------------------------------------------------------------------------
static main() {
if ( !add_segm_ex(0x400, 0x4D0, 0x40, 0, 0, 2, ADDSEG_NOSREG) ) {
warning("Can't create BIOS data segment.");
return;
}
set_segm_name(0x400, "bdata");
set_segm_class(0x400, "BIOSDATA");
CmtBdata();
}
entrytst
Sample that shows how to get list of entry points.
//
// This example shows how to get list of entry points.
//
#include <idc.idc>
static main() {
auto i;
auto ord,ea;
msg("Number of entry points: %ld\n",get_entry_qty());
for ( i=0; ; i++ ) {
ord = get_entry_ordinal(i);
if ( ord == 0 ) break;
ea = get_entry(ord);
msg("Entry point %08lX at %08lX (%s)\n",ord,ea,Name(ea));
}
}
find_insn
Script to be used with the 'grep' plugins.
#include <idc.idc>
// This script is to be used with the 'grep' ida plugin
// It looks for the specified instruction mnemonics and saves all matches
static find_insn(mnem)
{
auto ea;
for ( ea=get_inf_attr(INF_MIN_EA); ea != BADADDR; ea=next_head(ea, BADADDR) )
{
if ( print_insn_mnem(ea) == mnem )
save_match(ea, "");
}
}
fixuptst
Sample that gets fixup information about the file.
//
// This example shows how to get fixup information about the file.
//
#include <idc.idc>
static main() {
auto ea;
for ( ea = get_next_fixup_ea(get_inf_attr(INF_MIN_EA));
ea != BADADDR;
ea = get_next_fixup_ea(ea) ) {
auto type,sel,off,dis,x;
type = get_fixup_target_type(ea);
sel = get_fixup_target_sel(ea);
off = get_fixup_target_off(ea);
dis = get_fixup_target_dis(ea);
msg("%08lX: ",ea);
x = type & FIXUP_MASK;
if ( x == FIXUP_BYTE ) msg("BYTE ");
else if ( x == FIXUP_OFF16 ) msg("OFF16");
else if ( x == FIXUP_SEG16 ) msg("SEG16");
else if ( x == FIXUP_PTR32 ) msg("PTR32");
else if ( x == FIXUP_OFF32 ) msg("OFF32");
else if ( x == FIXUP_PTR48 ) msg("PTR48");
else if ( x == FIXUP_HI8 ) msg("HI8 ");
else msg("?????");
msg((type & FIXUP_EXTDEF) ? " EXTDEF" : " SEGDEF");
msg(" [%s,%X]",get_segm_name(get_segm_by_sel(sel)),off);
if ( type & FIXUP_EXTDEF ) msg(" (%s)",Name([sel2para(sel),off]));
if ( type & FIXUP_SELFREL ) msg(" SELF-REL");
if ( type & FIXUP_UNUSED ) msg(" UNUSED");
msg("\n");
}
}
functest
Sample that gets list of funcions.
//
// This example shows how to get list of functions.
//
#include <idc.idc>
static main() {
auto ea,x;
for ( ea=get_next_func(0); ea != BADADDR; ea=get_next_func(ea) ) {
msg("Function at %08lX: %s",ea,get_func_name(ea));
x = get_func_flags(ea);
if ( x & FUNC_NORET ) msg(" Noret");
if ( x & FUNC_FAR ) msg(" Far");
msg("\n");
}
ea = choose_func("Please choose a function");
msg("The user chose function at %08lX\n",ea);
}
kernel
Sample that insert custom comments for the imported DLLs.
//
// This file show how to insert you own comments for the imported DLLs.
// This file inserts a comment for the kernel function #23 'LOCKSEGMENT'.
// You may add your own comments for other functions and DLLs.
// To execute this file your should choose 'Execute IDC file' command
// from the IDA menu. Usually the hotkey is F2.
//
#include <idc.idc>
static main(void)
{
auto faddr;
auto fname;
msg("Loading comments...\n");
fname = sprintf("KERNEL_%ld", 23); // build the function name
faddr = get_name_ea_simple(fname); // get function address
if ( faddr != -1 ) { // if the function exists
update_extra_cmt(faddr,E_PREV + 0,";ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ");
update_extra_cmt(faddr,E_PREV + 1,"; LockSegment (2.x)");
update_extra_cmt(faddr,E_PREV + 2,"; ");
update_extra_cmt(faddr,E_PREV + 3,"; In: AX - segment to lock");
update_extra_cmt(faddr,E_PREV + 4,"; LockSegment function locks the specified discardable");
update_extra_cmt(faddr,E_PREV + 5,"; segment. The segment is locked into memory at the given");
update_extra_cmt(faddr,E_PREV + 6,"; address and its lock count is incremented (increased by one).");
update_extra_cmt(faddr,E_PREV + 7,"; Returns");
update_extra_cmt(faddr,E_PREV + 8,"; The return value specifies the data segment if the function is");
update_extra_cmt(faddr,E_PREV + 9,"; successful. It is NULL if the segment has been discarded or an");
update_extra_cmt(faddr,E_PREV + 10,"; error occurs.");
}
msg("Comment(s) are loaded.\n");
}
loaddef
Sample that loads DEF file with dialog.
// Load a DEF file with Dialog
// Saved the last browsed path in the Database
// This file is donated by Dietrich Teickner.
#include <idc.idc>
#define VERBOSE 1
#define WITHSELFEDITED 1
static main(void)
{
auto defFileName, defFile, w, p, modulImport;
defFileName = AskFileEx(0,"*.def","Choose a definition-file");
modulImport = defFileName;
while (1) {
p = strstr(modulImport,"\\");
if (-1 == p) break;
modulImport = substr(modulImport,p+1,-1);
};
p = strstr(modulImport,".");
if (-1 < p)
modulImport = substr(modulImport,0,p);
modulImport = translate(modulImport);
if(VERBOSE) msg("Opening definition file %s\n", defFileName);
defFile = fopen(defFileName, "rb");
if (0 != defFile)
{
auto defline, ea, bea, sea, eea, newName, oldName, badName, x, z, id;
//
// Process all of the DEF's in this file.
//
if(VERBOSE) msg("Processing %s\n", defFileName);
defline = "";
do
{
defline = ReadDefLine(defFile);
if (strlen(defline) == 0) break;
w = wordn(defline,1);
w = translate(w);
if ("LIBRARY" == w) {
w = wordn(substr(defline,strlen(w)+1,-1),1);
if (strlen(w) > 0) modulImport = w;
continue;
}
if ("EXPORTS" != w) continue;
if (strlen(modulImport) == 0) break;
sea = get_first_seg();
while ((-1 != sea) & (get_segm_name(sea) != modulImport)) {
sea = get_next_seg(sea);
}
if (-1 == sea) break;
w = get_segm_name(sea);
eea = get_segm_end(sea);
do
{
defline = ReadDefLine(defFile);
if (strlen(defline) == 0) break;
p = strstr(defline," @");
if (0 > p) continue;
w = substr(defline,p+2,-1);
defline = substr(defline,0,p);
w = wordn(w,1); /* import-number */
w = translate(modulImport)+"_"+w;
newName = w+"_"+wordn(defline,1);
if (WITHSELFEDITED) {
z = wordn(defline,1);
badName = z+"_"+w;
p = strstr(z,"@");
if (p != -1) {
x = substr(z,0,p);
badName = badName+" "+x+" "+w+"_"+x+" "+x+"_"+w;
}
while (substr(z,0,1) == "_") {
z = substr(z,1,-1);
badName = badName+" "+z+" "+w+"_"+z+" "+z+"_"+w;
if (p != -1) {
x = substr(x,1,-1);
badName = badName+" "+x+" "+w+"_"+x+" "+x+"_"+w;
}
}
z = " "+newName+" "+w+" "+defline+" "+badName+" ";
} else {
z = " "+newName+" "+w+" "+defline+" ";
}
x = "__imp_";
p = strlen(x);
for (ea = sea;ea < eea;ea++) {
oldName = Name(ea);
if (strstr(z," "+oldName+" ") != -1) break;
if (strstr(oldName,x) != 0) continue;
if (strstr(z," "+substr(oldName,p,-1)+" ") != -1) break;
}
if (ea == eea) continue;
p = strstr(defline,"@");
if (-1 != p) {
z = substr(defline,p+1,-1);
z = wordn(z,1);
z = atol(z);
p = get_frame_args_size(ea);
if (p != z) {
set_frame_size(ea,get_frame_lvar_size(ea),get_frame_regs_size(ea),z);
auto_wait();
}
}
if (oldName != newName) {
set_name(ea ,newName);
if(VERBOSE) msg("--> %x,%s->%s\n", ea, oldName, newName);
}
}
while (strlen(defline) > 0);
}
while (strlen(defline) > 0);
fclose(defFile);
}
}
static wordn(c,i) {
auto t, l, p, s;
p = 0;
l = strlen(c);
t = "";
while (0 < i) {
i = i-1;
while ((p < l) & (" " == substr(c,p,p+1))) p++;
while (p < l) {
s = substr(c,p,++p);
if (s == " ") break;
if (i == 0) t = t + s;
}
}
return (t);
}
static translate(c) {
auto s,t;
s = "abcdefghijklmnopqrst";
t = "ABCDEFGHIJKLMNOPQRST";
return translate2(c,s,t);
}
static translate2(c,s,t) {
auto i,j,k,l;
l = strlen(s) - strlen(t);
for (i = 0;i < l;i++) {
t = t + " ";
}
l = strlen(c);
for (i = 0;i < l;i++) {
k = substr(c,i,i+1);
j = strstr(s,k);
if (0 <= j) {
c = substr(c,0,i) + substr(t,j,j+1) + substr(c,i+1,-1);
}
}
return c;
}
static ReadDefLine(defFile)
{
auto line, wordstr, c, delim, i, first;
delim = ""+0x0d+" "+0x09+0x0a;
do {
line = "";
i = 0;
first = 1;
do {
wordstr = "";
c = "";
do {
wordstr = wordstr + c;
c = fgetc(defFile);
if (-1 != c) {
i = strstr(delim,c);
} else i = - 2;
} while (-1 == i);
if (strlen(wordstr) > 0) {
if (!first) line = line + " ";
first = 0;
line = line + wordstr;
};
} while (0 < i);
if ((strlen(line) > 0) & (substr(line,0,1) == ";")) line = "";
} while ((strlen(line) == 0) & (0 == i));
return(line);
}
static getPath(fileName) {
auto pos, path;
path = "";
while (1) {
pos = strstr(fileName,"\\");
if (-1 == pos) break;
path = path + substr(fileName,0,pos+1);
fileName = substr(fileName,pos+1,-1);
}
return path;
}
static AskFileEx(forSave, ext, dialogText) {
auto fileName, w, p, extArrayId, lastPath, newPath, extKey;
w = ext;
if (substr(w,0,1) == "*") w = substr(w,1,-1);
if (substr(w,0,1) == ".") w = substr(w,1,-1);
/* is case-sensitive */
extKey = "DT#"+w;
extArrayId = get_array_id("DT#EXT#Array");
if (-1 == extArrayId)
extArrayId = create_array("DT#EXT#Array");
lastPath = get_hash_string(extArrayId,extKey);
/* without this, we have at first only '*' as Mask, but not "*.ext". IDA 4.20 */
if ("" == lastPath)
lastPath = getPath(get_root_filename());
w = lastPath+"*."+w;
if(VERBOSE) msg("--> lastPath %s\n", w);
fileName = askfile(forSave,w,dialogText);
if (("" == fileName) | (-1 == extArrayId))
return fileName;
newPath = getPath(fileName);
if (("" != newPath) & (lastPath != newPath))
// Save the new path, associated with the extension in the Database
set_hash_string(extArrayId, extKey, newPath);
return fileName;
}
loadsym
Sample that loads a SYM file with dialog.
//
// Load a SYM file with Dialog
// Saved the last browsed path associated with the extension in the Database
// (use with dbg2map and mapsym)
//
// History:
//
// v1.00 - This file is originally donated by David Cattley.
// v1.07 - Bugfix, improved interface, handles larger SegDefs
// v1.08 - extended for save tha last used path associaded with *.sym in the current database
// set VAC to 0 for aktivating v1.07
// set VAC to 1 for sym-files from IBM/Microsoft MAPSYM for OS/2 (Loadsym V1.00)
//
#include <idc.idc>
#define VERBOSE 1
// set to version before IDA 4.30, for mapsym.exe VAC, not found any informations about the last changes
#define VAC 1
static main(void)
{
auto symFileName, symFile;
symFileName = AskFileEx(0,"*.sym","Choose the symbol-file");
if(symFileName=="")
{ if(VERBOSE) msg("Operation cancelled by user.\n");
return -1; }
if(VERBOSE) msg("Opening symbol file %s\n", symFileName);
symFile = fopen(symFileName, "rb");
if (0 != symFile)
{
auto nextMapDef;
//
// Process all of the MAPDEF's in this file.
//
// if(VERBOSE) msg("%0.4x: ", ftell(symFile));
if(VERBOSE) msg("Processing %s\n", symFileName);
nextMapDef = 0;
do
{
nextMapDef = DoMapDef(symFile, nextMapDef);
}
while (0 != nextMapDef);
}
else
{ if(VERBOSE) msg("Can't open symbol file:\n%s\n", symFileName);
return -1;
}
if(VERBOSE) msg("Symbol file has been loaded successfully.\n");
}
static DoMapDef(File, Position)
{
auto ppNextMap;
//
// Process the specified MAPDEF structure.
//
fseek(File, Position, 0);
if(VERBOSE) msg("%0.4x: ", ftell(File));
ppNextMap = readshort(File, 0);
if (0 == ppNextMap)
{
//
// This is the last one! It is special.
//
auto release, version;
release = fgetc(File);
version = fgetc(File);
if(VERBOSE) msg("VERSION Next:%x Release:%x Version:%x\n",
ppNextMap,
release,
version
);
}
else
{
auto bFlags, bReserved1, pSegEntry,
cConsts, pConstDef, cSegs, ppSegDef,
cbMaxSym, achModName;
auto i, nextSegDef;
bFlags = fgetc(File);
bReserved1 = fgetc(File);
pSegEntry = readshort(File, 0);
cConsts = readshort(File, 0);
pConstDef = readshort(File, 0);
cSegs = readshort(File, 0);
ppSegDef = readshort(File, 0);
cbMaxSym = fgetc(File);
achModName = ReadSymName(File);
if(VERBOSE) msg("MAPDEF Next:%x Flags:%x Entry:%x Con:%d@%x Seg:%d@%x Max:%d Mod:%s\n",
ppNextMap,
bFlags,
pSegEntry,
cConsts, pConstDef,
cSegs, ppSegDef,
cbMaxSym,
achModName
);
//
// Process the SEGDEFs in this MAPDEF
//
nextSegDef = ppSegDef << 4;
for (i=0; i<cSegs; i=i+1)
{
nextSegDef = DoSegDef(File, nextSegDef);
}
}
//
// Return the file position of the next MAPDEF
//
return (ppNextMap << 4);
}
static DoSegDef(File, Position)
{
auto ppNextSeg, cSymbols, pSymDef,
wSegNum, wReserved2, wReserved3, wReserved4,
bFlags, bReserved1, ppLineDef, bReserved2,
bReserved3, achSegName;
auto i, n, symPtr, segBase;
//
// Process the specified SEGDEF structure.
//
fseek(File, Position, 0);
if(VERBOSE) msg("%0.4x: ", ftell(File));
ppNextSeg = readshort(File, 0);
cSymbols = readshort(File, 0);
pSymDef = readshort(File, 0);
wSegNum = readshort(File, 0);
wReserved2 = readshort(File, 0);
wReserved3 = readshort(File, 0);
wReserved4 = readshort(File, 0);
bFlags = fgetc(File);
bReserved1 = fgetc(File);
ppLineDef = readshort(File, 0);
bReserved2 = fgetc(File);
bReserved3 = fgetc(File);
achSegName = ReadSymName(File);
if (VAC) {
segBase = get_segm_by_sel(wSegNum);
// the others will access the externals, sym-files from MAPSYM contains only internals
} else {
// segBase = get_segm_by_sel(wSegNum); //fixed
segBase = get_first_seg();
for (i=wSegNum; i > 1; i=i-1) { segBase = get_next_seg(segBase); }
}
if(VERBOSE) msg("SEGDEF Next:%x Sym:(%d)@%x Flags:%x Lines:%x Seg:%s [%04x %08x]\n",
ppNextSeg,
cSymbols, pSymDef,
bFlags,
ppLineDef,
achSegName, wSegNum, segBase
);
//
// Process the symbols in this SEGDEF
//
n = 2;
if (!VAC) {
// sym-files from MAPSYM (VAC) works with unshifted pSymDef
pSymDef = pSymDef << (bFlags & 0xFE);
if ((bFlags & 0xFE) != 0) n++;
}
for (i=0; i<cSymbols; i=i+1)
{
// fseek(File, Position+pSymDef+(i*2), 0); //fixed
fseek(File, Position+pSymDef+(i*n), 0);
if (n>2) symPtr = Position+(readlong(File, 0)&0xFFFFFF);
else symPtr = Position+readshort(File, 0);
DoSymDef(File, symPtr, (bFlags & 1), wSegNum);
}
//
// Return the position of the next SEGDEF
//
return (ppNextSeg << 4);
}
static DoSymDef(File, Position, Size, Segment)
{
auto dwSymVal, achSymName, ea, i;
fseek(File, Position, 0);
if(VERBOSE) msg("%0.4x: ", ftell(File));
if (0 == Size)
dwSymVal = readshort(File, 0);
else
dwSymVal = readlong(File, 0);
achSymName = ReadSymName(File);
//
// Calculate the EA of this symbols.
//
if (VAC) {
ea = get_segm_by_sel(Segment) + dwSymVal;
// sym-files from MAPSYM contains only internals
} else {
// ea = get_segm_by_sel(Segment) + dwSymVal; // fixed
ea = get_first_seg(); // This points to the externals ???
for (i=Segment; i > 1; i=i-1) { ea = get_next_seg(ea); }
ea = ea + dwSymVal;
}
if(VERBOSE) msg("SYM%d: %04x:%08x [%08x] %s\n",
(16+Size*16),
Segment, dwSymVal, ea,
achSymName);
//
// Now go and name the location!
//
set_name(ea, "");
set_name(ea, achSymName);
}
static ReadSymName(symFile)
{
auto i, nameLen, name;
name = "";
nameLen = fgetc(symFile);
for (i=0; i<nameLen; i=i+1)
{
name = name + fgetc(symFile);
}
return(name);
}
static getPath(fileName) {
auto pos, path;
path = "";
while (1) {
pos = strstr(fileName,"\\");
if (-1 == pos) break;
path = path + substr(fileName,0,pos+1);
fileName = substr(fileName,pos+1,-1);
}
return path;
}
static AskFileEx(forSave, ext, dialogText) {
auto fileName, w, p, extArrayId, lastPath, newPath, extKey;
w = ext;
if (substr(w,0,1) == "*") w = substr(w,1,-1);
if (substr(w,0,1) == ".") w = substr(w,1,-1);
/* is case-sensitive */
extKey = "DT#"+w;
extArrayId = get_array_id("DT#EXT#Array");
if (-1 == extArrayId)
extArrayId = create_array("DT#EXT#Array");
lastPath = get_hash_string(extArrayId,extKey);
/* without this, we have at first only '*' as Mask, but not "*.ext". IDA 4.20 */
if ("" == lastPath)
lastPath = getPath(get_input_file_path());
w = lastPath+"*."+w;
if(VERBOSE) msg("--> lastPath %s\n", w);
fileName = askfile(forSave,w,dialogText);
if (("" == fileName) | (-1 == extArrayId))
return fileName;
newPath = getPath(fileName);
if (("" != newPath) & (lastPath != newPath))
// Save the new path, associated with the extension in the Database
set_hash_string(extArrayId, extKey, newPath);
return fileName;
}
marktest
Sample that shows how to get list of marked positions.
//
// This example shows how to get list of marked positions.
//
#include <idc.idc>
static main() {
auto x;
put_bookmark(get_screen_ea(),10,5,5,6,"Test of Mark Functions");
for ( x=0; x<10; x++ )
msg("%d: %a %s\n",x,get_bookmark(x),get_bookmark_desc(x));
}
memcpy
Sample that shows how to get list of marked positions.
//
// This example shows how to get list of marked positions.
//
#include <idc.idc>
static main() {
auto x;
put_bookmark(get_screen_ea(),10,5,5,6,"Test of Mark Functions");
for ( x=0; x<10; x++ )
msg("%d: %a %s\n",x,get_bookmark(x),get_bookmark_desc(x));
}
ndk
Android bionic lib.
#include <idc.idc>
static main()
{
}
// Android Bionic libc
//
// These functions are called while loading startup signatures from
// elf.sig to obtain the address of main.
static get_main_ea(ea, got_ldr, got_off, main_off)
{
auto got_ea = 0;
if ( got_off != 0 )
{
auto _ea = TRUNC(ea + got_ldr);
create_insn(_ea);
got_ea = get_first_dref_from(_ea);
if ( got_ea == BADADDR )
return BADADDR;
got_ea = get_wide_dword(got_ea);
if ( got_ea == BADADDR )
return BADADDR;
got_ea = TRUNC(got_ea + ea + got_off + 8);
ea = TRUNC(ea + main_off);
create_insn(ea);
ea = get_first_dref_from(ea);
if ( ea == BADADDR )
return BADADDR;
ea = get_wide_dword(ea);
if ( ea == BADADDR )
return BADADDR;
}
ea = TRUNC(got_ea + ea);
ea = get_wide_dword(ea);
if ( ea == BADADDR )
return BADADDR;
// Check that segment is executable
if ( (get_segm_attr(ea, SEGATTR_PERM) & SEGPERM_EXEC) == 0 )
return BADADDR;
return ea;
}
static get_main_ea_pic(ea, got_ldr, got_off, main_off)
{
return get_main_ea(ea, long(got_ldr), long(got_off), long(main_off));
}
static get_main_ea_abs(ea)
{
return get_main_ea(ea, 0, 0, 0);
}
onload
File called after a new file is loaded into IDA.
//
// This IDC file is called after a new file is loaded into IDA
// database.
// IDA calls "OnLoad" function from this file.
//
// You may use this function to read extra information (such as
// debug information) from the input file, or for anything else.
//
#include <idc.idc>
// If you want to add your own processing of newly created databases,
// you may create a file named "userload.idc":
//
// #define USERLOAD_IDC
// static userload(input_file,real_file,filetype) {
// ... your processing here ...
// }
//
#softinclude <userload.idc>
// Input parameteres:
// input_file - name of loaded file
// real_file - name of actual file that contains the input file.
// usually this parameter is equal to input_file,
// but is different if the input file is extracted from
//