iOS逆向學習筆記 - 彙編(一) - 初識彙編
001--初識彙編
我們在學習逆向開發之前,我們要了解一個基本的逆向原理.首先我們是逆向iOS系統上面的APP.那麼我們知道,一個APP安裝在手機上面的可執行檔案本質上是二進位制檔案.因為iPhone手機本質上執行的指令是二進位制.是由手機上的CPU執行的.所以逆向開發是建立在分析二進位制上面.所以今天我們接下來的課程從非常基礎的東西開始講解.
組合語言的發展
機器語言
由0和1組成的機器指令.
- 加:0100 0000
- 減:0100 1000
- 乘:1111 0111 1110 0000
- 除:1111 0111 1111 0000
組合語言(assembly language)
使用助記符代替機器語言
如:
- 加:INC EAX 通過編譯器 0100 0000
- 減:DEC EAX 通過編譯器 0100 1000
- 乘:MUL EAX 通過編譯器 1111 0111 1110 0000
- 除:DIV EAX 通過編譯器 1111 0111 1111 0000
高階語言(High-level programming language)
C\C++\Java\OC\Swift,更加接近人類的自然語言
比如C語言:
- 加:A+B 通過編譯器 0100 0000
- 減:A-B 通過編譯器 0100 1000
- 乘:A*B 通過編譯器 1111 0111 1110 0000
- 除:A/B 通過編譯器 1111 0111 1111 0000
我們的程式碼在終端裝置上是這樣的過程:
[圖片上傳失敗...(image-4a9638-1526442897772)]
- 組合語言與機器語言一一對應,每一條機器指令都有與之對應的彙編指令
- 組合語言可以通過編譯得到機器語言,機器語言可以通過反彙編得到組合語言
- 高階語言可以通過編譯得到組合語言 \ 機器語言,但組合語言\機器語言幾乎不可能還原成高階語言
組合語言的特點
可以直接訪問、控制各種硬體裝置,比如儲存器、CPU等,能最大限度地發揮硬體的功能
能夠不受編譯器的限制,對生成的二進位制程式碼進行完全的控制
目的碼簡短,佔用記憶體少,執行速度快
彙編指令是機器指令的助記符,同機器指令一一對應。每一種CPU都有自己的機器指令集\彙編指令集,所以組合語言不具備可移植性
知識點過多,開發者需要對CPU等硬體結構有所瞭解,不易於編寫、除錯、維護
不區分大小寫,比如mov和MOV是一樣的
彙編的用途(哥麼我學了能幹啥?)
- 編寫驅動程式、作業系統(比如Linux核心的某些關鍵部分)
- 對效能要求極高的程式或者程式碼片段,可與高階語言混合使用(內聯彙編)
- 軟體安全
- 病毒分析與防治
- 逆向\加殼\脫殼\破解\外掛\免殺\加密解密\漏洞\黑客
- 理解整個計算機系統的最佳起點和最有效途徑
- 為編寫高效程式碼打下基礎
- 弄清程式碼的本質
- 函式的本質究竟是什麼?
- ++a + ++a + ++a 底層如何執行的?
- 編譯器到底幫我們幹了什麼?
- DEBUG模式和RELEASE模式有什麼關鍵的地方被我們忽略
- ......
最後來句裝13的話
越底層越單純!真正的程式設計師都需要了解的一門非常重要的語言,彙編!
組合語言的種類
-
目前討論比較多的組合語言有
- 8086彙編(8086處理器是16bit的CPU)
- Win32彙編
- Win64彙編
- ARM彙編(嵌入式、Mac、iOS)
- ......
我們iPhone裡面用到的是ARM彙編,但是不同的裝置也有差異.因CPU的架構不同.
架構 | 裝置 |
---|---|
armv6 | iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch |
armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 |
armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) |
arm64 | iPhone5S 以後 iPhoneX , iPad Air, iPad mini2以後 |
幾個必要的常識
- 要想學好彙編,首先需要了解CPU等硬體結構
- APP/程式的執行過程
[圖片上傳失敗...(image-a82a90-1526442897772)]
- 硬體相關最為重要是CPU/記憶體
- 在彙編中,大部分指令都是和CPU與記憶體相關的
匯流排
[圖片上傳失敗...(image-3645b4-1526442897772)][圖片上傳失敗...(image-8cc646-1526442897772)]
- 每一個CPU晶片都有許多管腳,這些管腳和匯流排相連,CPU通過匯流排跟外部器件進行互動
- 匯流排:一根根導線的集合
- 匯流排的分類
- 地址匯流排
- 資料匯流排
- 控制匯流排
[圖片上傳失敗...(image-1a7c3d-1526442897772)]
舉個例子
-
地址匯流排
- 它的寬度決定了CPU的定址能力
- 8086的地址匯流排寬度是20,所以定址能力是1M( 2^20 )
-
資料匯流排
- 它的寬度決定了CPU的單次資料傳送量,也就是資料傳送速度
- 8086的資料匯流排寬度是16,所以單次最大傳遞2個位元組的資料
-
控制匯流排
- 它的寬度決定了CPU對其他器件的控制能力、能有多少種控制
做個小練習
- 一個CPU 的定址能力為8KB,那麼它的地址匯流排的寬度為____
- 8080,8088,80286,80386 的地址匯流排寬度分別為16根,20根,24根,32根.那麼他們的定址能力分別為多少____KB, ____MB,____MB,____GB?
- 8080,8088,8086,80286,80386 的資料匯流排寬度分別為8根,8根,16根,16根,32根.那麼它們一次可以傳輸的資料為:____B,____B,____B,____B,____B,
- 從記憶體中讀取1024位元組的資料,8086至少要讀____次,80386至少要讀取____次.
答案
記憶體
記憶體地址空間的大小受CPU地址匯流排寬度的限制。8086的地址匯流排寬度為20,可以定位2^20個不同的記憶體單元(記憶體地址範圍0x00000~0xFFFFF),所以8086的記憶體空間大小為1MB
0x00000~0x9FFFF:主儲存器。可讀可寫
0xA0000~0xBFFFF:向視訊記憶體中寫入資料,這些資料會被顯示卡輸出到顯示器。可讀可寫
0xC0000~0xFFFFF:儲存各種硬體\系統資訊。只讀
進位制
學習進位制的障礙
很多人學不好進位制,原因是總以十進位制為依託去考慮其他進位制,需要運算的時候也總是先轉換成十進位制,這種學習方法是錯誤的.
我們為什麼一定要轉換十進位制呢?僅僅是因為我們對十進位制最熟悉,所以才轉換.
每一種進位制都是完美的,想學好進位制首先要忘掉十進位制,也要忘掉進位制間的轉換!
進位制的定義
- 八進位制由8個符號組成:0 1 2 3 4 5 6 7 逢八進一
- 十進位制由10個符號組成:0 1 2 3 4 5 6 7 8 9逢十進一
- N進位制就是由N個符號組成:逢N進一
做個練習
- 1 + 1 在____情況下等於 3 ?
.
.
.
.
.
.
.
.
.
.
.
.
.
十進位制由10個符號組成: 0 1 3 2 8 A B E S 7 逢十進一
如果這樣定義十進位制: 1 + 1 = 3!就對了!
這樣的目的何在?
傳統我們定義的十進位制和自定義的十進位制不一樣.那麼這10個符號如果我們不告訴別人這個符號表,別人是沒辦法拿到我們的具體資料的!用於加密!
十進位制由十個符號組成,逢十進一,符號是可以自定義的!!
進位制的運算
做個練習
- 八進位制運算
- 2 + 3 = __ , 2 * 3 = __ ,4 + 5 = __ ,4 * 5 = __.
- 277 + 333 = __ , 276 * 54 = __ , 237 - 54 = __ , 234 / 4 = __ .
八進位制加法表
0 1 2 3 4 5 6 7
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
...
1+1 = 2
1+2 = 3 2+2 = 4
1+3 = 4 2+3 = 5 3+3 = 6
1+4 = 5 2+4 = 6 3+4 = 7 4+4 = 10
1+5 = 6 2+5 = 7 3+5 = 10 4+5 = 11 5+5 = 12
1+6 = 7 2+6 = 10 3+6 = 11 4+6 = 12 5+6 = 13 6+6 = 14
1+7 = 10 2+7 = 11 3+7 = 12 4+7 = 13 5+7 = 14 6+7 = 15 7+7 = 16
八進位制乘法表
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27...
1*1 = 1
1*2 = 2 2*2 = 4
1*3 = 3 2*3 = 6 3*3 = 11
1*4 = 4 2*4 = 10 3*4 = 14 4*4 = 20
1*5 = 5 2*5 = 12 3*5 = 17 4*5 = 24 5*5 = 31
1*6 = 6 2*6 = 14 3*6 = 22 4*6 = 30 5*6 = 36 6*6 = 44
1*7 = 7 2*7 = 16 3*7 = 25 4*7 = 34 5*7 = 43 6*7 = 52 7*7 = 61
實戰四則運算
277 236 276 234
+ 333 - 54 * 54 / 4
-------- -------- -------- --------
二進位制的簡寫形式
二進位制: 1 0 1 1 1 0 1 1 1 1 0 0
三個二進位制一組: 101 110 111 100
八進位制: 5 6 7 4
四個二進位制一組: 1011 1011 1100
十六進位制: b b c
二進位制:從0 寫到 1111
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
這種二進位制使用起來太麻煩,改成更簡單一點的符號:
0 1 2 3 4 5 6 7 8 9 A B C D E F 這就是十六進位制了
資料的寬度
數學上的數字,是沒有大小限制的,可以無限的大。但在計算機中,由於受硬體的制約,資料都是有長度限制的(我們稱為資料寬度),超過最多寬度的資料會被丟棄。
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int test(){
int cTemp = 0x1FFFFFFFF;
return cTemp;
}
int main(int argc, char * argv[]) {
printf("%x\n",test());
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
計算機中常見的資料寬度
- 位(Bit): 1個位就是1個二進位制位.0或者1
- 位元組(Byte): 1個位元組由8個Bit組成(8位).記憶體中的最小單元Byte.
- 字(Word): 1個字由2個位元組組成(16位),這2個位元組分別稱為高位元組和低位元組.
- 雙字(Doubleword): 1個雙字由兩個字組成(32位)
那麼計算機儲存資料它會分為有符號數和無符號數.那麼關於這個看圖就理解了!
[圖片上傳失敗...(image-38c66c-1526442897772)]
無符號數,直接換算!
有符號數:
正數: 0 1 2 3 4 5 6 7
負數: F E D B C A 9 8
-1 -2 -3 -4 -5 -6 -7 -8
自定義進位制符號
練習
- 現在有10進位制數 10個符號分別是:2,9,1,7,6,5,4, 8,3 , A 逢10進1 那麼: 123 + 234 = ____
十進位制: 0 1 2 3 4 5 6 7 8 9
自定義: 2 9 1 7 6 5 4 8 3 A
92 99 91 97 96 95 94 98 93 9A
12 19 11 17 16 15 14 18 13 1A
72 79 71 77 76 75 74 78 73 7A
62 69 61 67 66 65 64 68 63 6A
52 59 51 57 56 55 54 58 53 5A
42 49 41 47 46 45 44 48 43 4A
82 89 81 87 86 85 84 88 83 8A
32 39 31 37 36 35 34 38 33 3A
922
那麼剛才通過10進位制運算可以轉化10進位制然後查表!但是如果是其他進位制.我們就不能轉換,要直接學會查表
- 現在有9進位制數 9個符號分別是:2,9,1,7,6,5,4, 8,3 逢9進1 那麼: 123 + 234 = ____
十進位制: 0 1 2 3 4 5 6 7 8
自定義: 2 9 1 7 6 5 4 8 3
92 99 91 97 96 95 94 98 93
12 19 11 17 16 15 14 18 13
72 79 71 77 76 75 74 78 73
62 69 61 67 66 65 64 68 63
52 59 51 57 56 55 54 58 53
42 49 41 47 46 45 44 48 43
82 89 81 87 86 85 84 88 83
32 39 31 37 36 35 34 38 33
922
暫存器
內部部件之間由匯流排連線
[圖片上傳失敗...(image-254fa2-1526442897772)]
- 對程式設計師來說,CPU中最主要部件是暫存器,可以通過改變暫存器的內容來實現對CPU的控制
- 不同的CPU,暫存器的個數、結構是不相同的
通用暫存器
-
ARM64擁有有31個64位的通用暫存器 x0 到 x30,這些暫存器通常用來存放一般性的資料,稱為通用暫存器(有時也有特定用途)
- 那麼w0 到 w28 這些是32位的. 因為64位CPU可以相容32位.所以可以只使用64位暫存器的低32位.
- 比如 w0 就是 x0的低32位!
[圖片上傳失敗...(image-c32708-1526442897772)]
通常,CPU會先將記憶體中的資料儲存到通用暫存器中,然後再對通用暫存器中的資料進行運算
假設記憶體中有塊紅色記憶體空間的值是3,現在想把它的值加1,並將結果儲存到藍色記憶體空間
[圖片上傳失敗...(image-5ddaf5-1526442897772)]
- CPU首先會將紅色記憶體空間的值放到X0暫存器中:mov X0,紅色記憶體空間
- 然後讓X0暫存器與1相加:add X0,1
- 最後將值賦值給記憶體空間:mov 藍色記憶體空間,X0
pc暫存器(program counter)
- 為指令指標暫存器,它指示了CPU當前要讀取指令的地址
- 在記憶體或者磁碟上,指令和資料沒有任何區別,都是二進位制資訊
- CPU在工作的時候把有的資訊看做指令,有的資訊看做資料,為同樣的資訊賦予了不同的意義
- 比如 1110 0000 0000 0011 0000 1000 1010 1010
- 可以當做資料 0xE003008AA
- 也可以當做指令 mov x0, x8
- CPU根據什麼將記憶體中的資訊看做指令?
- CPU將pc指向的記憶體單元的內容看做指令
- 如果記憶體中的某段內容曾被CPU執行過,那麼它所在的記憶體單元必然被pc指向過
bl指令
CPU從何處執行指令是由pc中的內容決定的,我們可以通過改變pc的內容來控制CPU執行目標指令
-
ARM64提供了一個mov指令(傳送指令),可以用來修改大部分暫存器的值,比如
- mov x0,#10、mov x1,#20
但是,mov指令不能用於設定pc的值,ARM64沒有提供這樣的功能
ARM64提供了另外的指令來修改PC的值,這些指令統稱為轉移指令,最簡單的是bl指令
bl指令 -- 練習
現在有兩段程式碼!假設程式先執行A,請寫出指令執行順序.最終暫存器x0的值是多少?
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
相關文章
- 逆向之彙編筆記筆記
- 彙編學習筆記筆記
- 【自用】彙編初學筆記 #1筆記
- iOS逆向-彙編基礎(一)iOS
- iOS逆向之旅(基礎篇) — 彙編(一)— 彙編基礎iOS
- 逆向學習筆記3——暫存器與彙編指令筆記
- iOS逆向學習筆記 - 彙編(四) - 迴圈&選擇[cmp 比較指令]iOS筆記
- 彙編基礎學習筆記筆記
- 學習筆記分享之彙編---2.彙編指令/語法筆記
- iOS逆向之旅(基礎篇) — 彙編(五) — 彙編下的BlockiOSBloC
- iOS逆向之旅(基礎篇) — 彙編(四) — 彙編下的函式iOS函式
- iOS逆向之旅(基礎篇) — 彙編(二) — 彙編下的 IF語句iOS
- 彙編學習筆記之轉移指令筆記
- 初識彙編-第一篇
- iOS逆向之旅(基礎篇) — 彙編(三) — 彙編下的 Switch語句iOS
- 彙編學習小記(三)-查表
- iOS彙編基礎(一)iOS
- 8086彙編學習
- iOS彙編入門教程(一)ARM64彙編基礎iOS
- 彙編學習筆記07——BCD碼及調整指令筆記
- Solidity語言學習筆記————38、Solidity彙編Solid筆記
- Solidity語言學習筆記————39、獨立彙編Solid筆記
- 彙編初步瞭解筆記筆記
- 彙編學習小記(一)-熟悉DEBUG環境
- 彙編初識與計算機組成計算機
- 彙編筆記(持續更新中)筆記
- 8086 彙編學習 Part 6
- 8086 彙編學習 Part 7
- 8086 彙編學習 Part 9
- 8086 彙編學習 Part 2
- 8086 彙編學習 Part 3
- 組合語言學習記錄--第一個彙編程式組合語言
- 彙編學習小記(二)-順序程式設計程式設計
- 我的彙編學習之路(1):指令
- iOS彙編入門教程(三)彙編中的 Section 與資料存取iOS
- 初學 Delphi 嵌入彙編[26] - 大小寫字母轉換
- iOS彙編入門教程(二)在Xcode工程中嵌入彙編程式碼iOSXCode
- Redis學習筆記(一)——初識RedisRedis筆記