为什么 CreateProcess 不能在 Windows 中的汇编中工作?

Why won't CreateProcess work in assembly in Windows?

我这里有一个调用 CreateProcess 的 C 程序...

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int main(int argc, char *argv[])
{
  STARTUPINFO st;
  ZeroMemory(%st, sizeof(STARTUPINFO));
  st.cb = sizeof(STARTUPINFO);
  PROCESS_INFORMATION pi;
  CreateProcessA("C:\WINDOWS\system32\cmd.exe",0,0,0,0,0,0,0,&st,&pi);
  return 0;
}

这 运行 很好,在 shell 中创建 shell。

我也有这段代码,通过 MinGW 编译器套件用 GAS 汇编编写,用于 Windows...

.extern _CreateProcessA@40
.def    _CreateProcessA@40; .scl 2; .type 32; .endef
.extern _ExitProcess@4
.def    _ExitProcess@4; .scl 2; .type 32; .endef

.text
.globl _main
.def   _main; .scl 2; .type 32; .endef

_main:
      push %ebp
      movl %esp, %ebp

      #PROCESS_INFORMATION...
      subl , %esp
      movl %esp, %eax

      #STARTUPINFO...
      subl , %esp
      movl , (%esp)
      movl %esp, %ebx

      #Application name with path : C:\WINDOWS\system32\cmd.exe...
      subl , %esp
      xor %edx, %edx
      movb %dx,         27(%esp)
      movb [=12=]x65,       26(%esp)
      movw [=12=]x7856,     24(%esp)
      movl [=12=]x2e646d63, 20(%esp)
      movl [=12=]x5c32336d, 16(%esp)
      movl [=12=]x65747379, 12(%esp)
      movl [=12=]x735c5357, 8(%esp)
      movl [=12=]x4f444e49, 4(%esp)
      movl [=12=]x575c3a43, (%esp)
      movl %esp, %ecx

      push %eax
      push %ebx
      push %edx
      push %edx
      push %edx
      push %edx
      push %edx
      push %edx
      push %edx
      push %ecx
      call _CreateProcessA@40

      movl %ebp, %esp
      pop  %ebp

      push %edx
      call _ExitProcess@4

它可以很好地编译和链接;

as createProc.s -o createProc.o
ld createProc.o -o createProc.exe -lkernel32

当它 运行 时,它确实 运行,它会在命令行上的 shell 内开始执行第二个 shell。有什么问题吗?

注意:我输入带有 movl 指令的字符串是有原因的,所以请不要建议我应该使用 .data、.bss 或标签。另请注意,我已经尝试在汇编程序的字符串中使用转义斜杠 (\\) 无济于事,如果使用转义斜杠,它实际上会崩溃。

关于编程风格
你应该忘记与 ESP.
混在一起 这样做的方法是在例程开始时设置堆栈帧,并使用 EBP 来寻址由此创建的 space。

你的路径有错字
您将 "c1\win...." 作为路径传递。那是行不通的。
您应该根据 ascii-table 仔细检查代码,或者检查调试器中进行 API 调用的参数..
我也不知道为什么你需要 29 个字节来存储字符串。据我所知,它适合 28 个字符。

使用栈帧的工作代码
这是使用堆栈框架按预期方式工作的代码。

//Set up stack frame.
00418200 55               push ebp
00418201 8BEC             mov ebp,esp
00418203 83C490           add esp,-
//Zero StartupInfoA
00418206 57               push edi
00418207 8D45A0           lea eax,[ebp-]
0041820A 8BF8             mov edi,eax
0041820C 33C0             xor eax,eax
0041820E B911000000       mov ecx,[=10=]000011
00418213 F3AB             rep stosd 
//st.cb = SizeOf(st)
00418215 C745A044000000   mov [ebp-],[=10=]000044
//Set the string: path = 'c:\windows\system32\cmd.exe'; 28 chars including trailing 0.
0041821C C745E4433A5C77   mov [ebp-c],5c3a43  //c:\w
00418223 C745E8696E646F   mov [ebp-],f646e69  //indo
0041822A C745EC77735C73   mov [ebp-],5c7377  //ws\s
00418231 C745F079737465   mov [ebp-],747379  //yste
00418238 C745F46D33325C   mov [ebp-[=10=]c],c32336d  //m32\
0041823F C745F8636D642E   mov [ebp-],e646d63  //cmd.
00418246 C745FC65786500   mov [ebp-],[=10=]657865  //exe- 
//Set up parameters for call
0041824D 8D4590           lea eax,[ebp-]        //ProcessInfo
00418250 50               push eax                 
00418251 8D45A0           lea eax,[ebp-]        //StartupInfoA
00418254 50               push eax
00418255 6A00             push [=10=]
00418257 6A00             push [=10=]
00418259 6A00             push [=10=]
0041825B 6A00             push [=10=]
0041825D 6A00             push [=10=]
0041825F 6A00             push [=10=]
00418261 6A00             push [=10=]
00418263 8D45E4           lea eax,[ebp-c]      //Path
00418266 50               push eax
//Call 
00418267 E80823FFFF       call CreateProcessA
//Clean up the stackframe
0041826C 5F               pop edi
0041826D 8BE5             mov esp,ebp
0041826F 5D               pop ebp

关于乱用ESP
如果将 ESP 设置为未对齐的地址,则会严重降低性能。

@HarryJohnson 想通了,所需要的只是将 STARTUPINFO 结构归零,

.extern _CreateProcessA@40
.def    _CreateProcessA@40; .scl 2; type 32; .endef
.extern _ExitProcess@4
.def    _ExitProcess@4; .scl 2; type 32; .endef

.text
.globl  _main
.def    _main; .scl 2; .type 32; .endef

_main:
       push %ebp
       movl %ebp, %esp

       xor %edx, %edx

       #PROCESS_INFORMATION...
       subl , %esp
       movl %esp, %eax

       #STARTUPINFO...
       subl , %esp
       movl %edx, 64(%esp)
       movl %edx, 60(%esp)
       movl %edx, 56(%esp)
       movl %edx, 52(%esp)
       movl %edx, 48(%esp)
       movl %edx, 44(%esp)
       movl %edx, 40(%esp)
       movl %edx, 36(%esp)
       movl %edx, 32(%esp)
       movl %edx, 28(%esp)
       movl %edx, 24(%esp)
       movl %edx, 20(%esp)
       movl %edx, 16(%esp)
       movl %edx, 12(%esp)
       movl %edx, 8(%esp)
       movl %edx, 4(%esp)
       movl %edx, (%esp)
       movb , (%esp)
       movl %esp, %ebx

       #Application name (C:\WINDOWS\system32\cmd.exe)...
       subl , %esp
       movb %dl, 27(%esp)
       movb [=10=]x65, 26(%esp)
       movw [=10=]x7865, 24(%esp)
       movl [=10=]x2e646d63, 20(%esp)
       movl [=10=]x5c32336d, 16(%esp)
       movl [=10=]x65747379, 12(%esp)
       movl [=10=]x735c5357, 8(%esp)
       movl [=10=]x4f444e49, 4(%esp)
       movl [=10=]x575c3a43, (%esp)
       movl %esp, %ecx

       push %eax
       push %ebx
       push %edx
       push %edx
       push %edx
       push %edx
       push %edx
       push %edx
       push %edx
       push %ecx
       call _CreateProcessA@40

       mov %ebp, %esp
       pop %ebp

       push %edx
       call _ExitProcess@4