国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

如何用幾行代碼打造應用程序熱補丁?(二)

企業動態
本文將會介紹一種自動生成應用程序熱補丁技術,可以生成應用程序和動態鏈接庫中任意函數的熱補丁。

一、前言

在《如何用幾行代碼打造應用程序熱補丁?(一)》中,我們介紹了應用程序熱補丁技術的基本原理,同時實現了一個簡單的熱補丁。但是無法對本地函數打熱補丁,同時手動編寫熱補丁比較麻煩、可能非常復雜容易出錯。

為了解決這些問題,本文將會介紹一種自動生成應用程序熱補丁技術,可以生成應用程序和動態鏈接庫中任意函數的熱補丁。

二、自動生成熱補丁綜述

自動生成熱補丁是利用熱補丁生成工具,對現有的源代碼和補丁文件進行處理,自動輸出熱補丁的技術。

我們知道,熱補丁的基本原理是新函數替換舊函數,也就是完整的函數的替換。補丁中可能包含一個或多個函數的修改,這些被修改的函數都會被替換掉。上一篇文章介紹過,熱補丁首先把新函數放入目標進程的內存中,然后修改舊函數的入口,使之跳轉到新函數。

自動生成熱補丁中最主要的部分是自動生成新函數的二進制代碼,也稱為是替換代碼。在生成替換代碼時,主要由以下部分組成:

  • 自動生成替換代碼。
  • 解析替換代碼中使用的符號。

接下來會對以上部分進行詳細的介紹。在介紹之前,必須假設系統環境是Linux X86/X86_64,應用程序是C語言編譯鏈接的ELF格式可執行文件,并且擁有原始程序的源代碼。

三、前后代碼比較生成替換代碼

1. 動機與挑戰

為了生成替換代碼,首先需要知道代碼修復之后,哪些函數發生了改變,然后根據這些改變,生成替換代碼。使用一種二進制比較的方法,通過比較原始程序的二進制和修復后程序的二進制,提取出生成替換代碼所需的全部信息。

我們選擇在目標文件(object file)的級別,進行前后比較。這樣做的好處是顯而易見的:

  • 首先,任何源代碼的改變都會在目標文件的二進制代碼中顯示出來。舉個例子,頭文件.h文件中函數的參數如果從int變成了long long,調用這個函數的.c文件由于隱含的類型轉換,并不發生改變。如果在前后代碼對比發生在源代碼級別,甚至預處理之后,也不能發現前后.c文件發生了改變。
  • 其次,我們不需要處理語言級別的特性,比如inline關鍵字、隱含類型轉換、宏等等。這些語言相關的特性可能隨著語言的發展會愈發復雜,并且我們也不希望熱補丁局限于某種語言。C語言、C++、匯編都是我們希望可以處理的語言。
  • 最后,我們只關心代碼的二進制表達。在目標文件的級別,二進制代碼和代碼組成信息是最完整的,在此進行前后代碼比較也是最合理的。

所以,生成替換代碼的思路是,通過比較前后編譯的目標文件,提取出差異部分,組成替換代碼。

比較目標文件也面臨很多挑戰,主要在于如何從提取出發生改變的函數。舉個例子,由于目標文件中默認所有的函數代碼都會放在.text段,同時.text段中的相對地址跳轉都是相對于.text段的。也就是說,如果某個函數發生了改變,就算是一行代碼的改變,后面的相對地址跳轉也很可能會發生改變(由于符號位置發生了改變)。

2. 解決辦法

我們對目標應用程序代碼和修復后代碼分別編譯,逐一比較兩次編譯產生的若干個目標文件。如圖所示:

對目標應用程序代碼和修復后代碼分別編譯

  • 首先,我們編譯原始源代碼,保留所有中間過程中產生的目標文件。
  • 然后,我們對原始源代碼打上修復補丁,再次編譯,構建系統(make)一般只會編譯改變的源文件,保留新生成的目標文件。如果沒有構建系統或者構建系統不如期工作,可以保留所有的目標文件。
  • 最后,我們比較新生成的目標文件和對應的原始代碼編譯出來的目標文件,提取出差異部分,組成替換代碼,生成熱補丁。

在比較過程中,我們希望做到可以在函數級別上進行比較,這樣可以只提取出發生改變的函數,并且我們也希望生成的替換代碼是地址無關的,因為替換代碼可能被加載到任意的內存地址。

