23、64位ARM汇编语言编程中的安全与指令集详解

64位ARM汇编语言编程中的安全与指令集详解

在编程领域,尤其是涉及到64位ARM汇编语言编程时,安全问题和指令集的掌握至关重要。下面将详细探讨防止栈上代码运行、缓冲区溢出缓解技术的权衡,以及ARM 64位指令集的相关内容。

防止栈上代码运行

最初,栈溢出攻击会将黑客的汇编语言程序作为缓冲区的常规部分进行复制,然后覆盖函数的返回地址,从而使这段代码得以执行。ARM CPU的硬件安全机制会将内存页面标记为可读、可写和可执行。为了防止代码在栈上运行,Linux移除了允许栈上代码执行的位,使栈仅具有读写权限。

要想在栈上执行代码,除非添加大量额外的编译和链接开关来启用栈代码执行,因为默认情况下该功能是关闭的。不过,这并不意味着在栈上执行代码完全不可能,只是难度大大增加,需要额外的漏洞利用手段来禁用此功能。此外,使用的共享库可能会禁用该功能,而开发者却可能对此一无所知。

缓冲区溢出缓解技术的权衡

在设计API时,需要格外小心以防止安全漏洞。应优先使用能对缓冲区溢出提供一定保护的例程,例如使用 strncpy 而非 strcpy ,并在源代码控制系统的代码签入过程中添加检查来强制执行这一点。然而,这些方法仍然存在权衡和弱点。

需要警惕数据泄露问题。如果在错误消息中包含内存地址,黑客可以利用它来确定位置无关可执行文件(PIE)的偏移量。虽然听起来不太可能,但有些程序员的通用错误报告机制会包含所有寄存器的内容,其中很可能包含内存地址。像Spectre和Meltdown这样的CPU漏洞就展示了如何访问CPU缓存中的内存位。黑客不太可能通过这种方式找到密码,但很可能会找到内存地址或栈金丝雀。

如果启用并整合所有可用的缓冲区溢出保护技术和工具,代码的运行速度可能会降低多达50%。这在某些应用程序或应用程序的某些部分可能是可以接受的,但对于需要高性能才能具有竞争力甚至可用的应用程序部分来说,就需要特别考虑。

对于需要大量优化的代码段,需要确保在该代码外部有一个层或模块来对传递给优化例程的数据进行清理和确保其正确性。必须保证这种数据检查不能被绕过,并且要确保数据符合优化例程中的所有假设。代码和安全审查有助于确保多双眼睛都检查过潜在问题,审查人员必须具备安全和黑客技术方面的专业知识,以便知道要注意什么。

需要注意的是,将数据检查代码放在用户界面模块通常是一个错误。例如,在编写Web应用程序时,UI通常用JavaScript编写并在浏览器中运行。由于JavaScript是一种解释型语言,黑客可以修改JavaScript以绕过任何错误检查,甚至可以完全不使用JavaScript,直接向Web服务器发送恶意消息。所有客户端/服务器应用程序都是如此,服务器必须验证其数据,而不能依赖UI层。

Linux的一些功能(如PIE)存在一个弱点,即如果链接任何禁用PIE的共享库,整个应用程序的PIE功能都会被禁用。因此,必须确保完成的可执行文件仍然启用了PIE,否则需要找到有问题的库并进行替换。禁用栈执行也是同样的道理,没有理由不使用PIE或防止栈执行,因为这些不会降低应用程序的性能。

同样,代码中可能启用了栈金丝雀,但使用的共享库可能没有使用该选项进行编译。因此,即使代码本身受到保护,但如果黑客在共享库的某个例程中发现缓冲区溢出,他们很可能能够利用它。由于栈金丝雀的使用成本较高,程序员通常会谨慎使用或根本不使用。

黑客非常聪明,会寻找应用程序防护中的小漏洞进行利用。他们很有耐心,如果发现一个漏洞不足以利用,就会继续寻找。通过结合多个信息片段和漏洞,他们可以找到破解程序安全的方法。

以下是缓冲区溢出缓解技术权衡的流程图:

