在逆向開發(fā)中,其中一個重要環(huán)節(jié)就是靜態(tài)分析。我們逆向iOS系統(tǒng)中的某個APP,而APP安裝在iPhone手機上的本質(zhì)就是一個可執(zhí)行的二進制文件,因為iPhone上的CPU執(zhí)行的指令就是二進制。所以靜態(tài)分析其實就是建立在分析二進制上面。而分析二進制,就不得不了解匯編語言。
語言的發(fā)展
1.機器語言:由0和1組成的機器指令。
加:0100 0000
減:0100 1000
乘:1111 0111 1110 0000
除:1111 0111 1111 0000
2.匯編語言(assembly language):使用助記符代替機器語言。
加:INC EAX 通過編譯器 0100 0000
減:DEC EAX 通過編譯器 0100 1000
乘:MUL EAX 通過編譯器 1111 0111 1110 0000
除:DIV EAX 通過編譯器 1111 0111 1111 0000
3.高級語言(High-level programming language):C/C++/OC/Swift/Java等更加接近人類的自然語言。
比如C語言:
加:A+B 通過編譯器 0100 0000
減:A-B 通過編譯器 0100 1000
乘:A*B 通過編譯器 1111 0111 1110 0000
除:A/B 通過編譯器 1111 0111 1111 0000
代碼在終端設(shè)備的編譯過程,如圖1所示:

匯編語言與機器語言一一對應,每一條機器指令都有與之對應的匯編指令
匯編語言可以通過編譯得到機器語言,機器語言可以通過反匯編得到匯編語言
高級語言可以通過編譯得到匯編語言 \ 機器語言,但匯編語言\機器語言幾乎不可能還原成高級語言
CPU簡介
在匯編中,大部分指令都是和CPU及內(nèi)存相關(guān),所以學好匯編必須對CPU有大致的了解。
總線
總線就是一根根導線的集合。
總線可分為:地址總線、數(shù)據(jù)總線、控制總線
①地址總線
它的寬度決定了CPU的尋址能力,例如:8086的地址總線寬度是20,所以尋址能力是1M( 2的20次方 )
②數(shù)據(jù)總線
它的寬度決定了CPU的單次數(shù)據(jù)傳送量,也就是數(shù)據(jù)傳送速度。例如:8086的數(shù)據(jù)總線寬度是16,所以單次最大傳遞2個字節(jié)的數(shù)據(jù)。
③控制總線
它的寬度決定了CPU對其他器件的控制能力、能有多少種控制。
進制
學習進制的障礙
很多人學不好進制,原因是總以十進制為依托去考慮其他進制,需要運算的時候也總是先轉(zhuǎn)換成十進制,這種學習方法是錯誤的。
我們?yōu)槭裁匆欢ㄒD(zhuǎn)換十進制呢?僅僅是因為我們對十進制最熟悉,所以才轉(zhuǎn)換。
每一種進制都是完美的,想學好進制首先要忘掉十進制,也要忘掉進制間的轉(zhuǎn)換!
進制的定義
①八進制由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
這樣的目的何在?
傳統(tǒng)我們定義的十進制和自定義的十進制不一樣,如果我們不告訴別人這個符號表,別人是沒辦法拿到我們的具體數(shù)據(jù)的!此方法就可用于加密!
數(shù)據(jù)的寬度
數(shù)學上的數(shù)字,是沒有大小限制的,可以無限的大。但在計算機中,由于受硬件的制約,數(shù)據(jù)都是有長度限制的(我們稱為數(shù)據(jù)寬度),超過最多寬度的數(shù)據(jù)會被丟棄。
計算機中常見的數(shù)據(jù)寬度
位(Bit): 1個位就是1個二進制位0或者1;
字節(jié)(Byte): 1個字節(jié)由8個Bit組成(8位).內(nèi)存中的最小單元Byte;
字(Word): 1個字由2個字節(jié)組成(16位),這2個字節(jié)分別稱為高字節(jié)和低字節(jié);
雙字(Doubleword): 1個雙字由兩個字組成(32位)。
計算機存儲數(shù)據(jù)它會分為有符號數(shù)和無符號數(shù),如圖2所示:

無符號數(shù),直接換算!
有符號數(shù):
正數(shù): 0 1 2 3 4 5 6 7
負數(shù): F E D B C A 9 8
-1 -2 -3 -4 -5 -6 -7 -8
CPU&寄存器
CPU除了有控制器、運算器還有寄存器。其中寄存器的作用就是進行數(shù)據(jù)的臨時存儲。
對于arm64系的CPU來說, 如果寄存器以x開頭則表明的是一個64位的寄存器,如果以w開頭則表明是一個32位的寄存器,在系統(tǒng)中沒有提供16位和8位的寄存器供訪問和使用。其中32位的寄存器是64位寄存器的低32位部分并不是獨立存在的。
- 對程序員來說,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實現(xiàn)對CPU的控制
- 不同的CPU,寄存器的個數(shù)、結(jié)構(gòu)是不相同的
通用寄存器
通用寄存器也稱數(shù)據(jù)地址寄存器,通常用來做數(shù)據(jù)計算的臨時存儲、累加、計數(shù)、地址保存等功能。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù),在CPU中當做一些常規(guī)變量來使用。
ARM64擁有有32個64位的通用寄存器 x0 到 x30,以及XZR(零寄存器),這些通用寄存器有時也有特定用途。
-
那么w0 到 w28 這些是32位的, 因為64位CPU可以兼容32位,所以可以只使用64位寄存器的低32位。比如 w0 就是 x0的低32位!
圖3.png
通常,CPU會先將內(nèi)存中的數(shù)據(jù)存儲到通用寄存器中,然后再對通用寄存器中的數(shù)據(jù)進行運算。
pc寄存器(program counter)
- 為指令指針寄存器,它指示了CPU當前要讀取指令的地址
- 在內(nèi)存或者磁盤上,指令和數(shù)據(jù)沒有任何區(qū)別,都是二進制信息
- CPU在工作的時候把有的信息看做指令,有的信息看做數(shù)據(jù),為同樣的信息賦予了不同的意義
- 比如 1110 0000 0000 0011 0000 1000 1010 1010
- 可以當做數(shù)據(jù) 0xE003008AA
- 也可以當做指令 mov x0, x8
- CPU根據(jù)什么將內(nèi)存中的信息看做指令?
- CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令
- 如果內(nèi)存中的某段內(nèi)容曾被CPU執(zhí)行過,那么它所在的內(nèi)存單元必然被pc指向過
浮點和向量寄存器
因為浮點數(shù)的存儲以及其運算的特殊性,CPU中專門提供浮點數(shù)寄存器來處理浮點數(shù)。
- 浮點寄存器 64位: D0 - D31 32位: S0 - S31
現(xiàn)在的CPU支持向量運算,(向量運算在圖形處理相關(guān)的領(lǐng)域用得非常的多)為了支持向量計算系統(tǒng)了也提供了眾多的向量寄存器。
- 向量寄存器 128位:V0-V31
高速緩存
iPhoneX上搭載的ARM處理器A11它的1級緩存的容量是64KB,2級緩存的容量8M。
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行。而寄存器的運行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個高速緩存存儲區(qū)域.當程序在運行時,先將要執(zhí)行的指令代碼以及數(shù)據(jù)復制到高速緩存中去(由操作系統(tǒng)完成),CPU直接從高速緩存依次讀取指令來執(zhí)行。
bl指令
- CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的,我們可以通過改變pc的內(nèi)容來控制CPU執(zhí)行目標指令
- ARM64提供了一個mov指令(傳送指令),可以用來修改大部分寄存器的值,比如mov x0,#10;mov x1,#20
- 但是,mov指令不能用于設(shè)置pc的值,ARM64沒有提供這樣的功能
ARM64提供了另外的指令來修改PC的值,這些指令統(tǒng)稱為轉(zhuǎn)移指令,最簡單的是bl指令
練習bl指令
.text
.global _A,_B
_A:
mov x0,#0x0000
mov x1,#0xffff
add x0,x1,#0x00ff
mov x1,x0
bl _B
mov x0,#0x00
ret
_B:
add x0,x0,#0x00
ret
1. mov x0,#0x000 ;將0x000賦值給x0 x0=0x000
2. mov x1,#0xffff ;將0xffff 賦值給x1 x1 =0xffff
3. add x0,x1,#0x00ff ;將0x00ff和x1相加賦值給x0 x0=0xffff
4. mov x1,x0 ;將x0的值賦值給x1 x1=0xffff
5. bl _B ;跳轉(zhuǎn)到B里,將x0和0x00相加,賦值給x0 x0 = 0xffff
6. mov x0,#0x00 ;將0x00賦值給x0 x0=0x00
所以最后x0的值為0