GCC編譯器提供了-ffunciton-sections和-fdata-section的編譯選項,作用是把函數和變量放入目標文件中獨立的段(每個函數代碼都由獨立的段來表示)。這樣編譯出的函數代碼都是地址無關的、更加通用的二進制,可以提取到替換代碼中被加載到內存的任意位置運行。

在對前后目標文件比較的時候,我們在ELF段的級別進行比較(也就是函數的級別,因為函數都在自己獨立的段中)。因為目標文件是ELF文件,遵守通用的標準。我們可以解析目標文件的ELF Header,找到段的開頭(Section Header),由此找到所有的段。這里我們建議使用一些ELF解析庫,如libelf、libbfd等。

逐一比較前后目標文件中的表示代碼的段,段的內容就是函數的代碼,找到發生改變的函數:

  • 首先,比較段的大小,如果大小不同,說明函數發生了改變。
  • 接著,對段的內容進行比較,如果某個字節不同,而且字節不屬于重定向的一部分,說明函數發生了改變。如果是重定向,檢查重定向計算之后的指令內容是否相同,如果不同,說明函數發生了改變(引用了與之前不同的函數或者變量)。
  • 最后,如果段的大小和段的內容都沒有改變,說明函數沒有改變。

需要注意的是,如果補丁中修改的是宏或inline函數,我們無法做到只提取宏或者inline函數的差異,因為宏和inline函數會在編譯過程中被放置在其調用函數中,所有調用函數都會改變,所以提取的是所有調用的函數。

此時的替換代碼還不能直接運行,因為替換代碼中還可能包含對其他符號的引用,我們需要在運行替換代碼之前解析這些符號。

四、替換代碼中的符號解析

1. 動機與挑戰

我們的替換代碼中只包含改變的函數代碼,這些函數中可能會引用其他沒有改變的符號(函數或變量),所以我們需要根據符號引用的規則(一般為相對PC地址的相對地址),對引用符號手動重定向。

解析符號地址面臨的挑戰主要有兩個:

  • 找到運行中的程序的符號所在的地址。
  • 如果存在兩個或者以上相同名字的符號,找到正確符號。

2. 解決方法

符號的地址是在最終鏈接的時候決定的,如果可執行文件是pie(position independent executable)或者是動態鏈接庫,符號的地址是一個相對地址,是相對于可執行文件或者動態鏈接庫的代碼段在內存中地址的偏移,計算公式Addr = Base + Offset。其他情況,符號的地址是一個絕對地址,無需計算。

同樣名稱的符號在可執行文件中可能出現多次(例如兩個文件中定義了名字相同的static變量),我們需要從中找到正確的符號。在鏈接之后,可執行文件中的符號表會遵守一些固定的規則,相同源文件中符號會一起連續地記錄,并且在記錄的開頭會有類型為STT_FILE的符號,名字為源文件的名字。

舉個例子,我們在1.c和2.c中同時定義了static int a,最終可執行文件中的符號表如下所示:

  1. # readelf -s exe 
  2. … 
  3. Symbol table '.symtab' contains 73 entries: 
  4. … 
  5.     41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 1.c 
  6.     42: 0000000000601038     4 OBJECT  LOCAL  DEFAULT   25 a 
  7.     43: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 2.c 
  8.     44: 000000000060103c     4 OBJECT  LOCAL  DEFAULT   25 a 

因此我們可以通過file+sym規則找到正確的符號位置。假設函數引用變量a,并且函數在2.c源文件中,我們首先找到類型為STT_FILE的2.c這個符號,然后找到符號a就可以了。

我們知道符號的地址后可以對替換代碼中的引用進行手動重定向編寫,將編譯時符號引用的重定向轉換為我們自己在運行時可以識別的重定向(self relocation)。

  • 首先,根據重定向類型和計算公式,計算出引用的符號,記錄符號的信息,其中符號的地址在運行時可以得到。
  • 然后,記錄原有的重定向信息,其中重定向的地址在運行時可以得到。
  • 最后,在替換代碼(熱補丁)被加載到目標程序的內存中時,通過之前記錄的重定向內容,修改替換代碼符號引用位置的內容,內容由重定向的類型、重定向的地址、符號的地址計算得到。

舉個例子,替換代碼中包含函數x,函數x會在地址P引用正在運行的程序中的函數y。當替換代碼被加載到程序的地址空間時,地址P可以被確定,函數y的符號地址S可以被確定,根據替換代碼中記錄的重定向信息(假設重定向類型是R_X86_64_PC32,Addend是A),那么地址P的內容需要被修改為S+A-P。這樣當函數x執行時才能引用到函數y的位置。