graph TD;
    A[设计API] --> B[使用保护例程];
    B --> C[代码签入检查];
    D[数据泄露风险] --> E[内存地址暴露];
    F[启用保护技术] --> G[性能下降];
    H[优化代码段] --> I[数据清理模块];
    I --> J[确保检查不被绕过];
    K[共享库问题] --> L[禁用相关功能];
    M[黑客利用漏洞] --> N[结合信息破解安全];
ARM 64位核心指令集

ARM 64位指令集分为两部分:核心指令集和NEON及FPU指令集。下表列出了部分核心指令及其简要描述:
| 指令 | 描述 |
| — | — |
| ADC{S} | 带进位加法 |
| ADD{S} | 加法 |
| ADDG | 带标签加法 |
| ADR | 形成PC相对地址 |
| ADRP | 形成PC相对地址到4KB页面 |
| AND{S} | 按位与 |
| ASR† | 算术右移 |
| ASRV | 可变算术右移 |
| AT† | 地址转换 |
| AUTDA, AUTDZA | 使用密钥A验证数据地址 |
| AUTDB, AUTDZB | 使用密钥B验证数据地址 |
| AUTIA, AUTIA1716 | 使用密钥A验证指令地址 |
| AUTIASP, AUTIAZ | 使用密钥A验证指令地址 |
| AUTIZA | 使用密钥A验证指令地址 |
| AUTIB, AUTIB1716 | 使用密钥B验证指令地址 |
| AUTIBSP, AUTIBZ | 使用密钥B验证指令地址 |
| AUTIZB | 使用密钥B验证指令地址 |
| AXFlag | 转换浮点条件标志 |
| B | 分支 |
| B.cond | 条件分支 |
| BFC† | 位域清除 |
| BFI† | 位域插入 |
| BFM | 位域移动 |
| BFXIL† | 低位位域提取和插入 |
| BIC{S} | 按位清位 |
| BL | 带链接分支 |
| BLR | 带链接分支到寄存器 |
| BLRAA, BLRAAZ | 带指针认证的带链接分支到寄存器 |
| BLRAB, BLRABZ | 带指针认证的带链接分支到寄存器 |
| BR | 分支到寄存器 |
| BRAA, BRAAZ | 带指针认证的分支到寄存器 |
| BRAB, BRABZ | 带指针认证的分支到寄存器 |
| BRK | 断点指令 |
| BTI | 分支目标识别 |
| CAS, CASA | 比较并交换内存中的字或双字 |
| CASAL, CASL | 比较并交换内存中的字或双字 |
| CASB, CASAB | 比较并交换内存中的字节 |
| CASALB, CASLB | 比较并交换内存中的字节 |
| CASH, CASAH | 比较并交换内存中的半字 |
| CASALH, CASLH | 比较并交换内存中的半字 |
| CASP, CASPA | 比较并交换内存中的一对字或双字 |
| CASPAL, CASPL | 比较并交换内存中的一对字或双字 |
| CBNZ | 非零比较并分支 |
| CBZ | 零比较并分支 |
| CCMN | 条件负比较 |
| CCMP | 条件比较 |
| CFINV | 反转进位标志 |
| CFP† | 按上下文限制控制流预测 |
| CINC† | 条件递增 |
| CINV† | 条件取反 |
| CLREX | 清除独占 |
| CLS | 计算前导符号位 |
| CLZ | 计算前导零 |
| CMN† | 负比较 |
| CMP† | 比较 |
| CMPP† | 带标签比较 |
| CNEG† | 条件取负 |
| CPP† | 按上下文限制缓存预取预测 |
| CRC32B, CRC32H | CRC32校验和 |
| CRC32W, CRC32X | CRC32校验和 |
| CRC32CB | CRC32C校验和 |
| CRC32CH | CRC32C校验和 |
| CRC32CW | CRC32C校验和 |
| CRC32CX | CRC32C校验和 |
| CSDB | 推测数据消耗屏障 |
| CSEL | 条件选择 |
| CSET† | 条件设置 |
| CSETM† | 条件设置掩码 |
| CSINC | 条件选择递增 |
| CSINV | 条件选择取反 |
| CSNEG | 条件选择取负 |
| DC† | 数据缓存操作 |
| DCPS1 | 调试将处理器状态更改为EL1 |
| DCPS2 | 调试将处理器状态更改为EL2 |
| DCPS3 | 调试将处理器状态更改为EL3 |
| DMB | 数据内存屏障 |
| DRPS | 调试恢复进程状态 |
| DSB | 数据同步屏障 |
| DVP† | 按上下文限制数据值预测 |
| EON | 按位异或非 |
| EOR | 按位异或 |
| ERET | 异常返回 |
| ERETAA, ERETAB | 带指针认证的异常返回 |
| ESB | 错误同步屏障 |
| EXTR | 提取寄存器 |
| GMI | 标签掩码插入 |
| HINT | 提示指令 |
| HLT | 暂停指令 |
| HVC | 管理程序调用 |
| IC† | 指令缓存操作 |
| IRG | 插入随机标签 |
| ISB | 指令同步屏障 |
| LDADD, LDADDA | 内存中字或双字的原子加法 |
| LDADDAL, LDADDL | 内存中字或双字的原子加法 |
| LDADDB, LDADDAB | 内存中字节的原子加法 |
| LDADDALB | 内存中字节的原子加法 |
| LDADDLB | 内存中字节的原子加法 |
| LDADDH | 内存中半字的原子加法 |
| LDADDAH | 内存中半字的原子加法 |
| LDADDALH | 内存中半字的原子加法 |
| LDADDLH | 内存中半字的原子加法 |
| LDAPR | 加载获取RCpc寄存器 |
| LDAPRB | 加载获取RCpc寄存器字节 |
| LDAPRH | 加载获取RCpc寄存器半字 |
| LDAPUR | 加载获取RCpc寄存器(未缩放) |
| LDAPURB | 加载获取RCpc寄存器字节(未缩放) |
| LDAPURH | 加载获取RCpc寄存器半字(未缩放) |
| LDAPURSB | 加载获取RCpc寄存器有符号字节(未缩放) |
| LDAPURSH | 加载获取RCpc寄存器有符号半字(未缩放) |
| LDAPURSW | 加载获取RCpc寄存器有符号字(未缩放) |
| LDAR | 加载获取寄存器 |
| LDARB | 加载获取寄存器字节 |
| LDARH | 加载获取寄存器半字 |
| LDAXP | 加载获取独占寄存器对 |
| LDAXR | 加载获取独占寄存器 |
| LDAXRB | 加载获取独占寄存器字节 |
| LDAXRH | 加载获取独占寄存器半字 |
| LDCLR, LDCLRA | 内存中字或双字的原子位清除 |
| LDCLRAL, LDCLRL | 内存中字或双字的原子位清除 |
| LDCLRB, LDCLRAB | 内存中字节的原子位清除 |
| LDCLRALB | 内存中字节的原子位清除 |
| LDCLRLB | 内存中字节的原子位清除 |
| LDCLRH, LDCLRAH | 内存中半字的原子位清除 |
| LDCLRALH | 内存中半字的原子位清除 |
| LDCLRLH | 内存中半字的原子位清除 |
| LDEOR, LDEORA | 内存中字或双字的原子异或 |
| LDEORAL, LDEORL | 内存中字或双字的原子异或 |
| LDEORB, LDEORAB | 内存中字节的原子异或 |
| LDEORALB | 内存中字节的原子异或 |
| LDEORLB | 内存中字节的原子异或 |
| LDEORH, LDEORAH | 内存中半字的原子异或 |
| LDEORALH | 内存中半字的原子异或 |
| LDEORLH | 内存中半字的原子异或 |
| LDG | 加载分配标签 |
| LDGV | 加载分配标签 |
| LDLAR | 加载LOAcquire寄存器 |
| LDLARB | 加载LOAcquire寄存器字节 |
| LDLARH | 加载LOAcquire寄存器半字 |
| LDNP | 带非临时提示的加载寄存器对 |
| LDP | 加载寄存器对 |
| LDPSW | 加载寄存器对有符号字 |
| LDR | 加载寄存器 |
| LDRAA, LDRAB | 带指针认证的加载寄存器 |
| LDRB | 加载寄存器字节 |
| LDRH | 加载寄存器半字 |
| LDRSB | 加载寄存器有符号字节 |
| LDRSH | 加载寄存器有符号半字 |
| LDRSW | 加载寄存器有符号字 |
| LDSET, LDSETA | 内存中字或双字的原子位设置 |
| LDSETAL, LDSETL | 内存中字或双字的原子位设置 |
| LDSETB, LDSETAB | 内存中字节的原子位设置 |
| LDSETALB | 内存中字节的原子位设置 |
| LDSETLB | 内存中字节的原子位设置 |
| LDSETH, LDSETAH | 内存中半字的原子位设置 |
| LDSETALH | 内存中半字的原子位设置 |
| LDSETLH | 内存中半字的原子位设置 |
| LDSMAX | 内存中字或双字的原子有符号最大值 |
| LDSMAXA | 内存中字或双字的原子有符号最大值 |
| LDSMAXAL | 内存中字或双字的原子有符号最大值 |
| LDSMAXL | 内存中字或双字的原子有符号最大值 |
| LDSMAXB | 内存中字节的原子有符号最大值 |
| LDSMAXAB | 内存中字节的原子有符号最大值 |
| LDSMAXALB | 内存中字节的原子有符号最大值 |
| LDSMAXLB | 内存中字节的原子有符号最大值 |
| LDSMAXH | 内存中半字的原子有符号最大值 |
| LDSMAXAH | 内存中半字的原子有符号最大值 |
| LDSMAXALH | 内存中半字的原子有符号最大值 |
| LDSMAXLH | 内存中半字的原子有符号最大值 |
| LDSMIN, LDSMINA | 内存中字或双字的原子有符号最小值 |
| LDSMINAL | 内存中字或双字的原子有符号最小值 |
| LDSMINL | 内存中字或双字的原子有符号最小值 |
| LDSMINB | 内存中字节的原子有符号最小值 |
| LDSMINAB | 内存中字节的原子有符号最小值 |
| LDSMINALB | 内存中字节的原子有符号最小值 |
| LDSMINLB | 内存中字节的原子有符号最小值 |
| LDSMINH | 内存中半字的原子有符号最小值 |
| LDSMINAH | 内存中半字的原子有符号最小值 |
| LDSMINALH | 内存中半字的原子有符号最小值 |
| LDSMINLH | 内存中半字的原子有符号最小值 |
| LDTR | (非特权)加载寄存器 |
| LDTRB | (非特权)加载寄存器字节 |
| LDTRH | (非特权)加载寄存器半字 |
| LDTRSB | (非特权)加载寄存器有符号字节 |
| LDTRSH | (非特权)加载寄存器有符号半字 |
| LDTRSW | (非特权)加载寄存器有符号字 |
| LDUMAX | 内存中字或双字的原子无符号最大值 |
| LDUMAXA | 内存中字或双字的原子无符号最大值 |
| LDUMAXAL | 内存中字或双字的原子无符号最大值 |
| LDUMAXL | 内存中字或双字的原子无符号最大值 |
| LDUMAXB | 内存中字节的原子无符号最大值 |
| LDUMAXAB | 内存中字节的原子无符号最大值 |
| LDUMAXALB | 内存中字节的原子无符号最大值 |
| LDUMAXLB | 内存中字节的原子无符号最大值 |
| LDUMAXH | 内存中半字的原子无符号最大值 |
| LDUMAXAH | 内存中半字的原子无符号最大值 |
| LDUMAXALH | 内存中半字的原子无符号最大值 |
| LDUMAXLH | 内存中半字的原子无符号最大值 |
| LDUMIN | 内存中字或双字的原子无符号最小值 |
| LDUMINA | 内存中字或双字的原子无符号最小值 |
| LDUMINAL | 内存中字或双字的原子无符号最小值 |
| LDUMINL | 内存中字或双字的原子无符号最小值 |
| LDUMINB | 内存中字节的原子无符号最小值 |
| LDUMINAB | 内存中字节的原子无符号最小值 |
| LDUMINALB | 内存中字节的原子无符号最小值 |
| LDUMINLB | 内存中字节的原子无符号最小值 |
| LDUMINH | 内存中半字的原子无符号最小值 |
| LDUMINAH | 内存中半字的原子无符号最小值 |
| LDUMINALH | 内存中半字的原子无符号最小值 |
| LDUMINLH | 内存中半字的原子无符号最小值 |
| LDUR | (未缩放)加载寄存器 |
| LDURB | (未缩放)加载寄存器字节 |
| LDURH | (未缩放)加载寄存器半字 |
| LDURSB | (未缩放)加载寄存器有符号字节 |
| LDURSH | (未缩放)加载寄存器有符号半字 |
| LDURSW | (未缩放)加载寄存器有符号字 |
| LDXP | 加载独占寄存器对 |
| LDXR | 加载独占寄存器 |
| LDXRB | 加载独占寄存器字节 |
| LDXRH | 加载独占寄存器半字 |
| LSL† | 逻辑左移 |
| LSLV | 可变逻辑左移 |
| LSR† | 逻辑右移 |
| LSRV | 可变逻辑右移 |
| MADD | 乘加 |
| MNEG† | 乘负 |
| MOV† | 移动 |
| MOVK | 带保留的宽移动 |
| MOVN | 带非的宽移动 |
| MOVZ | 带零的宽移动 |
| MRS | 移动系统寄存器 |
| MSR | 移动值到特殊寄存器 |
| MSUB | 乘减 |
| MUL† | 乘法 |
| MVN† | 按位取反 |
| NEG{S}† | 取负 |
| NGC{S}† | 带进位取负 |
| NOP | 无操作 |
| ORN | 按位或非 |
| ORR | 按位或 |
| PACDA, PACDZA | 使用密钥A的数据地址指针认证码 |
| PACDB, PACDZB | 使用密钥B的数据地址指针认证码 |
| PACGA | 使用通用密钥的指针认证码 |
| PACIA, PACIA1716 | 使用密钥A的指令地址指针认证码 |
| PACIASP, PACIAZ | 使用密钥A的指令地址指针认证码 |
| PACIZA | 使用密钥A的指令地址指针认证码 |
| PACIB, PACIB1716 | 使用密钥B的指令地址指针认证码 |
| PACIBSP, PACIBZ | 使用密钥B的指令地址指针认证码 |
| PACIZ | 使用密钥B的指令地址指针认证码 |
| PRFM | 预取内存 |
| PSB CSYNC | 性能采样同步屏障 |
| PSSBB | 物理推测存储旁路屏障 |
| RBIT | 反转位 |
| RET | 子程序返回 |
| RETAA, RETAB | 带指针认证的子程序返回 |
| REV | 反转字节 |
| REV16 | 反转16位半字中的字节 |
| REV32 | 反转32位字中的字节 |
| REV64† | 反转字节 |
| RMIF | 旋转、掩码插入标志 |
| ROR† | 循环右移 |
| RORV | 可变循环右移 |
| SB | 推测屏障 |
| SBC{S} | 带借位减法 |
| SBFIZ† | 有符号位域插入零 |
| SBFM | 有符号位域移动 |
| SBFX† | 有符号位域提取 |
| SDIV | 有符号除法 |
| SETF8, SETF16 | 评估8位或16位标志值 |
| SEV | 发送事件 |
| SEVL | 本地发送事件 |
| SMADDL | 有符号乘加长运算 |
| SMC | 安全监视器调用 |
| SMNEGL† | 有符号乘负长运算 |
| SMSUBL | 有符号乘减长运算 |
| SMULH | 有符号乘高 |
| SMULL | 有符号乘长(SMADDL的别名) |
| SSBB | 推测存储旁路屏障 |
| ST2G | 存储分配标签 |
| STADD, STADDL† | 内存中字或双字的原子加法(无返回) |
| STADDB† | 内存中字节的原子加法(无返回) |
| STADDLB† | 内存中字节的原子加法(无返回) |
| STADDH† | 内存中半字的原子加法(无返回) |
| STADDLH† | 内存中半字的原子加法(无返回) |
| STCLR, STCLRL† | 内存中字或双字的原子位清除(无返回) |
| STCLRB, STCLRLB† | 内存中字节的原子位清除(无返回) |
| STCLRH, STCLRLH† | 内存中半字的原子位清除(无返回) |
| STEOR, STEORL† | 内存中字或双字的原子异或(无返回) |
| STEORB, STEORLB† | 内存中字节的原子异或(无返回) |
| STEORH, STEORLH† | 内存中半字的原子异或(无返回) |
| STG | 存储分配标签 |
| STGP | 存储分配标签和寄存器对 |
| STGV | 存储标签向量 |
| STLLR | 存储LORelease寄存器 |
| STLLRB | 存储LORelease寄存器字节 |
| STLLRH | 存储LORelease寄存器半字 |
| STLR | 存储释放寄存器 |
| STLRB | 存储释放寄存器字节 |
| STLRH | 存储释放寄存器半字 |
| STLUR | (未缩放)存储释放寄存器 |
| STLURB | (未缩放)存储释放寄存器字节 |
| STLURH | (未缩放)存储释放寄存器半字 |
| STLXP | 存储释放独占寄存器对 |
| STLXR | 存储释放独占寄存器 |
| STLXRB | 存储释放独占寄存器字节 |
| STLXRH | 存储释放独占寄存器半字 |
| STNP | 带非临时提示的存储寄存器对 |
| STP | 存储寄存器对 |
| STR | 存储寄存器 |
| STRB | 存储寄存器字节 |
| STRH | 存储寄存器半字 |
| STSET, STSETL† | 内存中字或双字的原子位设置(无返回) |
| STSETB, STSETLB† | 内存中字节的原子位设置(无返回) |
| STSETH, STSETLH† | 内存中半字的原子位设置(无返回) |
| STSMAX† | 内存中字或双字的原子有符号最大值(无返回) |
| STSMAXL† | 内存中字或双字的原子有符号最大值(无返回) |
| STSMAXB† | 内存中字节的原子有符号最大值(无返回) |
| STSMAXLB† | 内存中字节的原子有符号最大值(无返回) |
| STSMAXH† | 内存中半字的原子有符号最大值(无返回) |
| STSMAXLH† | 内存中半字的原子有符号最大值(无返回) |
| STSMIN, STSMINL† | 内存中字或双字的原子有符号最小值(无返回) |
| STSMINB† | 内存中字节的原子有符号最小值(无返回) |
| STSMINLB† | 内存中字节的原子有符号最小值(无返回) |
| STSMINH† | 内存中半字的原子有符号最小值(无返回) |
| STSMINLH† | 内存中半字的原子有符号最小值(无返回) |
| STTR | (非特权)存储寄存器 |
| STTRB | (非特权)存储寄存器字节 |
| STTRH | (非特权)存储寄存器半字 |
| STUMAX† | 内存中字或双字的原子无符号最大值(无返回) |
| STUMAXL† | 内存中字或双字的原子无符号最大值(无返回) |
| STUMAXB† | 内存中字节的原子无符号最大值(无返回) |
| STUMAXLB† | 内存中字节的原子无符号最大值(无返回) |
| STUMAXH† | 内存中半字的原子无符号最大值(无返回) |
| STUMAXLH† | 内存中半字的原子无符号最大值(无返回) |
| STUMIN† | 内存中字或双字的原子无符号最小值(无返回) |
| STUMINL† | 内存中字或双字的原子无符号最小值(无返回) |
| STUMINB† | 内存中字节的原子无符号最小值(无返回) |
| STUMINLB† | 内存中字节的原子无符号最小值(无返回) |
| STUMINH† | 内存中半字的原子无符号最小值(无返回) |
| STUMINLH† | 内存中半字的原子无符号最小值(无返回) |
| STUR | (未缩放)存储寄存器 |
| STURB | (未缩放)存储寄存器字节 |
| STURH | (未缩放)存储寄存器半字 |
| STXP | 存储独占寄存器对 |
| STXR | 存储独占寄存器 |
| STXRB | 存储独占寄存器字节 |
| STXRH | 存储独占寄存器半字 |
| STZ2G | 存储分配标签(清零) |
| STZG | 存储分配标签(清零) |
| SUB{S} | 减法 |
| SUBG | 带标签减法 |
| SUBP{S} | 减法指针 |
| SVC | 超级用户调用 |
| SWP, SWPA | 内存中字或双字的交换 |
| SWPAL, SWPL | 内存中字或双字的交换 |
| SWPB, SWPAB | 内存中字节的交换 |
| SWPALB, SWPLB | 内存中字节的交换 |
| SWPH, SWPAH | 内存中半字的交换 |
| SWPALH, SWPLH | 内存中半字的交换 |
| SXTB† | 有符号扩展字节 |
| SXTH† | 有符号扩展半字 |
| SXTW† | 有符号扩展字 |
| SYS | 系统指令 |
| SYSL | 带结果的系统指令 |
| TBNZ | 测试位非零则分支 |
| TBZ | 测试位零则分支 |
| TLBI† | 转换后备缓冲器(TLB)无效操作 |
| TSB CSYNC | 跟踪同步屏障 |
| TST† | 测试位 |
| UBFIZ† | 无符号位域插入零 |
| UBFM | 无符号位域移动 |
| UBFX† | 无符号位域提取 |
| UDF | 永久未定义 |
| UDIV | 无符号除法 |
| UMADDL | 无符号乘加长运算 |
| UMNEGL† | 无符号乘负长运算 |
| UMSUBL | 无符号乘减长运算 |
| UMULH | 无符号乘高 |
| UMULL† | 无符号乘长 |
| UXTB† | 无符号扩展字节 |
| UXTH† | 无符号扩展半字 |
| WFE | 等待事件 |

