使用Frida对Windows平台的程序进行逆向分析

 Frida由于使用JavaScript语言安装钩子的便利性而在最近变得越来越流行。我看到许多研究都将Frida用于移动平台,但最近Windows似乎在使用方面有了更多的吸引力。在DarunGrim,我们正在研究安全研究人员可以用于日常工作的新方法。Frida是我们认为可用于Windows逆向工程的工具之一。但是,在我们的测试过程中,我们发现符号查找功能是该工具广泛使用的限制因素。我们进行了改进,现在Frida 12.9.8中可以使用它。我们非常感谢OleAndréVadlaRavnås在合并变更方面的帮助。

创新互联公司服务项目包括曲靖网站建设、曲靖网站制作、曲靖网页制作以及曲靖网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,曲靖网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到曲靖省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

我们将简要介绍一下所做的更改,并说明如何在现实世界中解决问题时使用改进的符号查找功能。

0x01 对Frida 12.9.8 的改进

Frida使用dbghelp.dll API在Windows平台中查找符号。但是它缺少符号服务器支持。我们增加了对符号服务器的支持,并改进了Windows中传递符号字符串的方式。在较旧的Frida实现中,查找每个符号花费了一些时间,因为它使用通配符模块名称查找任何符号。现在,你可以指定模块名称以加快符号查找的速度。

新的Frida将随symsrv.dll和dbghelp.dll一起提供,以支持包括Microsoft符号服务器在内的符号服务器。

这些是我们在Ole的帮助下所做的更改。

 
 
 
 
  1. · Add load_symbols() and improve the DbgHelp backend
  2. · Migrate agent to new DbgHelp layout on Windows
  3. · Frida 12.9.8

0x02 分析office的恶意宏

使用改进的Frida对一个Office Macro恶意软件进行分析,我们希望将其应用到Frida中进行深度分析。

代码注入

下图显示了Frida通常如何安装hook并从已安装的hook中获取消息。

此过程中涉及frida,session,脚本对象,以管理hook安装。hook回调是用JavaScript编写的。

