菜鸟的福音-x64dbg完美追踪方案

查看 233|回复 11
作者:pexufe   
声明:本帖只面向初学者和菜鸟,高手可以略过,一笑置之。
众所周知,破解的关键在于找到关键CALL。破解的两大利器,一个是静态分析的IDA,另一个是动态分析的OD。OD早就不更新了,并且不支持64位系统。现在动态分析主要靠X64dbg了。
X64dbg更新很快,但作者对于帮助文档却惜墨如金,有很多实用的强大功能,都需要自己去摸索。
刚才提到寻找关键CALL,IDA虽然F5生成伪码功能强大,并且可以生成函数调用图,但对于复杂的调用看起来就很不直观。并且IDA只能单个文件静态分析,对于跨模块调用就无能为力。这里着重说下X64dbg的追踪方案。
对于一些简单的程序,可以通过搜索字符串,下API断点等很多方式来查找关键CALL。而有些程序的加密做的比较彻底,导入导出表只有编号没有名称,打开反汇编后一脸懵。并且还在很多地方使用类似call esi的指令来调用,不一行行跟的情况下,很难知道函数间到底是如何调用的。逐行跟的话耗费时间不说,还很考验破解者的功底和耐心。x64dbg提供有追踪功能,也可以生成追踪文件。但如果步进F7追踪的话,生成的文件会很大,并且中间过程每行指令的注释不会保留下来;如果步过F8追踪的话,又会错过很多细节,说不定就会和关键CALL失之交臂。怎样能只追踪我们想要的东西,其它的都略过,或者说先想办法粗定位到关键CALL,然后再逐行分析呢?
重点就在于学会使用条件跟踪。x64dbg提供了强大的表达式功能,奈何帮助文档太拉胯,晦涩难懂,一般人看到都会敬而远之。这里要重点感谢一位大佬,大家可以在网上搜索X64Dbg 介绍->表达式,里面对于x64dbg表达式的使用进行了详细讲解,值得反复学习和体会。众所周知,程序就是一堆函数组成,而函数的关键在于参数和返回值。知道了参数和返回值后,对于函数的功能就可以管中窥豹。而利用好条件断点,就可以让我们抓取函数调用时的参数和返回值,让日志只记录我们想要的功能。待找到关键CALL以后,再生成追踪文件进行详细跟。大家都知道函数调用前参数存在ESP+4*n中,而函数返回值存在EAX里。我们就可以根据这些下条件跟踪。


条件断点.jpg (54.27 KB, 下载次数: 0)
下载附件
条件跟踪
2023-11-11 22:46 上传

方法就是在日志文本中可以输入{modname@cip} {p:cip} {i:cip} {a:cip} {"EAX"} {a:eax} {a:[eax]} {"[ESP]"} {a:[esp]} {"[ESP+4]"} {a:[esp+4]} {"[ESP+8]"} {a:[esp+8]} {"[ESP+C]"} {a:[esp+C]} {"[ESP+10]"} {a:[esp+10]},日志条件是dis.isbranch(cip) || dis.isret(cip),这样就可以自动记录下每次函数调用时的参数和返回值。最大单步次数默认是50000,可以根据自己机器的情况自行设置。步进转换条件设置成mod.party(dis.branchdest(cip))==1,这样系统模块的调用就变成F8步过,就能过滤掉很多系统内部的无效跟踪。万一发现有部分系统模块跳转用户模块过程漏跟的情况,再设置条件断点,把步进转换条件去掉。如果除了参数和返回值外,还想跟踪寄存器值的变化,也可以在日志文件里加上{"EBX"} {a:ebx} {a:[ebx]} {"ECX"} {a:ecx} {a:[ecx]} {"EDX"} {a:edx} {a:[edx]} {"ESI"} {a:esi} {a:[esi]} {"Edi"} {a:edi} {a:[edi]}等。如果日志条件想把call和ret的下一条指令也跟踪上,可以写成这样 !mod.party(cip) && (dis.isbranch(cip)|| dis.isret(cip)|| ReadByte(cip-1)==cc || dis.iscall(dis.prev(cip)) || dis.isret(dis.prev(cip)));如果不想跟踪JCC、只想跟踪JMP和CALL,可以把dis.isbranch(cip)改成(dis.isbranch(cip) && !dis.iscond(cip))。


跟踪日志.jpg (137.88 KB, 下载次数: 0)
下载附件
跟踪日志
2023-11-10 11:46 上传

设置后生成的跟踪日志就是这样,记录下来后再通过modname可以帮助我们过滤一些不需要关心的系统模块调用。稍微遗憾的是有些CALL在反汇编窗口里能看到具体名称,但生成日志后就只看到地址、看不到名称了,需要在回看跟踪日志的时候手动添加。比如反汇编窗口中看到的指令是这样call dword ptr ds:[],但日志里却是call dword ptr ds:[0x6BC4A574],日志里并不能根据导入导出表自动把常量区的内存地址替换成函数名称。我试尽了表达式里的各种方法都无法实现,希望后续x64dbg版本的更新能把它优化下。另外x64dbg强大的表达式功能还可以实现符合匹配正则表达式和字符串内容的指令才记录跟踪,比如{dis.match(rip,"text.+,0x1")}或者{strstr(dis.text(cip),"call esi"}等,大家可以参考前面提到的X64Dbg 介绍->表达式一文自行体验。
通过条件跟踪的灵活应用,就有助于我们菜鸟知道函数调用的整个过程,快速粗定位到关键CALL,事半功倍。

函数, 条件

pexufe
OP
  


nody 发表于 2023-11-13 15:43
怪了,我没有步进转换条件

步进转换条件只有2023.1.25之前的版本才有,新的版本作者把这个功能去掉了。这个功能有利有弊,可以帮助过滤掉一些不相关的系统模块调用,但有时候也会造成漏跟踪。
pexufe
OP
  

我看有人说从2023.2.23 开始的版本取消了步进转换功能,然后引入了指令 StepUser 和 StepSystem 来实现用户代码和系统代码的步进。你可以查阅相关文档测试一下
无闻无问   

确实,能跟踪就能了解流程,才能有效虐…
楼主的分享,很有效果啊
vihp   

学习到了。楼主讲的很详细。
尹铭   

学习了感谢楼主~!
张道陵   

学习了感谢楼主~!
testblog   

说的很详细,感谢分享。
pojieyonghu   

楼主讲的很详细。
NMCchan   

我来学习一下了
您需要登录后才可以回帖 登录 | 立即注册

返回顶部