五、POC:生成替換代碼、符號解析

本章節利用objdump等工具,對生成替換代碼中的關鍵步驟進行POC驗證。

假設我們有目標程序T(修復后名為T-patched),包含如下代碼:

  1. void print(int i) 
  2.         while (i) { 
  3.                 printf("%d ", i--); 
  4.         } 
  5.         printf("\n"); 
  6.  
  7. void func() 
  8.         print(4); 

patch文件如下:

  1. void func() 
  2. -       print(4); 
  3. +       print(6); 
  4.  } 

分別將源代碼和修復后的源代碼編譯,生成T.o和T-patched.o。

通過objdump我們可以發現func函數前后發生了改變,地址0x4的指令不同。(其他函數不變,省略)。如下所示:

  1. # objdump -hdr -j .text.func T.o 
  2. … 
  3. Disassembly of section .text.func: 
  4.  
  5. 0000000000000000 <func>
  6.    0:   55                      push   %rbp 
  7.    1:   48 89 e5                mov    %rsp,%rbp 
  8.    4:   bf 04 00 00 00          mov    $0x4,%edi 
  9.    9:   e8 00 00 00 00          callq  e <func+0xe> 
  10.                         a: R_X86_64_PLT32       print-0x4 
  11.    e:   c9                      leaveq 
  12.    f:   c3                      retq 
  1. # objdump -hdr -j .text.func T-patched.o 
  2. … 
  3. Disassembly of section .text.func: 
  4.  
  5. 0000000000000000 <func>
  6.    0:   55                      push   %rbp 
  7.    1:   48 89 e5                mov    %rsp,%rbp 
  8.    4:   bf 06 00 00 00          mov    $0x6,%edi 
  9.    9:   e8 00 00 00 00          callq  e <func+0xe> 
  10.                         a: R_X86_64_PLT32       print-0x4 
  11.    e:   c9                      leaveq 
  12.    f:   c3                      retq 

所以提取出T-patched.o中的.text.func段。這就完成了替換代碼的提取。

因為T-patched.o中的func函數在0xa的位置上引用了print函數,我們需要對print符號進行解析,在替換代碼(熱補丁)被加載到目標進程內存時,對0xa-0xd的四個字節重定向。

我們記錄下這個重定向,類型R_X86_64_PLT32,Addend -4,符號print。

在替換代碼被加載到目標進程中時,我們可以確定替換代碼加載的地址。假設替換代碼中func地址為0x7fa357ed79b0,原程序中print地址為0x7fa358a9979c。那么我們根據之前記錄的重定向信息進行計算(V = S + A - P),將func偏移0xa的位置(4字節)寫入0xbc1dde,計算方法如下:

  1. 0x7fa358a9979c + (-4) - 0x7fa357ed79ba = 0xbc1dde 

這樣重定向之后,替換代碼中的func函數就能正確引用到原程序中的print函數。

最后,我們通過GDB觀察T程序打入熱補丁之后的行為:

  1. (gdb) disas func 
  2. Dump of assembler code for function func: 
  3.    0x00007fa358a997d8 <+0>:     movabs $0x7fa357ed79b0,%rax 
  4.    0x00007fa358a997e2 <+10>:    jmpq   *%rax 
  5. … 

以上可以看出原程序的func函數會跳轉到0x7fa357ed79b0執行。

  1. (gdb) disas 0x7fa357ed79b0 
  2. Dump of assembler code for function func: 
  3.    0x00007fa357ed79b0 <+0>:     push   %rbp 
  4.    0x00007fa357ed79b1 <+1>:     mov    %rsp,%rbp 
  5.    0x00007fa357ed79b4 <+4>:     mov    $0x6,%edi 
  6.    0x00007fa357ed79b9 <+9>:     callq  0x7fa358a9979c <print> 
  7.    0x00007fa357ed79be <+14>:    leaveq 
  8.    0x00007fa357ed79bf <+15>:    retq 
  9. End of assembler dump. 

以上可以看出0x7fa357ed79b0是熱補丁中func函數的入口,也能看出0x00007fa357ed79b9地址的指令中引用了正確的print符號。

我們通過objdump、gdb驗證了替換代碼的靜態和動態形式,展示了自動生成熱補丁的具體細節,希望可以借此讓讀者對此有更清晰的理解。

六、其他注意事項