以下代码显示了如何使用这些对象来安装分配给self.script_text变量的JavaScript hook代码以使用process_id变量进行处理的示例。

 
 
 
 
  1. https://github.com/ohjeongwook/Frida.examples.vbe/blob/master/code.py
  2. import os
  3. import sys
  4. import frida
  5. import process
  6. class Instrumenter:
  7.     def __init__(self, script_text):
  8.         self.sessions = []
  9.         self.script_text = script_text
  10.         self._device = frida.get_local_device()
  11.         self._device.on("child-added", self._on_child_added)
  12.         self._device.on("child-removed", self._on_child_removed)
  13.         self._device.on("output", self._on_output)
  14.         
  15.     def __del__(self):
  16.         for session in self.sessions:
  17.             session.detach()
  18.     def run(self, process_name):
  19.         proc = process.Runner(process_name, suspended = True)
  20.         if not proc.create():
  21.             return
  22.         process_id = proc.get_id()
  23.         self.instrument(process_id)
  24.         if proc:
  25.             proc.resume()
  26.     def instrument(self, process_id):
  27.         session = frida.attach(process_id)
  28.         self.sessions.append(session)
  29.         session.enable_child_gating()
  30.         script = session.create_script(self.script_text)
  31.         script.on('message', self.on_message)
  32.         script.load()
  33.     def on_message(self, message, data):
  34.         print("[%s] => %s" % (message, data))
  35.     def _on_child_added(self, child):
  36.         print(" new child: {}".format(child))
  37.         self.instrument(child.pid)
  38.     def _on_child_removed(self, child):
  39.         print(" child terminated: {}".format(child))
  40.     def _on_output(self, pid, fd, data):
  41.         print(" output: pid={}, fd={}, data={}".format(pid, fd, repr(data)))
  42. 符号查找:resolveName
  43. Frida JavaScript API在API文档中有很好的描述。
  44. 使用Frida进行hook的第一步是找到目标函数。
  45. 如果函数已导出,则只需使用导出的函数名和DLL名称调用Module.findExportByName方法。
  46. Module.findExportByName(dllName, name)
  47. 但是,如果该函数未导出并且仅记录在例如PDB符号文件中,则可以调用DebugSymbol.getFunctionByName方法。使用Frida 12.9.8,你可以传递“ DLLName!FunctionName”符号,以在指定特定功能时提高准确性,并在定位它们时获得更好的性能。
  48. 有时,为模块加载符号可能很慢,因为它可能来自远程符号服务器。因此,你需要调用DebugSymbol.load方法来启动符号的加载,以便我们加载最少数量的符号。
  49. 下面是一个示例代码,该示例代码使用Module.findExportByName和DebugSymbol方法查找任何带符号或导出的函数。它使用字典来缓存其发现,以删除所有重复的信息。如果你要hook大量函数,则可以节省整个符号查找时间。
  50. vbe.js
  51. https://github.com/ohjeongwook/Frida.examples.vbe/blob/master/vbe.js
  52. var loadedModules = {}
  53. var resolvedAddresses = {}
  54. function resolveName(dllName, name) {
  55.   var moduleName = dllName.split('.')[0]
  56.   var functionName = moduleName + "!" + name
  57.   if (functionName in resolvedAddresses) {
  58.     return resolvedAddresses[functionName]
  59.   }
  60.   log("resolveName " + functionName);
  61.   log("Module.findExportByName " + dllName + " " + name);
  62.   var addr = Module.findExportByName(dllName, name)
  63.   if (!addr || addr.isNull()) {
  64.     if (!(dllName in loadedModules)) {
  65.       log(" DebugSymbol.loadModule " + dllName);
  66.       try {
  67.         DebugSymbol.load(dllName)
  68.       } catch (err) {
  69.         return 0;
  70.       }
  71.       log(" DebugSymbol.load finished");
  72.       loadedModules[dllName] = 1
  73.     }
  74.     try {
  75.       log(" DebugSymbol.getFunctionByName: " + functionName);
  76.       addr = DebugSymbol.getFunctionByName(moduleName + '!' + name)
  77.       log(" DebugSymbol.getFunctionByName: addr = " + addr);
  78.     } catch (err) {
  79.       log(" DebugSymbol.getFunctionByName: Exception")
  80.     }
  81.   }
  82.   resolvedAddresses[functionName] = addr
  83.   return addr
  84. }
  85. function loadModuleForAddress(address) {
  86.   var modules = Process.enumerateModules()
  87.   var i
  88.   for (i = 0; i < modules.length; i++) {
  89.     if (address >= modules[i].base && address <= modules[i].base.add(modules[i].size)) {
  90.       log(" " + modules[i].name + ": " + modules[i].base + " " + modules[i].size + " " + modules[i].path)
  91.       var modName = modules[i].path
  92.       if (!(modName in loadedModules)) {
  93.         log("  DebugSymbol.loadModule " + modName);
  94.         try {
  95.           DebugSymbol.load(modName)
  96.         } catch (err) {
  97.           return 0;
  98.         }
  99.         loadedModules[modName] = 1
  100.       }
  101.       break
  102.     }
  103.   }
  104. }
  105. var hookedFunctions = {}
  106. var addressToFunctions = {}
  107. var blackListedFunctions = {
  108.   'I_RpcClearMutex': 1
  109. }
  110. function hookFunction(dllName, funcName, callback) {
  111.   if (funcName in blackListedFunctions) {
  112.     return
  113.   }
  114.   var symbolName = dllName + "!" + funcName
  115.   if (symbolName in hookedFunctions) {
  116.     return
  117.   }
  118.   hookedFunctions[symbolName] = 1
  119.   var addr = resolveName(dllName, funcName)
  120.   if (!addr || addr.isNull()) {
  121.     return
  122.   }
  123.   if (addr in hookedFunctions) {
  124.     return
  125.   }
  126.   hookedFunctions[addr] = 1
  127.   addressToFunctions[addr] = symbolName
  128.   log('Interceptor.attach: ' + symbolName + '@' + addr);
  129.   Interceptor.attach(addr, callback)
  130. }
  131. function hookPointers(address, count) {
  132.   if (address.isNull())
  133.     return
  134.   var currentAddress = address
  135.   for (var i = 0; i < count; i++) {
  136.     var readAddress = ptr(currentAddress).readPointer();
  137.     readAddress = ptr(readAddress)
  138.     var symbolInformation = DebugSymbol.fromAddress(readAddress)
  139.     var name = readAddress
  140.     if (symbolInformation && symbolInformation.name) {
  141.       name = symbolInformation.name
  142.     }
  143.     log('Hooking ' + readAddress + ": " + name)
  144.     try {
  145.       Interceptor.attach(readAddress, {
  146.         onEnter: function (args) {
  147.           log('[+] ' + name)
  148.         }
  149.       })
  150.     } catch (err) {}
  151.     currentAddress = currentAddress.add(4)
  152.   }
  153. }
  154. function hookFunctionNames(moduleName, funcNames) {
  155.   for (var i = 0; i < funcNames.length; i++) {
  156.     var funcName = funcNames[i]
  157.     try {
  158.       hookFunction(moduleName, funcName, {
  159.         onEnter: function (args) {
  160.           var name = ''
  161.           if (this.context.pc in addressToFunctions) {
  162.             name = addressToFunctions[this.context.pc]
  163.           }
  164.           log("[+] " + name + " (" + this.context.pc + ")")
  165.         }
  166.       })
  167.     } catch (err) {
  168.       log("Failed to hook " + funcName)
  169.     }
  170.   }
  171. }
  172. function BytesToCLSID(address) {
  173.   if (address.isNull())
  174.     return
  175.   var data = new Uint8Array(ptr(address).readByteArray(0x10))
  176.   var clsid = "{" + getHexString(data[3]) + getHexString(data[2]) + getHexString(data[1]) + getHexString(data[0])
  177.   clsid += '-' + getHexString(data[5]) + getHexString(data[4])
  178.   clsid += '-' + getHexString(data[7]) + getHexString(data[6])
  179.   clsid += '-' + getHexString(data[8]) + getHexString(data[9])
  180.   clsid += '-' + getHexString(data[10]) + getHexString(data[11]) + getHexString(data[12]) + getHexString(data[13]) + getHexString(data[14]) + getHexString(data[15])
  181.   clsid += '}'
  182.   return clsid
  183. }
  184. function log(message) {
  185.   console.log(message)
  186. }
  187. function dumpAddress(address) {
  188.   log('[+] address: ' + address);
  189.   if (address.isNull())
  190.     return
  191.   var data = ptr(address).readByteArray(50);
  192.   log(hexdump(data, {
  193.     offset: 0,
  194.     length: 50,
  195.     header: true,
  196.     ansi: false
  197.   }));
  198. }
  199. function dumpBytes(address, length) {
  200.   if (address.isNull())
  201.     return
  202.   var data = ptr(address).readByteArray(length);
  203.   log(hexdump(data, {
  204.     offset: 0,
  205.     length: length,
  206.     header: true,
  207.     ansi: false
  208.   }));
  209. }
  210. function dumpSymbols(address, count) {
  211.   if (address.isNull())
  212.     return
  213.   var currentAddress = address
  214.   for (var i = 0; i < count; i++) {
  215.     var readAddress = ptr(currentAddress).readPointer();
  216.     readAddress = ptr(readAddress)
  217.     var symbolInformation = DebugSymbol.fromAddress(readAddress)
  218.     if (symbolInformation && symbolInformation.name) {
  219.       log(currentAddress + ":\t" + readAddress + " " + symbolInformation.name)
  220.     } else {
  221.       log(currentAddress + ":\t" + readAddress)
  222.     }
  223.     currentAddress = currentAddress.add(4)
  224.   }
  225. }
  226. function dumpBSTR(address) {
  227.   log('[+] address: ' + address);
  228.   if (address.isNull())
  229.     return
  230.   var length = ptr(address - 4).readULong(4);
  231.   log("length: " + length)
  232.   var data = ptr(address).readByteArray(length);
  233.   log(hexdump(data, {
  234.     offset: 0,
  235.     length: length,
  236.     header: true,
  237.     ansi: false
  238.   }));
  239. }
  240. function getString(address) {
  241.   if (address.isNull())
  242.     return
  243.   var dataString = ''
  244.   var offset = 0
  245.   var stringEnded = false
  246.   while (!stringEnded) {
  247.     var data = new Uint8Array(ptr(address.add(offset)).readByteArray(10));
  248.     if (data.length <= 0) {
  249.       break
  250.     }
  251.     var i;
  252.     for (i = 0; i < data.length; i++) {
  253.       if (data[i] == 0x0) {
  254.         stringEnded = true
  255.         break
  256.       }
  257.       dataString += String.fromCharCode(data[i])
  258.     }
  259.     offset += data.length
  260.   }
  261.   log("dataString: " + dataString)
  262.   return dataString;
  263. }
  264. function dumpWSTR(address) {
  265.   if (address.isNull())
  266.     return
  267.   var dataString = ''
  268.   var offset = 0
  269.   var stringEnded = false
  270.   while (!stringEnded) {
  271.     var data = new Uint8Array(ptr(address.add(offset)).readByteArray(20));
  272.     if (data.length <= 0) {
  273.       break
  274.     }
  275.     var i;
  276.     for (i = 0; i < data.length; i += 2) {
  277.       if (data[i] == 0x0 && data[i + 1] == 0x0) {
  278.         stringEnded = true
  279.         break
  280.       }
  281.       dataString += String.fromCharCode(data[i])
  282.     }
  283.     offset += data.length
  284.   }
  285.   log("dataString: " + dataString)
  286.   return dataString;
  287. }
  288. function hookRtcShell(moduleName) {
  289.   hookFunction(moduleName, "rtcShell", {
  290.     onEnter: function (args) {
  291.       log("[+] rtcShell")
  292.       var variantArg = ptr(args[0])
  293.       dumpAddress(variantArg);
  294.       var bstrPtr = ptr(variantArg.add(8).readULong())
  295.       dumpBSTR(bstrPtr);
  296.     }
  297.   })
  298. }
  299. function hookVBAStrCat(moduleName) {
  300.   hookFunction(moduleName, "__vbaStrCat", {
  301.     onEnter: function (args) {
  302.       log("[+] __vbaStrCat")
  303.       // log('[+] ' + name);
  304.       // dumpBSTR(args[0]);
  305.       // dumpBSTR(args[1]);
  306.     },
  307.     onLeave: function (retval) {
  308.       dumpBSTR(retval);
  309.     }
  310.   })
  311. }
  312. function hookVBAStrComp(moduleName) {
  313.   hookFunction(moduleName, "__vbaStrComp", {
  314.     onEnter: function (args) {
  315.       log('[+] __vbaStrComp');
  316.       log(ptr(args[1]).readUtf16String())
  317.       log(ptr(args[2]).readUtf16String())
  318.     }
  319.   })
  320. }
  321. function hookRtcCreateObject(moduleName) {
  322.   hookFunction(moduleName, "rtcCreateObject", {
  323.     onEnter: function (args) {
  324.       log('[+] rtcCreateObject');
  325.       dumpAddress(args[0]);
  326.       dumpBSTR(args[0]);
  327.       log(ptr(args[0]).readUtf16String())
  328.     },
  329.     onLeave: function (retval) {
  330.       dumpAddress(retval);
  331.     }
  332.   })
  333. }
  334. function hookRtcCreateObject2(moduleName) {
  335.   hookFunction(moduleName, "rtcCreateObject2", {
  336.     onEnter: function (args) {
  337.       log('[+] rtcCreateObject2');
  338.       dumpAddress(args[0]);
  339.       dumpBSTR(args[1]);
  340.       log(ptr(args[2]).readUtf16String())
  341.     },
  342.     onLeave: function (retval) {
  343.       dumpAddress(retval);
  344.     }
  345.   })
  346. }
  347. //  int __stdcall CVbeProcs::CallMacro(CVbeProcs *this, const wchar_t *)
  348. function hookCVbeProcsCallMacro(moduleName) {
  349.   hookFunction(moduleName, "CVbeProcs::CallMacro", {
  350.     onEnter: function (args) {
  351.       log('[+] CVbeProcs::CallMacro');
  352.       dumpAddress(args[0]);
  353.       dumpWSTR(args[1]);
  354.     },
  355.     onLeave: function (retval) {
  356.       dumpAddress(retval);
  357.     }
  358.   })
  359. }
  360. function hookDispCall(moduleName) {
  361.   hookFunction(moduleName, "DispCallFunc", {
  362.     onEnter: function (args) {
  363.       log("[+] DispCallFunc")
  364.       var pvInstance = args[0]
  365.       var oVft = args[1]
  366.       var instance = ptr(ptr(pvInstance).readULong());
  367.       log(' instance:' + instance);
  368.       log(' oVft:' + oVft);
  369.       var vftbPtr = instance.add(oVft)
  370.       log(' vftbPtr:' + vftbPtr);
  371.       var functionAddress = ptr(ptr(vftbPtr).readULong())
  372.       loadModuleForAddress(functionAddress)
  373.       var functionName = DebugSymbol.fromAddress(functionAddress)
  374.       if (functionName) {
  375.         log(' functionName:' + functionName);
  376.       }
  377.       dumpAddress(functionAddress);
  378.       var currentAddress = functionAddress
  379.       for (var i = 0; i < 10; i++) {
  380.         try {
  381.           var instruction = Instruction.parse(currentAddress)
  382.           log(instruction.address + ': ' + instruction.mnemonic + ' ' + instruction.opStr)
  383.           currentAddress = instruction.next
  384.         } catch (err) {
  385.           break
  386.         }
  387.       }
  388.     }
  389.   })
  390. }
  391. hookRtcShell('vbe7')
  392. hookVBAStrCat('vbe7')
  393. hookVBAStrComp('vbe7')
  394. hookRtcCreateObject('vbe7')
  395. hookRtcCreateObject2('vbe7')
  396. hookCVbeProcsCallMacro('vbe7')
  397. hookDispCall('oleaut32')

