iOS逆向

前言:想必大家都知道了,新浪閱讀整個(gè)業(yè)務(wù)線砍掉的事情,是的,朕的大清亡了,不過賠償很到位,也有了幸福感。從北京回到鄭州休息好一陣子,思考了一下未來的工作方向,業(yè)余時(shí)間總結(jié)一下所學(xué)知識(shí)吧。

以下就是學(xué)習(xí)過程中的筆記!

  • 函數(shù)的本質(zhì)
    寄存器:64位:x0-x30,XZR(零寄存器)
    32位:W0-W30,WZR(零寄存器)
    PC寄存器:用來確定CPU即將執(zhí)行的地址;
    改變PC寄存器:使用bl跳轉(zhuǎn)值指令

    • 棧:是一種具有特殊的訪問方式的存儲(chǔ)空間(后進(jìn)先出)
      sp寄存器在任一時(shí)刻都會(huì)保存棧頂?shù)牡刂罚?br> 只要調(diào)用函數(shù)就會(huì)開辟??臻g;系統(tǒng)通過操作SP寄存器,SP往高地址走時(shí)都屬于棧區(qū)域,SP往低地址走時(shí)這塊區(qū)域是沒有用的。

    • 對(duì)內(nèi)存的操作就是讀和寫,

    • ldr 把內(nèi)存數(shù)據(jù)讀到寄存器,str把寄存器寫到內(nèi)存;

    • 函數(shù)調(diào)用完畢,要做棧平衡。

    • fp寄存器也稱為x29寄存器屬于通用寄存器,在某一時(shí)刻我們可以利用它保存棧底地址。

    • bl和ret指令
      bl標(biāo)號(hào):

      • 將下一條指令的地址放到lr(x30)寄存器;
      • 轉(zhuǎn)到標(biāo)號(hào)處執(zhí)行。

      ret指令:

      • 默認(rèn)使用x30中的值,x30放的是回去的路。

