我們知道,我們平時(shí)編程寫的高級(jí)語(yǔ)言,是經(jīng)過(guò)編譯器編譯以后,變成了CPU可以執(zhí)行的機(jī)器指令:
而CPU能支持的指令,都在它的指令集里面了。很久以來(lái),我都在思考一個(gè)問(wèn)題:CPU有沒有未公開的指令?或者說(shuō):CPU有沒有隱藏的指令?為什么會(huì)有這個(gè)問(wèn)題?平常我們談?wù)摼W(wǎng)絡(luò)安全問(wèn)題的時(shí)候,大多數(shù)時(shí)候都是在軟件層面。談應(yīng)用程序的漏洞、后端服務(wù)的漏洞、第三方開源組件的漏洞乃至操作系統(tǒng)的漏洞。但很少有機(jī)會(huì)去觸及硬件,前幾年爆發(fā)的熔斷和幽靈系列漏洞,就告訴我們,CPU也不是可信任的。要是CPU隱藏有某些不為人知的指令,這是一件非常可怕的事情。如果某一天,某些國(guó)家或者某些團(tuán)體組織出于某種需要,利用這些隱藏的指令來(lái)發(fā)動(dòng)攻擊,后果不堪設(shè)想。雖然想到過(guò)這個(gè)問(wèn)題,但我一直沒有付諸實(shí)踐去認(rèn)真的研究。直到前段時(shí)間,有一位老師分享了一份PDF給我,解答了我的疑惑。這份PDF內(nèi)容是2017年頂級(jí)黑客大會(huì)Black Hat上的一篇報(bào)告:
這份PDF深度研究了x86架構(gòu)CPU中隱藏的指令,原報(bào)告因?yàn)槭怯⑽模雌饋?lái)有些晦澀,這篇文章,我嘗試用大家易懂的語(yǔ)言來(lái)給大家分享一下這篇非常有意思的干貨。有些人會(huì)問(wèn):真的會(huì)有隱藏指令的存在嗎,CPU的指令集不是都寫在指令手冊(cè)里了嗎?我們以單字節(jié)指令為例,單字節(jié)的范圍是0x00-0XFF,總共256種組合,Intel的指令手冊(cè)中是這樣介紹單字節(jié)指令的:
橫向?yàn)閱巫止?jié)的高四位,縱向?yàn)閱巫止?jié)的低四位,順著表格定位,可以找到每一個(gè)單字節(jié)指令的定義。比如我們常見的nop指令的機(jī)器碼是0x90,就是行為9,列為0的那一格。但是不知道你發(fā)現(xiàn)沒有,這張表格中還有些單元格是空的,比如0xF1,那CPU拿到一個(gè)為0xF1的指令,會(huì)怎么執(zhí)行呢?指令手冊(cè)沒告訴你。這篇報(bào)告的主要內(nèi)容就是告訴你,如何去尋找這些隱藏的指令。
該算法的指導(dǎo)思想在于:快速跳過(guò)指令中無(wú)關(guān)緊要的字節(jié)。
怎么理解這句話?比如壓棧的指令push,下面幾條雖然字節(jié)序列不同,但變化的只是數(shù)據(jù),其實(shí)都是壓棧指令,對(duì)于這類指令,就沒必要花費(fèi)時(shí)間去遍歷:
觀察指令中的有意義的字節(jié),它們對(duì)指令的長(zhǎng)度和異常表現(xiàn)會(huì)產(chǎn)生沖擊。又該怎么理解這句話?還是上面那個(gè)例子,當(dāng)嘗試修改第一個(gè)字節(jié)68的時(shí)候,這一段二進(jìn)制序列可能就完全變成了別的指令,甚至指令長(zhǎng)度都會(huì)發(fā)生變化(比如把68改成90,那就變成了一個(gè)字節(jié)的nop指令),那么就認(rèn)為這第一個(gè)字節(jié)是一個(gè)有意義的字節(jié),修改了它會(huì)對(duì)指令的長(zhǎng)度產(chǎn)生重要影響。反之,如果修改后面字節(jié)的數(shù)據(jù),會(huì)發(fā)現(xiàn)這仍然是一條5個(gè)字節(jié)的壓棧指令,長(zhǎng)度沒變化,也沒有其他異常行為表現(xiàn)與之前不同,那么就認(rèn)為后面幾個(gè)字節(jié)是無(wú)關(guān)緊要的字節(jié)。在這個(gè)指導(dǎo)思想下,我們來(lái)看一個(gè)例子:從下面這一段數(shù)據(jù)開始出發(fā):
我們從兩個(gè)字節(jié)的指令開始遍歷:
把最后那個(gè)字節(jié)的內(nèi)容+1,嘗試去執(zhí)行它:
發(fā)現(xiàn)指令長(zhǎng)度沒有變化,那就繼續(xù)+1,再次嘗試執(zhí)行它:
一直這樣加下去,直到發(fā)現(xiàn)加到4的時(shí)候,指令長(zhǎng)度發(fā)生了變化,長(zhǎng)度超過(guò)了2(但具體是多少還不知道,后文會(huì)解釋):
那么在這個(gè)基礎(chǔ)上,長(zhǎng)度增加1位,以指令長(zhǎng)度為3的指令來(lái)繼續(xù)上面的探索過(guò)程:從最后一位開始+1做起。
隨著分析的深入,梳理一下指令搜索的路徑圖:
當(dāng)某一條的最后一個(gè)字節(jié)遍歷至FF時(shí),開始往回走(就像遞歸,不能一直往下,總有回去的時(shí)候):
往回走一個(gè)字節(jié),將其+1,繼續(xù)再來(lái):
按照這個(gè)思路,整個(gè)要搜索的指令空間壓縮到可以接受遍歷的程度:
可能第一個(gè)字節(jié)0F就是一條指令。也可能前面兩個(gè)字節(jié)0F 6A是一條指令。還可能前面五個(gè)字節(jié)0F 6A 60 6A 79 6D是一條指令。到底是什么情況,我們不知道,讓我們用程序來(lái)嘗試推導(dǎo)出來(lái)。準(zhǔn)備兩個(gè)連續(xù)的內(nèi)存頁(yè)面,前面一個(gè)擁有可執(zhí)行的權(quán)限,后面一個(gè)不能執(zhí)行。
記住:當(dāng)CPU發(fā)現(xiàn)指令位于不可執(zhí)行的頁(yè)面中時(shí),它會(huì)拋異常!現(xiàn)在,在內(nèi)存中這樣放置上面的數(shù)據(jù)流:第一個(gè)字節(jié)放在第一個(gè)頁(yè)面的末尾位置,后面在字節(jié)放在第二個(gè)不可執(zhí)行的頁(yè)面上。
然后JMP到這條指令的地址,嘗試去執(zhí)行它,CPU中的譯碼器開始譯碼:
譯碼器譯碼發(fā)現(xiàn)是0F,不是單字節(jié)指令,還需要繼續(xù)分析后面的字節(jié),繼續(xù)取第二個(gè)字節(jié):
但注意,第二個(gè)字節(jié)是位于不可執(zhí)行的頁(yè)面,CPU檢查發(fā)現(xiàn)后會(huì)拋出頁(yè)錯(cuò)誤異常:
如果我們發(fā)現(xiàn)CPU拋了異常,并且異常的地址指向了第二個(gè)頁(yè)面的地址,那么我們可以斷定:這條指令的長(zhǎng)度肯定不止一個(gè)字節(jié)。
既然不止一個(gè)字節(jié),那就往前挪一下,放兩個(gè)字節(jié)在可執(zhí)行頁(yè)面,從第三個(gè)字節(jié)開始放在不可執(zhí)行頁(yè)面,繼續(xù)這個(gè)過(guò)程。
繼續(xù)上面這個(gè)過(guò)程,放三個(gè)字節(jié)在可執(zhí)行頁(yè)面:
四個(gè):
當(dāng)放了四個(gè)字節(jié)在可執(zhí)行頁(yè)面之后,事情發(fā)生了變化:指令可以執(zhí)行了!雖然也拋了異常(因?yàn)樘熘肋@是個(gè)什么指令,會(huì)拋什么異常),但頁(yè)錯(cuò)誤的地址不再是第二個(gè)頁(yè)面的地址了!
有了這個(gè)信號(hào),我們就知道,前面4個(gè)字節(jié)是一條完整的指令:
挖掘成果,收獲頗豐:
這些都是Intel指令集手冊(cè)中未交待,但CPU卻能執(zhí)行的指令。然后是AMD Athon的CPU:
挖掘成果:
那這些隱藏的指令是做什么的呢?有些已經(jīng)被逆向工程分析了。還有的就是毫無(wú)記錄,只有Intel/AMD自己人知道了,誰(shuí)知道它們用這些指令是來(lái)干嘛的?軟件即便是開源都能爆出各種各樣的問(wèn)題,何況是黑盒一樣的硬件。CPU作為計(jì)算機(jī)中的基石,它要是出了問(wèn)題,那可是大問(wèn)題。我不是陰謀論,害人之心不可有,但防人之心不可無(wú)。看完這些,我對(duì)國(guó)產(chǎn)、安全、自主可控這幾個(gè)字的理解又加深了一層。

