近日接到一个需求,要求让两台机器拥有同样的机器码校验结果。
就需求本身来说十分常见,在网上进行的简单的搜寻也出现了很多结果,本以为找个现成的方案略加改动就能收工,但事情似乎没我想的那么乐观…
折腾了好一段时间后总算找到个像样的方法,结果也如愿以偿的完美通过校验,并且方案也控制在普通的软件层面,因此这边写下来做一个记录,以供后人参考。
该方案只对目标软件生效,且需要对目标软件进行小幅度修改
祖宗之法
首先,我们先对市面上常见的方案做一下简单的分析总结,目前而言过机器码校验总共有以下数种方法:
- – 内核层Hook拦截 驱动级方案
- – Vmware 虚拟机,去虚拟化方案
- – 直接修改系统硬件信息,驱动级方案
理论上来说这三种方案都是经过了前人校验的方案,但实际上用下来却各有各的问题。
首先是版本与兼容性,早年间基于WinXP和Win7开发的相关软件在Win10/11上还能勉强使用,
但是对于驱动和内核Hook这种偏底层的东西却几乎完全不能用,而第一种和第三种方案如果驱动无法正常安装,那么剩下的软件就只是个没有作用的空壳。
第二种方案,主要依赖于修改vmx文件和vmware的二进制执行文件来达到目的,但是不同的硬件和系统信息的存放处和修改方法各不相同,基于Vmware Workstation版本也会出现各种各样的大小差异,资料不齐全,也难以下手。
在前后倒腾了数天之后,我明白了前人的力量是有极限的,所以我决定自己从头开始研究新方案了。
抽丝剥茧
机器码,也就是基于当前设备的硬件/软件信息进行组合拼接混淆后生成的一段代码。
而事实上,大多数情况下我们并不需要去了解具体的混淆/加密手法,因为这个过程通常是固定的。
我们只需要能给他提供同样的数据源,那么生成的结果也一定是固定的。因此,我们的目的就变成了先弄清楚数据来源。
对目标软件使用ida进行逆向分析,分析其中可疑的代码:
很显然,通过其中的ROOT/CIMV2
和WQL
,我们可以知道他至少使用了WMI WQL
进行的硬件信息的获取,但实际上的获取条目和规则却不得而知。
在这里我们接着分析,又发现了可疑代码:
看起来有点像sql查询的感觉对吧,这样看也许不够直观,因为其中的字符串被做了rot13
加密,我们稍微做一下注释和重命名:
是不是感觉豁然开朗?不出意外,那么这里大概率是机器码中信息源的一部分。但是虽然知道了条目,却分析不到具体的查询条件,并且查询函数还有数个变种,其他地方也可能散落着WQL查询语句,而但凡漏掉其中一个,我们都难以通过校验。
也就是说,我们需要一种方法,能够一次性获取到软件中所用到的全部且完整的WQL查询语句,该拿出老三样了。
Detours,启动!
先获取刚刚分析到的WQL初始化函数的特征码,再根据特征码进行Hook转发,很快我们就得到了软件中所有的WQL查询语句
SELECT Manufacturer FROM Win32_ComputerSystem SELECT Model FROM Win32_ComputerSystem SELECT Name FROM Win32_Processor SELECT ProcessorType FROM Win32_Processor SELECT ProcessorId FROM Win32_Processor SELECT IdentifyingNumber FROM Win32_ComputerSystemProduct SELECT SerialNumber FROM Win32_BIOS SELECT SerialNumber FROM Win32_BaseBoard SELECT Product FROM Win32_BaseBoard SELECT Manufacturer FROM Win32_PhysicalMemory SELECT PartNumber FROM Win32_PhysicalMemory SELECT SerialNumber FROM Win32_PhysicalMemory SELECT Model FROM Win32_DiskDrive where Index='0' SELECT SerialNumber FROM Win32_DiskDrive where Index='0'
不愧是我们的Hook老伙计,一出手便直接拿下。
轻松拿下
根据上面的查询语句,我们便能清晰的知道具体的查询项,那么接下来,就该思考如何修改数据源了。
首先直接修改肯定是不行的,因为我们一开始所试验的前人的方案已经证实过了这条路不太好走。此时我脑袋一歪,嘴角逐渐上扬,只花了数秒,就想到一个歪点子。
虽然我对WQL这玩意不太熟悉,但是大概将其理解成一个数据库,而在我们找到的第一份可疑代码中的ROOT/CIMV2
其实是WMI的命名空间,某种程度上也相当于数据库的库名,而这个数据库是和系统数据相关的,没法直接修改。
但是如果我新建一个数据库填上我想要的数据,再修改软件中的数据库名,是否就能将他的查询重定向到我们自己的数据库呢?理论可行,开始实践。
先把上面的WQL查询代码丢给AI,很快便出来一份mof文件(用于创建WMI数据库),对mof文件进行编译执行,我们便得到了自己的WMI数据库
再到010Editor里修改目标程序中的ROOT/CIMV2
为ROOT/CIMV3
,保存并运行程序,校验通过,轻松拿下,也就是说软件只用了WMI查询。
接下来要做的就是把过程自动化了,先在源主机上通过cpp进行wql查询后将数据存入json,再到目标主机上根据json生成mof文件并执行,之后替换目标程序的指定数据。流程一遍过,也是轻松拿下。
战后复盘
思路:先通过Hook获取WQL的具体语句,根据语句反向生成数据库,之后修改软件重定向到自建数据库即可
优点:不需要修改硬件,不会涉及到驱动层,除去测试阶段的Hook对软件的修改只在字节数量级内,且可以同时对多个软件配不同的数据库使用。
缺点:只能处理WMI的部分,其他查询需要另外处理,必须要修改目标软件,对于有自检和安全措施的软件会带来额外的棘手问题。
这里又有读者会问了,软件有防篡改的不多见,但是加壳的就很常见了,对于加壳/无法脱壳软件,我们该如何处理呢?
好问题,加壳主要在WQL的语句的获取和WMI命名空间的修改上存在困难,但前者可以通过沙盒或者对系统dll Hook进行解决,后者则得通过实时内存修改去处理了。
总结,对WQL查询特攻的过机器码校验方案,存在一定的局限性。文章之中有不足或错误之处,欢迎各位同行指出。
评论(0)
暂无评论