【问题标题】:Assembly Syscalls in 64-bit Windows64 位 Windows 中的汇编系统调用
【发布时间】:2018-10-01 12:59:34
【问题描述】:

我在安装了 Cygwin 的 Windows 10 上。我一直在使用 Cygwin 编译/汇编 c 和使用 Cygwin 安装的“gcc”和“nasm”的汇编程序。据我所知,nasm 有一个 -f win64 模式,所以它可以汇编 64 位程序。现在,对于 windows 上的 x64 汇编编程,youtube 似乎缺少教程。 youtube 上的大多数汇编编程教程都是针对 x64 linux 或 x32 windows 的,我需要能够在 x64 windows 上将字符串打印到控制台,而无需使用任何外部函数,例如 C 的“printf”。

对我不起作用的 StackOverflow 链接:

64-bit windows assembler

据我所知,nasm 使用 -f win64 扩展名支持 64 位窗口。此外,答案与如何在 x64 位窗口上用汇编编写实际程序无关

How to write hello world in assembler under Windows?

所有给出代码的答案都只给出过时的 Windows 版本(32 位)的代码,除了一个。我尝试了一个适用于 64 位的答案,但是链接目标文件的命令给我一个错误,系统找不到指定的路径。

windows x64 assembler?

这个网站不包含任何代码,这是我需要的。另外,我正在尝试用 nasm 编写 Hello World 程序。

64 bit assembly, when to use smaller size registers

这个问题实际上包含一个 hello world 程序的代码,但是当在 windows 10(我的设备)上的 cygwin 下执行时,我遇到了分段错误。

Why does Windows64 use a different calling convention from all other OSes on x86-64?

我曾尝试使用 objdump -d 反汇编一个 C Hello World 程序,但这会调用 printf,一个预构建的 C 函数,并且我试图避免使用外部函数。

我尝试过其他外部函数(例如 Messagebox),但它们返回错误,因为有些东西无法识别这些函数。另外,我尽量不使用任何外部函数,只使用系统调用、系统输入或中断。

代码:

尝试 #1:

    section .data
    msg db "Hello, World!", 10, 0
    section .text
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, 14
    syscall
    mov rax, 60
    mov rdi, 0
    syscall

问题:正确组装和链接,但运行时抛出分段错误。

尝试 #2:

    section .text
    mov ah, 0eh
    mov al, '!', 0
    mov bh, 0
    mov bl, 0
    int 10h

问题:没有正确组装;说“test.asm:3:错误:操作码和操作数的组合无效”

尝试 #3:

    section .text
    msg db 'test', 10, 0
    mov rdi, 1
    mov rsi, 1
    mov rdx, msg
    mov rcx, 5
    syscall
    mov rdi, 60
    mov rsi, 0
    syscall

问题:正确组装和链接,但运行时抛出分段错误。

尝试 #4:

    section .text
    mov ah, 0eh
    mov al, '!'
    mov bh, 0
    mov bl, 0
    int 10h

问题:正确组装和链接,但运行时抛出分段错误。

我只需要一个在 64 位 Windows 10 上运行的 hello world 汇编程序示例。32 位程序在我运行时似乎返回错误。如果在不使用外部函数的情况下无法将字符串打印到控制台,那么使用外部函数并在 64 位 Windows 10 上运行的程序示例将会很好。

我听说 windows 中的系统调用的地址与 linux 中的地址大不相同。

【问题讨论】:

  • This MASMForum link 会帮助你。它是获得最佳 MASM64 Windows 源代码的关键。
  • 尝试 2 是 16 位 DOS 代码,不能作为 windows 可执行文件运行,mov al,imm8 指令只能包含单个 8 位立即数,所以你必须选择如果你想要数字 '!' (@ 987654334@ IIRC ASCII 表)或编号0,不能同时分配给注册al。尝试 3:除非您使用某些标签指定代码开始的位置,否则它可能从 .text 部分的开头开始,将字符串数据“test”作为指令执行(懒得检查它们形成什么样的指令)。像_start: 这样的标签通常与链接器配合使用来指定代码的入口点
  • Attemp 4 又是 16 位 DOS 代码(使用 BIOS 中断 int 10h),因此您可以在某些 DOS 模拟器/VM 下使用这个代码,例如 dosbox。 ..(我猜尝试 1 和 3 正在使用 linux 或 OSX 系统调用,但我不知道 windows 64b 系统调用是如何工作的,所以我什至无法识别正确的方法,我在过去十年中只使用 linux,有时使用 DOS在dosbox中)
  • 是否有一个特殊的标志可以用 ld 设置来指定程序的开始位置?我尝试将 _start 放在那里并将消息放在 .data 部分中,它仍然显示“非法指令”,所以我假设 ld 仍然不知道从哪里开始。
  • 这个问题有点像this

标签: windows assembly x86-64 system-calls interrupt


【解决方案1】:

尝试 #1:

尝试 #2:

Windows 内部使用中断或系统调用。但是,它们并未正式记录在案,并且它们可能会在Microsoft 想要更改它们的任何时候进行更改

只有少数.dll文件直接使用系统调用指令;所有程序都直接或间接访问这些.dll 文件。

某个序列(例如mov rax, 5syscall)可能在 Windows 更新之前具有“打印文本”的含义,而 Microsoft 可能会在 Windows 更新之后将此序列的含义更改为“删除文件” .

为此,Microsoft 只需替换内核和官方“允许”使用syscall 指令的.dll 文件。

调用 Windows 操作系统函数的唯一方法是调用 .dll 文件中的函数,以确保您的程序在下一次 Windows 更新后仍能正常工作 - 与您执行此操作的方法相同在 C 程序中。

示例(32 位代码):

push 1
push msg
push 14
call _write
mov dword [esp], 0
call _exit

【讨论】:

  • 作者请求的是 64 位代码。 x86_64 中的 C 级 Windows API 还是 32 位接口吗?哪些 DLL 提供 _write_exit
  • @mcandre 我回答的主要方面是“平台无关”部分:直接使用系统调用是行不通的。 x86_32 示例代码只是为了使答案的最后一部分更清晰,而不是给出“有效”的代码示例。
  • 自发布此内容以来已经有一段时间了,但我弄清楚了要使用哪些 dll 文件以及如何包含它们。 C:\\Windows\\System32\\msvcrt.dll 似乎提供了整个 C 标准库,您所要做的就是说“extern [whatever C function]”并将 msvcrt.dll 与您的目标文件链接。它不使用系统调用,但考虑到你所说的 Windows 中的系统调用不稳定,我可以在汇编中使用 C 的标准库。无论如何,这可能是使其独立于平台的唯一方法。
  • 只有 1 个问题:您知道实际上是否有较低级别的 dll 文件可以用来代替 msvcrt.dll 吗? C 中的 sizeof 因实现而异的事实让我有些担心。我在 System32 中找到了 user32.dll 和 kernel32.dll,这些提供 windows 库吗?
  • 解决了我自己的问题。 Visual Studio 附带一个名为 dumpbin 的东西,它与 /exports 一起允许您查看 .dll 文件附带的所有函数。事实证明,kernel32.dll 确实提供了 windows api。
猜你喜欢
  • 1970-01-01
  • 2016-01-16
  • 2012-05-29
  • 2018-06-06
  • 1970-01-01
  • 2010-12-18
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多