iOS【安全攻防】初识汇编

今天我们来学习以下内容:

  • 汇编概述
  • 总线
  • 进制
  • 寄存器


我们在学习逆向开发之前,我们要了解一个基本的逆向原理。首先我们是逆向iOS系统上面的APP,那么我们知道,一个APP安装在手机上面的可执行文件本质上是二进制文件,因为iPhone手机本质上执行的指令是二进制,是由手机上的CPU执行的,所以逆向开发是建立在分析二进制上面。

一、汇编概述

1、汇编语言的发展

(1)机器语言

由0和1组成的机器指令(说白了是电信号)

    • 加:0100 0000
    • 减:0100 1000
    • 乘:1111 0111 1110 0000
    • 除:1111 0111 1111 0000

我们所写的代码最终跑在机器上的是什么东西?是机器语言,是一堆的0,1,也叫做指令。

(2)汇编语言(assembly language)

使用助记符代替机器语言,也称为符号语言

    • 加:INC EAX 通过编译器 0100 0000
    • 减:DEC EAX 通过编译器 0100 1000
    • 乘:MUL EAX 通过编译器 1111 0111 1110 0000
    • 除:DIV EAX 通过编译器 1111 0111 1111 0000

(3)高级语言(High-level programming language)

C\C++\Java\OC\Swift,更加接近人类的自然语言
比如C语言:

    • 加:A+B 通过编译器 0100 0000
    • 减:A-B 通过编译器 0100 1000
    • 乘:A*B 通过编译器 1111 0111 1110 0000
    • 除:A/B 通过编译器 1111 0111 1111 0000

我们的代码在终端设备上是这样的过程:

  • 汇编语言与机器语言一一对应,每一条机器指令都有与之对应的汇编指令
  • 汇编语言可以通过编译得到机器语言,机器语言可以通过反汇编得到汇编语言
  • 高级语言可以通过编译得到汇编语言 \ 机器语言,但汇编语言\机器语言几乎不可能还原成高级语言

2、汇编语言的特点

  • 可以直接访问、控制各种硬件设备,比如存储器、CPU等,能最大限度地发挥硬件的功能
  • 能够不受编译器的限制,对生成的二进制代码进行完全的控制
  • 目标代码简短,占用内存少,执行速度快
  • 汇编指令是机器指令的助记符,同机器指令一一对应。每一种CPU都有自己的机器指令集\汇编指令集,所以汇编语言不具备可移植性
  • 知识点过多,开发者需要对CPU等硬件结构有所了解,不易于编写、调试、维护
  • 不区分大小写,比如mov和MOV是一样的

3、汇编的用途

  • 编写驱动程序、操作系统(比如Linux内核的某些关键部分)
  • 对性能要求极高的程序或者代码片段,可与高级语言混合使用(内联汇编)
  • 软件安全
    • 病毒分析与防治
    • 逆向\加壳\脱壳\破解\外挂\免杀\加密解密\漏洞\黑客
  • 理解整个计算机系统的最佳起点和最有效途径
  • 为编写高效代码打下基础
  • 弄清代码的本质
    • 函数的本质究竟是什么?
    • sizeof
    • ++a + ++a + ++a 底层如何执行的?
    • 编译器到底帮我们干了什么?
    • DEBUG模式和RELEASE模式有什么关键的地方被我们忽略
    • ......

越底层越单纯!真正的程序员都需要了解的一门非常重要的语言,汇编!

4、汇编语言的种类

目前讨论比较多的汇编语言有

  • 8086汇编(8086处理器是16bit的CPU)
  • Win32汇编
  • Win64汇编
  • ARM汇编(嵌入式、Mac、iOS)
  • ......

我们iPhone里面用到的是ARM汇编,但是不同的设备也有差异.因CPU的架构不同.

架构 设备
armv6 iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touc
armv7 iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4
armv7s iPhone5, iPhone5C, iPad4(iPad with Retina Display)
arm64 iPhone5S 以后 iPhoneX , iPad Air, iPad mini2以后

