CreateProcessA函数在MASM64(ml64.exe)中不起作用

时间:2016-07-17 10:37:08

标签: windows winapi assembly masm

我想编写启动另一个程序(进程)的程序。我正在使用Visual Studio 2015中的MASM64(ml64.exe)。

程序不起作用。没有显示任何内容。在调试器中,我得到了访问冲突。

我不知道我的代码有什么问题。

我的代码:

extrn ExitProcess : proc
extrn MessageBoxA : proc
extrn CreateProcessA : proc

PROCESS_INFORMATION    struct 
hProcess    DWORD    ?
hThread    DWORD    ?
dwProcessId    DWORD    ?
dwThreadId    DWORD    ?
PROCESS_INFORMATION    ends

STARTUPINFOA    struct 
cb    DWORD    ?
lpReserved    DWORD    ?
lpDesktop    DWORD    ?
lpTitle    DWORD    ?
dwX    DWORD    ?
dwY    DWORD    ?
dwXSize    DWORD    ?
dwYSize    DWORD    ?
dwXCountChars    DWORD    ?
dwYCountChars    DWORD    ?
dwFillAttribute    DWORD    ?
dwFlags    DWORD    ?
wShowWindow    WORD    ?
cbReserved2    WORD    ?
lpReserved2    DWORD    ?
hStdInput    DWORD    ?
hStdOutput    DWORD    ?
hStdError    DWORD    ?
STARTUPINFOA    ends

.const
MB_ICONINFORMATION equ 40h
ERROR_ALREADY_EXISTS equ 0B7h
NORMAL_PRIORITY_CLASS equ 020h

.data
szText db "This is first application which creates new process using CreateProcessA.", 00h
szCaption db "Information",00h
processInfo PROCESS_INFORMATION <>
startupInfo STARTUPINFOA <>
szProcName db "D:\Apps\SampleApp.exe", 00h

.code
    Main proc
        ;not sure if correct - begin
        lea rax, processInfo
        lea rbx, startupInfo


        sub rsp, 60h 
        push rax
        push rbx
        push 00h
        push 00h
        push NORMAL_PRIORITY_CLASS
        push 00h
        mov r9, 00h
        mov r8, 00h
        mov rdx, 00h
        lea rcx, szProcName
        call CreateProcessA
        add rsp, 60h 
        ;not sure if correct - end

        sub rsp, 28h
        mov r9, MB_ICONINFORMATION
        lea r8, szCaption
        lea rdx, szText
        xor rcx, rcx
        call MessageBoxA
        add rsp, 28h

        Exit:
        xor rcx, rcx
        call ExitProcess
    Main endp
end

的build.bat

@echo off

ml64.exe prog1.asm /link /entry:Main /subsystem:windows /defaultlib:"kernel32.Lib" /defaultlib:"user32.Lib"

pause

提前感谢您的帮助。

4 个答案:

答案 0 :(得分:3)

您应该检查PROCESS_INFORMATION和STARTUPINFO结构的定义,因为它们可能在x86和x64之间有所不同。例如,句柄被定义为指针,而不是DWORD(32位整数)。

答案 1 :(得分:3)