這種前后目標文件比較生成替換代碼的方法,要求我們必須擁有正在運行的目標程序的源代碼。同時,在編譯目標文件時強烈建議使用和目標程序相同版本的gcc和編譯選項,使用不同的gcc和不同的選項可能會導致目標文件和原始程序的二進制不匹配,導致不能生成正確的替換代碼。不正確的替換代碼可能會導致符號解析錯誤,進而是程序崩潰,這里需要特別注意。

七、寫在最后

本文介紹了二進制比較方式的自動生成熱補丁技術,相比于上一篇文章中介紹的簡單熱補丁技術,優勢在于:

  1. 通過工具自動生成熱補丁,無需手動編寫熱補丁,減少了人為出錯的可能。
  2. 可以修復本地函數和全局函數,并且不需要引入函數的依賴鏈。
  3. 兼容多種編譯型語言(C語言、C++、匯編等,具體實現不同,但是思路一致)。

使用這種熱補丁生成技術,可以解決應用程序幾乎所有的安全漏洞。例如最近出現的QEMU CVE-2017-2615(cirrus驅動內存越界訪問),我們對有bug的函數都打上了熱補丁,通過替換bug函數,實現了在線熱修復。

生成熱補丁是應用程序熱補丁技術框架中非常關鍵的一個組件,本文介紹了一種自動生成熱補丁的技術,但是完整、成熟的熱補丁框架還包含了其他技術,例如多線程、管理多個熱補丁、多版本管理、熱補丁與程序之間的一致性檢查等等。

【本文是51CTO專欄機構作者“大U的技術課堂”的原創文章,轉載請通過微信公眾號(ucloud2012)聯系作者】

 戳這里,看該作者更多好文

責任編輯:趙寧寧 來源: 51CTO專欄
相關推薦

2017-06-07 23:15:30

應用程序熱補丁代碼

2017-03-15 17:57:04

代碼免重啟BUG

2013-02-22 09:28:45

MEAP軟件移動應用開發HTML5

2023-12-21 08:00:00

ChatGPT人工智能大型語言模型

2013-02-21 14:15:41

開發Tizen

2011-06-07 09:36:41

BlackBerry 應用程序

2022-09-19 00:37:13

SaaS云計算開發

2015-11-05 10:16:33

2011-07-21 16:19:30

iOS Twitter

2024-10-10 13:30:00

2018-09-18 09:30:17

微信熱補丁Android

2019-01-16 10:33:41

Linux

2013-11-19 15:35:01

2010-01-18 17:32:03

2021-05-17 07:45:06

Linux系統程序

2010-02-05 18:21:24

Android應用程序

2017-12-10 14:13:14

云服務云原生應用程序

2012-06-11 09:37:41

2021-10-11 09:00:00

云原生Kubernetes安全

2020-12-28 14:40:47

云計算云應用SaaS
點贊
收藏

51CTO技術棧公眾號

