zoukankan      html  css  js  c++  java
  • iOS程序破解——ARM汇编基础

    原文在此:http://www.cnblogs.com/mddblog/p/4951650.html

    一、Thumb指令与ARM指令

    Thumb指令为16位,因此存储代码的密度高,节省存储空间。但是功能不全,它只是ARM指令(32位)集的补充,是ARM指令集下的一个子集。在初级阶段我们不需要了解这些知识,只要有个概念知道有这么个东西就可以。

    二、ARM的寄存器初步了解

      R0-R3:        用于函数参数及返回值的传递,超过4个参数,其它参数存在栈中,在ARM中栈是向下生长的,R0还可以作为返回值。
      R4-R6, R8, R10-R11: 没有特殊规定,就是普通的通用寄存器
      R7:          栈帧指针,指向母函数与被调用子函数在栈中的交界。
      R9:          在iOS3.0被操作系统保留
      R12:          内部过程调用寄存器,动态链接时会用到,不必深究
      R13:          SP(stack pointer),是栈顶指针
      R14:          LR(link register),存放函数的返回地址。
      R15:          PC(program counter),指向当前指令地址。
      CPSR:         当前程序状态寄存器,在用户状态下存放像condition标志中断禁用等标志的。
      另外还有VFP(向量浮点运算)相关的寄存器,不在列举。

    三、常用汇编

      助记符  说明
      ADC    带进位的加法
      ADD    加法
      AND    逻辑与
      B      分支跳转,很少单独使用
      BL          分支跳转,跳转后返回地址存入r14
      BX          分支跳转,并切换指令模式(Thumb/ARM)
      CMP        比较值,结果存在程序状态寄存器,一般用于分支判断
      BEQ        结果为0则跳转
      BNE        结果不为0跳转
      LDR        加载寄存器,从内存加载到寄存器
      LDRB      装载字节到寄存器
      LDRH      装载半字到寄存器(一个字是32位)
      LSL         逻辑左移 这是一个选项,不是指令
      LSR         逻辑右移 这是一个选项,不是指令
      MOV        传送值/寄存器到一个寄存器 
      STR         存储一个寄存器,寄存器值存到内存
      STRB       存储一个字节
      STRH       存储一个半字
      SUB         减法
      PUSH POP 堆栈操作

      更多指令请参考这里

    四、函数调用

      函数的参数、局部变量、返回地址都在栈上存着,这部分栈上的内存称为栈帧。和R0~R15(不一定全部)、CPSR等一起构成了函数的运行环境。每一个函数系统都会分配一个栈帧,执行完成后系统自动收回。每个函数都以为R0~R15、CPSR等CPU相关寄存器为自己一人享有,所以要做一些必要操作。

      举个例子:假设A调用B时,那么A要保存自己的运行环境(保存现场),B执行完后,要恢复A的运行环境(恢复现场);另外A还可以通过R0—R4来传递参数,参数超过4个可以通过栈,B返回时可以通过R0传递返回值。其中主要涉及的就是栈的操作和寄存器的操作。下图为函数调用前后栈的布局,左边为调用前,右边为调用后,当B返回时应回到左边状态(A调用B之前的状态,就像没有调用B一样)。

      在上图中,一个栈帧除了已经提到的参数区域(parameter area)、链接区域(linkage area)、局部变量存储区(local storage area)外还有栈帧指针存放区域(saved frame pointer)、寄存器存储区(saved registers area),栈帧指针上面已介绍(R7);寄存器存储区:保存非易失寄存器(R4,R5,R6,R8,R10,R11),后面的汇编代码例子会介绍。

      开始调用(现场保护):

      1)LR入栈;

      2)R7入栈,包存要恢复的寄存器入栈;

      3)R7 = SP地址;

      4)将callee会修改且在返回caller时需要恢复的寄存器入栈;

      5)分配栈空间给子程序使用。

      下图为汇编代码(使用hopper disassemble反编译的代码),分析如下:

      第一行:将LR, R7, R4-R6入栈;

      第二行:r7=sp-0xc(指向old R7),之所以减去0xc因为PUSH后,r4,r5,r6占去12个字节;

      第三行:保存要恢复的寄存器;

      第四行:给当前函数开辟栈空间。

      函数返回(恢复现场):

      1)释放栈空间;

      2)恢复所保存的寄存器;

      3)恢复R7;

      4)将之前存放的LR从栈上弹出到PC,这样函数就返回了。

      下图为汇编代码(使用hopper disassemble反编译的代码),分析如下:

      第一行:释放栈空间;

      第二行:恢复保存的寄存器;

      第三行:恢复保存的寄存器,恢复R7,将之前存放的LR从栈上弹出到PC。

      更详细函数调用请参考这里

      iOS内存分区请参考这里

     

     

  • 相关阅读:
    Spring总结九:事务管理机制
    Spring总结七:AOP动态代理的实现
    Spring总结六:AOP(面向切面编程)
    Nginx静态网站的部署
    Spring总结五:小结 使用spring访问servlet
    javascript 的dateObj.getTime() 在为C#的获取方式
    操作JavaScript数组
    判断是否是对象的原型
    JavaScript判断对象 是什么类型的.
    Javascript中类型: undefined, number ,string ,object ,boolean
  • 原文地址:https://www.cnblogs.com/mddblog/p/4951650.html
Copyright © 2011-2022 走看看