ARM 64位NEON和FPU指令集也为编程提供了强大的功能,后续将继续深入探讨。掌握这些指令集对于编写高效、安全的64位ARM汇编语言程序至关重要。

实践与展望

在掌握了上述关于防止栈上代码运行、缓冲区溢出缓解技术以及ARM 64位指令集的知识后,我们可以通过一些实践来加深理解。

实践建议
  • 实验练习 :可以尝试完成以下练习,以更好地掌握相关知识。
    1. 在讨论启用栈金丝雀时的尾声代码时,提到指令 eor x0, x1, x0 X0 X1 相等时会将 X0 置为零。查阅异或指令的逻辑规则,并说明其工作原理。
    2. 考虑 strcpy 的各种API,选择一个用于 toupper 的API并实现它,以防止缓冲区溢出。
    3. 为第15章的 upper.c 程序启用栈金丝雀,进行测试以观察其正常工作以及捕获栈溢出的情况。
    4. 对一些现有的示例程序启用PIE,确保它们能正常工作。
    5. 思考是否始终开启最大保护并接受性能损失是最安全的方法。
  • 项目实践 :可以思考并开展一些自己的汇编语言项目,例如:
    1. 控制连接到NVIDIA Jetson Nano GPIO引脚的机器人。
    2. 使用汇编语言代码,甚至利用NEON处理器来优化AI对象识别算法。
    3. 为Linux内核中与ARM相关的部分做出贡献,以提高操作系统的性能。
    4. 增强GCC以生成更高效的ARM代码。
    5. 构思一些可能成为下一个热门应用的原创项目。
