iOS逆向-04:if 、循环、switch

int g = 12;

int func(int a,int b){
    printf("boy");
    int c = a + g + b;
    return c;
}

int main(int argc, char * argv[]) {
   
    func(10, 20);
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
image.png

adrp

adrp(Address Page)
内存地址按页寻址

取常量

adrp x0, 1
这句代码的操作如下:
将1的值左移12位得到0x1000
将0x1048ae12c的低12位清零得到0x1048ae000
将0x1000和0x1048ae000相加得到0x1048af000
add x0, x0, #0xf89
0x1048af000 + 0xf89 = 0x1048aff89
此时x0的值为0x1048aff89,这个地址里面存的也就是"boy"

一个页的大小是4096,而0xFFF为4095,加上1就是0x1000(即4096),所以是1左移12位即可得到一个页的首地址(注:macOS的pageSize是 4k(0x1000),而iPhone的pageSize是16k(0x4000),但是16仍是4的倍数,adrp兼容者mac和iPhone,所以此时定位的仍然是一页数据)

全局变量也是一样

image.png

Hopper反汇编

image.png
image.png

image.png

全局变量g = 0xc 也就是12
也可以通过mach-o来查看


image.png
image.png

还原代码

int gl = 12;

int funcC(int a, int b) {
//    0000000100006118         sub        sp, sp, #0x20                               ; CODE XREF=_main+32
//    000000010000611c         stp        x29, x30, [sp, #0x10]
//    0000000100006120         add        x29, sp, #0x10
    
//    0000000100006124         stur       w0, [x29, #-0x4]
//    0000000100006128         str        w1, [sp, #0x8]
//    000000010000612c         adrp       x0, #0x100007000                            ; argument #1 for method imp___stubs__printf

//    0000000100006130         add        x0, x0, #0xf89                              ; "boy"
//    0000000100006134         bl         imp___stubs__printf
    
    printf("boy");
//    0000000100006138         ldur       w8, [x29, #-0x4]
    int w8 = a;
//    000000010000613c         adrp       x9, #0x10000d000
//    0000000100006140         add        x9, x9, #0x570                              ; _g
    int x9 = gl;
//    0000000100006144         ldr        w10, x9
//    0000000100006148         add        w8, w8, w10
    int w10 = x9;
    w8 = w8 + w10;
//    000000010000614c         ldr        w10, [sp, #0x8]
    w10 = b;
//    0000000100006150         add        w8, w8, w10
    w8 += w10;
//    0000000100006154         str        w8, [sp, #0x4]
//    0000000100006158         ldr        w8, [sp, #0x4]
    
//    000000010000615c         mov        x0, x8
    int w0 = w8;
//    0000000100006160         ldp        x29, x30, [sp, #0x10]
//    0000000100006164         add        sp, sp, #0x20
    return w0;
}

继续精简还原

从下往上还原

int funcC(int a, int b) {
    printf("boy");
    int w8 = a;
    int x9 = gl;
    int w10 = x9;
    w8 = w8 + w10;
//    w10 = b;
//    w8 += w10;
//    int w0 = w8;
//   return w0;
    return w8+b;//上面几句还原
}

依次类推得到最终结果

int gl = 12;
int funcC(int a, int b) {
    printf("boy");
    return a+gl+b;
}

if 语句

我们看看下面代码的汇编

int g = 12;
void func(int a,int b){
    if (a > b) {
        g = a;
    }else{
        g = b;
    }
}
image.png

通过上面可以看出if else 判断就是 通过cmp + 标号实现的,大于小于都是通过cmp相减。

cmp(Compare)比较指令

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

  • BL 标号:跳转到标号处执行
  • B.GT 标号:比较结果是大于(greater than),执行标号,否则不跳转
  • B.GE 标号:比较结果是大于等于(greater than or equal to),执行标号,否则不跳转
  • B.EQ 标号:比较结果是等于,执行标号,否则不跳转
  • B.HI 标号:比较结果是无符号大于,执行标号,否则不跳转
  • B.LT 标号:比较结果是小于,执行标号,否则不跳转
  • B.LE 标号:比较结果是小于等于,执行标号,否则不跳转
  • B.NE 标号:比较结果是不等于,执行标号,否则不跳转
  • B.LS 标号:比较结果是无符号小于等于,执行标号,否则不跳转
  • B.LO 标号:比较结果是无符号小于,执行标号,否则不跳转
  • B.HI 标号:比较结果是无符号大于,执行标号,否则不跳转
  • B.HS 标号:比较结果是无符号大于等于,执行标号,否则不跳转

循环

for (int i = 0; i < 100; i++) {
        nSum = nSum + 1;
    }
image.png

Switch

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

1 .当有三个case时,可以看到汇编和if else if 是一样的


image.png
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容