首页 文章

程序集8086-从堆栈中推送和弹出寄存器不起作用

提问于
浏览
1

我是一个初学者,由于某种原因,推出和弹出堆栈对我来说不起作用 . 我的bootloader:

org 0x7c00
bits 16
jmp main
print:
    pop bx
    mov al, [bx]
    mov ah, 0eh
    int 10h
    ret
main:
    mov bx, msg
    push bx
    call print

    cli
    hlt

    msg: db 'Hello World!', 0
    times 510 - ($-$$) db 0
    dw 0xAA55

应该做的是,我相信,将地址 msgbx 推入堆栈,然后将其检索到 bx . 但是,情况似乎并非如此 . 'H' 无法打印 . 而是打印 '-' . 如果我使用 msg 作为有效地址,它可以工作 .

Edit :正如Duncan指出的那样, call 指令正在推送堆栈顶部的返回地址,这使得上面的程序使用了BIOS中断的返回地址!我现在 pop 返回地址 dx 然后 pop 进入 bx ,完成后使用 bxjmp 的值 dx

org 0x7c00
bits 16
jmp main
print:
    pop dx
    pop bx
    mov al, [bx]
    mov ah, 0eh
    int 10h
    jmp dx
main:
    mov bx, msg
    push bx
    call print

    cli
    hlt

    msg: db 'Hello World!', 0
    times 510 - ($-$$) db 0
    dw 0xAA55

2 回答

  • 2

    call 指令将程序计数器推入堆栈, ret 从堆栈中弹出顶部值并跳转到它 .

    所以你不能通过在调用之前推送参数来将参数传递给函数,并在调用中弹出它们,因为保存的pc会妨碍它 .

    选项可能包括设置帧指针,以便您可以访问仍在堆栈中的参数,然后将它们作为返回的一部分弹出 .

    或者对于这个简单的东西你可以将返回地址弹出到另一个寄存器而不是返回你只是跳转到它 .

  • 0

    jmp far 0:main 开始,以规范化 cs:ip ,因为某些BIOS将使用 cs=0 调用您,而某些BIOS将使用 cs=0x07c0 调用 .

    print:
        pop bx
        mov al, [bx]
        mov ah, 0eh
        int 10h
        ret
    

    也许你在shell漏洞利用中看到过这样的东西,但正确的用法看起来像这样:

    call print  ; this will put `msg` at top of stack!
    msg: db 'H'
    print:
        pop bx      ; load `msg` address
        ... no RET !! (there's nowhere to return to)
    

    当你不知道你的代码将位于何处时,这是一个如何将正确的偏移量放入堆栈的技巧(shell利用通常进入某个缓冲区溢出区域,带有一些随机地址) .

    在引导加载程序中不需要这样,因为你处于固定位置 0000:7C00 并且你可以像这样组装,所以使用一些自定义"pass argument value by register"自定义程序的自定义"pass argument value by register"调用约定很好,完全没有涉及堆栈(除了使用它来存储返回地址) call + ret 对) .


    在使用之前初始化堆栈,即在main的开头你可能想要做的例如:

    main:
        ; set ss:sp to 0000:7C00 (so you have about ~29kB of RAM for stack)
        xor ax,ax
        mov ss,ax       ; disables interrupts for 1 more instruction
        mov sp,0x7C00   ; so sp set must follow the `ss` setup
    

    当然不要将它用于任何深度递归,29kB是小堆栈(但是对于合理编写的引导加载程序来说很多,从磁盘加载一些内核,实际上100-200B的堆栈应该足够了) .

    并设置 ds 当然!正如您所做的那样 mov al,[bx] 已经设置好了 . 在你的情况下,最简单的方法是将所有内容保存在 0000:7C00 ,所以在 mov ss,ax 之前你也可以做 mov ds,ax .

相关问题