亚洲欧美色婷婷| 亚洲va码欧洲m码| 国产小视频在线观看| 国产v综合v亚洲欧| 国内精品视频免费| 日韩精品一区二区久久| 久久久亚洲欧洲日产国码aⅴ| 亚洲女同志freevdieo| 欧美在线一区二区| 88av在线| 一区二区三区在线免费播放| 日韩欧美xxxx| 成人av综合在线| 欧美亚洲视频一区| 免费成人在线视频观看| 日韩成人av网站| 在线视频观看日韩| 成人自拍网站| 91久久午夜| 久久精品国产99精品国产亚洲性色| 久久久久电影| 成人午夜高潮视频| 欧美激情成人| 69堂成人精品视频免费| 一区二区三区午夜视频| 91久久久久久| 中文字幕日韩欧美精品高清在线| 成人免费网站在线观看| 天天操夜夜操国产精品| 亚洲一区二区三区在线免费观看| 91综合视频| 亚洲精品欧美日韩| 欧美精品99| 国产区日韩欧美| 亚洲美女黄网| 亚洲国产日韩美| 国产精品亚洲第一区在线暖暖韩国| 中文字幕一区二区三区有限公司 | 777午夜精品电影免费看| 亚洲精品电影在线观看| 成人性生交大片免费观看网站| 亚洲色在线视频| 日本中文字幕视频一区| 久久久久久久999| 欧美三级午夜理伦三级小说| 国产成人亚洲综合91| 久久福利影院| 九色91在线视频| 韩日欧美一区二区三区| 国自产拍偷拍精品啪啪一区二区| 久久影院午夜论| aaa大片免费观看| 色婷婷久久综合| 九色porny丨入口在线| 不卡av在线网站| 欧美一级本道电影免费专区| 精品国产免费久久久久久尖叫| 久久国产婷婷国产香蕉| 粉嫩虎白女毛片人体| 亚洲综合在线免费观看| 久操视频在线播放| 这里只有精品视频| 综合色就爱涩涩涩综合婷婷| 官网99热精品| 国产成人综合亚洲91猫咪| 亚洲欧洲日本精品| 精品视频123区在线观看| 超级碰碰久久| 日本欧美黄网站| 久久伊人亚洲| 手机在线成人免费视频| 欧美午夜不卡在线观看免费| 成人开心激情| 国产精品人成电影| 老司机免费视频一区二区三区| 99视频免费播放| 欧美年轻男男videosbes| 欧美日韩破处视频| 91久久极品少妇xxxxⅹ软件| 国产成人精品亚洲日本在线桃色| 国外亚洲成av人片在线观看| 日韩精品专区在线| 日本妇女一区| 亚洲精品国产精品国自产观看| 亚洲国产精品传媒在线观看| 国产黄在线播放| 欧美成人午夜激情在线| 激情偷拍久久| aaaaaa亚洲| 欧美日韩国产成人在线免费| 福利一区二区免费视频| 97人人模人人爽人人少妇| 国产成人丝袜美腿| 大胆av不用播放器在线播放| 欧美成人激情视频| 日韩中文字幕91| 啊灬啊灬啊灬啊灬高潮在线看 | 久久九九99| 色老板在线视频| 亚洲欧洲视频在线| 夜夜嗨一区二区三区| 日本调教视频在线观看| 精品国产一区二区三区四区在线观看 | 97人人爽人人喊人人模波多| 久久成人在线| 污污网站在线| 欧美极度另类性三渗透| 国产精品一品二品| 成人video亚洲精品| 国产精品一二区| 中文字幕在线一区| jizz内谢中国亚洲jizz| 亚洲一区二区三区久久 | 精品视频在线播放色网色视频| 欧美有码在线| eeuss中文| 日本道色综合久久| 国产福利资源一区| 亚洲欧洲精品在线 | 精品一卡二卡三卡四卡日本乱码 | 群体交乱之放荡娇妻一区二区| 蜜桃传媒视频麻豆一区 | 亚洲精品视频在线| 免费视频观看成人| 日韩理论片在线观看| 夜色激情一区二区| 一区二区精彩视频| 欧美高清中文字幕| 日韩欧美久久久| 欧美gayvideo| 黄页大全在线免费观看| 久久成人18免费网站| 国产毛片精品国产一区二区三区| 尤物视频在线免费观看| 国产精品久久久久久久久借妻| av爱爱亚洲一区| 国产精品18| 国产在线xxxx| 精品久久久久久亚洲综合网 | 欧美日韩国产一区在线| 都市激情久久| 欧美亚洲另类色图| 一个色综合导航| 精品一区二区三区免费毛片爱| 午夜激情在线观看| 国产一区玩具在线观看| 欧美视频13p| 久久影视一区| 视频黄页在线| 国产精品欧美日韩久久| 依依成人精品视频| 韩国精品主播一区二区在线观看 | 亚洲成av人片乱码色午夜| 日本在线免费观看视频| 欧美一级淫片videoshd| 国产一区二区电影| 亚洲色图官网| 欧妇女乱妇女乱视频| 亚洲一区二区国产| 高清成人在线观看| 福利在线一区| 国产xxxxx18| 国产在线观看91精品一区| 亚洲一区免费视频| 日韩在线观看电影完整版高清免费悬疑悬疑| 成人网免费看| 91嫩草在线视频| 91高清在线观看| 一级成人国产| 热色播在线视频| 18禁裸男晨勃露j毛免费观看| 欧美极品少妇xxxxx| 午夜av一区二区| 青青草成人在线观看| 国产不卡精品在线| 在线播放国产区| 就去色蜜桃综合| 久久久精品免费视频| 精品久久中文字幕| 久久99精品久久久久久国产越南| 日本一区影院| www免费网站在线观看| 美女扒开大腿让男人桶| 国产福利视频一区二区| 国产三级一区| 99国产成+人+综合+亚洲欧美| 亚洲欧美卡通另类91av| 高清不卡一二三区| 欧美日韩中文一区二区| 国产福利视频一区| 岛国av一区二区三区| 国产一区二区三区久久| 欧美最新精品| 日本成人中文字幕在线| 国产精品一区二区三区成人| 56国语精品自产拍在线观看| 国产成人三级在线观看| 久久精品国产亚洲blacked| av香蕉成人| 免费一级淫片|