总结

在编程世界中,安全和性能是两个关键的考量因素。防止栈上代码运行和缓解缓冲区溢出是保障程序安全的重要手段,但在实施这些技术时需要权衡性能。同时,熟悉ARM 64位指令集是编写高效汇编语言程序的基础。

大型银行、信贷机构和其他在线企业系统经常发生重大数据泄露事件,即使这些大公司有资金聘请最好的安全顾问并使用最好的工具,仍然会不断受到攻击。这提醒我们在自己的编程工作中要保持警惕,认真对待黑客问题。

通过阅读本文,你应该对如何为Android、iOS和Linux编写64位汇编语言程序有了更深入的了解,包括编写基本程序、使用浮点运算单元(FPU)和先进的NEON处理器执行单指令多数据(SIMD)指令。

编程是一门实践性很强的学科,只有通过不断实践才能真正掌握。希望你能积极尝试上述的实践建议,不断探索和创新,在64位ARM汇编语言编程的道路上取得更好的成果。

64位ARM汇编语言编程中的安全与指令集详解

ARM 64位NEON及FPU指令集

除了核心指令集,ARM 64位指令集还包含NEON及FPU指令集,这些指令集为处理多媒体和浮点运算提供了强大的支持。虽然文档中未详细列出这些指令,但我们知道它们在特定的应用场景中非常关键。例如,在AI对象识别算法中,NEON处理器可以通过执行SIMD指令来加速数据处理,提高算法的运行效率。