5、几个必要的常识

  • 要想学好汇编,首先需要了解CPU等硬件结构
  • APP/程序的执行过程

  • 硬件相关最为重要是CPU/内存
  • 在汇编中,大部分指令都是和CPU与内存相关的

二、总线

                      

  • 每一个CPU芯片都有许多管脚,这些管脚和总线相连,CPU通过总线跟外部器件进行交互
  • 总线:一根根导线的集合
  • 总线的分类
    • 地址总线
    • 数据总线
    • 控制总线

举个例子:

1、地址总线

  • 它的宽度决定了CPU的寻址能力
  • 8086的地址总线宽度是20,所以寻址能力是1M( 220 )

2、数据总线

  • 它的宽度决定了CPU的单次数据传送量,也就是数据传送速度
  • 8086的数据总线宽度是16,所以单次最大传递2个字节的数据

3、控制总线

  • 它的宽度决定了CPU对其他器件的控制能力、能有多少种控制
做个小练习
* 一个CPU 的寻址能力为8KB,那么它的地址总线的宽度为____
* 8080,8088,80286,80386 的地址总线宽度分别为16根,20根,24根,32根.那么他们的寻址能力分别为多少____KB, ____MB,____MB,____GB?
* 8080,8088,8086,80286,80386 的数据总线宽度分别为8根,8根,16根,16根,32根.那么它们一次可以传输的数据为:____B,____B,____B,____B,____B,
* 从内存中读取1024字节的数据,8086至少要读____次,80386至少要读取____次.
答案:
* 13
* 64KB  1MB  16MB  4GB
* 1B    1B   2B    2B   4B
* 512   256

    

  • 内存地址空间的大小受CPU地址总线宽度的限制。8086的地址总线宽度为20,可以定位220个不同的内存单元(内存地址范围0x00000~0xFFFFF),所以8086的内存空间大小为1MB
  • 0x00000~0x9FFFF:主存储器。可读可写
  • 0xA0000~0xBFFFF:向显存中写入数据,这些数据会被显卡输出到显示器。可读可写
  • 0xC0000~0xFFFFF:存储各种硬件\系统信息。只读

三、进制

学习进制的障碍:

很多人学不好进制,原因是总以十进制为依托去考虑其他进制,需要运算的时候也总是先转换成十进制,这种学习方法是错误的.
我们为什么一定要转换十进制呢?仅仅是因为我们对十进制最熟悉,所以才转换.
每一种进制都是完美的,想学好进制首先要忘掉十进制,也要忘掉进制间的转换!

1、进制的定义

  • 八进制由8个符号组成:0 1 2 3 4 5 6 7 逢八进一
  • 十进制由10个符号组成:0 1 2 3 4 5 6 7 8 9逢十进一
  • N进制就是由N个符号组成:逢N进一

1 + 1 在____情况下等于 3 ? 十进制由10个符号组成: 0 1 3 2 8 A B E S 7 逢十进一,如果这样定义十进制: 1 + 1 = 3!就对了!这样的目的何在?传统我们定义的十进制和自定义的十进制不一样,那么这10个符号如果我们不告诉别人这个符号表,别人是没办法拿到我们的具体数据的!用于加密!十进制由十个符号组成,逢十进一,符号是可以自定义的!!

2、进制的运算

做个练习:

八进制运算
2 + 3 = __ , 2 * 3 = __ ,4 + 5 = __ ,4 * 5 = __.
277 + 333 = __ , 276 * 54 = __ , 237 - 54 = __ , 234 / 4 = __ .

实战四则运算:
   277         236         276         234
+  333       -  54       *  54       /   4
--------    --------    --------    --------

八进制加法表:

 0  1  2  3  4  5  6  7
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
...

1+1 = 2
1+2 = 3   2+2 = 4
1+3 = 4   2+3 = 5   3+3 = 6
1+4 = 5   2+4 = 6   3+4 = 7   4+4 = 10
1+5 = 6   2+5 = 7   3+5 = 10  4+5 = 11  5+5 = 12
1+6 = 7   2+6 = 10  3+6 = 11  4+6 = 12  5+6 = 13  6+6 = 14
1+7 = 10  2+7 = 11  3+7 = 12  4+7 = 13  5+7 = 14  6+7 = 15  7+7 = 16

