安装

安装模拟器: unicorn

https://github.com/unicorn-engine/unicorn
一般通过pip安装:

  1. pip install unicorn

安装 flareEmu

从FireEye的Git下载 : https://github.com/fireeye/flare-emu
下载 flare_emu.py 就好, 是FireEye针对unicorn模拟器开发的一个帮助类


使用Emu

在使用时, 可不关心解密函数的算法, 然后直接模拟参数传递, 和结果的读取就好

decodeStr

  1. from __future__ import print_function
  2. import idc
  3. import idaapi
  4. import idautils
  5. import flare_emu
  6. def decrypt(address, argv):
  7. print("%08X" % address, argv)
  8. myEH = flare_emu.EmuHelper()
  9. stack = []
  10. dwRet = idc.next_head(address)
  11. stack.append(dwRet) # RetAddr
  12. stack.append(argv[0])
  13. print(stack)
  14. # 用于设置栈, 栈的0号元素为返回地址 为 [EBP+4], 1号为第一个Arg [EBP+8]
  15. myEH.emulateRange(idc.get_name_ea_simple("sub_401667"), stack=stack)
  16. dwEAX = myEH.getRegVal("eax") # 从虚拟机中获得eax的值
  17. print ("EAX:%08X" % dwEAX)
  18. return myEH.getEmuString(dwEAX) # 从虚拟机中获得字符串, 地址是EAX的值
  19. def decrypt1(argv):
  20. myEH = flare_emu.EmuHelper()
  21. # 用于设置寄存器
  22. myEH.emulateRange(idc.get_name_ea_simple("q_decodeStr"), registers={'eax': argv[0]})
  23. dwEAX = myEH.getRegVal("eax")
  24. print ("EAX:%08X" % dwEAX)
  25. return myEH.getEmuString(dwEAX)
  26. g_bIsNotIter = False
  27. # 迭代地址
  28. def iterateCallback(eh, address, argv, userData):
  29. global g_bIsNotIter
  30. if g_bIsNotIter:
  31. return
  32. g_bIsNotIter = True
  33. print("=" * 80)
  34. print("%08X" % address)
  35. print(argv)
  36. # print(userData)
  37. print("%08X" % argv[0])
  38. #return
  39. s = decrypt(address, argv)
  40. #s = decrypt(argv)
  41. print("%016X: %s" % (address, s))
  42. idc.set_cmt(address, s, 0)
  43. idc.set_cmt(argv[0], s, 0)
  44. if __name__ == '__main__':
  45. eh = flare_emu.EmuHelper()
  46. # 启动一个虚拟机 模拟器
  47. #eh.iterate(idc.get_name_ea_simple("q_decodeStr"), iterateCallback)
  48. eh.iterate(idc.get_name_ea_simple("sub_401667"), iterateCallback)

官方示例: rename_dynamic_imports.py

  1. ############################################
  2. # Copyright (C) 2018 FireEye, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
  5. # http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-BSD-3-CLAUSE or
  6. # https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be
  7. # copied, modified, or distributed except according to those terms.
  8. #
  9. # Author: James T. Bennett
  10. #
  11. # IDApython script that names global variables after their import names when dynamically resolved using GetProcAddress
  12. # Point it to a target function (or somewhere within the function) to begin emulation from
  13. #
  14. # Dependencies:
  15. # https://github.com/fireeye/flare-emu
  16. ############################################
  17. import flare_emu
  18. import struct
  19. import idc
  20. import idautils
  21. import logging
  22. def makeName(addr, name):
  23. names = list(map(lambda x: x[1], list(idautils.Names())))
  24. i = 0
  25. myname = name
  26. while myname in names:
  27. myname = name + "_%d" % i
  28. i += 1
  29. idc.set_name(addr, myname, idc.SN_CHECK)
  30. def instructionHook(uc, address, size, userData):
  31. try:
  32. eh = userData["EmuHelper"]
  33. if (idc.print_insn_mnem(address) == "mov" and
  34. idc.get_operand_type(address, 0) == 2 and
  35. idc.get_name(idc.get_operand_value(address, 0))[:6] == "dword_"):
  36. if "imp" in userData:
  37. makeName(idc.get_operand_value(address, 0), userData["imp"])
  38. del(userData["imp"])
  39. except Exception as err:
  40. print "Error in instructionHook: %s" % str(err)
  41. eh.stopEmulation(userData)
  42. def callHook(address, argv, funcName, userData):
  43. try:
  44. eh = userData["EmuHelper"]
  45. # save last import string passed to a call to GetProcAddress
  46. if funcName == "GetProcAddress":
  47. arg = eh.getEmuString(argv[1])
  48. if len(arg) > 2:
  49. userData["imp"] = arg
  50. # for code that checks for a return value
  51. eh.uc.reg_write(eh.regs["ret"], 1)
  52. except Exception as err:
  53. print "Error in callHook: %s" % str(err)
  54. eh.stopEmulation(userData)
  55. if __name__ == '__main__':
  56. eh = flare_emu.EmuHelper()
  57. sVa = idc.ida_kernwin.ask_str("0", 0, "Enter the start address (hex)")
  58. sVa = int(sVa, 16)
  59. eVa = idc.ida_kernwin.ask_str("0", 0, "Enter the end address (hex), specify 0 to emulate to end of function")
  60. eVa = int(eVa, 16)
  61. if (sVa >= idc.get_inf_attr(idc.INF_MIN_EA) and sVa <= idc.get_inf_attr(idc.INF_MAX_EA) and
  62. (eVa == 0 or (eVa >= idc.get_inf_attr(idc.INF_MIN_EA) and eVa <= idc.get_inf_attr(idc.INF_MAX_EA)))):
  63. if eVa == 0:
  64. eVa = None
  65. mu = eh.emulateRange(sVa, eVa, instructionHook=instructionHook, callHook=callHook)
  66. else:
  67. print "Error: supplied addresses not within IDB address range"