IDC

首先,什么是IDC?
IDC是IDA中支持的一门与C语言类似的语言,但是它是解释型的,并不是编译型的,于此同时IDC还融合了一些python中的元素以方便一些内容的处理。

在IDA中按下【shift+F2】可调出脚本编译器

IDC语句

IDC支持C中的语言,除了switch

IDC表达式

IDC几乎都能支持C语言中的操作运算表达(加减乘除、判等家族),但是明确说明不支持+=。
在进行操作运算的时候,只有操作中存在64bit的操作,那么其他操作也会编程64bit的。

IDC预定义符号

IDC有一些符号是提前定义好了的,其内容和含义如下:

_NT_           IDA is running under MS Windows
_LINUX_        IDA is running under Linux
_MAC_          IDA is running under Mac OS X
_UNIX_         IDA is running under Unix (linux or mac)
_EA64_         64-bit version IDA
_QT_           GUI version of IDA (Qt)
_GUI           GUI version of IDA
_TXT_          Text version of IDA
_IDA_VERSION_  The current IDA version. For example: "7.5"
_IDAVER_       The current, numerical IDA version. For example: "750" means v7.5

IDC字符串操作(切片)

IDC中对于字符串的操作应该是借鉴了python,其string类型的操作支持切片操作(slices)。

str[i1:i2] - substring from i1 to i2. i2 is excluded,If i1 >= i2, empty string is returned.
str[idx]   - one character substring at 'idx'.
             this is equivalent to str[idx:idx+1]
str[:idx]  - substring from the beginning of the string to idx
             this is equivalent to str[0:idx]
str[idx:]  - substring from idx to the end of the string
             this is equivalent to str[idx:0x7fffffff]

IDC异常处理

IDC异常处理中,可以使用的表达语句:

      auto e;
      try 
      {
        ... some statements that cause a runtime error...
      }
      catch ( e )
      {
        // e holds the exception information
        // it is an instance of the exception class
      }


throw xx;  #抛出

IDC程序

如果只是需要进行简单的查询或者查看,可以直接编写个别行的函数完成编写,但是如果一个脚本应用需要执行大量的IDC程序,并且还可能会在很多场景下需要重复使用,那么我们可能需要创建一个独立的IDC程序文件。
IDC程序文件要求用户使用用户定义的函数,并且至少定义一个没有参数的main函数,此外主程序文件中必须包含idc.idc头文件。

#idc程序文件基本结构
#Include <idc.idc>
static main(){
   Message("this is a IDC scipt file");
}
IDC支持如下C预处理指令:

#include <文件> ;将指定的文件包含在当前文件中

#define <宏名称>[可选项] ;创建宏,可以选择给宏分配指定的值

#ifdef <名称>; 测试指定的宏是否存在

#else 与ifdef一起使用

#endif 通过ifdef指定定义终止符

#undef <名称> ;删除指定的宏

常用idc函数

读取和修改数据的函数

下面这些函数可用于访问IDA数据库中的各个字节、字及双字。

  • long Byte(long addr): 从虚拟地址addr处读取一个字节(1字节)的值。
  • long Word(long addr): 从虚拟地址addr处读取一个字节(2字节)的值。
  • long Dword(long addr): 从虚拟地址addr处读取一个双字(4字节)的值。
  • void PatchByte(long addr,long val): 设置虚拟地址addr处一个字节(1字节)的值为val。
  • void PatchWord(long addr,long val): 设置虚拟地址addr处一个字节(2字节)的值为val。
  • void PatchDword(long addr,long val): 设置虚拟地址addr处一个双字(4字节)的值为val。
  • bool isLoaded(long addr): 如果虚拟地址addr中包含有效数据则返回,否则返回0。
    用户交互函数
    idc脚本没有任何调试工具,所以可以依靠输出函数实现调试。
    一个个打太多了,别人总结好的
字符串操作函数

在这里插入图片描述

数据库名称操作函数

在这里插入图片描述

处理函数的函数

在这里插入图片描述

代码交叉引用函数

在这里插入图片描述

数据交叉引用函数

在这里插入图片描述

数据库操纵函数

在这里插入图片描述

数据库搜素函数

在这里插入图片描述

反汇编行组件

在这里插入图片描述

补充
简单的IF语句
#include <idc.idc>

static main()
{
    auto CurrAddress = ScreenEA(); 
    if(CurrAddress == 0x401161)
    {
       Message("程序OEP => 0x%x \n",CurrAddress);
    }
    else
    {
      Message("没有扎到OEP \n");
    }
}
for语句
#include <idc.idc>

static main()
{
    auto origEA,currEA,funcStart,funcEnd;
    
    origEA = ScreenEA();
    // origEA = OEP 如果origEA 不在函数内则返回-1
    funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
    
    funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
    
    //Message("OEP: %x 起始地址: %x --> 结束地址: %x \n",origEA,funcStart,funcEnd);
    
    // NextHead 在currEA开始的位置寻找下一条指令的地址
    for(currEA = funcStart; currEA != -1; currEA=NextHead(currEA,funcEnd))
    {
        Message("--> %8x \n",currEA);
    }
}
while语句实现
#include <idc.idc>

