可怕!CPU竟然暗藏了这么多未公开的指令
liebian365 2024-10-18 09:33 5 浏览 0 评论
我们知道,我们平时编程写的高级语言,是经过编译器编译以后,变成了CPU可以执行的机器指令:
而CPU能支持的指令,都在它的指令集里面了。
很久以来,我都在思考一个问题:
CPU有没有未公开的指令?
或者说:
CPU有没有隐藏的指令?
为什么会有这个问题?
平常我们谈论网络安全问题的时候,大多数时候都是在软件层面。谈应用程序的漏洞、后端服务的漏洞、第三方开源组件的漏洞乃至操作系统的漏洞。
但很少有机会去触及硬件,前几年爆发的熔断和幽灵系列漏洞,就告诉我们,CPU也不是可信任的。
要是CPU隐藏有某些不为人知的指令,这是一件非常可怕的事情。
如果某一天,某些国家或者某些团体组织出于某种需要,利用这些隐藏的指令来发动攻击,后果不堪设想。
虽然想到过这个问题,但我一直没有付诸实践去认真的研究。
直到前段时间,极客时间的一位老师分享了一份PDF给我,解答了我的疑惑。
这份PDF内容是2017年顶级黑客大会Black Hat上的一篇报告:《us-17-Domas-Breaking-The-x86-ISA》,作者是大神:@xoreaxeaxeax,熟悉汇编的同学知道这名字是什么意思吗?
这份PDF深度研究了x86架构CPU中隐藏的指令,原报告因为是英文,看起来有些晦涩,这篇文章,我尝试用大家易懂的语言来给大家分享一下这篇非常有意思的干货。
有些人会问:真的会有隐藏指令的存在吗,CPU的指令集不是都写在指令手册里了吗?
我们以单字节指令为例,单字节的范围是0x00-0XFF,总共256种组合,Intel的指令手册中是这样介绍单字节指令的:
横向为单字节的高四位,纵向为单字节的低四位,顺着表格定位,可以找到每一个单字节指令的定义。比如我们常见的nop指令的机器码是0x90,就是行为9,列为0的那一格。
但是不知道你发现没有,这张表格中还有些单元格是空的,比如0xF1,那CPU拿到一个为0xF1的指令,会怎么执行呢?
指令手册没告诉你。
这篇报告的主要内容就是告诉你,如何去寻找这些隐藏的指令。
指令集的搜索空间
想要找到隐藏的指令,得先明确一个问题:一条指令到底有多长,换句话说,有几个字节,我们应该在什么样的一个范围内去寻找隐藏指令。
如果指令长度是固定的,比如JVM那样的虚拟机,那问题好办,直接遍历就行了。
但问题难就难在,x86架构CPU的指令集属于复杂指令集CISC,它的指令不是固定长度的。
有单字节指令,比如:
90 nop
CC int 3
C3 ret
也有双字节指令,比如:
8B C8 mov ecx,eax
6A 20 push 20h
还有三四节、四字节、五字节···最长能有十几个字节,比如这条指令:
指令:lock add qword cs:[eax + 4 * eax + 07e06df23h], 0efcdab89h
机器码:2e 67 f0 48 818480 23df067e 89abcdef
一个字节、两个字节,甚至三个四个遍历都还能接受,4个字节最多也就42亿多种组合,对于计算机来说,也还能接受。
但越往后,容量是呈指数型增长,这种情况再去遍历,显然是不现实的。
指令搜索算法
这份报告中提出了一种深度优先的搜索算法:
该算法的指导思想在于:快速跳过指令中无关紧要的字节。
怎么理解这句话?
比如压栈的指令push,下面几条虽然字节序列不同,但变化的只是数据,其实都是压栈指令,对于这类指令,就没必要花费时间去遍历:
68 6F 72 6C 64 push 646C726Fh
68 6F 2C 20 77 push 77202C6Fh
68 68 65 6C 6C push 6C6C6568h
第一个字节68就是关键字节,后面的四个字节都是压入栈中的数据,就属于无关紧要的字节。
如果能识别出这类,快速跳过,将能够大面积减少需要遍历的搜索空间。
(PS:本文来自公众号:编程技术宇宙)
上面只是一个例子,如何能够系统化的过滤掉这类指令呢?报告中提出了一个方案:
观察指令中的有意义的字节,它们对指令的长度和异常表现会产生冲击。
又该怎么理解这句话?
还是上面那个例子,当尝试修改第一个字节68的时候,这一段二进制序列可能就完全变成了别的指令,甚至指令长度都会发生变化(比如把68改成90,那就变成了一个字节的nop指令),那么就认为这第一个字节是一个有意义的字节,修改了它会对指令的长度产生重要影响。
反之,如果修改后面字节的数据,会发现这仍然是一条5个字节的压栈指令,长度没变化,也没有其他异常行为表现与之前不同,那么就认为后面几个字节是无关紧要的字节。
在这个指导思想下,我们来看一个例子:
从下面这一段数据开始出发:
我们从两个字节的指令开始遍历:
把最后那个字节的内容+1,尝试去执行它:
发现指令长度没有变化(具体怎么判断指令长度变没变,下一节会重点讨论),那就继续+1,再次尝试执行它:
一直这样加下去,直到发现加到4的时候,指令长度发生了变化,长度超过了2(但具体是多少还不知道,后文会解释):
那么在这个基础上,长度增加1位,以指令长度为3的指令来继续上面的探索过程:从最后一位开始+1做起。
随着分析的深入,梳理一下指令搜索的路径图:
当某一条的最后一个字节遍历至FF时,开始往回走(就像递归,不能一直往下,总有回去的时候):
往回走一个字节,将其+1,继续再来:
按照这个思路,整个要搜索的指令空间压缩到可以接受遍历的程度:
如何判定指令长度
现在来解答前面遗留的一个问题。
上面这个算法能够工作的一个重要前提是:
我们得知道,给末尾字节+1后,有没有影响指令的长度。
要判断某个字节是不是关键字节,就得知道这个字节的内容变化,会不会影响到指令长度,所以如果无法判断长度有没有变化,那上面的算法就无从谈起了。
所以如何知道长度有没有变化呢?报告中用到了一个非常巧妙的方法。
假设我们要评估下面这一串数据,前面开头到底多少个字节是一条完整指令。
可能第一个字节0F就是一条指令。
也可能前面两个字节0F 6A是一条指令。
还可能前面五个字节0F 6A 60 6A 79 6D是一条指令。
到底是什么情况,我们不知道,让我们用程序来尝试推导出来。
准备两个连续的内存页面,前面一个拥有可执行的权限,后面一个不能执行。
记住:当CPU发现指令位于不可执行的页面中时,它会抛异常!
现在,在内存中这样放置上面的数据流:第一个字节放在第一个页面的末尾位置,后面在字节放在第二个不可执行的页面上。
然后JMP到这条指令的地址,尝试去执行它,CPU中的译码器开始译码:
译码器译码发现是0F,不是单字节指令,还需要继续分析后面的字节,继续取第二个字节:
但注意,第二个字节是位于不可执行的页面,CPU检查发现后会抛出页错误异常:
如果我们发现CPU抛了异常,并且异常的地址指向了第二个页面的地址,那么我们可以断定:这条指令的长度肯定不止一个字节。
既然不止一个字节,那就往前挪一下,放两个字节在可执行页面,从第三个字节开始放在不可执行页面,继续这个过程。
继续上面这个过程,放三个字节在可执行页面:
四个:
当放了四个字节在可执行页面之后,事情发生了变化:
指令可以执行了!虽然也抛了异常(因为天知道这是个什么指令,会抛什么异常),但页错误的地址不再是第二个页面的地址了!
有了这个信号,我们就知道,前面4个字节是一条完整的指令:
挖掘隐藏指令
现在核心算法和判断指令长度的方法都介绍完了,可以正式来开挖,挖出那些隐藏的指令了!
以一台Intel Core i7的CPU为目标,来挖一挖:
挖掘成果,收获颇丰:
这些都是Intel指令集手册中未交待,但CPU却能执行的指令。
然后是AMD Athon的CPU:
挖掘成果:
那这些隐藏的指令是做什么的呢?
有些已经被逆向工程分析了。
还有的就是毫无记录,只有Intel/AMD自己人知道了,谁知道它们用这些指令是来干嘛的?
软件即便是开源都能爆出各种各样的问题,何况是黑盒一样的硬件。
CPU作为计算机中的基石,它要是出了问题,那可是大问题。
我不是阴谋论,害人之心不可有,但防人之心不可无。
看完这些,我对国产、安全、自主可控这几个字的理解又加深了一层。
各位朋友,你对这些隐藏指令怎么看?欢迎评论区分享你的观点。
原作者:公众号—— 轩辕之风
相关推荐
- 快递查询教程,批量查询物流,一键管理快递
-
作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...
- 一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递
-
对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...
- 快递查询单号查询,怎么查物流到哪了
-
输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...
- 3分钟查询物流,教你一键批量查询全部物流信息
-
很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...
- 快递单号查询,一次性查询全部物流信息
-
现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...
- 快递查询工具,批量查询多个快递快递单号的物流状态、签收时间
-
最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...
- 快递查询软件,自动识别查询快递单号查询方法
-
当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...
- 教你怎样查询快递查询单号并保存物流信息
-
商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...
- 简单几步骤查询所有快递物流信息
-
在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...
- 物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号
-
最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...
- 连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息
-
快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...
- 快递查询教程,快递单号查询,筛选更新量为1的单号
-
最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...
- 掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析
-
在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...
- 从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息
-
在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...
- 物流单号查询,在哪里查询快递
-
如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)