安全与性能的平衡

在64位ARM汇编语言编程中,安全和性能的平衡是一个持续的挑战。我们已经了解到,启用各种缓冲区溢出保护技术和工具可能会导致代码运行速度降低多达50%。这就需要开发者根据具体的应用场景来做出权衡。

对于一些对性能要求不高的应用,如后台数据处理任务,我们可以启用所有可用的保护技术,以确保程序的安全性。但对于那些对性能要求极高的应用,如实时游戏或高频交易系统,我们需要更加谨慎地选择保护技术。

以下是在不同应用场景下平衡安全与性能的建议列表:
1. 对性能要求不高的应用
- 启用所有缓冲区溢出保护技术,如栈金丝雀、PIE等。
- 使用安全的API,如 strncpy 代替 strcpy
- 进行严格的代码审查,确保代码的安全性。
2. 对性能要求较高的应用
- 对需要优化的代码段进行单独处理,在代码外部添加数据清理和验证模块。
- 选择性地启用保护技术,避免过度保护导致性能下降。
- 进行性能测试,找到安全和性能的最佳平衡点。

应对黑客攻击的策略

黑客总是在寻找程序中的漏洞进行攻击,因此我们需要采取一系列策略来保护程序的安全。

首先,要确保代码的质量。编写高质量的代码可以减少缓冲区溢出等漏洞的出现。在编写代码时,要遵循安全编程的最佳实践,如使用安全的API、进行边界检查等。