static main()
{
    auto origEA,currEA,funcStart,funcEnd;
    
    origEA = ScreenEA();
    // origEA = OEP 如果origEA 不在函数内则返回-1
    funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
    
    funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
    
    //Message("OEP: %x 起始地址: %x --> 结束地址: %x \n",origEA,funcStart,funcEnd);
    
    while(currEA != BADADDR)
    {
        Message("--> %x \n",currEA);
        currEA = NextHead(currEA,funcEnd);
    }
}
idc函数
#include <idc.idc>

// 定义一个函数
static OutPutAddress(MyString)
{
    auto currAddress;
    currAddress = ScreenEA();
    Message("%d \n",MyString);
    return currAddress;
}

static main()
{
    auto ret = OutPutAddress(123);
    Message("%x \n",ret);
    
}
idc获取函数名
#include <idc.idc>

static main()
{
    auto origEA,currEA,funcStart,funcEnd;
    
    origEA = ScreenEA();
    // origEA = OEP 如果origEA 不在函数内则返回-1
    funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
    
    funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
    
    //Message("OEP: %x 起始地址: %x --> 结束地址: %x \n",origEA,funcStart,funcEnd);
    
    while(currEA != BADADDR)
    {
        Message("--> %x name: %s \n",currEA,GetFunctionName(currEA));
        currEA = NextHead(currEA,funcEnd);
    }
}
idc枚举所有函数
#include <idc.idc>

static main()
{
    auto currAddr,func,endSeg,funcName,counter;
    
    currAddr = ScreenEA();
    func = SegStart(currAddr);
    endSeg = SegEnd(currAddr);
    
    Message("%x --> %x \n",func,endSeg);
    
    counter = 0;
    
    while(func != BADADDR && func < endSeg)
    {
        funcName = GetFunctionName(func);
        if(funcName != " ")
        {
            Message("%x --> %s \n",func,funcName);
            counter++;
        }
        func = NextFunction(func);
    }
     
}
枚举指定函数并输出
#include <idc.idc>

static main()
{
    auto currAddr,func,endSeg,funcName,counter;
    
    currAddr = ScreenEA();
    func = SegStart(currAddr);
    endSeg = SegEnd(currAddr);
    
    Message("%x --> %x \n",func,endSeg);
    
    counter = 0;
    
    while(func != BADADDR && func < endSeg)
    {
        funcName = GetFunctionName(func);
        if(funcName != " ")
        {
        
            if(funcName == "__lock")
            {
                Message("%x --> %s \n",func,funcName);
            }
            
            counter++;
        }
        func = NextFunction(func);
    }
}
寻找特殊指令,并高亮显示
#include <idc.idc>
static main(void)
{
    auto head, op;
    head = NextHead(0x00000000, 0xFFFFFFFF);
    while ( head != BADADDR )
    {
        op = GetMnem(head);
        Message("%x %s \n",head,op);

        
        if ( op == "jmp" || op == "call" )
            SetColor(head, CIC_ITEM, 0x010187);
            
        if (op == "xor")
            SetColor(head, CIC_ITEM, 0x010198);
        head = NextHead(head, 0xFFFFFFFF);
    }
}
ida dump

将函数dump到本地

#include <idc.idc>

static getFuncName(ea)
{
    auto funcName = get_func_name(ea);
      
    auto dm = demangle_name(funcName, get_inf_attr(INF_LONG_DN));
    if(dm != 0)
    {
        funcName = dm;
    }
    return funcName;
}

static functionDump(ea)
{
    auto funcName = 0;
    auto end = 0x0;
    auto file_open = get_idb_path()[0:-4] + "_dump.log";
    auto stream = fopen(file_open, "w");
    auto peekAhead;

    while( ea != BADADDR )
    {
        ea = NextFunction(ea);      
        peekAhead = NextFunction(ea);
        end = FindFuncEnd(ea);   
        funcName = getFuncName(ea);

        if(peekAhead == BADADDR)
        {
            fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end, funcName);
            ea = peekAhead;
            continue;
        }
            end = peekAhead - 1;      
            fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end,funcName);
    }
        fclose(stream);
}

static main()
{
    functionDump(0x40000);
}
全量反汇编:
#include <idc.idc>

static main(void)
{


    auto decode = 0x401000;
    auto xref;
    
    for(xref = RfirstB(decode); xref != BADADDR; xref = RnextB(decode,xref))
    {
         Message("xref: %x\n",xref);
    
    auto i = 0;
      auto inst = xref;
    auto op;
        
        
       while((i < 100) )
       {
        inst = FindCode(inst,0x00); // flag set to backwards
      op = GetDisasm(inst); // get
      
      Message("%x --> %s \n",inst,op);
        i++;
       }
    } 
}
查找特定指令片段
#include <idc.idc>

