给定以下代码:
L1 db "word", 0
mov al, [L1]
mov eax, L1
里面的括号[L1]
代表什么?
这个问题专门针对 NASM。英特尔语法程序集的另一个主要风格是 MASM 样式,当不涉及寄存器时,括号的工作方式不同:
请参阅MASM32 中的混淆括号
给定以下代码:
L1 db "word", 0
mov al, [L1]
mov eax, L1
里面的括号[L1]
代表什么?
这个问题专门针对 NASM。英特尔语法程序集的另一个主要风格是 MASM 样式,当不涉及寄存器时,括号的工作方式不同:
请参阅MASM32 中的混淆括号
[L1]
表示地址 L1 处的内存内容。mov al, [L1]
在这里运行后,al
寄存器将接收地址 L1 处的字节(字母 'w')。
这种类型的操作数,例如[ebp]
,称为内存操作数。
这里的所有答案都很好,但我看到没有一个说明遵循这一严格规则的警告 -如果括号,则取消引用,除非它是lea
指令。
lea
是上述规则的一个例外。说我们已经
mov eax, [ebp - 4]
的值ebp
减去 4 并且括号表示将结果值作为地址,并且驻留在该地址的值存储在 中eax
。但是,在lea
' 的情况下,括号并不意味着:
lea eax, [ebp - 4]
的值ebp
减去 4 并将结果值存储在 中eax
。该指令将仅计算地址并将计算的值存储在目标寄存器中。请参阅MOV 和 LEA 有什么区别?了解更多详情。
简单的意思是在标签 L1 标记的地址处获取内存。
如果你喜欢 C,那么可以这样想:[L1]
是一样的*L1
括号表示取消引用地址。例如
mov eax, [1234]
意思是,将地址 1234 的内容移动到 EAX。所以:
1234 00001
EAX 将包含 00001。
直接内存寻址-al
将加载位于内存地址的值L1
。
它们的意思是,不是将寄存器的值或数值移动到寄存器中,而是将L1
寄存器al
值或数值L1
视为指向内存的指针,获取该内存地址的内容,然后将该内容移动到al
.
在这种情况下,L1 是一个内存位置,但如果寄存器名称在括号中,则同样的逻辑将适用:
mov al, [ebx]
也称为负载。
与许多汇编语言一样,这意味着间接。换句话说,第一个mov
加载al
的是(换句话说就是字节)的内容,而不是地址。L1
'w'
您的第二个mov
实际上加载eax
了地址 L1
,您可以稍后取消引用该地址以获取或设置其内容。
在这两种情况下,L1
概念上都认为是地址。
它表明寄存器应该用作实际位置的指针,而不是作用于寄存器本身。
在 MASM 中,括号与寄存器一起使用时与 NASM 一样工作,在这种情况下不是可选的。(对于不涉及寄存器的寻址模式,情况有所不同,请参阅MASM32 中的混淆括号)
括号表示寄存器包含一个指针,并且机器代码需要该指针的值(指针是字节寻址的:指针是内存的第 x 个字节;一个字节是 8 个二进制数字;一个十六进制数字是 4二进制数字;一个字节是 2 个十六进制数字;从那里开始);如果它在指令的 src 部分。
在二进制机器码中,(在 notepad.exe 中输入十六进制数字,然后将十六进制数字转换为 \xhexadecimal result~python_reference)以获得寄存器中指针的值,它可以在正在执行的指令的 ModR/M 字节中定义写在notepad.exe中,我相信这是10个字符。(我将首先完成我的 MASM 体验,然后我将继续通过阅读窗口的内核/恶意软件分析来收集有关在 notepad.exe 中键入什么内容的信息;我将回到这篇文章并写一篇例子)
1 .686
2 .model flat, c
3 option casemap :none
4
5 include C:\masm32\include\kernel32.inc
6 includelib C:\masm32\lib\kernel32.lib
7
8 .data
9 message db "Hello world!", 0
10 .code
11
12 main proc
13 call testfunc
14 COMMENT @
15 push 0FFFFh
16 push testfunc
17 pop ax
18 @
19 invoke ExitProcess, 404
20 main ENDP
21
22 testfunc proc
23 sub esp, 1
24 mov al, 0FFh
25 mov [esp], al
26 COMMENT @
27 push 0FFFFh
28 push 05EFFB880h
29 push 0773BFF5Ch
30 push 0FB038Fh
31 mov al, [esp+8]
32 @
33 invoke ExitProcess, [esp]
34 testfunc ENDP
35
36 END main
Windows:
如果您要输入执行结果,并比较:
C:\masm32\bin\ml /c /Zd /coff script_name.asm
C:\masm32\bin\Link /SUBSYSTEM:CONSOLE script_name.obj
script_name.exe
echo %ERRORLEVEL%
程序的退出状态(用 打印echo
)将是存储到堆栈内存的数字,mov [esp], al
作为 ExitProcess 的 arg,以十六进制 FF 结尾。(%ERRORLEVEL%
将数字转换为一串十进制数字,而不是十六进制,但它是相同的数字。)
但是,如果没有[]周围[esp]
:我们还必须将 AL 更改为 EAX(因为 x86 CPU 没有将 8 位寄存器移动到 32 位寄存器底部的指令)。并删除最后一次在代码行中使用字母“esp”周围的括号;这将导致指向 esp 中的堆栈区域的指针。
1 testfunc proc
2 mov eax, esp
3 mov bl, 0FFh
4 mov [eax], bl
5 COMMENT @
6 push 0FFFFh
7 push 05EFFB880h
8 push 0773BFF5Ch
9 push 0FB038Fh
10 mov al, [esp+8]
11 @
12 invoke ExitProcess, [esp]
13 testfunc ENDP
标签:可选括号
上面的代码证明了括号始终有效(使用代码中的值作为指针并获取指针的值)在语言中将机器代码解释为可读的方式而不是字节,并且知道 Windows 内核将如何执行一个 exe 文件(逆向工程窗口的内核,以便在记事本中从头开始制作您自己的 exe 文件,其中没有足够的支持;但是,恶意软件分析确实有足够的支持。)
(如果要测试代码:将最后代码中的行替换为testfunc,并与行相同的方式执行):在这种情况下,eax等于esp在堆栈段内存中的指针(堆栈段很重要,因为它有自己的指令:从/到立即数、寄存器或内存操作数的 PUSH 和 POP 32 位值)。因此,当您执行它时,裸esp
操作数是 ESP 寄存器的值,一个指针值,而不是堆栈上的内存内容。
我会偶尔回来编辑这篇文章(如果我真的很擅长组装的话。);因此,这可以作为组装的终极指南。我刚刚开始组装并在组装中的特定范围脚本中快速找到最重要的位查找器。
到目前为止帮助我制作这个脚本的资源:
5 小时的 C++ 完整教程:
帮助我找出像 DWORD 之类的东西(无符号长)。
https://www.bing.com
我读到第 3 卷的一半,然后浏览了其余部分
https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
Davy Wybrial 的汇编语言教程在看完之后值得一看:
https
://www.youtube.com/watch?v=wLXIWKUWpSs&ab_channel=DavyWybiral
英特尔软件开发人员手册的“操作部分”部分:
如何在 Windows (MASM) 上开始编码组装
https://www.youtube.com/watch?v=lCjbwLeLNfs&ab_channel=CharlesClayton
再次,我会回到这里(这篇文章,以及我未来的文章)并尝试教育每个人,所以我的知识与每个人阅读是平等的。