Day14:IDApython与SMC

IDApythonAPI、SMC自修改代码

IDApython

基础API

  • idc.here() / idc.get_screen_ea():返回光标所在处的地址
  • idc.get_inf_attr(INF_MIN_EA) / idc.get_inf_attr(INF_MAX_EA):返回最小/最大地址(没有随机化地址情况下)
  • idc.generate_disasm_line(ea,0):返回ea所在处的汇编指令
  • idc.prev_head(ea)/next_head(ea):返回ea处上一条/下一条指令地址
  • idc.print_insn_mnem(ea):打印ea处的助记符(即mov,add什么的)
  • idc.print_operand(ea,n):打印ea处第n个操作数(n=0或者1)

段相关API

  • idautils.Segments():返回段起始地址列表
  • idc.get_segm_name(ea):返回ea所在段的名字
  • idc.get_segm_start(ea)/get_segm_end(ea):返回ea所在段的起始地址/结束地址
  • idc.get_next_seg(ea):返回ea所在段的下一个段的起始地址

函数相关API

  • idautils.Functions(start_addr,end_addr):返回地址间的函数对象(不写参数就是所有函数对象)
  • idautils.FuncItems(ea):返回ea所在函数所有指令的地址(相当于地址列表)
  • idaapi.get_func(ea):获得ea所在函数的对象(含有如start_ea、end_ea、size等属性)
  • idc.get_func_name(ea):返回ea所在函数的名字
  • idc.get_func_attr(ea,FUNCATTR_START) / idc.get_func_attr(ea,FUNCATTR_END):返回ea所在函数的起始地址/结束地址
  • idc.get_next_func(ea) / idc.get_prev_func(ea):返回ea所在函数的上一个/下一个函数的起始地址

指令相关API

  • ida_ua.insn_t(),返回一个空的指令对象(或者说创建一个空的指令对象),包含函数的一些属性
  • idaapi.decode_insn(out,ea),解析ea所在处的指令,把解析的结果给out(out必须是一个指令对象)
    • out.ea:指令的起始地址
    • out.size:指令占用的字节数
    • out.get_cannon_mnemonic():指令的助记符
    • out.itype:助记符的十进制码

操作数相关API

  • idc.get_operand_value(ea,n):返回ea处第n个操作数的值
  • idc.get_operand_type(ea,n):返回ea处第n个操作数的类型

数据读写相关API

  • idc.get_bytes(ea,size):返回ea处size大小的bytes
  • idc.patch_byte(ea,content):修改ea处的1字节为content
  • idc.patch_word(ea,content):修改ea处的2字节为content
  • idc.patch_dword(ea,content):修改ea处的4字节为content
  • idc.patch_qword(ea,content):修改ea处的8字节为content

调试相关API

  • ida_dbg.load_debugger(“local”,0):启动调试器

  • ida_dbg.add_bpt(ea):在ea处下断点

  • ida_dbg.del_bpt(ea):删除ea处断点

  • ida_dbg.start_process(path,args,sdir):启动调试进程,参数对应路径、命令行参数、工作目录

  • ida_dbg.step_into():单步步入

  • ida_dbg.step_over():单步步过

  • ida_dbg.step_until_ret():运行到返回

  • idc.get_reg_value(regname):获取regname寄存器的值

  • idc.set_reg_value(value,regname):设置regname寄存器的值

其他操作相关API

  • idautils.XrefsFrom(ea):返回ea处引用的对象(有属性frm、to、type)

  • idautils.XrefsTo(ea):返回所有引用ea处的对象(有属性frm、to、type)(Ctrl+X)

    示例:

    1
    2
    3
    4
    5
    6
    7
    import idautils,idaapi
    for xref in idautils.XrefsTo(here()):
    print(xref.to)#here()
    print(xref.frm)#调用here()的函数地址
    for xref in idautils.XrefsFrom(here()):
    print(xref.frm)#here()
    print(xref.to)#here()引用的函数地址
  • idautils.Strings():返回包含所有字符串的对象(有属性ea、length、strtype)(shift+F12)

  • idc.get_strlit_contents(ea):返回ea处的字符串

    示例:

    1
    2
    3
    4
    5
    import idc,idautils
    for s in idautils.Strings():
    string=idc.get_strlit_contents(s.ea)
    print(string)
    #打印所有字符串

自修改代码(SMC)

  • 自修改代码(Self-Modifying-Code)指某部分代码以加密后的形式存在于程序中,程序执行到这部分代码的时候才会进行动态解密,和加壳有点异曲同工。常用来加密关键逻辑,使其不可直接静态分析

  • 特征:

    程序中存在对程序自身某部分的运算,一般还需要VirtualProtect() / mprotect()来改变内存的属性以便将解密后的代码数据写入内存,或者使用VirtualAlloc把解密后的代码数据写入堆中执行(为了避免API暴露,还可能会新增一个有RWX属性的段来存放加密后的代码)。

  • 应对方法有两种:一种是动态调试得到解密后的关键逻辑,另一种是使用脚本解密关键逻辑后再覆盖回去

    • 示例:2021-羊城杯-babysmc

      PS:本来想要自己写一个简单程序试试手的,研究了半个下午没研究出来,程序修正到解密函数可以解密出正确代码了,但是调用关键逻辑check的时候莫名其妙跑飞了,在那个安全检查的位置,跳转后像是个畸形函数,不知道是不是改内存属性的时候影响到了,所以只能去找网上的题目了

    • 这是优化后的主函数:

      主函数

      优化的来源就是,enc的位置是一团数字,而loc_7FF6BF081D00处开始是正常代码,加上对下面的decrypt函数的分析,可以确定enc就是被加密后的first_part

    • 这是decrypt函数:

      decrypt函数

      非常明显地调用了VirtualProtect函数,解密逻辑很简单,就是ror后异或0x5a(ror查出来是循环右移,3就是右移的位数了,这点看汇编可能更清晰点)

    • 下面就是今天的成果展示了(ror由DS协助实现),SMC解密脚本:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      import idautils,idc,idaapi

      enc=idc.get_bytes(0x00007FF6BF081085,0x00007FF6BF081D00-0x00007FF6BF081085)
      loc=0x00007FF6BF081085

      def ror(value, shift, bits=8):
      shift %= bits # 确保位移量在有效范围内
      return (value >> shift) | ((value << (bits - shift)) & ((1 << bits) - 1))

      for i in enc:
      idc.patch_byte(loc,(ror(i,3)^0x5a)&0xff)
      loc+=1
      print("done")
    • 本来是要写完的,但是first_part的函数解析完好几百行了,是我看不懂的加密🫠去找WP,发现是非常混淆的base64,还加了异或,但是我没看出逻辑,索性点到为止,改天把编码和密码的部分补上再说。

    • 本来也尝试了动调解密,但是调着调着给我下起东西来了,虽然链接看着是微软的,但是还是有点怕,就舍弃这个方法了(下的是kernel.pdb好像,DS说是缺失符号文件🫠🫠)

作者

SydzI

发布于

2025-08-05

更新于

2025-10-03

许可协议

评论