除了初始化STARTUPINFO并确保使用正确的数据类型(指针在64位Windows中为64位宽,而DWORD始终为32位),您还需要正确分配参数区域(有时也被称为&#34;影子空间&#34;):

  

参数区域始终位于堆栈的底部(即使使用了alloca),因此在任何函数调用期间它始终与返回地址相邻。
  它至少包含四个条目,但始终有足够的空间来容纳可能被调用的任何函数所需的所有参数   请注意,总是为寄存器参数分配空间,即使参数本身从不归属于堆栈也是如此;确保被调用者已为其所有参数分配了空间。

强调我的,here

假设正确初始化了所需的所有数据结构,可能会调用CreateProcessA

; Stack is assumed aligned here

push rax                     ; Not aligned (08h)
push rbx                     ; Aligned     (10h)
push 00h                     ; Not aligned (18h)                    
push 00h                     ; Aligned     (20h)
push NORMAL_PRIORITY_CLASS   ; Not aligned (28h)
push 00h                     ; Aligned     (30h)

; Make room for the first four (register) parameters
; Stack is aligned, not need to subtract 28h, just 20h (4*8)

sub rsp, 20h

mov r9, 00h                  
mov r8, 00h
mov rdx, 00h
lea rcx, szProcName
call CreateProcessA

add rsp, 50h

请注意,调用者负责在通话后清理堆栈。

您想要使用sub rsp, ...在堆栈上保留空间并非完全错误 当然,你必须正确地进行数学计算,但最重要的是,该技术不能立即与push es兼容。

一旦有sub rsp, ...,就需要一个或多个mov [rsp+...], ...类型的间接存储来设置参数。 push es只会再次移动堆栈指针 ,使以前的所有工作都无用。

答案 2 :(得分:0)

在你的函数中保留足够的空间来调用具有如此多参数的子函数。 在函数序言中使用.ALLOCSTACK

然后只需分配整个参数列表

mov QWORD PTR [rsp+48h], rax                     
mov QWORD PTR [rsp+40h], rbx                     
mov QWORD PTR [rsp+38h], 00h                     
mov QWORD PTR [rsp+30h], 00h                     
mov QWORD PTR [rsp+28h], NORMAL_PRIORITY_CLASS
mov QWORD PTR [rsp+20h], 00h

xor r9, r9    ; pass 0              
xor r8, r8    ; pass 0
xor edx, edx  ; pass 0  (higher DWORD becomes always also zero, saving the REX-byte)
lea rcx, szProcName
call CreateProcessA  

答案 3 :(得分:0)

这是一个有点老的问题,但因为我刚刚解决了它,所以把它写下来。 现在我正在努力解决同样的问题,但 NASM。 问题是相同的,但语法会有所不同。 您的问题是您的 STARTUPINFOA 和 PROCESS_INFORMATION 不正确,原因有两个:

  1. 指针在 x64 系统上是 DWORD64
  2. 您没有考虑过 64 位系统上的结构填充

正确的 NASM 语法结构如下:

; https://msdn.microsoft.com/library/windows/desktop/ms686331.aspx
STRUC _STARTUPINFOA
    .cb:                resq 1
    .lpReserved:        resq 1
    .lpDesktop:         resq 1
    .lpTitle:           resq 1
    .dwX:               resd 1
    .dwY:               resd 1
    .dwXSize:           resd 1
    .dwYSize:           resd 1
    .dwXCountChars:     resd 1
    .dwYCountChars:     resd 1
    .dwFillAttribute:   resd 1
    .dwFlags:           resd 1
    .wShowWindow:       resd 1
    .cbReserved2:       resd 1
    .lpReserved2:       resq 1
    .hStdInput:         resq 1
    .hStdOutput:        resq 1
    .hStdError:         resq 1
ENDSTRUC

; https://msdn.microsoft.com/library/windows/desktop/ms684873.aspx
STRUC _PROCESS_INFORMATION
    .hProcess:          resq 1
    .hThread:           resq 1
    .dwProcessId:       resd 1
    .dwThreadId:        resd 1
ENDSTRUC

稍微解释一下:

  1. resq = DWORD64
  2. resd = DWORD32

如果遵循结构,大多数字段都可以正确填充,但有几个字段不同。原因是结构填充。 MS 编译器选择结构中最大的元素,然后将所有其他字段填充到它。为了举个例子,STARTUPINFOA案例如下所示:

  1. 编译器选择 DWORD64 作为最大元素
  2. cb 字段是 DWORD,但由于它无法用下一个字段 (lpReserved: DWORD64) 填充它,因此将其填充为 DWORD64
  3. lpReserved、lpDesktop 和 lpTitle 已经是 DWORD64
  4. 从 dwX 到 dwFlags,大小可以用下一个元素填充,所以没有变化
  5. wShowWindow 和 cbReserved2 只是 WORD,因此编译器将它们一起填充为 8 个字节,因此每个字段都更改为 DWORD
  6. 从 lpReserved2 到 hStdError 已经是 DWORD64

当我完成正确的填充后,它就像魅力一样。祝你好运! :)