八进制乘法表:

0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27...
1*1 = 1
1*2 = 2   2*2 = 4
1*3 = 3   2*3 = 6   3*3 = 11
1*4 = 4   2*4 = 10  3*4 = 14  4*4 = 20
1*5 = 5   2*5 = 12  3*5 = 17  4*5 = 24  5*5 = 31
1*6 = 6   2*6 = 14  3*6 = 22  4*6 = 30  5*6 = 36  6*6 = 44
1*7 = 7   2*7 = 16  3*7 = 25  4*7 = 34  5*7 = 43  6*7 = 52  7*7 = 61

3、二进制的简写形式

       二进制: 1 0 1 1 1 0 1 1 1 1 0 0
三个二进制一组: 101 110 111 100
       八进制:   5   6   7   4
四个二进制一组: 1011 1011 1100
     十六进制:    b    b    c

二进制:从0 写到 1111
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
这种二进制使用起来太麻烦,改成更简单一点的符号:
0 1 2 3 4 5 6 7 8 9 A B C D E F 这就是十六进制了

//十六进制古时候就有了,古秤,半斤八两

4、数据的宽度

数学上的数字,是没有大小限制的,可以无限的大。但在计算机中,由于受硬件的制约,数据都是有长度限制的(我们称为数据宽度),超过最多宽度的数据会被丢弃。

输入以下代码:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int test(){
    int cTemp = 0x1FFFFFFFF;
    return cTemp;
}

