【问题标题】:assembly x86 code and process virtual memory汇编 x86 代码和进程虚拟内存
【发布时间】:2018-04-22 09:33:18
【问题描述】:

我正在尝试理解下面的一段代码

data dd 1,2,3,4,5,6
myfunc:
lea eax, data
cmp eax, DWORD PTR [ebp-8]
jle SHORT L1
mov ecx, DWORD PTR [ebp-8]
add  ecx, DWORD PTR [ebp-4] 
mov DWORD PTR [ebp-4], ecx 
mov edx, DWORD PTR [ebp-4] 
sub edx, DWORD PTR [ebp-8]
mov DWORD PTR [ebp-8], edx
 mov  eax, DWORD PTR [ebp-4]
 sub eax, DWORD PTR [ebp-8]
 mov DWORD PTR [ebp-4], eax
 L1:
 mov eax, DWORD PTR [ebp-8]

第一行我知道它将被加载到进程虚拟内存中,因为dd 是用4 bytes 定义的,所以可能是这样的吗?

data dd 1,2,3,4,5,6

4004000  01 ; 1
4004001  00 ; 0
4004002  00 ; 0
4004003  00 ; 0

4004004  02 ; 2
4004005  00 ; 0
4004006  00 ; 0
4004007  00 ; 0

4004008  03 ; 3
4004009  00 ; 0
400400A  00 ; 0
400400B  00 ; 0

4004008  04 ; 4
4004009  00 ; 0
400400A  00 ; 0
400400B  00 ; 0

400400C  05 ; 5
400400D  00 ; 0
400400E  00 ; 0
400400F  00 ; 0

4004010  06 ; 6
4004011  00 ; 0
4004012  00 ; 0
4004013  00 ; 0

但是,在标签之后,它会将 var data 的内存地址加载到 eax 寄存器中,然后将 eax 的值与 [ebp-8] 处存在的 DWORD 进行比较

我不明白的是,我认为 ebp 中没有地址,所以可能是它丢失了mov ebp,esp

即使我将 esp 移动到 ebp 我不明白的部分是代码说 ebp-8 应该是 ebp-4 可能指向定义的第一个 DWORD 的地址?

有人可以指导我正确的方向吗?

谢谢!

【问题讨论】:

  • 是的,使用[ebp-8] 而不在函数顶部使用push ebp / mov ebp,esp 很奇怪。但这将是一个本地的,而不是一个函数 arg,(因为它低于 EBP),所以它只是一个独立的函数是没有意义的。它可能是现有函数可以跳转到的块。顺便说一句,lea eax, data 很傻; mov eax, OFFSET data 更短更快,没有缺点。 cmp eax, DWORD PTR [ebp-8] 似乎将静态地址(eax)与局部变量进行比较。代码看起来很垃圾;是编译器生成的调试模式吗?
  • 嘿彼得,是的,它看起来很垃圾,它可能是 IDA Pro 提供给我的一个用于研究目的的块,从一个反汇编的 PE 中了解这个函数的作用以及指令对 cpu 寄存器的影响.因此,如果我在函数myfunc 之外执行push ebpmov ebp,esp,我将在ebp 中有起始地址,但是当它尝试与eax 进行比较时,它不会是invalid 地址,因为ebp-4不存在?我试图了解这些指令在执行时会做什么
  • 当然ebp-4 会存在。它甚至会被映射到您的进程的地址空间中。它将低于esp,因此会被异步破坏,除非您的函数也执行sub esp, 12。一个普通的函数这样做来为当地人保留空间。
  • 很明显这不是函数的开始,或者是使用父函数栈帧的私有辅助函数。标签不是真的myfunc 是吗?你只是猜测它是函数的开始而不是函数中的块吗?
  • 感谢@Peter Cordes,不幸的是,一旦ebp 寄存器发生减法和加法,我仍然无法弄清楚寄存器的内容是什么。我没有更多信息,它是函数中的一个块,它只是我所拥有的摘录。

标签: assembly x86 disassembly


【解决方案1】:

...它可能是来自 IDA Pro 的反汇编 PE 提供给我用于研究目的的块,以了解此函数的作用以及指令对 cpu 寄存器的影响

...我试图了解这些指令在执行时会做什么

...不幸的是,一旦ebp 寄存器发生这种减法和加法,我仍然无法弄清楚寄存器的内容是什么

mov ecx, DWORD PTR [ebp-8]
add  ecx, DWORD PTR [ebp-4] 
mov DWORD PTR [ebp-4], ecx 
mov edx, DWORD PTR [ebp-4] 
sub edx, DWORD PTR [ebp-8]
mov DWORD PTR [ebp-8], edx
mov  eax, DWORD PTR [ebp-4]
sub eax, DWORD PTR [ebp-8]
mov DWORD PTR [ebp-4], eax

这段代码本质上只是切换[ebp-8][ebp-4]的局部变量。
与其需要 9 条指令并破坏 3 个寄存器,不如这样写:

    mov edx, [ebp-8]
    mov eax, [ebp-4] 
    mov [ebp-4], edx
    mov [ebp-8], eax

lea eax, data
cmp eax, DWORD PTR [ebp-8]
jle SHORT L1
...
L1:
mov eax, DWORD PTR [ebp-8]

为了清楚起见重写测试:

    cmp DWORD PTR [ebp-8], data
    jge SHORT L1
    ...
L1:
    mov eax, [ebp-8]

如果[ebp-8]处的局部变量大于等于数组的起始地址,则成为EAX处的结果。

如果[ebp-8]处的局部变量小于数组的起始地址,则[ebp-4]的原始内容成为EAX中的结果。


如果切换部分不重要,下一个代码将产生相同的EAX

    mov eax, [ebp-8]
    cmp eax, data
    jge SHORT L1
    mov eax, [ebp-4]
L1:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 2013-12-13
    相关资源
    最近更新 更多