LDR 说明符组合 UXTW

逆向工程 部件 手臂 arm64
2021-06-13 23:15:16

对不起,如果这个问题看起来很愚蠢,但我是 arm64 的新手,接下来的 2 条流水线严重损坏了我的大脑:

LDR             W0, [X30,W0,UXTW#2]
ADD             X30, X30, W0,UXTW

我已经阅读了文档,使用了带有不同关键字的 google,但似乎与程序集相关的所有内容都是由机器写入机器的。

我知道它修补了子程序的返回地址,但是很难理解它UTXW#2什么以及它如何影响LDR

有人可以解释我在这 2 行中发生的“魔法”吗?

1个回答

不确定我在这篇文章中选择了 uxtw 右键单击​​并在 Google 上搜索 UXTW
第一个命中是Arm 文档

SUB  Wd|WSP, Wn|WSP, Wm{, extend {#amount}} ; 32-bit general registers

SUB  Xd|SP, Xn|SP, Rm{, extend {#amount}}  ; 64-bit general registers

extend

    Is the extension to be applied to the second source operand:  

    32-bit general registers 

        Can be one of UXTB, UXTH, LSL|UXTW, UXTX, SXTB, SXTH, SXTW or SXTX.

        If Rd or Rn is WSP then LSL is preferred rather than UXTW,  
and can be omitted when amount is 0. 
In all other cases extend is required and must be UXTW rather than LSL.

    64-bit general registers

        Can be one of UXTB, UXTH, UXTW, LSL|UXTX, SXTB, SXTH, SXTW or SXTX.

        If Rd or Rn is SP then LSL is preferred rather than UXTX,  
and can be omitted when amount is 0.    
In all other cases extend is required and must be UXTX rather than LSL.

sxtw 是有符号扩展字 8000->ffff8000
uxtw 是无符号扩展字 8000->00008000

引用另一个相关的热门话题

扩展运算符

扩展运算符的主要目的是扩大在寄存器中找到的较窄的值以匹配操作的位数。扩展运算符的形式为 kxtw,其中 k 是我们想要加宽的整数类型,w 是窄值的宽度。对于前者,整数的种类可以是U(无符号)或S(有符号,即二进制补码)。对于后者,宽度可以是 B、H 或 W,分别表示字节(寄存器的最低 8 位有效位)、半字(寄存器的最低 16 位有效位)或字(寄存器的最低有效位 32 位)。

这意味着扩展运算符是 uxtb、sxtb、uxth、sxth、uxtw、sxtw。

这些运算符的存在是因为有时我们必须将源值的范围从较小的位宽提升到较大的位宽。在后面的章节中,我们将看到许多发生这种情况的情况。例如,我们可能需要在 64 位寄存器中添加一个 32 位寄存器。如果两个寄存器都表示二进制补码整数,则

添加 x0, x1, w2, sxtw // x0 ← x1 + ExtendSigned32To64(w2)

使用这些扩展运算符时必须考虑某种上下文。例如,下面的两个指令的含义略有不同:

添加 x0, x1, w2, sxtb // x0 ← x1 + ExtendSigned8To64(w2) 添加 w0, w1, w2, sxtb // w0 ← w1 + ExtendSigned8To32(w2)

在这两种情况下,w2 的最低有效 8 位都被扩展,但在第一种情况下,它们被扩展到 64 位,在第二种情况下被扩展到 32 位。延伸与转移

通过在扩展运算符之后指定一个数量,可以扩展一个值,然后将其左移 1、2、3 或 4 位。例如

mov x0, #0 // x0 ← 0 mov x1, #0x1234 // x0 ← 0x1234 add x2, x0, x1, sxtw #1 // x2 ← x0 + (ExtendSigned16To64(x1) << 1) // 这会设置 x2 to 0x2468 add x2, x0, x1, sxtw #2 // x2 ← x0 + (ExtendSigned16To64(x1) << 2) // 这将 x2 设置为 0x48d0 add x2, x0, x1, sxtw #3 // x2 ← x0 + (ExtendSigned16To64(x1) << 3) // 这将 x2 设置为 0x91a0 add x2, x0, x1, sxtw #4 // x2 ← x0 + (ExtendSigned16To64(x1) << 4) // 这将 x2 设置为 0x12340

这在这一点上可能看起来有点奇怪和随意,但在后面的章节中我们将看到这在许多情况下实际上很有用。

这就是今天的全部内容。

这是一个示例独角兽 python 仿真

#code modified from unicorn sample
from __future__ import print_function
from unicorn import *
from unicorn.arm64_const import *
print (
"Register X30 on start = 0x10\n"
"Register W0  on start = 0x02\n"
"Emulate 5 ARM64 instructions that follows\n"
"ADD X30, X30, W0,UXTW#0\n"
"ADD X30, X30, W0,UXTW#1\n"
"ADD X30, X30, W0,UXTW#2\n"
"ADD X30, X30, W0,UXTW#3\n"
"ADD X30, X30, W0,UXTW#4\n"
"Register X30 on end = 0x10+0x2+0x4+0x8+0x10+0x20 == 0x4e"
)
CODE =  b"\xDE\x43\x20\x8B\xDE\x47\x20\x8B\xDE\x4b\x20\x8B\xDE\x4f\x20\x8B\xDE\x53\x20\x8B"
ADDRESS    = 0x10000
def test_arm64():
    try:
        mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
        mu.mem_map(ADDRESS, 2 * 1024 * 1024)
        mu.mem_write(ADDRESS, CODE)
        mu.reg_write(UC_ARM64_REG_X30, 0x10)
        mu.reg_write(UC_ARM64_REG_W0, 2)
        for i in range (ADDRESS,ADDRESS + len(CODE),4):
            mu.emu_start(i, i + 4)
            x30 = mu.reg_read(UC_ARM64_REG_X30)
            w0  =  mu.reg_read(UC_ARM64_REG_W0) 
            print(">>> x30  = 0x%x w0 = 0x%x" %(x30,w0))
    except UcError as e:
        print("ERROR: %s" % e)

if __name__ == '__main__':
    test_arm64()

仿真结果

:\>python uniaarch64.py
Register X30 on start = 0x10
Register W0  on start = 0x02
Emulate 5 ARM64 instructions that follows
ADD X30, X30, W0,UXTW#0
ADD X30, X30, W0,UXTW#1
ADD X30, X30, W0,UXTW#2
ADD X30, X30, W0,UXTW#3
ADD X30, X30, W0,UXTW#4
Register X30 on end = 0x10+0x2+0x4+0x8+0x10+0x20 == 0x4e
>>> x30  = 0x12 w0 = 0x2
>>> x30  = 0x16 w0 = 0x2
>>> x30  = 0x1e w0 = 0x2
>>> x30  = 0x2e w0 = 0x2
>>> x30  = 0x4e w0 = 0x2

当您在 W0 中以 -0x2 开头时,请查看扩展结果

>>> x30  = 0x10000000e w0 = 0xfffffffe
>>> x30  = 0x30000000a w0 = 0xfffffffe
>>> x30  = 0x700000002 w0 = 0xfffffffe
>>> x30  = 0xefffffff2 w0 = 0xfffffffe
>>> x30  = 0x1effffffd2 w0 = 0xfffffffe

SXTW 和 -2

>>> x30  = 0xe w0 = 0xfffffffe
>>> x30  = 0xa w0 = 0xfffffffe
>>> x30  = 0x2 w0 = 0xfffffffe
>>> x30  = 0xfffffffffffffff2 w0 = 0xfffffffe
>>> x30  = 0xfffffffffffffff0 w0 = 0xfffffffe

SXTW 和 2

>>> x30  = 0x12 w0 = 0x2
>>> x30  = 0x16 w0 = 0x2
>>> x30  = 0x1e w0 = 0x2
>>> x30  = 0x2e w0 = 0x2
>>> x30  = 0x30 w0 = 0x2