[TOC]
回顧-函數(shù)
指令:bl、ret
指令:pc芒率、lr篙顺、sp
棧:函數(shù)開(kāi)辟
? 存放局部變量、參數(shù)匪蟀,寄存器保護(hù)萄窜;
函數(shù)嵌套:
? funcA -> funcB -> funcA:每次進(jìn)入一個(gè)函數(shù)都會(huì)開(kāi)辟一片椚鼋埃空間;第二次進(jìn)入funcA函數(shù)依然會(huì)開(kāi)辟新的椝氡茫空間佃延,即高級(jí)代碼只有一份夷磕,可以復(fù)用,但內(nèi)存不能復(fù)用尺棋,需要重新開(kāi)辟绵跷;
? 死遞歸 ==》內(nèi)存溢出
參數(shù):存放位置成福、大小荆残,是否入棧
狀態(tài)寄存器(標(biāo)記寄存器)
cpsr : current program status register内斯,按位起作用,記錄特定信息嘿期。
cpsr對(duì)if的作用:可以改變z為來(lái)控制if的比較結(jié)果;
cpsr是32位的寄存器萄传,包含4個(gè)字節(jié)秀菱,高4位低8位有特定含義,其余中間位為預(yù)留位衍菱。
? 其中低8位(包括I脊串、F清钥、T和M[4:0],稱為控制位)由系統(tǒng)控制缕坎,除非cpu運(yùn)行在特權(quán)模式下篡悟。
? 高4位(31-28)組成CPSR,條件碼標(biāo)記位荷腊,這4位可以由算數(shù)或邏輯運(yùn)算結(jié)果所改變停局,可以決定某條指令是否執(zhí)行,意義重大!企孩。
內(nèi)嵌(對(duì)外聯(lián))匯編代碼:
// N位
void funcB() {
asm (
"mov w0, #0xffffffff\n"
"adds w0, w0, #0x0\n" // 需要改變cpsr寄存器需要在運(yùn)算指令后面加上s勿璃,如adds
// 用0x7fffffff替代0x0fffffff,然后add 0x0后N位還為0歧沪,因?yàn)?f在有符號(hào)數(shù)據(jù)中依然為正數(shù)
//"adds w0, w0, w0\n" // w0=w0+w0, ==> w0=w0*2 ==> w0=w0<<1莲组,即進(jìn)行左移
);
}
CPSR
N(Negative)
第31位,符號(hào)標(biāo)志位撵孤,記錄指令執(zhí)行后邪码,得到的結(jié)果是否為負(fù)數(shù),是負(fù)數(shù)置為1闭专,否則置為0影钉;
Z(Zero)
第30位粪滤,0標(biāo)記位杖小,標(biāo)記相關(guān)指令執(zhí)行后其結(jié)果是否為0 ,為0標(biāo)記位1昂勉,否則標(biāo)記位0扫腺;
C(Carry)
第29位,進(jìn)位標(biāo)志位攒至,一般情況下,進(jìn)行無(wú)符號(hào)數(shù)的運(yùn)算。
- 加法時(shí)库菲,有進(jìn)位時(shí)C=1熙宇,否則C=0溉浙;
- 減法時(shí)(含CMP,compare)戳稽,有借位時(shí)C=0广鳍,否則C=1;
? <u>Notes:不進(jìn)不借吨铸,C位不變祖秒,保存上一次,運(yùn)算時(shí)不區(qū)分有無(wú)符號(hào)竭缝,結(jié)果再進(jìn)行區(qū)分</u>
? 加法:重復(fù)進(jìn)行0xaaaaaaaa + 0xaaaaaaaa
時(shí), 0xa
可轉(zhuǎn)為二進(jìn)制時(shí)1010
,所以在相加時(shí)(此時(shí)可視為左移)
時(shí)會(huì)有進(jìn)位的現(xiàn)象咙俩,C位在1和0之間進(jìn)行切換阿趁。如:
mov w0,#0xaaaaaaaa坛猪;0xa 的二進(jìn)制是 1010
adds w0,w0,w0墅茉; 執(zhí)行后 相當(dāng)于 1010 << 1 進(jìn)位1(無(wú)符號(hào)溢出) 所以C標(biāo)記 為 1
adds w0,w0,w0; 執(zhí)行后 相當(dāng)于 0101 << 1 進(jìn)位0(無(wú)符號(hào)沒(méi)溢出) 所以C標(biāo)記 為 0
adds w0,w0,w0悍募; 重復(fù)上面操作
adds w0,w0,w0
? 減法:做減法時(shí)0x00000000 - 0x000000ff
,產(chǎn)生借位以躯,借位后,相當(dāng)于計(jì)算0x100000000 - 0x000000ff=0xffffff01
颠通。由于借了一位膀懈,所以C位 用來(lái)標(biāo)記借位启搂。如:
mov w0,#0x0
subs w0,w0,#0xff ;
subs w0,w0,#0xff
subs w0,w0,#0xff
負(fù)數(shù)計(jì)算公式
負(fù)數(shù) :將無(wú)符號(hào)數(shù)轉(zhuǎn)換成有符號(hào)數(shù)。計(jì)算機(jī)表示有符號(hào)數(shù)的正負(fù)時(shí)牢撼,數(shù)的二進(jìn)制都采用相同表示疑苫,如1111 1111
捍掺,無(wú)符號(hào)時(shí)=255挺勿,有符號(hào)時(shí)-1。運(yùn)算過(guò)程:將1111 1111
取反+1
不瓶。而0x80
=-128/128
計(jì)算公式:取反+1湃番。包括10進(jìn)制負(fù)數(shù)---->二進(jìn)制,二進(jìn)制——>10進(jìn)制負(fù)數(shù)
2到10尊惰,包括最高位(符號(hào))一起取反,然后取反后+1
10到2题禀,先求絕對(duì)值部分的2進(jìn)制迈嘹,對(duì)結(jié)果取反秀仲,再+1神僵;
負(fù)數(shù)的補(bǔ)碼就是對(duì)反碼加1,而正數(shù)不變,正數(shù)的原碼反碼補(bǔ)碼是一樣的
如:-42(10進(jìn)制) = d6(16)
42 = 0010 1010 -----> 1101 0101 -- +1 --> = 1101 0110 = d6(16)
如:0xa8(16) = -58(16) = -88(10)
a8 = 1010 1000 -----> 0101 0111 -- +1 --> = 0101 1000 = -58(16)
將a8轉(zhuǎn)成-58的含義覆劈?為了做加法责语?坤候,內(nèi)存不認(rèn)識(shí)-58的負(fù)號(hào)
V(Overflow)
第28位是V,溢出標(biāo)志位徘键。在進(jìn)行有符號(hào)數(shù)運(yùn)算的時(shí)候吹害,如果超過(guò)了機(jī)器所能標(biāo)識(shí)的范圍,稱為溢出虚青。
- 正數(shù) + 正數(shù) 為負(fù)數(shù) 溢出
- 負(fù)數(shù) + 負(fù)數(shù) 為正數(shù) 溢出
- 正數(shù) + 負(fù)數(shù) 不可能溢出
內(nèi)存分區(qū)
分區(qū):
? 代碼區(qū):可讀可寫(xiě)可執(zhí)行
? 棧區(qū)域:放參數(shù)和局部變量
? 堆區(qū)域: 動(dòng)態(tài)申請(qǐng)它呀,可讀可寫(xiě)
? 全局: 可讀可寫(xiě)(在傳遞時(shí),傳遞的是地址)
? 常量: 只讀(有編譯器規(guī)定)
adrp
adrp = address page
尋找常量和全局變量的指令棒厘,如:
adrp x0, 2 // 2可以為其他數(shù)N
add x0, x0, #0xd10 // 0xd10 可以為其他任意值0x***
解釋如下:
adrp x0, 2
1.將2的值,左移12位 2 0000 0000 0000 == 0x1000
2.將PC寄存器的低12位清零 0x1000ba89c ==> 0x1000ba000
3.將將1 和 2 的結(jié)果相加 給 X0 寄存器!!
4. 1. + 2. => 0x1000bcd10
快捷方式:倒數(shù)4位加上N纵穿,后三位替換為0x***
? 地址0x1000bcd10即為所要找的常量或全局變量的地址
正向開(kāi)發(fā)時(shí),此時(shí)的0x1000bcd10是指向一個(gè)int的正整數(shù)的全局變量奢人,使用p *(int *)0x1000bcd10
可以將其存放的值打印出來(lái)谓媒,使用*(int *)
將地址轉(zhuǎn)換為指定的類型;如果是char類型何乎,使用char *
句惯。參見(jiàn)視頻26’’土辩。
? 左移12位抢野,是尋找偏移地址启涯,12位的尋址能力為212=22^10 = 4KB的范圍,4KB(12位)為編譯器決定的*
? 這些的偏移量都是在編譯階段確定的,游戲外掛等有可能采用這種方法。
還原高級(jí)代碼
IDA操作
- IDA在加載Mach-O時(shí)
Ready按鈕
變綠色時(shí)敞掘,表示加載分析完成盖腕。 - 窗口左側(cè)時(shí)所有方法的列表劲厌;
- 選擇某個(gè)方法雙擊進(jìn)入方法窗口;
- 右擊進(jìn)入的方法窗口選擇
Text View
進(jìn)入全屏顯示; - 第4可以用點(diǎn)擊后按空格替換;
- var_4寇漫、var_8為IDA提供的方便變量冗澈;
- 匯編中可以使用雙擊進(jìn)行方法的跳轉(zhuǎn);
還原代碼
? 如何判斷是全局還是常量?暫時(shí)將全局視為帶有“_”;
? 函數(shù)是否有返回值:如果有返回值,在調(diào)用ret指令會(huì)對(duì)x0寄存器進(jìn)行操作巾兆;否則不會(huì)。
? 傳入?yún)?shù)類型:如果有參數(shù)傳入,函數(shù)進(jìn)入時(shí)會(huì)對(duì)x0窒朋、x1…進(jìn)行數(shù)據(jù)保護(hù)抵赢,進(jìn)行入椊鼙辏或者,直接對(duì)x0袜漩,x1賦予立即數(shù)。另外在調(diào)用前的上一級(jí)函數(shù)也會(huì)對(duì)x0座掘,x1進(jìn)行操作形真。
? 在優(yōu)化高級(jí)代碼時(shí),從后到前,反向優(yōu)化;
? 在驗(yàn)證環(huán)節(jié),可以將還原回來(lái)的高級(jí)代碼重新生成mach-o文件然后在反匯編宝当,得到匯編代碼進(jìn)行對(duì)比订晌。