static main()
{
    auto currAddr,startSeg,endSeg;
    
    currAddr = ScreenEA();
    startSeg = SegStart(currAddr);
    endSeg = SegEnd(currAddr);
    
    Message("OEP = %x 起始地址: %x 结束地址: %x \n",currAddr,startSeg,endSeg);
    
    while(startSeg < endSeg)
    {
        auto op = GetDisasm(startSeg);
        
        // 查找第一条指令
        if(strstr(op,"push    esi")==0)
        {
            startSeg++;
            op = GetDisasm(startSeg);
            if(strstr(op,"push    edi"))
            {
                Message("特征: %x \n",startSeg-1);
            }
        }
        startSeg++;
    }
}
全局数组操作:

数组是全局的,并写入数据库,白嫖完了,一定得释放

#include <idc.idc>

static main()
{
    // 创建数组元素
    auto array_ptr = CreateArray("array");
    // 获取数组指针
    auto ptr = GetArrayId("array");
    
    Message("获取到的操作指针: %x \n",ptr);
    
    // 设置两个字符串变量
    SetArrayString(ptr,0,"hello");
    SetArrayString(ptr,1,"lyshark");
    
    // 设置两个整数变量
    SetArrayLong(ptr,2,100);
    SetArrayLong(ptr,3,200);
    
    // 如果提取字符串使用 AR_STR 标记 ,提取整数使用 AR_LONG
    auto st = GetArrayElement(AR_STR,ptr,0);
    auto st1 = GetArrayElement(AR_STR,ptr,1);
    Message("提取字符串变量: %s %s !\n",st,st1);
    
    auto lo = GetArrayElement(AR_LONG,ptr,2);
    Message("提取整数变量: %d \n",lo);
    
    // 删除数组的0号元素
    DelArrayElement(AR_STR,ptr,0);
    // 注销整个数组
    DeleteArray(ptr);
}
字符串处理函数:
#include <idc.idc>

static main()
{
    // 格式化字符串,类似于sprintf
    auto name = form("hello %s","lyshark");
    Message("格式化后的内容: %s \n",name);
    
    Message("十六进制转为整数: %d \n",xtol("0x41"));
    Message("十进制100转为八进制: %d \n",ltoa(100,8));
    Message("十进制100转换二进制: %d \n",ltoa(100,2));
    Message("字符A的ASCII: %d \n",ord("A"));
    Message("计算字符串长度: %d \n",strlen("hello lyshark"));
    
    // 在著字符串中寻找子串
    auto main = "hello lyshark";
    auto sub = "lyshark";
    Message("寻找子串: %d \n",strstr(main,sub));
}
反汇编函数:
#include <idc.idc>

static main()
{
// 索索特征码
    auto code = FindBinary(0x401020,1,"55 8B EC");
    Message("%x \n",code);


    // 反汇反汇编代码
    code = GetDisasm(0x401000);
    Message("%s \n",code);
    
    // 反汇 位于地址处的指令
    code = GetMnem(0x401000);
    Message("%s \n",code);
    
    // 反汇opcode
    code = GetOpnd(0x401070,0);
    Message("%s \n",code);
}
枚举函数(枚举栈帧)
#include <idc.idc>

static main()
{
    auto addr,args,end,locals,frame,firstArg,name,ret;
    
    for(addr = NextFunction(addr); addr != BADADDR; addr = NextFunction(addr))
    {
        name = Name(addr);
        end = GetFunctionAttr(addr,FUNCATTR_END);
        locals = GetFunctionAttr(addr,FUNCATTR_FRSIZE);
        // 得到栈帧大小
        frame = GetFrame(addr);
        // 栈中保存返回地址偏移量
        ret = GetMemberOffset(frame," r");
        if(ret == -1)continue;
        firstArg = ret +4;
        args = GetStrucSize(frame) - firstArg;
        Message("函数: %s 开始: 0x%x 结束: 0x%x 大小: %d bytes 栈帧: %d bytes (%d args) \n",name,addr,end,locals,args,args/4);
    }
}
检索交叉引用(全部):
#include <idc.idc>

static main()
{
    auto func,end,target,inst,name,flags,xref;
    
    flags = SEARCH_DOWN | SEARCH_NEXT;
    
    func = GetFunctionAttr(ScreenEA(),FUNCATTR_START);
    
    if(func != -1)
    {
        name =Name(func);
        end = GetFunctionAttr(func,FUNCATTR_END);
        for(inst = func;inst < end; inst = FindCode(inst,flags))
        {
            for(target = Rfirst(inst);target != BADADDR; target = Rnext(inst,target))
            {
                xref = XrefType();
                if(xref == fl_CN || xref == fl_CF)
                {
                    Message("%s call -> %sfrom --> %x \n",name,Name(target),inst);
                }
            }
        }
    }
}