背景:
在分析一些大家族病毒样本核心层时(如:Emotet、LokiBot等)经常会发现它们的导入函数很少,需要用哪个函数时,都是根据函数名称hash动态获取的。此类特征也可以作为一个启发查杀点,日后有空再谈!通常遇到这种情况我们想要知道调的是哪个api,都是动态调试过去看下,但是那么多加密的函数名称,总不能动态一个一个过去看,然后手动在ida上标明,毕竟动态分析相比于静态分析还是比较耗时的,那么有什么办法可以跑一次样本,然后获取我们所需的所有api函数名称,以及对应地址呢?有了这个log的话,我们就可以写idc或idapython帮我们在ida上标出,这样静态看的话可以提高不少效率。以下举个例子,是笔者最近看的LokiBot家族核心层代码,如下图所示:
通过交叉引用可以看到这样动态获取函数地址的函数有224个,还是挺多的。下面看下如何用x64dbgpy解决吧!
x64dbgpy环境安装:
x64dbgpy下载及安装:
项目地址:https://github.com/x64dbg/x64dbgpy
下载release文件后解压并将对应x86,x64插件放入x64dbg插件目录,如下图所示:
python 2.7安装:
因为x86与x64样本都有可能遇到,所以x86与x64的python都需要安装。由于步骤都是一样的,所以笔者以python 2.7 x86举例。
安装好以后,x64dbgpy就可以使用了。
脚本思路及x64dbgpy api探索:
思路:get_fun_addr函数返回值是所需的api地址,所以在其内部返回处打个断点,脚本运行到断点处获取eax值(函数地址),根据eax值拿到对应的api名称,最终跳出get_fun_addr函数,获取eip值,这样就知道哪里调用什么函数了。
x64dbgpy api探索:x64dbgpy的api使用大家可以自行查看对应的sdk,在此只挑选本次需要使用的简要说下:
根据意思不难理解,我们需要debug模块下的Run(运行)、StepOver(步过)、StepOut(跳出)函数,register模块下的GetEAX、GetEIP函数,我们可以拿到eax值后,只需要根据值获取对应的api名称即可,看此sdk代码,按理说function模块的函数就可以满足需求,但是经过笔者多次测试最终没有通过x64dbgpy直接获取想要的函数名称。当我在x64dbg命令行直接敲函数地址时可以直接显示对应名称,但是使用DbgScriptCmdExec函数执行相应命令时确没有回显且这个函数在x64dbgpy中是个bool型,此处陷入了僵局,如果大家有好的办法,欢迎指点!!!!!
通过键盘模拟获取函数名称:
在经历过无数次尝试后,还是未发现有什么好的办法通过api地址获取函数名称,最终笔者发现在寄存器上右击有个快捷键“Ctrl+S”可以自动复制函数名称到粘贴板,曲线救国吧,因为问题得解决不能一直卡着。
下面我们有两个需要一个是模拟键盘,一个是获取剪切板数据,下面介绍两个python库:pyperclip、pykeyboard
pyperclip、pykeyboard安装:
pyperclip安装:这个直接pip安装即可,可用此获取剪切板数据
pykeyboard安装:此库包含在PyUserInput库中,所以需要下面两个依赖库pywin32,pyhook
一:安装pywin32:
直接pip安装pywin32会出错,升级pip(python -m pip install --upgrade pip)后会惊喜的发现整个pip都坏掉了。安装什么都会提示:报错:sys.stderr.write(f"ERROR: {exc}")
此处可以通过 “curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py”下载get-pip.py后重新安装pip修复,且重新安装后pywin32就可以正常安装了。
二:安装pyhook:
直接通过pip安装会发现安装不下来,此处推荐离线安装,去https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyhook这里下载x86版安装。
三:安装PyUserInput:
安装好一,二步后,可以很顺利的通过pip直接安装PyUserInput,安装好之后就可以使用pykeyboard。
运行脚本:
import x64dbgpy.pluginsdk._scriptapi.debug as dbg
import pyperclip
from pykeyboard import *
import time
if __name__ == '__main__':
i = 0
run_counts = 20
with open("C:\Users\test\Desktop\log.txt","a") as fa:
while i < run_counts:
k = PyKeyboard()
pyperclip.copy('')
dbg.Run()
dbg.StepOut()
dbg.StepOver()
#hot key
k.press_key(k.control_key )
k.tap_key("s")
k.release_key(k.control_key )
time.sleep(0.5)
api_name = pyperclip.paste()
eax_value = reg.GetEAX()
eip_value = reg.GetEIP()
data = "eip: " + hex(eip_value) + " api_addr: " + hex(eax_value) + " api: " + api_name + "\n"
print data
fa.write(data)
api_name = ""
i = i+1
脚本运行时,断点大家自行设置,我是获取的eax值,由于要配合键盘,所以当我下好断点之后,我会点击一下eax值,然后alt+F7通过键盘选择脚本然后运行,再此过程中不能通过鼠标点击操作,不然光标聚集不到eax寄存器,热键失效。下面看下跑出的日志效果,我只跑了20次,运行次数大家自行设置。
总结:
后续的ida相关脚本大家根据需求自行编写,相当于曲线获取动态api函数地址及其名称吧。希望大家看完此篇博文能够学到x64dbgpy的安装及api使用,python2.7 pip安装pywin32,pyhook,安装过程中相关的错误处理。最最最重要的思想是,当一条路实在走不通的时候,希望大家能够及时切换思路,切勿钻进牛角尖,即浪费了时间同时最后问题也得不到解决!!!!!(技术low不low不在此讨论范围内,不管黑猫白猫,抓到老鼠就是好猫!!!!!请结合这篇随笔(黑猫与白猫)食用)