assembly 64位Windows中的程序集系统调用

hsvhsicv  于 2023-01-09  发布在  Windows
关注(0)|答案(2)|浏览(161)

我在windows 10上,安装了cygwin,我一直在使用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写你好世界程序。
64 bit assembly, when to use smaller size registers
这个问题实际上包含了hello world程序的代码,但是当在windows10(我的设备)上的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

问题:组装不当;显示"测试. 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中的大不相同。

zvms9eto

zvms9eto1#

尝试#1:
尝试#2:
Windows内部使用中断或系统调用。但是它们没有正式记录,并且可以随时更改Microsoft想要更改它们
只有少数.dll文件直接使用系统调用指令;所有程序都直接或间接地访问这些.dll文件。
在Windows更新之前,某个序列(例如mov rax, 5syscall)可能具有"打印文本"的含义,而Microsoft可能在Windows更新之后将此序列的含义更改为"删除文件"。
要做到这一点,微软只需替换内核和.dll文件,这些文件被正式"允许"使用syscall指令。
调用Windows操作系统函数的唯一方法是调用.dll文件中的函数-就像在C程序中执行此操作一样,这样可以保证您的程序在下一次Windows更新后仍然可以工作。
示例(32位代码):

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

ecfsfe2w2#

请看ReactOS源代码。此程序使用NT API将Hello,world!\n打印到控制台。

const char *msg = "Hello, world!\n";
HANDLE hStdout = NtCurrentPeb()->ProcessParameter->StandardOutput;
IO_STATUS_BLOCK IoStatusBlock;
NtWriteFile(hStdout
            NULL, 
            NULL, 
            NULL, 
            &IoStatusBlock, 
            (PVOID)msg,
            14,
            NULL,
            NULL);
NtTerminateProcess(NtCurrentProcess, 0);
extern NtWriteFile
extern NtTerminateProcess

%define NtCurrentPeb() gs:[0x60]
%define ProcessParameter 32
%define StandardOutput 40
%define NtCurrentProcess() -1

section .rdata
        msg db `Hello, world!\n\0`
section .bss
        IoStatusBlock resb 16
section .text
        global main
main:
        sub rsp, 88 
        mov rcx, NtCurrentPeb()
        mov rcx, ProcessParameter[rcx]
        mov rcx, StandardOutput[rcx]
        xor edx, edx
        xor r8d, r8d
        xor r9d, r9d
        mov qword 32[rsp], IoStatusBlock
        mov qword 40[rsp], msg
        mov qword 48[rsp], 14
        mov qword 56[rsp], 0
        mov qword 64[rsp], 0
        call NtWriteFile

        mov rcx, NtCurrentProcess()
        xor edx, edx
        call NtTerminateProcess
        int3

解释

首先,我们通过从PEB访问_RTL_USER_PARAMETERS来提取StandardOutput句柄。
调用NtWriteFileStandardOutput
调用NtTerminateProcess退出。

调用约定

syscall指令清除用于rflags的R11和用于RIPRCX,因此第一个参数在R10上。
| 系统调用编号|参数0|参数1|精氨酸2|精氨酸3|
| - ------| - ------| - ------| - ------| - ------|
| 拉克斯|R10|黑索今|八国集团|第九代|
关于堆栈参数,由于卷影存储(32字节),它从40[rsp]开始,8字节来自call指令。

兼容性

可在NT 6.3(Windows 8.1)及更高版本中运行。NT 6.1(Windows 7)及更旧版本不运行。

相关问题