我們?cè)趯W(xué)習(xí)逆向開(kāi)發(fā)之前,我們要了解一個(gè)基本的逆向原理.首先我們是逆向iOS系統(tǒng)上面的APP.那么我們知道,一個(gè)APP安裝在手機(jī)上面的可執(zhí)行文件本質(zhì)上是二進(jìn)制文件.因?yàn)閕Phone手機(jī)本質(zhì)上執(zhí)行的指令是二進(jìn)制.是由手機(jī)上的CPU執(zhí)行的.所以逆向開(kāi)發(fā)是建立在分析二進(jìn)制上面.所以今天我們接下來(lái)的課程從非常基礎(chǔ)的東西開(kāi)始講解.
匯編語(yǔ)言的發(fā)展
機(jī)器語(yǔ)言
由0和1組成的機(jī)器指令.
- 加:0100 0000
- 減:0100 1000
- 乘:1111 0111 1110 0000
- 除:1111 0111 1111 0000
匯編語(yǔ)言(assembly language)
使用助記符代替機(jī)器語(yǔ)言
如:
- 加:INC EAX 通過(guò)編譯器 0100 0000
- 減:DEC EAX 通過(guò)編譯器 0100 1000
- 乘:MUL EAX 通過(guò)編譯器 1111 0111 1110 0000
- 除:DIV EAX 通過(guò)編譯器 1111 0111 1111 0000
高級(jí)語(yǔ)言(High-level programming language)
C\C++\Java\OC\Swift,更加接近人類的自然語(yǔ)言
比如C語(yǔ)言:
- 加:A+B 通過(guò)編譯器 0100 0000
- 減:A-B 通過(guò)編譯器 0100 1000
- 乘:A*B 通過(guò)編譯器 1111 0111 1110 0000
- 除:A/B 通過(guò)編譯器 1111 0111 1111 0000
我們的代碼在終端設(shè)備上是這樣的過(guò)程:
- 匯編語(yǔ)言與機(jī)器語(yǔ)言一一對(duì)應(yīng),每一條機(jī)器指令都有與之對(duì)應(yīng)的匯編指令
- 匯編語(yǔ)言可以通過(guò)編譯得到機(jī)器語(yǔ)言三圆,機(jī)器語(yǔ)言可以通過(guò)反匯編得到匯編語(yǔ)言
- 高級(jí)語(yǔ)言可以通過(guò)編譯得到匯編語(yǔ)言 \ 機(jī)器語(yǔ)言须蜗,但匯編語(yǔ)言\機(jī)器語(yǔ)言幾乎不可能還原成高級(jí)語(yǔ)言
匯編語(yǔ)言的特點(diǎn)
可以直接訪問(wèn)、控制各種硬件設(shè)備旺隙,比如存儲(chǔ)器、CPU等,能最大限度地發(fā)揮硬件的功能
能夠不受編譯器的限制卒密,對(duì)生成的二進(jìn)制代碼進(jìn)行完全的控制
目標(biāo)代碼簡(jiǎn)短,占用內(nèi)存少棠赛,執(zhí)行速度快
匯編指令是機(jī)器指令的助記符,同機(jī)器指令一一對(duì)應(yīng)哮奇。每一種CPU都有自己的機(jī)器指令集\匯編指令集,所以匯編語(yǔ)言不具備可移植性
知識(shí)點(diǎn)過(guò)多睛约,開(kāi)發(fā)者需要對(duì)CPU等硬件結(jié)構(gòu)有所了解鼎俘,不易于編寫(xiě)、調(diào)試痰腮、維護(hù)
不區(qū)分大小寫(xiě)而芥,比如mov和MOV是一樣的
匯編的用途
- 編寫(xiě)驅(qū)動(dòng)程序、操作系統(tǒng)(比如Linux內(nèi)核的某些關(guān)鍵部分)
- 對(duì)性能要求極高的程序或者代碼片段膀值,可與高級(jí)語(yǔ)言混合使用(內(nèi)聯(lián)匯編)
- 軟件安全
- 病毒分析與防治
- 逆向\加殼\脫殼\破解\外掛\免殺\加密解密\漏洞\黑客
- 理解整個(gè)計(jì)算機(jī)系統(tǒng)的最佳起點(diǎn)和最有效途徑
- 為編寫(xiě)高效代碼打下基礎(chǔ)
- 弄清代碼的本質(zhì)
- 函數(shù)的本質(zhì)究竟是什么?
- ++a + ++a + ++a 底層如何執(zhí)行的?
- 編譯器到底幫我們干了什么?
- DEBUG模式和RELEASE模式有什么關(guān)鍵的地方被我們忽略
- ......
最后來(lái)句裝13的話
越底層越單純!真正的程序員都需要了解的一門(mén)非常重要的語(yǔ)言,匯編!
匯編語(yǔ)言的種類
-
目前討論比較多的匯編語(yǔ)言有
- 8086匯編(8086處理器是16bit的CPU)
- Win32匯編
- Win64匯編
- ARM匯編(嵌入式棍丐、Mac、iOS)
- ......
我們iPhone里面用到的是ARM匯編,但是不同的設(shè)備也有差異.因CPU的架構(gòu)不同.
架構(gòu) | 設(shè)備 |
---|---|
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以后 |
幾個(gè)必要的常識(shí)
- 要想學(xué)好匯編,首先需要了解CPU等硬件結(jié)構(gòu)
- APP/程序的執(zhí)行過(guò)程
- 硬件相關(guān)最為重要是CPU/內(nèi)存
- 在匯編中,大部分指令都是和CPU與內(nèi)存相關(guān)的
總線
- 每一個(gè)CPU芯片都有許多管腳歌逢,這些管腳和總線相連,CPU通過(guò)總線跟外部器件進(jìn)行交互
- 總線:一根根導(dǎo)線的集合
- 總線的分類
- 地址總線
- 數(shù)據(jù)總線
- 控制總線
舉個(gè)例子
-
地址總線
- 它的寬度決定了CPU的尋址能力
- 8086的地址總線寬度是20翘狱,所以尋址能力是1M( 2^20 )
-
數(shù)據(jù)總線
- 它的寬度決定了CPU的單次數(shù)據(jù)傳送量秘案,也就是數(shù)據(jù)傳送速度
- 8086的數(shù)據(jù)總線寬度是16,所以單次最大傳遞2個(gè)字節(jié)的數(shù)據(jù)
-
控制總線
- 它的寬度決定了CPU對(duì)其他器件的控制能力、能有多少種控制
做個(gè)小練習(xí)
- 一個(gè)CPU 的尋址能力為8KB,那么它的地址總線的寬度為_(kāi)___
- 8080,8088,80286,80386 的地址總線寬度分別為16根,20根,24根,32根.那么他們的尋址能力分別為多少____KB, ____MB,____MB,____GB?
- 8080,8088,8086,80286,80386 的數(shù)據(jù)總線寬度分別為8根,8根,16根,16根,32根.那么它們一次可以傳輸?shù)臄?shù)據(jù)為:____B,____B,____B,____B,____B,
- 從內(nèi)存中讀取1024字節(jié)的數(shù)據(jù),8086至少要讀____次,80386至少要讀取____次.
答案
內(nèi)存
內(nèi)存地址空間的大小受CPU地址總線寬度的限制阱高。8086的地址總線寬度為20赚导,可以定位2^20個(gè)不同的內(nèi)存單元(內(nèi)存地址范圍0x00000~0xFFFFF),所以8086的內(nèi)存空間大小為1MB
0x00000~0x9FFFF:主存儲(chǔ)器赤惊『鹁桑可讀可寫(xiě)
0xA0000~0xBFFFF:向顯存中寫(xiě)入數(shù)據(jù),這些數(shù)據(jù)會(huì)被顯卡輸出到顯示器未舟∪Π担可讀可寫(xiě)
0xC0000~0xFFFFF:存儲(chǔ)各種硬件\系統(tǒng)信息。只讀
進(jìn)制
學(xué)習(xí)進(jìn)制的障礙
很多人學(xué)不好進(jìn)制裕膀,原因是總以十進(jìn)制為依托去考慮其他進(jìn)制员串,需要運(yùn)算的時(shí)候也總是先轉(zhuǎn)換成十進(jìn)制,這種學(xué)習(xí)方法是錯(cuò)誤的.
我們?yōu)槭裁匆欢ㄒD(zhuǎn)換十進(jìn)制呢昼扛??jī)H僅是因?yàn)槲覀儗?duì)十進(jìn)制最熟悉寸齐,所以才轉(zhuǎn)換.
每一種進(jìn)制都是完美的,想學(xué)好進(jìn)制首先要忘掉十進(jìn)制,也要忘掉進(jìn)制間的轉(zhuǎn)換抄谐!
進(jìn)制的定義
- 八進(jìn)制由8個(gè)符號(hào)組成:0 1 2 3 4 5 6 7 逢八進(jìn)一
- 十進(jìn)制由10個(gè)符號(hào)組成:0 1 2 3 4 5 6 7 8 9逢十進(jìn)一
- N進(jìn)制就是由N個(gè)符號(hào)組成:逢N進(jìn)一
做個(gè)練習(xí)
- 1 + 1 在____情況下等于 3 ?
.
.
.
.
.
.
.
.
.
.
.
.
.
十進(jìn)制由10個(gè)符號(hào)組成: 0 1 3 2 8 A B E S 7 逢十進(jìn)一
如果這樣定義十進(jìn)制: 1 + 1 = 3!就對(duì)了!
這樣的目的何在?
傳統(tǒng)我們定義的十進(jìn)制和自定義的十進(jìn)制不一樣.那么這10個(gè)符號(hào)如果我們不告訴別人這個(gè)符號(hào)表,別人是沒(méi)辦法拿到我們的具體數(shù)據(jù)的!用于加密!
十進(jìn)制由十個(gè)符號(hào)組成,逢十進(jìn)一,符號(hào)是可以自定義的!!
進(jìn)制的運(yùn)算
做個(gè)練習(xí)
- 八進(jìn)制運(yùn)算
- 2 + 3 = __ , 2 * 3 = __ ,4 + 5 = __ ,4 * 5 = __.
- 277 + 333 = __ , 276 * 54 = __ , 237 - 54 = __ , 234 / 4 = __ .
八進(jìn)制加法表
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
八進(jìn)制乘法表
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
實(shí)戰(zhàn)四則運(yùn)算
277 236 276 234
+ 333 - 54 * 54 / 4
-------- -------- -------- --------
二進(jìn)制的簡(jiǎn)寫(xiě)形式
二進(jìn)制: 1 0 1 1 1 0 1 1 1 1 0 0
三個(gè)二進(jìn)制一組: 101 110 111 100
八進(jìn)制: 5 6 7 4
四個(gè)二進(jìn)制一組: 1011 1011 1100
十六進(jìn)制: b b c
二進(jìn)制:從0 寫(xiě)到 1111
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
這種二進(jìn)制使用起來(lái)太麻煩访忿,改成更簡(jiǎn)單一點(diǎn)的符號(hào):
0 1 2 3 4 5 6 7 8 9 A B C D E F 這就是十六進(jìn)制了
數(shù)據(jù)的寬度
數(shù)學(xué)上的數(shù)字,是沒(méi)有大小限制的斯稳,可以無(wú)限的大海铆。但在計(jì)算機(jī)中,由于受硬件的制約挣惰,數(shù)據(jù)都是有長(zhǎng)度限制的(我們稱為數(shù)據(jù)寬度)卧斟,超過(guò)最多寬度的數(shù)據(jù)會(huì)被丟棄。
#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]));
}
}
計(jì)算機(jī)中常見(jiàn)的數(shù)據(jù)寬度
- 位(Bit): 1個(gè)位就是1個(gè)二進(jìn)制位.0或者1
- 字節(jié)(Byte): 1個(gè)字節(jié)由8個(gè)Bit組成(8位).內(nèi)存中的最小單元Byte.
- 字(Word): 1個(gè)字由2個(gè)字節(jié)組成(16位),這2個(gè)字節(jié)分別稱為高字節(jié)和低字節(jié).
- 雙字(Doubleword): 1個(gè)雙字由兩個(gè)字組成(32位)
那么計(jì)算機(jī)存儲(chǔ)數(shù)據(jù)它會(huì)分為有符號(hào)數(shù)和無(wú)符號(hào)數(shù).那么關(guān)于這個(gè)看圖就理解了!
無(wú)符號(hào)數(shù),直接換算!
有符號(hào)數(shù):
正數(shù): 0 1 2 3 4 5 6 7
負(fù)數(shù): F E D B C A 9 8
-1 -2 -3 -4 -5 -6 -7 -8
自定義進(jìn)制符號(hào)
練習(xí)
- 現(xiàn)在有10進(jìn)制數(shù) 10個(gè)符號(hào)分別是:2憎茂,9珍语,1,7竖幔,6板乙,5,4拳氢, 8募逞,3 , A 逢10進(jìn)1 那么: 123 + 234 = ____
十進(jìn)制: 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
那么剛才通過(guò)10進(jìn)制運(yùn)算可以轉(zhuǎn)化10進(jìn)制然后查表!但是如果是其他進(jìn)制.我們就不能轉(zhuǎn)換,要直接學(xué)會(huì)查表
- 現(xiàn)在有9進(jìn)制數(shù) 9個(gè)符號(hào)分別是:2,9馋评,1放接,7,6留特,5纠脾,4玛瘸, 8,3 逢9進(jìn)1 那么: 123 + 234 = ____
十進(jìn)制: 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