FASM 将 Hello World 写入控制台,根本不包含任何包含项或依赖项

blu*_*yke 3 windows assembly x86-64 system-calls fasm

我见过

Windows下如何用汇编程序编写hello world?

使用 DOS 在 Fasm 中将 hello,world 写入控制台

如何在fasm中写入控制台?

我已经尝试/看到了像这个答案中的 MASM 示例的代码

;---ASM Hello World Win64 MessageBox

extrn MessageBoxA: PROC
extrn ExitProcess: PROC

.data
title db 'Win64', 0
msg db 'Hello World!', 0

.code
main proc
  sub rsp, 28h  
  mov rcx, 0       ; hWnd = HWND_DESKTOP
  lea rdx, msg     ; LPCSTR lpText
  lea r8,  title   ; LPCSTR lpCaption
  mov r9d, 0       ; uType = MB_OK
  call MessageBoxA
  add rsp, 28h  
  mov ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
main endp

End
Run Code Online (Sandbox Code Playgroud)

(我在 Windows 64 位上收到错误“非法指令”,extrn MessageBoxA:PROC因为 FASM 不理解该 MASM 指令。)

还有这个问题中的FASM 示例

 ; Example of 64-bit PE program


format PE64 GUI 
entry start 

section '.text' code readable executable 

  start: 
      sub     rsp,8*5         ; reserve stack for API use and make stack dqword aligned 

    mov     r9d,0 
    lea     r8,[_caption] 
    lea     rdx,[_message] 
    mov    rcx,0 
    call    [MessageBoxA] 

    mov     ecx,eax 
    call    [ExitProcess] 

section '.data' data readable writeable 

  _caption db 'Win64 assembly program',0 
  _message db 'Hello World!',0 

section '.idata' import data readable writeable 

  dd 0,0,0,RVA kernel_name,RVA kernel_table 
  dd 0,0,0,RVA user_name,RVA user_table 
  dd 0,0,0,0,0 

  kernel_table: 
    ExitProcess dq RVA _ExitProcess 
    dq 0 
  user_table: 
    MessageBoxA dq RVA _MessageBoxA 
    dq 0 

  kernel_name db 'KERNEL32.DLL',0 
  user_name db 'USER32.DLL',0 

  _ExitProcess dw 0 
    db 'ExitProcess',0 
  _MessageBoxA dw 0 
    db 'MessageBoxA',0
Run Code Online (Sandbox Code Playgroud)

但它显示一个消息框,并且还具有外部依赖项“kernel32.dll”和“user32.dll”

还尝试了FASM 论坛的这个例子

format pe console


include 'win32ax.inc'

entry main

section '.data!!!' data readable writeable

strHello db 'Hello World !',13,10,0
strPause db 'pause',0

section '.txt' code executable readable

main:
       ; you can use crt functions or windows API.
       cinvoke printf,strHello
       cinvoke system,strPause; or import getc()
       ; or
       ; invoke printf,srtHello
       ; add esp, 4

       ; or use WriteFile and GetStdHandle APIs
       push 0
       call [ExitProcess]
      
section '.blah' import data readable

library kernel32,'kernel32.dll',\
    msvcrt,'msvcrt.dll'    ;; C-Run time from MS. This is always on every windows machine

import kernel32,\
          ExitProcess,'ExitProcess'
import msvcrt,\
          printf,'printf',\
          system,'system'
Run Code Online (Sandbox Code Playgroud)

但这取决于win32ax.inc其他进口

format PE console
include 'win32ax.inc'
.code
start:
        invoke  WriteConsole,<invoke GetStdHandle,STD_OUTPUT_HANDLE>,"Hello World !",13,0
        invoke  Sleep,-1
.end start
Run Code Online (Sandbox Code Playgroud)

但需要“win32ax.inc”导入

我可以从 FASM 论坛找到没有 win32ax 的最接近的:

format pe64 console
entry start

STD_OUTPUT_HANDLE       = -11

section '.text' code readable executable

start:
        sub     rsp,8*7         ; reserve stack for API use and make stack dqword aligned
        mov     rcx,STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        mov     rcx,rax
        lea     rdx,[message]
        mov     r8d,message_length
        lea     r9,[rsp+4*8]
        mov     qword[rsp+4*8],0
        call    [WriteFile]
        mov     ecx,eax
        call    [ExitProcess]

section '.data' data readable writeable

message         db 'Hello World!',0
message_length  = $ - message

section '.idata' import data readable writeable

        dd      0,0,0,RVA kernel_name,RVA kernel_table
        dd      0,0,0,0,0

kernel_table:
        ExitProcess     dq RVA _ExitProcess
        GetStdHandle    dq RVA _GetStdHandle
        WriteFile       dq RVA _WriteFile
                        dq 0

kernel_name     db 'KERNEL32.DLL',0
user_name       db 'USER32.DLL',0

_ExitProcess    db 0,0,'ExitProcess',0
_GetStdHandle   db 0,0,'GetStdHandle',0
_WriteFile      db 0,0,'WriteFile',0    
Run Code Online (Sandbox Code Playgroud)

但仍然需要 kernel32.dll 和 user32.dll

有什么方法可以在没有任何外部 DLL 的情况下做到这一点吗?我知道程序 fasm 本身就可以做到这一点,并打印到控制台,不是吗?

Mar*_*nau 5

有什么方法可以在没有任何外部 DLL 的情况下做到这一点吗?

在 Windows 下:绝对不行!

Windows 使用一些方法(可能syscall)进入操作系统,但是没有官方的入口点。

"Hello world"这意味着在当前 Windows 版本中显示消息框的完全相同的程序(不太可能但)可能会在下一次 Windows 更新后执行完全不同的操作!

因为微软假设每个 Windows 程序仅通过使用与.dll内核版本匹配的文件来调用操作系统,所以他们可以做到这一点。

我不了解 Windows 10,但较旧的 Windows 版本(我不记得是 XP、Vista 还是 7)甚至简单地假设.exe如果不使用任何.dll文件,文件会立即返回:该程序不甚至在这种情况下开始!

  • @bluejayke:这不是一个“骗局”,这只是一个你不喜欢的设计决定。MacOS 不能完全保证稳定性,但作为开源的它至少是可用的并且有文档记录。Linux 确实有记录的稳定内核 ABI,可能是因为内核和 C 库是分开开发的。如果您不喜欢被骗,请使用更好的操作系统(以及一般的免费软件)。 (5认同)
  • 这不是一个“骗局”;而是一个“骗局”。它是一个未记录的私有 API。每个软件都有这个。 (3认同)

dxi*_*xiv 5

我知道只有程序 fasm 本身可以做到这一点,并打印到控制台

事实并非如此,fasm 也使用 kernel32 API。

在此输入图像描述

FWIW kernel32 被加载到 Windows 中每个进程的内存空间中,因此使用 kernel32 API 不会有任何损失或开销。