IDA的调试脚本idc
IDA的脚本有两种,⼀种是idc,另⼀种是IDAPython。
可以通过File->Script file;File->Script command访问IDA的脚本引擎。
1、IDC语⾔
1.1 IDC变量
IDC的3种数据类型:整数(IDA⽂档使⽤类型名称long)、字符串和浮点值。当然也包括对象、引⽤和函数指针1.1.1 局部变量声明
1 2auto addr, reg, val; //legal, multiple variables declared with no initializers auto count = 0; // declaration with initialization
IDC认可使⽤/**/的C风格多⾏注释,//的⾏注释1.1.2 全局变量声明
1 2 3 4 5 6extern outsideGlobal; static main(){
extern insideGlobal; outsideGlobal = "Global"; insideGlobal = 1;
}
可以在函数内部或外部声明全部变量,但不能⼦啊声明变量的时候提供初始值。
1.2 IDC表达式
除了少数⼏个特例外,IDC⼏乎⽀持C的所有算数和逻辑运算符,包括三元运算(?:),但是不⽀持op=(+=、*=、>>=等)形式的符合赋值运算符。
IDC的字符串运算与C的有所不同。在IDC中,⽀持类python的字符串复制、拼接、分⽚操作。
1 2 3auto str="String to slice"; auto s1,s2,s3,s4;
s1 = str[7:9];
需要注意的是IDC没有数组数据类型。
1.3 IDC语句
IDC的语句以很好结束。switch语句是IDC唯⼀不⽀持的C风格复合语句。在使⽤for循环的时候,需要记住的是,IDC不⽀持复合赋值运算符op=。
并且IDC引⼊了try/catch块和相关的switch语句,在语法上它们类似C++⼀场处理。
感动签名IDC的块中,可以声明新的变量,只要变量声明位于花括号内的第⼀个语句即可。但是IDC并不严格限制新引⼊的变量的作⽤范围,因此,你可以在声明这些变量的花括号以外引⽤它们。
1.4 IDC函数
IDC仅仅在独⽴程序(.idc⽂件)中⽀持⽤户定义的函数。iDC命令对话框不⽀持⽤户定义的函数。IDC⽤于声明⽤户定义的函数的语法与C语⾔的差异甚⼤。在IDC中,static关键字⽤于引⼊⼀个⽤户定义的函数,函数的参数列表仅包含⼀个以逗号分隔的参数名列表。
1 2 3 4static my_func(x, y, z){ auto a,b,c; ......
}
并且参数可以采⽤传值或者传参的⽅式。
现在已经可以将函数引⽤作为⼀个参数传递给另⼀个函数,并将函数引⽤作为函数的返回结果。下⾯的代码清单说明了使⽤函数参数和函数作为返回值的情况。
1 2 3 4 5 6 7 8 9 10 11static getFunc(){柳州富达
return Message; //return the built-in Message function as a result
}
static useFunc(func, arg){
func(arg); // func here is expected to be a function reference
}
static main(){
auto f = getFunc();
f("Hello world!\n"); // invoke the returned function f
useFunc(f, "XXS"); // no need for & operator, functions always call-by-reference }
1.5 IDC对象
IDC定义了⼀个成为object的根类,最终所有类都是由它衍⽣⽽来,并且在创建新类时⽀持单⼀继承。
IDC并不使⽤访问说明符,如public 或private,所有类成员均为有效公共类。类声明仅包含类成员函数的定义。要在类中创建数据成员,只需要创建⼀个给数据成员赋值的赋值语句即可。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18class ExampleClass{
ExampleClass(x,y){ // constructor
this.a = x; // all ExampleClass objects hava data member a
this.b = y; // all ExampleClass objects hava data member b
}
~ExampleClass(){ // destructor
}
foo(x){
this.a = this.a + x;
}
}
staic main(){
/* ExampleClass ex;*/ // this is not a valid variable declaration
一生一世美人骨怎么剃的骨auto ex = ExampleClass(1,2); // this is right
ex.foo(10);
ex.z = "string"; // object ex now has a member z, BUT class does not }
1.6 IDC程序
献王为什么有雮尘珠需要有主函数,并且主程序⽂件还必须包含idc.idc⽂件以获得它包含的有⽤宏定义。
1 2 3 4#include <idc.idc> // useful include directive static main(){
// do something
}
IDC认可的预处理指令
#include <⽂件>
#define<;宏名称>[可选值] 创建⼀个宏,可以选择给它分配指定的值。IDC预定义了许多宏来测试脚本执⾏环境,如\NT\、\LINUX\、\MAC\、\GUI\、\TXT\
#ifdef<;名称> 测试指定的宏是否存在,如果存在,可以选择处理其后的任何语句
#else 与上⾯的#ifdef配合使⽤
#endif
#undef<;名称> 删除指定宏
1.7 IDC错误处理
运⾏IDC脚本时,可能遇到两种错误:解析错误、运⾏时错误。
解析错误指的是令程序⽆法运⾏的错误,包括语法错误、引⽤未定义变量、函数参数数量错误等。
运⾏时错误会使⼀段脚本⽴即终⽌运⾏。当然,当⼀个脚本运⾏时间过长,也会发⽣运⾏时错误。
调试IDC脚本很⿇烦,除了⼤量使⽤输出语句外,没有其他办法调试IDC脚本。
1.8 IDC永久数据存储
前⾯提到IDC没有传统意义上的数据,即声明⼀个⼤型存储块,然后使⽤下标访问块中的数据项的数组。但是IDC确实有全局永久数组,这可以看成已命名的永久对象,⽽且这些对象是稀疏数组。数组中的同时保存⼀个整数值和⼀个字符串值,IDC的全局数组⽆法存储浮点值。
long CreateArray(string name) 返回数组句柄
long GetArrayId(string name) 返回索引句柄
long SetArrayLong(long id, long idx, long value) 将整数value存储到数组id中idx位置
long SetArrayString(long id, long idx, string str)
string or long GetArrayElement(long tag, long id, long idx) 提取的是整数还是字符串,有tag参数的值决定,必须是常量AR_LONG(整数)或AR_STR(字符串)
long DelArrayElement(long tag, long id, long idx)
void DeleteArray(long id) 删除句柄id对应的数组
long RenameArray(long id, string newname)
2、IDC的常⽤函数
2.1 读取和修改数据的函数
long Byte(long addr) 从虚拟地址addr中读取⼀个字节值
long Word(long addr) 从虚拟地址addr中读取⼀个字(2字节)值
long Dword(long addr) 从虚拟地址addr中读取⼀个双字(4字节)值
void PatchByte(long addr, long val) 设置虚拟地址addr处的⼀个字节值
void PatchWord(long addr, long val) 设置虚拟地址addr处的⼀个字值
void PatchDword(long addr, long val) 设置虚拟地址addr处的⼀个双字值
bool isLoaded(long addr) 如果addr包含有效数据,则返回1,否则0
需要注意的是,我们在做这种操作的时候应该考虑字节顺序。
2.2 ⽤户交互函数
void Message(string format, ...) 格式化打印。接受printf风格的格式化字符串
void print(...) 在输出窗⼝打印每个参数的字符串表⽰形式
void Wording(string format, ...) 对话框中显⽰⼀条格式化信息
string AskStr(string default, string prompt) 显⽰⼀个输⼊框,要求⽤户输⼊⼀个额字符串值。如果操作成功,则返回⽤户的字符串;如果对话框被取消,则返回0
string AskFile(long doSave, string mask, string prompt) 显⽰⼀个⽂件选择对话框,以简化选择⽂件的任务。新⽂件保存数据(doSave=1),或选择现有的⽂件读取数据(doSave=0)。可以根据mask(如*.*或*.idc)过滤显⽰的⽂件列表。如果操作成功,则会返回选定⽂件的名称;如果对话框被取消,返回0
string AskYN(long default, string prompt) ⽤是或否的问题提⽰⽤户。突出⼀个默认的答案(1为是,0为否,-1为取消)。返回值是⼀个选定答案的整数。
五一国际劳动节的来历和意义long ScreenEA() 返回当前光标所在位置的虚拟地址
bool Jump(long addr) 跳转到反汇编窗⼝的指定地址
2.3 字符串操纵函数
string form(string format, ...) //preIDA5.6 类似c语⾔的sprintf函数,返回⼀个新年字符串,该字符串根据所提供的格式化字符串和值进⾏格式化
string sprintf(string format, ...) //IDA5.6+ sprintf⽤于替代form
long atol(string val) 将⼗进制值val转化成对应的整数值
long xtol(string val) 将⼗六进制值val(可选择以0x开头)转换成对应的整数值
string ltoa(long val, long radix) 以指定的radix(2、8、10或16)返回val的字符串值
string ord(string ch) 返回单字符字符串ch的ASCII值
long strlen(string str) 返回所提供字符串的长度
long strstr(string str, string substr) 返回str中substr的索引,如果没有发现⼦字符串,则返回-1
string substr(string str, long start, long end) 返回包含str中由start到end-1位置的字符的⼦字符串。如果使⽤分⽚,此字符串等同于str[start:end]
2.4 ⽂件输⼊/输出函数
long fopen(string filename, string mode) 返回⼀个整数⽂件句柄(如果发⽣错误,则返回0),供所有IDC⽂件 输⼊/输出函数使⽤。mode参数与C语⾔的fopen函数使⽤相同的模式(r,w,等)
void fclose(long handle) 关闭fopen中⽂件句柄指定的⽂件
void filelength(long handle) 返回指定⽂件的长度,如果发⽣错误,则返回-1
long fgetc(long handle) 从给定⽂件中读取⼀个字节。如果发⽣错误,则返回-1
long fputc(long val, long handle) 写⼊⼀个字节到指定⽂件中,如果操作成功,则返回0;如果发⽣错误,则返回-1
long fprintf(long handle, string format, ...) 将格式化字符串写⼊到指定⽂件中
long writestr(long handle, string str) 将指定的字符串写⼊到给定⽂件中
string/long readstr(long handle) 从给定⽂件中读取⼀个字符串。这个函数读取到下⼀个换⾏符位置的所有字符(包括⾮ASCII字符),包括换⾏符本⾝(ASCII 0x0a)。操作成功,返回字符串;如果读到⽂件结尾,则返回-1
long writelong(long handle, long val, long bigendian) 使⽤⼤端(bigendian=1)或⼩端(bigendian=0)字节顺序将⼀个4字节整数写⼊到指定⽂件
long readlong(long handle, long bigendian) 使⽤⼤端(bigendian=1)或⼩端(bigendian=0)字节顺序从给定⽂件中读取⼀个4字节整数
long writeshort(long handle, long val, long bigendian) 使⽤⼤端(bigendian=1)或⼩端(bigendian=0)字节顺序将⼀个2字节整数写⼊到指定⽂件
long readshort(long handle, long bigendian) 使⽤⼤端(bigendian=1)或⼩端(bigendian=0)字节顺序从给定⽂件中读取⼀个2字节整数
bool loadfile(long handle, long pos, long addr, long length) 从给定⽂件的pos位置读取length数量的字节,并将这些字节写⼊到以addr地址开头的数据库中
bool savefile(long handle, long pos, long addr, long length) 将以addr数据库地址开头的length数量的
厉内荏的意思字节写⼊到给定⽂件的pos 位置
2.5 操纵数据库名称
string Name(long addr) 返回与给定地址有关的名称,如果该位置没有名称,则返回空字符串。如果名称被标记为局部名称,这个函数并不敢回⽤户定义的名称
string NameEx(long from, long addr) 返回与addr有关的名称。如果该位置没有名称,则返回空字符串。如果from是⼀个同样包含addr的函数中的地址,则这个函数返回⽤户定义的局部名称。
bool MakeNameEx(long addr, string name, long flags) 将给定的名称分配给给定的地址。改名称使⽤flags位掩码中指定的属性创建⽽成。这些标志在帮助系统中的MakeNameEx⽂档中记载描述,可以⽤于指定各种属性,如名称是局部名称还是公共名称、名称是否应在名称窗⼝中列出。
long LockByName(string name) 返回⼀个位置(名称已给定)的地址。如果数据库中没有该名称,则返回BADADDR(-1)
long LockByNameEx(long funcaddr, string localname) 在包含funcaddr的函数中搜索给定的局部名称。如果给定的函数中没有这个名称,则返回BADADDR(-1)
2.6 处理函数的函数
long GetFunctionAttr(long addr, long attrib) 返回包含给定地址的函数的被请求的属性。⽂档中有属性常量。如要查⼀个函数的结束地址,可以使⽤GetFunctionAttr(addr, FUNCTION_END)
string GetFunctionName(long addr) 返回包含给定地址的函数的名称。如果给定地址并不属于⼀个函数,则返回⼀个空字符串long NextFunction(long addr) 返回给定地址后的下⼀个函数的起始地址。如果数据库中给定地址后没有其他函数,则返回-1 long PrevFunction(long addr) 返回给定地址之前距离最近的函数的起始地址。如果数据库中给定地址后没有其他函数,则返回-1
当然,也可以通过函数名,使⽤LockByName函数查函数的起始地址
2.7 代码交叉引⽤函数
long Rfirst(long from) 返回给定地址向其转交控制权的第⼀个位置。如果给定地址没有引⽤其他地址,则返回BADAADDR(-1)long Rnext(long from, long current) 如果current已经在前⼀次调⽤Rfirst或Rnext时返回,则返回给定地址(from)转交控制权的下⼀个位置。如果没有其他交叉引⽤存在,则返回BADADDR
long XrefType() 返回⼀个常量,说明某个交叉引⽤查询函数(如Rfirst)返回的最后⼀个交叉引⽤的类型。对于代码交叉引⽤,这些常量包括fl_CN(近调⽤)、fl_CF(远调⽤)、fl_JN(近跳转)、fl_JF(远跳转)和fl_F(普通顺序流)
long RfirstB(long to) 返回转交控制权到给定地址的第⼀个位置。如果不存在对给定地址的交叉引⽤,则返回BADADDR(-1)long RnextB(long to, long current) 如果current已经在前⼀次调⽤RfirstB或RnextB时返回,则返回下⼀个转交控制权给给定地址(to)的位置。如果不存在其他堆给定位置的交叉引⽤,则返回BADADDR(-1)
每次调⽤⼀个交叉引⽤函数,IDA都会设置⼀个内部IDC状态变量,指出返回的最后⼀个交叉引⽤的类型。如果需要知道你收到的交叉引⽤的类型,那么在调⽤其他交叉引⽤查询函数之前,必须调⽤XrefType函数
2.8 数据交叉引⽤函数
long Dfirst(long from) 返回给定地址引⽤⼀个数据值得第⼀个位置。如果给定地址没有引⽤其他地址,则返回BADADDR
long Dnext(long from, long current) 如果current已经在前⼀次调⽤Dfirst或Dnext时返回,则返回给定地址(from)向其引⽤⼀个数据值的下⼀个位置。如果没有其他交叉引⽤存在,则返回BADADDR
long XrefType() 返回⼀个常量,说明某个交叉引⽤查询函数(如Dfirst)返回的最后⼀个交叉引⽤的类型。对于数据交叉引⽤,这些常量包括dr_0(提供的偏移量)、dr_w(数据写⼊)和dr_R(数据读取)
long DfirstB(long to) 返回将给定地址作为数据引⽤的第⼀个位置。如果不存在引⽤给定地址的交叉引⽤,则返回BADADDR
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论