int main(int argc, char * argv[]) {
    printf("%x\n",test());//ffffffff
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

我们可以看到1是存不进去的,int类型占4个字节(如下图)

计算机中常见的数据宽度:

  • 位(Bit): 1个位就是1个二进制位.0或者1
  • 字节(Byte): 1个字节由8个Bit组成(8位).内存中的最小单元Byte.
  • 字(Word): 1个字由2个字节组成(16位),这2个字节分别称为高字节和低字节.
  • 双字(Doubleword): 1个双字由两个字组成(32位)

那么计算机存储数据它会分为有符号数和无符号数.那么关于这个看图就理解了!

无符号数,直接换算!
有符号数:
正数:  0    1    2    3    4    5    6    7
负数:  F    E    D    B    C    A    9    8
      -1   -2   -3   -4   -5   -6   -7   -8

5、自定义进制符号

练习

现在有10进制数 10个符号分别是:2,9,1,7,6,5,4, 8,3 , A 逢10进1 那么: 123 + 234 = ____

十进制:    0  1  2  3  4  5  6  7  8  9
自定义:    2  9  1  7  6  5  4  8  3  A
         92 99 91 97 96 95 94 98 93 9A
         12 19 11 17 16 15 14 18 13 1A
         72 79 71 77 76 75 74 78 73 7A
         62 69 61 67 66 65 64 68 63 6A
         52 59 51 57 56 55 54 58 53 5A
         42 49 41 47 46 45 44 48 43 4A
         82 89 81 87 86 85 84 88 83 8A
         32 39 31 37 36 35 34 38 33 3A
         922
那么刚才通过10进制运算可以转化10进制然后查表!但是如果是其他进制.我们就不能转换,要直接学会查表

现在有9进制数 9个符号分别是:2,9,1,7,6,5,4, 8,3 逢9进1 那么: 123 + 234 = ____

十进制:    0  1  2  3  4  5  6  7  8
自定义:    2  9  1  7  6  5  4  8  3
         92 99 91 97 96 95 94 98 93
         12 19 11 17 16 15 14 18 13
         72 79 71 77 76 75 74 78 73
         62 69 61 67 66 65 64 68 63
         52 59 51 57 56 55 54 58 53
         42 49 41 47 46 45 44 48 43
         82 89 81 87 86 85 84 88 83
         32 39 31 37 36 35 34 38 33
         922

四、寄存器

内部部件之间由总线连接

  • 对程序员来说,CPU中最主要部件是寄存器,可以通过改变寄存器的内容来实现对CPU的控制
  • 不同的CPU,寄存器的个数、结构是不相同的

1、通用寄存器

  • ARM64拥有有31个64位的通用寄存器 x0 到 x30,这些寄存器通常用来存放一般性的数据,称为通用寄存器(有时也有特定用途)

    • 那么w0 到 w28 这些是32位的. 因为64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
    • 比如 w0 就是 x0的低32位!

  • 通常,CPU会先将内存中的数据存储到通用寄存器中,然后再对通用寄存器中的数据进行运算
  • 假设内存中有块红色内存空间的值是3,现在想把它的值加1,并将结果存储到蓝色内存空间

    • CPU首先会将红色内存空间的值放到X0寄存器中:mov X0,红色内存空间
    • 然后让X0寄存器与1相加:add X0,1
    • 最后将值赋值给内存空间:mov 蓝色内存空间,X0

2、pc寄存器(program counter)

  • 为指令指针寄存器,它指示了CPU当前要读取指令的地址
  • 在内存或者磁盘上,指令和数据没有任何区别,都是二进制信息
  • CPU在工作的时候把有的信息看做指令,有的信息看做数据,为同样的信息赋予了不同的意义
    • 比如 1110 0000 0000 0011 0000 1000 1010 1010
    • 可以当做数据 0xE003008AA
    • 也可以当做指令 mov x0, x8
  • CPU根据什么将内存中的信息看做指令?
    • CPU将pc指向的内存单元的内容看做指令
    • 如果内存中的某段内容曾被CPU执行过,那么它所在的内存单元必然被pc指向过

3、bl指令

  • CPU从何处执行指令是由pc中的内容决定的,我们可以通过改变pc的内容来控制CPU执行目标指令
  • ARM64提供了一个mov指令(传送指令),可以用来修改大部分寄存器的值,比如
    • mov x0,#10、mov x1,#20
  • 但是,mov指令不能用于设置pc的值,ARM64没有提供这样的功能
  • ARM64提供了另外的指令来修改PC的值,这些指令统称为转移指令,最简单的是bl指令
bl指令 -- 练习

现在有两段代码!假设程序先执行A,请写出指令执行顺序.最终寄存器x0的值是多少?

_A:
    mov x0,#0xa0
    mov x1,#0x00
    add x1, x0, #0x14
    mov x0,x1
    bl _B
    mov x0,#0x0
    ret

_B:
    add x0, x0, #0x10
    ret

原文地址:https://www.cnblogs.com/wangchan/p/8809521.html

时间: 2024-11-09 00:43:46

iOS【安全攻防】初识汇编的相关文章

iOS安全攻防(二十三):Objective-C代码混淆

iOS安全攻防(二十三):Objective-C代码混淆 class-dump可以很方便的导出程序头文件,不仅让攻击者了解了程序结构方便逆向,还让着急赶进度时写出的欠完善的程序给同行留下笑柄. 所以,我们迫切的希望混淆自己的代码. 混淆的常规思路 混淆分许多思路,比如: 1)花代码花指令,即随意往程序中加入迷惑人的代码指令 2)易读字符替换 等等 防止class-dump出可读信息的有效办法是易读字符替换. Objective-C的方法名混淆 混淆的时机 我们希望在开发时一直保留清晰可读的程序代

iOS安全攻防(二十四):敏感逻辑的保护方案(1)

iOS安全攻防(二十四):敏感逻辑的保护方案(1) Objective-C代码容易被hook,暴露信息太赤裸裸,为了安全,改用C来写吧! 当然不是全部代码都要C来写,我指的是敏感业务逻辑代码. 本文就介绍一种低学习成本的,简易的,Objective-C逻辑代码重写为C代码的办法. 也许,程序中存在一个类似这样的类: @interface XXUtil : NSObject + (BOOL)isVerified; + (BOOL)isNeedSomething; + (void)resetPass