设置符号路径

在Windows环境下设置符号服务器有多种方法,建议你从命令行设置_NT_SYMBOL_PATH变量。Windows调试器的符号路径对变量的用法有很好的描述。

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/symbol-path
以下将使用“ c:\ symbols”作为其本地符号存储来缓存正式的Microsoft符号服务器。

setx _NT_SYMBOL_PATH SRV*c:\symbols*https://msdl.microsoft.com/download/symbols
以下命令将使系统使用默认的符号存储目录。

setx _NT_SYMBOL_PATH SRV*https://msdl.microsoft.com/download/symbols
运行恶意软件并观察行为

我们使用以下示例测试Frida的符号查找功能。恶意样本做了一些混淆,可以使用Frida hook轻松分析。

我们在此处提供的代码可从以下GitHub存储库中找到。

 
 
 
 
  1. https://github.com/ohjeongwook/Frida.examples.vbe
  2. var loadedModules = {}
  3. var resolvedAddresses = {}
  4. function resolveName(dllName, name) {
  5.   var moduleName = dllName.split('.')[0]
  6.   var functionName = moduleName + "!" + name
  7.   if (functionName in resolvedAddresses) {
  8.     return resolvedAddresses[functionName]
  9.   }
  10.   log("resolveName " + functionName);
  11.   log("Module.findExportByName " + dllName + " " + name);
  12.   var addr = Module.findExportByName(dllName, name)
  13.   if (!addr || addr.isNull()) {
  14.     if (!(dllName in loadedModules)) {
  15.       log(" DebugSymbol.loadModule " + dllName);
  16.       try {
  17.         DebugSymbol.load(dllName)
  18.       } catch (err) {
  19.         return 0;
  20.       }
  21.       log(" DebugSymbol.load finished");
  22.       loadedModules[dllName] = 1
  23.     }
  24.     try {
  25.       log(" DebugSymbol.getFunctionByName: " + functionName);
  26.       addr = DebugSymbol.getFunctionByName(moduleName + '!' + name)
  27.       log(" DebugSymbol.getFunctionByName: addr = " + addr);
  28.     } catch (err) {
  29.       log(" DebugSymbol.getFunctionByName: Exception")
  30.     }
  31.   }
  32.   resolvedAddresses[functionName] = addr
  33.   return addr
  34. }