解讀一下:
stp x29, x30, [sp, #-0x10]!

  • 將x29,x30放到sp減去0x10的位置并且sp減去0x10

什么條件才能這樣寫?

  • ??臻g只需要保護(hù)29和30,沒有額外的??臻g;也就是函數(shù)里面只是一個(gè)簡單的調(diào)用,沒有局部變量。

ldr x30, [sp], #0x10

  • [sp]表示:把它當(dāng)作內(nèi)存地址,取出其中的值

函數(shù)的參數(shù)與返回值:
什么時(shí)候節(jié)約內(nèi)存:寫入到棧區(qū),寫入到內(nèi)存時(shí)。
寄存器不存在節(jié)約內(nèi)存。
寄存器里面有個(gè)運(yùn)算器

  • 參數(shù) x0-x7,w0-w7
    補(bǔ)充:
    返回值 x0
    補(bǔ)充:
    sp棧頂
    x29棧底
    orr = mov

為什么參數(shù)最好8個(gè)?

  • 通過寄存器的訪問是最高效的

還原高級(jí)代碼
函數(shù)調(diào)用棧
eg:main函數(shù)參數(shù)入棧:保護(hù)現(xiàn)場;
當(dāng)函數(shù)參數(shù)多的時(shí)候x0-x7放到棧區(qū)域進(jìn)行保護(hù)
先放參數(shù)、再放局部變量

  • 棧里面存在野指針?
    eg1:用4個(gè)字節(jié)去訪問8字節(jié)的地址;
    eg2:一個(gè)指針指向垃圾地址。
    棧里面一般不存放真實(shí)的結(jié)構(gòu)體數(shù)據(jù)(不過在函數(shù)內(nèi)部也可能有純粹的結(jié)構(gòu)體,一般我們使用的第三方框架都是使用malloc開辟內(nèi)存區(qū)域,再去創(chuàng)建結(jié)構(gòu)體放到里面),一般存放簡單的引用型數(shù)據(jù)(指針)。

  • 什么時(shí)候29、30需要保護(hù)?
    有嵌套調(diào)用的時(shí)候。

  • 什么時(shí)候用到更多的棧?
    當(dāng)有參數(shù)和局部變量的時(shí)候。

  • 狀態(tài)寄存器(又稱:標(biāo)記寄存器):當(dāng)前執(zhí)行方法的狀態(tài)
    32位寄存器的最高4位

    • N:記錄相關(guān)的指令執(zhí)行結(jié)束后,結(jié)果是否位負(fù),如果為負(fù)
    • N=1
    • Z:計(jì)算結(jié)果如果為0,Z=1
    • C:無符號(hào)加法進(jìn)位,C=1;無符號(hào)減法有借位C=0;
    • V:有符號(hào)溢出標(biāo)記,有溢出V=1;
      正+正=負(fù) v=1
      負(fù)-負(fù)=正 v=1
  • if指令可以改變標(biāo)志寄存器
    add sub orr 會(huì)影響標(biāo)志寄存器

  • 內(nèi)存:

    • 代碼區(qū):存放代碼、可讀可寫
    • 棧區(qū):放參數(shù)、局部變量、臨時(shí)數(shù)據(jù)
    • 堆區(qū):動(dòng)態(tài)申請(qǐng)
    • 常量區(qū):只讀

帶#就是立即數(shù)(數(shù)字)

解讀:adrp x0, 1

  • 1、將pc寄存器的值低12位清0
  • 2、將1左移12位
  • 3、將整兩個(gè)值相加,賦值給x0寄存器

方法編號(hào):是個(gè)字符串常量存放在MackO文件里面

虛擬內(nèi)存和物理內(nèi)存
虛擬內(nèi)存:
物理內(nèi)存:
adrp x0, #0x1
adrp里面要么是全局變量要么是局部變量要么就是一個(gè)對(duì)象的屬性。

image.png

  • 全局變量和常量

    • 一般內(nèi)存中獲取全局變量和常量時(shí),出現(xiàn)adrp和add兩條指令獲得一個(gè)地址的情況。
    • ADRP(Address Page)
      • adrp x0, 1

        • 將1的值,左移12位!16進(jìn)制就是0x1000
        • 將當(dāng)前PC寄存器低12位清0
        • 將以上兩個(gè)結(jié)果相加,存放到x0寄存器
      • 通過ADD指令,獲取這頁內(nèi)存中的偏移。-
        image.png
      • image.png

        使用hopper還原高級(jí)代碼:

    • 一句一句還原成高級(jí)代碼。
      先看main函數(shù)在bl調(diào)用func時(shí)有木有把參數(shù)傳進(jìn)去,有說明有參數(shù)。再看func函數(shù)體內(nèi)有木有對(duì)x0做操作,一般情況下如果有說明有返回值(可能會(huì)在棧里面)但是不能確定返回值類型,可以確定方法編號(hào),從中確定返回值類型。
    • 由下到上簡化
  • CMP比較指令:把一個(gè)寄存器的內(nèi)容和另一個(gè)寄存器的內(nèi)容或立即數(shù)進(jìn)行比較,但不存儲(chǔ)結(jié)果,只是正確的更改標(biāo)志寄存器,底層做的是減法運(yùn)算。

    • B.LE標(biāo)號(hào): 標(biāo)記結(jié)果是小于等于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.LT標(biāo)號(hào): 標(biāo)記結(jié)果是小于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.GE標(biāo)號(hào): 標(biāo)記結(jié)果是大于等于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.GT標(biāo)號(hào): 標(biāo)記結(jié)果是大于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.EQ標(biāo)號(hào): 標(biāo)記結(jié)果是等于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.NQ標(biāo)號(hào): 標(biāo)記結(jié)果是不等于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • B.HI標(biāo)號(hào): 標(biāo)記結(jié)果是無符號(hào)大于,執(zhí)行標(biāo)號(hào),否則不跳轉(zhuǎn)
    • 稍后補(bǔ)充....
  •  adrp x30, #0x100008000
     add x30, x30, #0xcf0
     還原成高級(jí)代碼為:int *x30 = &g;
    
  • 循環(huán)&選擇

    • cmp和subs區(qū)別?cmp不會(huì)保存結(jié)果,subs會(huì)保存結(jié)果。
    • do while判斷條件在后面,滿足條件往前跳
    • while和for很像,判斷條件在前面,滿足條件往前跳
  • switch

    • 分之少于3個(gè)沒有意義和if else很像
    • 各個(gè)分支常量差值比較大時(shí),編譯器會(huì)在內(nèi)存和效率之間取舍
    • 分支較多時(shí),編譯器會(huì)生成一個(gè)表,進(jìn)行跳轉(zhuǎn)
  • 代碼優(yōu)化

    • 非本文件的函數(shù)或代碼編譯器不會(huì)優(yōu)化
  • 指針

    • 指針可以做簡單的運(yùn)算。如:自增/自減
  • block反匯編:最主要的是找到invoke(實(shí)現(xiàn)地址)、signature(類型),進(jìn)而重寫block,hook別人的block。

    • 先看一下block源碼
      #define BLOCK_DESCRIPTOR_1 1
      struct Block_descriptor_1 {
      uintptr_t reserved;
      uintptr_t size;
      };
    
      #define BLOCK_DESCRIPTOR_2 1
      struct Block_descriptor_2 {
      // requires BLOCK_HAS_COPY_DISPOSE
      BlockCopyFunction copy;
      BlockDisposeFunction dispose;
      };
      struct Block_descriptor_3 {
        // requires BLOCK_HAS_SIGNATURE
        const char *signature;
        const char *layout;   // contents depend on 
         BLOCK_HAS_EXTENDED_LAYOUT
        };
       struct Block_layout {
        void *isa;
        volatile int32_t flags; // contains ref count
        int32_t reserved;
        BlockInvokeFunction invoke;//實(shí)現(xiàn)地址!
        struct Block_descriptor_1 *descriptor;
       // imported variables
       };
    
    • 尋找invoke和signature
      實(shí)例一: 高級(jí)代碼如下:
     int main(int argc, char * argv[]) {
         void (^block)(void) = ^(){
             NSLog(@"nslog");
          };
          block();
          return 0;
      }
    

    匯編代碼如下:

     0x1000ba2a0 <+12>: adrp   x8, 2
     0x1000ba2a4 <+16>: add    x8, x8, #0x70             ; =0x70 
     0x1000ba2a8 <+20>: stur   wzr, [x29, #-0x4]
     0x1000ba2ac <+24>: stur   w0, [x29, #-0x8]
     0x1000ba2b0 <+28>: str    x1, [sp, #0x10]
     ->  0x1000ba2b4 <+32>: mov    x0, x8
     0x1000ba2b8 <+36>: bl     0x1000ba5fc               ; symbol 
    stub for: objc_retainBlock
     0x1000ba2bc <+40>: str    x0, [sp, #0x8]
     0x1000ba2c0 <+44>: ldr    x8, [sp, #0x8]
     0x1000ba2c4 <+48>: mov    x0, x8
     0x1000ba2c8 <+52>: ldr    x8, [x8, #0x10]
     0x1000ba2cc <+56>: blr    x8
    
    (lldb) x 0x1000bc070 
    0x1000bc070: 18 86 f9 9f 01 00 00 00 00 00 00 50 00 00 
    00 00  ...........P....
    0x1000bc080: f8 a2 0b 00 01 00 00 00 50 c0 0b 00 01 00 
    00 00  ........P.......
    
    (lldb) dis -s 0x01000ba2f8
    反匯編`__main_block_invoke:
    0x1000ba2f8 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x1000ba2fc <+4>:  stp    x29, x30, [sp, #0x10]
    0x1000ba300 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x1000ba304 <+12>: str    x0, [sp, #0x8]
    0x1000ba308 <+16>: str    x0, [sp]
    0x1000ba30c <+20>: adrp   x0, 2
    0x1000ba310 <+24>: add    x0, x0, #0xb0             ; =0xb0 
    0x1000ba314 <+28>: bl     0x1000ba5a8               ; symbol stub for: NSLog
    

    實(shí)例二: 高級(jí)代碼如下:

     int main(int argc, char * argv[]) {
         int a = 10;
         void (^block)(void) = ^(){
            NSLog(@"nslog--%d", a);
         };
         block();
         return 0;
    }
    

    匯編代碼如下:

      0x10004a24c <+12>:  adrp   x8, 2
      0x10004a250 <+16>:  add    x8, x8, #0x58             ; =0x58 
      0x100082254 <+20>:  adrp   x9, 0
      0x100082258 <+24>:  add    x9, x9, #0x2e0            ; 
      =0x2e0 
    
    (lldb) x 0x100084058
     0x100084058: 00 00 00 00 00 00 00 00 24 00 00 00 00 00 
     00 00  ........$.......
     0x100084068: 8c 3f 08 00 01 00 00 00 fb 33 08 00 01 00 
     00 00  .?.......3......
    
    (lldb) x 0x1000822e0
     0x10004a2e0: ff c3 00 d1 fd 7b 02 a9 fd 83 00 91 a0 83 1f 
     f8  .....{..........
     0x10004a2f0: e8 03 00 aa e8 0b 00 f9 09 20 40 b9 e0 03 
     09 aa  ......... @.....
    
     (lldb) p (char *)0x0100083f8c
     (char *) $1 = 0x0000000100083f8c "v8@?0"
    
     dis -s 0x1000822e0
     反匯編`__main_block_invoke:
     0x1000822e0 <+0>:  sub    sp, sp, #0x30             ; =0x30 
     0x1000822e4 <+4>:  stp    x29, x30, [sp, #0x20]
     0x1000822e8 <+8>:  add    x29, sp, #0x20            ; =0x20 
     0x1000822ec <+12>: stur   x0, [x29, #-0x8]
     0x1000822f0 <+16>: mov    x8, x0
     0x1000822f4 <+20>: str    x8, [sp, #0x10]
     0x1000822f8 <+24>: ldr    w9, [x0, #0x20]
     0x1000822fc <+28>: mov    x0, x9
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容