iOS安全攻防之使用 Frida 绕过越狱设备检测

Frida 是 一款有趣的手机应用安全分析工具. 文章参考:Bypass Jailbreak Detection with Frida in iOS applications

汇编语言1:初识汇编

我这里学习汇编语言的思路就是逆向C++源码. 先从最简单的一个程序入手: 为什么程序的开头两句总会是 push ebp mov ebp,esp ? 先来看一个程序: 这个程序调用fun()时,fun的汇编代码也是如此,开头调用这两句汇编: 其实,这里ebp中保存的是你当前的函数(main函数)的栈基址,当你进入一个子函数(func函数)的时候,你要使用这个子函数的栈空间,此时进入子函数的栈空间就要先保存当前函数的栈基址.将此时的 esp 赋予 ebp 以便后面用 ebp 来作为栈基并以此通过 [

开窍小老虎,一步一个脚印之 初识汇编(一)

最近一直浸淫在计算机编程中无法自拔.哲学 认识论中讲过.人类的求知的过程是由两次飞跃.第一是从感性认识到理性认识:第二是从理性认识到实践.这段话对有些人是适用的.我就是其中的一名.在知乎上求助问题“学计算机要懂汇编吗?”,地下有人回复说,对有些人是必须要学会的.因为当我们满脸疑惑的问别人,别人可能会甩我们一脸“你问这个有用吗?”,可我们的脑袋上都套着一句话“你不明白这个,你怎么能看第二章呢?”,对于我来讲,知识的断层是特别影响我求知的道路. 说说我的学习路线.<VS2010轻松学习C#-从零到深

iOS开发-Quartz2D初识

Quartz2D如果单独的从Quartz,那么会发现Quartz是一个开源的Java作业调度框架,单独从英文翻译的角度来看的话Quartz的英文是石英,如果有的时候不小心搜索会发现手表推荐.本文中介绍的Quartz是位于MAC OS X的Drawin核心之上的绘图层,有时候也认为是CoreGraphics.Quartz直接地支持Aqua,借由显示2D绘图图形来创建用户接口,包含实时绘制(rendering)和次像素(sub-pixel)精准的反锯齿,由Quartz Compositor和Quar

开窍小老虎,一步一个脚印之 初识汇编(二)

汇编语言,有三类指令组成: 1:汇编指令,机器码的助记符,有对应的机器码 2:伪指令:没有对应的机器码,由编译器执行,计算机并不执行 3:其他符号:如+ -等,由编译器识别,没有对应的机器码. 内存: 内存被分为若干个存储单元,一个存储单元存储8个bit,也就是一个byte.每个存储单元从0开始编号,如果一个存储器有128个存储单元,编号从0~127,他的容量是128个字节.现在我的内存是6G,=6*1024*1024个字节.这个编号可以看做是存储单元在存储器中的地址.就像一条街,每个房子都有门

iOS开发_初识视频直播

一.使用第三方ijkPlayer框架开发直播 1.去到B站得github主页,找到ijkplayer项目,下载源码 ijkplayer下载地址 2.Demo的使用以及如何编译Demo 请移步如何快速的开发一个完整的iOS直播app(播放篇) 其实里面讲的很详细,我也是参照这个写的Demo.然后在他的基础上加了一点东西.(不废话我直接上我的代码) 先看看效果图 特点 1.纯代码Masonry布局 2.集成ijkplayer第三方库,实现拉流播放 3.打包ijkplayer静态库,实现release

iOS进阶学习-初识AFNetworking

一.AFNetworking简介 AFNetworking是一个 在iOS开发中 使用非常多网络开源库 适用于iOS以及Mac OS X.它构建于在(Apple iOS开发文档) NSURLConnection ,  NSOperation , 以及其他熟悉的Foundation技术之上. 它拥有良好的架构,丰富的api,以及模块化构建方式,使得使用起来非常轻松. 官方链接http://cocoadocs.org/docsets/AFNetworking/1.3.0/. AFNetworking