《us-17-Domas-Breaking-The-x86-ISA》
,作者是大神:@xoreaxeaxeax
,熟悉匯編的同學(xué)知道這名字是什么意思嗎?

指令集的搜索空間
想要找到隱藏的指令,得先明確一個(gè)問(wèn)題:一條指令到底有多長(zhǎng),換句話說(shuō),有幾個(gè)字節(jié),我們應(yīng)該在什么樣的一個(gè)范圍內(nèi)去尋找隱藏指令。如果指令長(zhǎng)度是固定的,比如JVM那樣的虛擬機(jī),那問(wèn)題好辦,直接遍歷就行了。但問(wèn)題難就難在,x86架構(gòu)CPU的指令集屬于復(fù)雜指令集CISC,它的指令不是固定長(zhǎng)度的。有單字節(jié)指令,比如:90 nopCC int 3C3 ret也有雙字節(jié)指令,比如:
8B C8 mov ecx,eax6A 20 push 20h還有三四節(jié)、四字節(jié)、五字節(jié)···最長(zhǎng)能有十幾個(gè)字節(jié),比如這條指令:
指令:lock add qword cs:[eax + 4 * eax + 07e06df23h], 0efcdab89h機(jī)器碼:2e 67 f0 48 818480 23df067e 89abcdef一個(gè)字節(jié)、兩個(gè)字節(jié),甚至三個(gè)四個(gè)遍歷都還能接受,4個(gè)字節(jié)最多也就42億多種組合,對(duì)于計(jì)算機(jī)來(lái)說(shuō),也還能接受。但越往后,容量是呈指數(shù)型增長(zhǎng),這種情況再去遍歷,顯然是不現(xiàn)實(shí)的。
指令搜索算法
這份報(bào)告中提出了一種深度優(yōu)先的搜索算法:

第一個(gè)字節(jié)68就是關(guān)鍵字節(jié),后面的四個(gè)字節(jié)都是壓入棧中的數(shù)據(jù),就屬于無(wú)關(guān)緊要的字節(jié)。如果能識(shí)別出這類,快速跳過(guò),將能夠大面積減少需要遍歷的搜索空間。上面只是一個(gè)例子,如何能夠系統(tǒng)化的過(guò)濾掉這類指令呢?報(bào)告中提出了一個(gè)方案:
- 68 6F 72 6C 64 push 646C726Fh
- 68 6F 2C 20 77 push 77202C6Fh
- 68 68 65 6C 6C push 6C6C6568h











如何判定指令長(zhǎng)度
現(xiàn)在來(lái)解答前面遺留的一個(gè)問(wèn)題。上面這個(gè)算法能夠工作的一個(gè)重要前提是:我們得知道,給末尾字節(jié)+1后,有沒有影響指令的長(zhǎng)度。要判斷某個(gè)字節(jié)是不是關(guān)鍵字節(jié),就得知道這個(gè)字節(jié)的內(nèi)容變化,會(huì)不會(huì)影響到指令長(zhǎng)度,所以如果無(wú)法判斷長(zhǎng)度有沒有變化,那上面的算法就無(wú)從談起了。所以如何知道長(zhǎng)度有沒有變化呢?報(bào)告中用到了一個(gè)非常巧妙的方法。假設(shè)我們要評(píng)估下面這一串?dāng)?shù)據(jù),前面開頭到底多少個(gè)字節(jié)是一條完整指令。











挖掘隱藏指令
現(xiàn)在核心算法和判斷指令長(zhǎng)度的方法都介紹完了,可以正式來(lái)開挖,挖出那些隱藏的指令了!以一臺(tái)Intel Core i7的CPU為目標(biāo),來(lái)挖一挖:




審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。
舉報(bào)投訴
-
cpu
+關(guān)注
關(guān)注
68文章
11054瀏覽量
216264 -
編譯器
+關(guān)注
關(guān)注
1文章
1657瀏覽量
49971
原文標(biāo)題:可怕!CPU 暗藏了這些未公開的指令!
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
熱點(diǎn)推薦
CPU的各種指令和執(zhí)行流程
在集成電路設(shè)計(jì)中,CPU的指令是指計(jì)算機(jī)中央處理單元(CPU)用來(lái)執(zhí)行計(jì)算任務(wù)的基本操作指令集。這些指令
采購(gòu)GUTOR UPS備品備件,隱藏的“雷區(qū)” 你了解嗎?
在GUTOR UPS備品備件采購(gòu)之路上,困難重重,選型、渠道甄別、成本把控、安裝部署、售后保障,樁樁件件都是棘手難題。隱藏的“雷區(qū)” 你了解嗎?
發(fā)表于 03-21 16:08
STM32H745BIT6單片機(jī)怎么看哪個(gè)引腳配置哪個(gè)內(nèi)核啊?
STM32H745BIT6單片機(jī)怎么看哪個(gè)引腳配置哪個(gè)內(nèi)核啊,在數(shù)據(jù)手冊(cè)里沒看到
發(fā)表于 03-13 06:08
TMS320C62x DSP CPU和指令集參考指南
電子發(fā)燒友網(wǎng)站提供《TMS320C62x DSP CPU和指令集參考指南.pdf》資料免費(fèi)下載
發(fā)表于 12-17 16:24
?0次下載

TPA3112用tina仿真后面的揚(yáng)聲器怎么看發(fā)出的聲音怎么樣?
TPA3112用tina仿真后面的揚(yáng)聲器怎么看發(fā)出的聲音怎么樣啊
發(fā)表于 11-04 07:29
前端總線頻率怎么看的
前端總線的定義 前端總線是計(jì)算機(jī)系統(tǒng)中CPU與內(nèi)存、北橋芯片之間數(shù)據(jù)傳輸?shù)耐ǖ馈K?fù)責(zé)將CPU的指令和數(shù)據(jù)傳輸?shù)絻?nèi)存和北橋芯片,同時(shí)也將內(nèi)存和北橋芯片的數(shù)據(jù)傳輸回CPU。前端總線的性
CPU時(shí)鐘周期、機(jī)器周期和指令周期的關(guān)系
CPU時(shí)鐘周期、機(jī)器周期和指令周期是計(jì)算機(jī)體系結(jié)構(gòu)中三個(gè)緊密相連且至關(guān)重要的概念,它們共同構(gòu)成了CPU執(zhí)行指令和處理數(shù)據(jù)的基本時(shí)間框架。以下是對(duì)這三個(gè)周期之間關(guān)系的詳細(xì)解析。
請(qǐng)問(wèn)AD657的共模和差模輸入電容怎么看?
如題,AD657的共模和差模輸入電容怎么看??輸入阻抗是10的12次方歐姆, 輸入電容是5.2pf??
發(fā)表于 09-06 07:07
matlab bp神經(jīng)網(wǎng)絡(luò)分析結(jié)果怎么看
使用內(nèi)置的神經(jīng)網(wǎng)絡(luò)工具箱來(lái)實(shí)現(xiàn)BP神經(jīng)網(wǎng)絡(luò)的構(gòu)建、訓(xùn)練和分析。 網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì) 在進(jìn)行BP神經(jīng)網(wǎng)絡(luò)分析之前,首先需要設(shè)計(jì)合適的網(wǎng)絡(luò)結(jié)構(gòu)。網(wǎng)絡(luò)結(jié)構(gòu)主要包括輸入層、隱藏層和輸出層。輸入層的神經(jīng)元數(shù)量取決于問(wèn)題的特征維度,輸出層的神經(jīng)元數(shù)量取決于問(wèn)題的輸出維度。隱藏層的
STM32H745BIT6單片機(jī)怎么看哪個(gè)引腳配置哪個(gè)內(nèi)核?
STM32H745BIT6單片機(jī)怎么看哪個(gè)引腳配置哪個(gè)內(nèi)核啊,在數(shù)
發(fā)表于 07-03 07:38
cpu控制器負(fù)責(zé)什么運(yùn)算
、設(shè)計(jì)和實(shí)現(xiàn)等方面的內(nèi)容。 CPU控制器的功能 CPU控制器是計(jì)算機(jī)系統(tǒng)中最重要的組件之一。它的主要功能包括: 1.1 指令執(zhí)行:CPU控制器負(fù)責(zé)執(zhí)行程序中的
怎么看編碼器上的參數(shù)?
編碼器是一種用于測(cè)量運(yùn)動(dòng)和位置的設(shè)備,常用于工業(yè)控制、機(jī)器人和自動(dòng)化設(shè)備等領(lǐng)域。編碼器的工作原理基于數(shù)碼信號(hào)與機(jī)械旋轉(zhuǎn)之間的特定關(guān)系,可以將物理運(yùn)動(dòng)轉(zhuǎn)換為數(shù)字信號(hào)。 一、怎么看編碼器上的參數(shù) (一

評(píng)論