因此,当你启动Word进程且进程ID为3064时,可以使用以下命令从存储库中包含的vbe.js安装hook。安装hook之后,你可以打开恶意文档以观察其行为

 
 
 
 
  1. > python inject.py -p 3064 vbe.js
  2. resolveName vbe7!rtcShell
  3. Module.findExportByName vbe7 rtcShell
  4. Interceptor.attach: vbe7!rtcShell@0x652a2b76
  5. resolveName vbe7!__vbaStrCat
  6. Module.findExportByName vbe7 __vbaStrCat
  7.  DebugSymbol.loadModule vbe7
  8.  DebugSymbol.load finished
  9.  DebugSymbol.getFunctionByName: vbe7!__vbaStrCat
  10.  DebugSymbol.getFunctionByName: addr = 0x651e53e6
  11. Interceptor.attach: vbe7!__vbaStrCat@0x651e53e6
  12. resolveName vbe7!__vbaStrComp
  13. Module.findExportByName vbe7 __vbaStrComp
  14.  DebugSymbol.getFunctionByName: vbe7!__vbaStrComp
  15.  DebugSymbol.getFunctionByName: addr = 0x651e56a2
  16. Interceptor.attach: vbe7!__vbaStrComp@0x651e56a2
  17. resolveName vbe7!rtcCreateObject
  18. Module.findExportByName vbe7 rtcCreateObject
  19. Interceptor.attach: vbe7!rtcCreateObject@0x653e6e4c
  20. resolveName vbe7!rtcCreateObject2
  21. Module.findExportByName vbe7 rtcCreateObject2
  22. Interceptor.attach: vbe7!rtcCreateObject2@0x653e6ece
  23. resolveName vbe7!CVbeProcs::CallMacro
  24. Module.findExportByName vbe7 CVbeProcs::CallMacro
  25.  DebugSymbol.getFunctionByName: vbe7!CVbeProcs::CallMacro
  26.  DebugSymbol.getFunctionByName: addr = 0x6529019b
  27. Interceptor.attach: vbe7!CVbeProcs::CallMacro@0x6529019b
  28. resolveName oleaut32!DispCallFunc
  29. Module.findExportByName oleaut32 DispCallFunc
  30. Interceptor.attach: oleaut32!DispCallFunc@0x747995b0
  31. [!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.

hook监控office的宏行为

vbe.js很少有hook来监视恶意Office文档的行为。

__vbaStrCat

vbe7.dll是已找到Visual Basic运行时引擎的DLL,里面有很多有趣的函数。但是首先,我们想观察字符串去混淆操作

vbe7!__ vbaStrCat是在Visual Basic中串联字符串时调用的函数。

.text:651E53E6 ; __stdcall __vbaStrCat(x, x)
.text:651E53E6 ___vbaStrCat@8 proc near ; CODE XREF: _lblEX_ConcatStr↑p
许多基于宏的恶意软件文档都使用基于字符串的混淆。通过观察字符串的动作,你可以观察最终的去混淆字符串的构造。

以下hook代码将为每个调用打印出连接的字符串。

 
 
 
 
  1. https://github.com/ohjeongwook/Frida.examples.vbe/blob/master/vbe.js
  2. var loadedModules = {}
  3. var resolvedAddresses = {}
  4. function resolveName(dllName, name) {
  5.   var moduleName = dllName.split('.')[0]
  6.   var functionName = moduleName + "!" + name
  7.   if (functionName in resolvedAddresses) {
  8.     return resolvedAddresses[functionName]
  9.   }
  10.   log("resolveName " + functionName);
  11.   log("Module.findExportByName " + dllName + " " + name);
  12.   var addr = Module.findExportByName(dllName, name)
  13.   if (!addr || addr.isNull()) {
  14.     if (!(dllName in loadedModules)) {
  15.       log(" DebugSymbol.loadModule " + dllName);
  16.       try {
  17.         DebugSymbol.load(dllName)
  18.       } catch (err) {
  19.         return 0;
  20.       }
  21.       log(" DebugSymbol.load finished");
  22.       loadedModules[dllName] = 1
  23.     }
  24.     try {
  25.       log(" DebugSymbol.getFunctionByName: " + functionName);
  26.       addr = DebugSymbol.getFunctionByName(moduleName + '!' + name)
  27.       log(" DebugSymbol.getFunctionByName: addr = " + addr);
  28.     } catch (err) {
  29.       log(" DebugSymbol.getFunctionByName: Exception")
  30.     }
  31.   }
  32.   resolvedAddresses[functionName] = addr
  33.   return addr
  34. }
  35. function loadModuleForAddress(address) {
  36.   var modules = Process.enumerateModules()
  37.   var i
  38. 名称栏目:使用Frida对Windows平台的程序进行逆向分析
    URL分享:http://www.hantingmc.com/qtweb/news49/273549.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联