Executable isn't compatible with 64 bits proce

2019-09-01 04:28发布

问题:

My problem is that this: When I try to execute an .exe assembled in NASM and Windows 8 64 bits tells me that this .exe isn't compatible with 64 bits. So, how should I assemble this code (I obtained it from the Web)?

Used code

STD_OUTPUT_HANDLE   equ -11
STD_INPUT_HANDLE    equ -10
NULL                equ 0

global start
extern ExitProcess, GetStdHandle, WriteConsoleA, ReadConsoleInputA

section .data    ;message we want to display on console
    msg                 db "Press a key to continue...", 13, 10, 0
    msg.len             equ $ - msg
    consoleInHandle     dd 1

section .bss     ;buffers declaration
    buffer_out          resd 2
    buffer_in           resb 32

section .text
    start:       ;starting point of our program
        push    STD_OUTPUT_HANDLE
        call    GetStdHandle   ;call to get a handle to the
        push    NULL           ;specified mode (input, output...)
        push    buffer_out
        push    msg.len
        push    msg
        push    eax            ;contains the GetStdHandle result
        call    WriteConsoleA  ;call to print our msg in console

    read:
        push    STD_INPUT_HANDLE
        call    GetStdHandle        ;new call to get input handle
        push    NULL
        push    1
        push    buffer_in
        push    eax
        call    ReadConsoleInputA   ;call to detect user input
                                    ;this function will wait til
    exit:                           ;it detects enough keypresses
        push    NULL                ;(in this case, 1)
        call    ExitProcess

Command used to assemble this: nasm -fwin32 main.asm -o main.exe

回答1:

You ran the assembler this way:

nasm -fwin32 main.asm -o main.exe

If you assemble with -fwin32 this will not generate an executable. It actually generates an object file. The issue is that an OBJ file in this case is not an executable. It would be like taking a TXT file, renaming it an EXE and trying to run that. It won't.

So you should have executed nasm this way:

nasm -fwin32 main.asm -o main.obj

This outputs a file main.obj. You can't run an object file. It must be processed by a linker to produce an exe. The linker will also be used to resolve the systems calls like WriteConsoleA, ExitProcess etc.

There are many linkers out there including Microsoft's linker called link.exe. I do not know if you have a Microsoft compiler installed or not, so I am going to recommend using a free one to help you along. You can download one called GoLink from here. You can read the GoLink manual here. Once downloaded you can extract GoLink.exe to the same directory as your nasm.exe.

The command you will need to use to link main.obj to produce main.exe is:

GoLink.exe main.obj kernel32.dll /fo main.exe /console

This will take main.obj and kernel32.dll and link them together and produce an executable called main.exe. kernel32.dll is the DLL(shared library) that holds the system functions WriteConsoleA, ExitProcess, ReadConsoleInputA and GetStdHandle. Without it the linker will not be able to create a final executable and will exit with an error saying as such.

You have one major problem in your program that will likely make it crash when inputting characters. I have modified it to look like this:

STD_OUTPUT_HANDLE   equ -11
STD_INPUT_HANDLE    equ -10
NULL                equ 0

global start
extern ExitProcess, GetStdHandle, WriteConsoleA, ReadConsoleInputA

section .data    ;message we want to display on console
    msg                 db "Press a key to continue...", 13, 10, 0
    msg.len             equ $ - msg

section .bss     ;buffers declaration
    buffer_out          resd 1
    buffer_in           resb 32
    events_read         resd 1

section .text
    start:       ;starting point of our program
        push    STD_OUTPUT_HANDLE
        call    GetStdHandle   ;call to get a handle to the
        push    NULL           ;specified mode (input, output...)
        push    buffer_out
        push    msg.len
        push    msg
        push    eax            ;contains the GetStdHandle result
        call    WriteConsoleA  ;call to print our msg in console

    read:
        push    STD_INPUT_HANDLE
        call    GetStdHandle        ;new call to get input handle
        push    events_read         ;push dword buffer to return # of events read
                                    ;This paramater can't be NULL/0
        push    1
        push    buffer_in
        push    eax
        call    ReadConsoleInputA   ;call to detect user input
                                    ;this function will wait til
    exit:                           ;it detects enough keypresses
        push    NULL                ;(in this case, 1)
        call    ExitProcess

Your code originally had:

push    NULL

I changed it to:

push    events_read         ;push dword buffer to return # of events read
                            ;This paramater can't be NULL/0

I also added the events_read variable (a single DWORD allocated with resd to the .bss section):

    events_read         resd 1

You can find the Microsoft documentation for ReadConsoleInputA here to find out more about the parameters. Note that with 32 bit windows applications parameters are pushed onto the stack in reverse order as they appear in the documentation. The documentation says:

BOOL WINAPI ReadConsoleInput( _In_ HANDLE hConsoleInput, _Out_ PINPUT_RECORD lpBuffer, _In_ DWORD nLength, _Out_ LPDWORD lpNumberOfEventsRead );

Parameters

hConsoleInput [in] A handle to the console input buffer. The handle must have the GENERIC_READ access right. For more information, see Console Buffer Security and Access Rights.

lpBuffer [out] A pointer to an array of INPUT_RECORD structures that receives the input buffer data. The storage for this buffer is allocated from a shared heap for the process that is 64 KB in size. The maximum size of the buffer will depend on heap usage.

nLength [in] The size of the array pointed to by the lpBuffer parameter, in array elements.

lpNumberOfEventsRead [out] A pointer to a variable that receives the number of input records read.