【问题标题】:Get argv[2] address in assembler x64在汇编器 x64 中获取 argv[2] 地址
【发布时间】:2016-06-22 05:11:32
【问题描述】:

edi 是 argc,rsi 是 argv

   0x0000000000400535 <+8>: mov    %edi,-0x4(%rbp)
   0x0000000000400538 <+11>:    mov    %rsi,-0x10(%rbp)

这里我得到了 argv 指针

(gdb) x/8x $rbp-0x10
0x7ffdb7cac380: 0xb7cac478  0x00007ffd  0x00000000  0x00000003
0x7ffdb7cac390: 0x00000000  0x00000000  0x1f130b45  0x00007ff3

指针 0x7ffdb7cac478

所以我的 argv[2] 在这里:

(gdb) x/8x 0x7ffdb7cac478+16
0x7ffdb7cac488: 0xb7cacd8a  0x00007ffd  0x00000000  0x00000000

在地址 0x7ffdb7cacd8a

我需要得到argv[2]的地址,所以我想写这个汇编代码:

伪代码:

x - 从地址 $rbp-0x10 加载 8 个字节 //(指向 argv 的指针)

y - 从 x 值+16 加载 8 个字节 //(指向 argv[2] 的指针)

我需要稍后跳转到 y。

如何在汇编器 x64 中编写代码? x 和 y 可以使用哪个寄存器?

我希望这是可以理解的。我是初学者。

我在这里问是因为我不知道从哪里开始研究。

更新:

试过这个:

bits 64
ldr r8, rbp, #0x10
ldr r9, r8, #0x10
jmp r9

但它甚至无法编译......我正在使用 nasm。

我猜上面是针对 ARM 架构的,对于下面的 amd64 (x64) 应该这样做。对吗?

更新 2:

bits 64
lea r8, [rbp-0x10]
lea r9, [r8+0x10]
jmp r9

更新 3:

也不行……

bits 64
lea r8, [rbp-0x10]
mov r9, [r8]
mov r10, [r9+0x10]
jmp r10

【问题讨论】:

  • 没有什么比从您最喜欢的汇编程序参考中阅读有关寄存器和程序流程的信息更好的了。对于x and y 使用哪些寄存器,您可以使用任意两个通用寄存器。对于“我该怎么做”,答案是尝试,如果遇到困难,请发布您的进度。
  • 这些是我的第一个汇编步骤,没有任何喜欢的参考。你能指点一下吗?一个很大的帮助是至少告诉哪个指令将 x 个字节加载到一个地址?是 ldr,ldi 吗?我应该搜索什么?
  • 添加了我尝试过的代码...甚至无法编译:/
  • 添加了另一个代码...这可以编译,但不确定它是否正确
  • 试试nasm.us/doc

标签: assembly


【解决方案1】:

你写的是main()还是_start

如果你写main,它是一个普通函数,它的参数在rdirsi,遵循正常的调用约定。链接见标签wikito the x86-64 ABI

如果您正在编写 _start,则数据在堆栈上,如 ABI 的进程启动部分中所述:[rsp] = argc,以及上面的指针数组 char *arg[],从 rsp+8 开始。它是堆栈上的一个实际数组,而不是像main 这样的数组的指针

rbp 是没有意义的,除非你初始化它。它包含调用者留下的任何内容。


您的代码片段也很愚蠢:您从不初始化 rbp。您应该假设它在进程入口处保存垃圾。只有rsp 保证有用。

lea 只是一个使用有效地址语法/编码的移位和加法指令。 mov 是加载/存储的助记符。

    ;; your code with comments, also assuming that RBP was initialized
    bits 64
    lea r8, [rbp-0x10]      ; r8 = rbp-0x10
    mov r9, [r8]            ; should have just done mov r9, [rbp-0x10]
    mov r10, [r9+0x10]
    jmp r10                 ; jump to argv[2]???

您是否将机器码字节放入argv[2]?跳转到字符串通常没有用。

当然,由于rbp 没有初始化,它实际上并没有访问argv[2]


工作示例

如果您想查看发生了什么,请在调试器中单步执行此操作。

; get argc and argv from the stack, for x86-64 SysV ABI
global _start
_start:
    mov   ecx,  [rsp]             ;   load argc (assuming it's smaller than 2^32)

    cmp   ecx, 3
    jb  .argc_below_3
                                  ;   argv[0] is at rsp+8
    mov   rsi,  [rsp+8 +  8*2]    ;   argv[2]  (the 3rd element)
    movzx eax,  byte [rsi]        ;   first char of argv[2]

    ; if you stop here in a debugger, you can see the character from the second arg.

    ; fall through and exit
.argc_below_3:
    xor edi, edi
    mov eax, 231                  ;  exit_group(0)
    syscall

【讨论】:

  • 如果我们正在为main() linux 64 写作,您能否添加如何访问char** argv 参数。或者是否可以将我指向一些可以获取此信息的文档?感谢您的宝贵时间。
  • @NasreddineGalfout:进入main,RSI = argv 就像我在这个答案中提到的那样。另请参阅What are the calling conventions for UNIX & Linux system calls on i386 and x86-64,它也涵盖了函数调用约定。或者,如果您不确定如何以某种特定方式使用它,请查看编译器生成的 C main 代码:How to remove "noise" from GCC/clang assembly output?
  • 感谢彼得的回复。为此(第二天),我一直在寻找四个小时。我设法找到了一种使用 objconv lib 将 c prog 转换为 nasm 可读格式的方法。我怎么真的没有看到它。我所需要的只是一种读取传递给我的 main() 并存储在 argv 中的命令行的方法。我知道他们在 RSI 中,但我没有得到他们。我想请你指点我一个简单的方法来理解如何在 64 linux 中从 RSI 检索该信息。
  • 我想我找到了。非常感谢你的帮助。如果您有任何信息(我可能遇到的陷阱),请分享。再次感谢您的帮助。对于任何有同样问题的人,请参阅this post 您的第一个 argv[1] 位于 qword [rsi+8] (linux 64)
  • @NasreddineGalfout:是的,没错。 stackoverflow.com/tags/x86/info 中有一个常见问题解答部分,我已经介绍了人们经常发布问题的各种常见陷阱。到目前为止,最重要的技能是使用像 GDB 这样的调试器来单步执行并观察寄存器/内存的变化。有了它和指令集参考,你就可以弄清楚其他任何东西是如何/为什么起作用的。 (和strace ./my_program 跟踪系统调用并确保您得到正确的参数。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 2015-04-02
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多