其次,要对代码进行定期的安全审查。安全审查可以帮助我们发现潜在的安全漏洞,并及时进行修复。审查人员应该具备安全和黑客技术方面的专业知识,以便能够识别各种类型的漏洞。

此外,还要关注共享库的安全性。共享库可能会引入安全风险,如禁用PIE或栈执行等功能。因此,在使用共享库时,要确保其安全性,并对其进行严格的测试。

以下是应对黑客攻击的策略流程图:

graph TD;
    A[编写高质量代码] --> B[使用安全API];
    B --> C[进行边界检查];
    D[定期安全审查] --> E[发现潜在漏洞];
    E --> F[及时修复漏洞];
    G[关注共享库安全] --> H[确保库的安全性];
    H --> I[进行严格测试];
    J[黑客攻击] --> K[利用漏洞];
    L[采取防护策略] --> M[阻止攻击];
总结与展望

通过对防止栈上代码运行、缓冲区溢出缓解技术以及ARM 64位指令集的深入探讨,我们了解到在64位ARM汇编语言编程中,安全和性能是两个不可忽视的因素。我们需要在保证程序安全的前提下,尽可能地提高程序的性能。

未来,随着技术的不断发展,黑客攻击的手段也会越来越复杂。因此,我们需要不断学习和更新知识,提高自己的安全意识和编程能力。同时,我们也可以通过参与开源项目、与其他开发者交流等方式,共同提高整个编程社区的安全水平。

希望本文能够帮助你更好地理解64位ARM汇编语言编程中的安全和指令集相关知识,并在实际编程中应用这些知识,编写出更加安全、高效的程序。

最后,再次强调实践的重要性。编程是一门实践性很强的学科,只有通过不断地实践和探索,才能真正掌握相关知识和技能。建议你按照前面提到的实践建议,积极开展实验和项目实践,在实践中不断成长和进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值