iOS 逆向工程 app安全 网络安全iOS逆向工程女程序猿

iOS 汇编基础(三)还原高级代码之循环和判断

2018-05-02  本文已影响33人  meryin

一 if 和 if else

1. if
int g = 30;
void func(int a,int b){
   if (a >b) {
     g = a;
   }
 }

int main(int argc, char * argv[]) {
    func(10, 20);
   return 0;
}

上面func的汇编代码如下:

067A0 _func                                   ; CODE XREF: _main+28↓p

 var_8           = -8
 var_4           = -4
 SUB             SP, SP, #0x10 //拉伸栈空间
STR             W0, [SP,#0x10+var_4] //把w0写入内存 int var_4=w0
STR             W1, [SP,#0x10+var_8] //把w1写入内存 int var_8 =w1
LDR             W0, [SP,#0x10+var_4] //把w0从内存var_4中读出来 int w0= var_4
LDR             W1, [SP,#0x10+var_8] //把w1从内存var_8中读出来 int w1= var_8
 CMP             W0, W1  //比较w0和w1
B.LE            loc_1000067CC  //如果w0<=w1那么跳转到loc_1000067CC处执行
ADRP            X8, #_g@PAGE 
ADD             X8, X8, #_g@PAGEOFF  //以上两句获取全局变量g的储存地址
LDR             W9, [SP,#0x10+var_4]  //int w9=var_4
STR             W9, [X8]  // 把w9读到x8的内存地址中去,即 *x8=w9

 loc_1000067CC                          
                ADD             SP, SP, #0x10  //恢复栈 栈平衡
                RET    //返回的时候没有任何操作以及没有对x0进行操作,所以没有返回值

main函数的汇编如下:

 _main
__text:00000001000068F8
__text:00000001000068F8 var_10          = -0x10
__text:00000001000068F8 var_8           = -8
__text:00000001000068F8 var_4           = -4
__text:00000001000068F8 var_s0          =  0
__text:00000001000068F8
__text:00000001000068F8                 SUB             SP, SP, #0x20
__text:00000001000068FC                 STP             X29, X30, [SP,#0x10+var_s0]
__text:0000000100006900                 ADD             X29, SP, #0x10
__text:0000000100006904                 MOV             W8, #0xA
__text:0000000100006908                 MOV             W9, #0x14
__text:000000010000690C                 STUR            WZR, [X29,#var_4]
__text:0000000100006910                 STR             W0, [SP,#0x10+var_8]
__text:0000000100006914                 STR             X1, [SP,#0x10+var_10]
__text:0000000100006918                 MOV             X0, X8
__text:000000010000691C                 MOV             X1, X9
__text:0000000100006920                 BL              _func
__text:0000000100006924                 MOV             W8, #0
__text:0000000100006928                 MOV             X0, X8
__text:000000010000692C                 LDP             X29, X30, [SP,#0x10+var_s0]
__text:0000000100006930                 ADD             SP, SP, #0x20
__text:0000000100006934                 RET
__text:0000000100006934 ; End of function _main
void func(int a, int b)
{
  int var_4=w0;
  int var_8 =w1;
  int w0= var_4;
  int w1= var_8;
  if (w0 <= w1}
  {
      return;
  }
  g = *x8;
  int w9=var_4;
  *x8 = w9;
}  由此获得 void func(int a,intb){ if (a>b){g = a} }
2. if else
int  func(){
    int a=10;
    int b=20;
    if (a >b) {
        g = a;
    }
    else{
         g=b;
    }
    return g;
}

汇编如下:

 var_8           = -8
var_4           = -4
SUB             SP, SP, #0x10   //拉伸16字节栈空间
MOV             W8, #0x14   //int w8 = 0x14即int w8=20;
MOV             W9, #0xA   //int w9 = 10;
STR             W9, [SP,#0x10+var_4]    
STR             W8, [SP,#0x10+var_8]
LDR             W8, [SP,#0x10+var_4]
LDR             W9, [SP,#0x10+var_8]   //以上为w8,w9进行内存保护
CMP             W8, W9  // if(w8 <= w9)执行loc_1000068E0处代码
B.LE            loc_1000068E0
ADRP            X8, #_g@PAGE
ADD             X8, X8, #_g@PAGEOFF  //获取全局变量g
LDR             W9, [SP,#0x10+var_4]
STR             W9, [X8]    //x8地址的内容为var_4的内容
B               loc_1000068F0  //跳转到loc_1000068F0处执行
---------------------------------------------------------------------------
 loc_1000068E0                         
ADRP            X8, #_g@PAGE
ADD             X8, X8, #_g@PAGEOFF //获取全局变量g储存到x8的地址中
LDR             W9, [SP,#0x10+var_8]
 STR             W9, [X8]  //x8的内容为var_8的内容

 loc_1000068F0                          
ADRP            X8, #_g@PAGE
ADD             X8, X8, #_g@PAGEOFF //获取全局变量g储存到x8的地址中
LDR             W0, [X8] //x8的内容为x0的内容
ADD             SP, SP, #0x10 //栈平衡
RET

int func()
{
  int w8 = 20;
  int w9=10;
  if(w8 > w9)
  {
    g=w8;
   }
  else{
    g = w9;
  }
  *x8 = g;
  int w0=*x8;
  return w0;
}
总结:CMP 和B.LE(小于等于)再加上B组成if else,只有cmp和B组成if等判断语句

二 常见的cmp(Compare)比较指令

CMP 把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志。
一般CMP做完判断后会进行跳转,后面通常会跟上B指令!

三 循环

1. do while
void funa(int a)
{
    do{
        a++;
    }while (a<=g);
    /*
 var_4           = -4
 SUB             SP, SP, #0x10
 STR             W0, [SP,#0x10+var_4]  //参数w0入栈 int var_4 = w0;
loc_1000068D4 
 LDR             W8, [SP,#0x10+var_4]  //int w8= var_4;
ADD             W8, W8, #1     //int w8=w8+1;
STR             W8, [SP,#0x10+var_4]  //int var_4 = w8;
 ADRP            X8, #_g@PAGE
ADD             X8, X8, #_g@PAGEOFF  // *x8 = g
 LDR             W9, [SP,#0x10+var_4]  //int w9= var_4;
LDR             W10, [X8]  //w10=*x8;
CMP             W9, W10  
 B.LE            loc_1000068D4 // if(w9 <=w10)返回去执行loc_1000068D4
ADD             SP, SP, #0x10 //栈平衡
 RET
     */
    
}
2. while
void funb(int b){
    while (b<g) {
        b++;
    }
    /*
 var_4           = -4
 SUB             SP, SP, #0x10
STR             W0, [SP,#0x10+var_4]
 loc_1000068D0                           
 ADRP            X8, #_g@PAGE
 ADD             X8, X8, #_g@PAGEOFF
 LDR             W9, [SP,#0x10+var_4]
 LDR             W10, [X8]
 CMP             W9, W10
B.GE            loc_1000068F8
 LDR             W8, [SP,#0x10+var_4]
ADD             W8, W8, #1
 STR             W8, [SP,#0x10+var_4]
B               loc_1000068D0
 ---------------------------------------------------------------------------
 loc_1000068F8                      
 ADD             SP, SP, #0x10
RET
     */
}
3. for循环
void func(int a){
    int sum = 0;
    for (int i=0;i<a; i++) {
        sum +=i;
    }
}

int main(int argc, char * argv[]) {
    func(3);
    return 0;
}

func的汇编代码是:

 var_C           = -0xC
 var_8           = -8
 var_4           = -4

SUB             SP, SP, #0x10
STR             W0, [SP,#0x10+var_4]
STR             WZR, [SP,#0x10+var_8]
 STR             WZR, [SP,#0x10+var_C]

 loc_1000068C8                          
LDR             W8, [SP,#0x10+var_C]
 LDR             W9, [SP,#0x10+var_4]
CMP             W8, W9
 B.GE            loc_1000068F8
 LDR             W8, [SP,#0x10+var_C]
LDR             W9, [SP,#0x10+var_8]
ADD             W8, W9, W8
STR             W8, [SP,#0x10+var_8]
LDR             W8, [SP,#0x10+var_C]
ADD             W8, W8, #1
STR             W8, [SP,#0x10+var_C]
B               loc_1000068C8
 ---------------------------------------------------------------------------

 loc_1000068F8                          
ADD             SP, SP, #0x10
RET

四 Swicth

1. case选择条件连续且分支小于等于3时

代码如下:


void funA(int a){
    switch (a) {
        case 1:
            printf("1");
            break;
        case 2:
            printf("2");
            break;
        case 3:
            printf("3");
            break;
        default:
            printf("default");
            break;
    }
}

int main(int argc, char * argv[]) {
    funA(2);
    return 0;
}

xcode动态汇编分析如下:


2. case选择条件连续且分支大于3时

代码如下:

void funA(int a){
    switch (a) {
        case 1:
            printf("1");
            break;
        case 2:
            printf("2");
            break;
        case 3:
            printf("3");
            break;
        case 4:
            printf("4");
            break;
        default:
            printf("default");
            break;
    }
}
1.png
switch总结:

1、假设switch语句的分支比较少的时候(例如3,少于4的时候没有意义)没有必要使用此结构,相当于if。
2、各个分支常量的差值较大的时候,编译器会在效率还是内存进行取舍,这个时候编译器还是会编译成类似于if,else的结构。
3、在分支比较多的时候:在编译的时候会生成一个表(跳转表每个地址四个字节)。

五 查看全局或者常量

int sum(int a, int b){
    printf("string");
    return a + 3*g;
}
0x100aee7d0 <+20>: adrp   x0, 1
0x100aee7d4 <+24>: add    x0, x0, #0xf18            ; =0xf18 
0x100aee7d8 <+28>: bl     0x100aeebe8               ; symbol stub for: printf

1、x0=0x100aee7d0去掉低12位 0x=0x100aee000;1左移3位得到0x1000,0x=0x100aef000
2、0x=0x+0xf18即0x=0x100aeff18
3、用p (char*)0x100aeff18查看得到(char *) $1 = 0x0000000100aeff18 "string"

六 编译器优化

int sum(int a, int b){
    printf("string");
    return a +b;
}
int main(int argc, char * argv[]) {
    int c = sum(1, 2);
    return 0;
}
 0x10050ab44 <+0>:  stp    x29, x30, [sp, #-0x10]!
    0x10050ab48 <+4>:  mov    x29, sp
    0x10050ab4c <+8>:  adr    x0, #0x13cc               ; "string"
    0x10050ab50 <+12>: nop    
    0x10050ab54 <+16>: bl     0x10050abd0               ; symbol stub for: printf
->  0x10050ab58 <+20>: mov    w0, #0x0
    0x10050ab5c <+24>: ldp    x29, x30, [sp], #0x10
    0x10050ab60 <+28>: ret    
int main(int argc, char * argv[]) {
    int c = sum(1, 2);
    NSLog(@"%d",c);
    return 0;
}

就算用到了int c,编译器会直接把结果赋给c:

  0x1001e2b10 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x1001e2b14 <+4>:  stp    x29, x30, [sp, #0x10]
    0x1001e2b18 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x1001e2b1c <+12>: adr    x0, #0x13fc               ; "string"
    0x1001e2b20 <+16>: nop    
    0x1001e2b24 <+20>: bl     0x1001e2bc4               ; symbol stub for: printf
->  0x1001e2b28 <+24>: orr    w8, wzr, #0x3
    0x1001e2b2c <+28>: str    x8, [sp]
    0x1001e2b30 <+32>: adr    x0, #0x1508               ; @"%d"
    0x1001e2b34 <+36>: nop    
    0x1001e2b38 <+40>: bl     0x1001e2ba0               ; symbol stub for: NSLog
    0x1001e2b3c <+44>: mov    w0, #0x0
    0x1001e2b40 <+48>: ldp    x29, x30, [sp, #0x10]
    0x1001e2b44 <+52>: add    sp, sp, #0x20             ; =0x20 
    0x1001e2b48 <+56>: ret    

六 多线程之间共用寄存器,会对当前寄存器进行保护,操作系统会对内存进行保护,以防止资源抢夺。

上一篇 下一篇

猜你喜欢

热点阅读