【问题标题】:Why won't CreateProcess work in assembly in Windows?为什么 CreateProcess 不能在 Windows 的程序集中工作?
【发布时间】:2016-08-28 21:17:17
【问题描述】:

我这里有一个调用 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;
}

运行良好,在外壳中创建外壳。

我也有这段代码,通过适用于 Windows 的 MinGW 编译器套件以 GAS 程序集编写...

.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 $16, %esp
      movl %esp, %eax

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

      #Application name with path : C:\WINDOWS\system32\cmd.exe...
      subl $29, %esp
      xor %edx, %edx
      movb %dx,         27(%esp)
      movb $0x65,       26(%esp)
      movw $0x7856,     24(%esp)
      movl $0x2e646d63, 20(%esp)
      movl $0x5c32336d, 16(%esp)
      movl $0x65747379, 12(%esp)
      movl $0x735c5357, 8(%esp)
      movl $0x4f444e49, 4(%esp)
      movl $0x575c3a43, (%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 或标签。另请注意,我已经尝试在汇编程序中的字符串中使用转义斜杠(\\)无济于事,如果使用转义斜杠,它实际上会崩溃。

【问题讨论】:

  • 您的代码甚至没有汇编。你确定你能运行它吗?
  • Cmd.exe 是命令解释器。 Explorer.exe 是外壳。请修正您的术语。
  • 可能有错字,但代码在我端运行完美,只是没有从 cmd.exe 创建新进程。亲爱的 IInspectable;如果你运行我的 C 程序,你会看到它在一个 shell 中创建了第二个 shell,Explorer.exe 就是 GUI。
  • 最明显的区别是 C 代码将 STARTUPINFO 结构归零,除非我遗漏了什么,否则汇编代码不会。如果这不能解决问题(或者即使解决了!),您应该添加错误检查 - 检查 CreateProcess 的返回值,如果它为零,则调用 GetLastError 并将结果返回给用户。 (如果你还没有这样的机制,最简单的方法是让它成为你的应用程序的退出代码。)
  • 请再次阅读我的评论。我从来没有声称,你的代码应该启动一个 GUI 进程。这是关于术语的,在 Windows 中,cmd.exe 被称为“命令处理器”,而不是“shell”,正如您坚持的那样。请修正您的术语以及误导性标签。

标签: windows assembly mingw


【解决方案1】:

关于编程风格
您应该忘记与ESP 混在一起。
这样做的方法是在您的例程开始时设置一个堆栈帧并使用EBP 来处理由此创建的空间。

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

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

//Set up stack frame.
00418200 55               push ebp
00418201 8BEC             mov ebp,esp
00418203 83C490           add esp,-$70
//Zero StartupInfoA
00418206 57               push edi
00418207 8D45A0           lea eax,[ebp-$60]
0041820A 8BF8             mov edi,eax
0041820C 33C0             xor eax,eax
0041820E B911000000       mov ecx,$00000011
00418213 F3AB             rep stosd 
//st.cb = SizeOf(st)
00418215 C745A044000000   mov [ebp-$60],$00000044
//Set the string: path = 'c:\windows\system32\cmd.exe'; 28 chars including trailing 0.
0041821C C745E4433A5C77   mov [ebp-$1c],$775c3a43  //c:\w
00418223 C745E8696E646F   mov [ebp-$18],$6f646e69  //indo
0041822A C745EC77735C73   mov [ebp-$14],$735c7377  //ws\s
00418231 C745F079737465   mov [ebp-$10],$65747379  //yste
00418238 C745F46D33325C   mov [ebp-$0c],$5c32336d  //m32\
0041823F C745F8636D642E   mov [ebp-$08],$2e646d63  //cmd.
00418246 C745FC65786500   mov [ebp-$04],$00657865  //exe- 
//Set up parameters for call
0041824D 8D4590           lea eax,[ebp-$70]        //ProcessInfo
00418250 50               push eax                 
00418251 8D45A0           lea eax,[ebp-$60]        //StartupInfoA
00418254 50               push eax
00418255 6A00             push $00
00418257 6A00             push $00
00418259 6A00             push $00
0041825B 6A00             push $00
0041825D 6A00             push $00
0041825F 6A00             push $00
00418261 6A00             push $00
00418263 8D45E4           lea eax,[ebp-$1c]      //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 设置为未对齐的地址,则会严重降低性能。

【讨论】:

  • “乱搞” ESP 是我学习汇编编程的方式,并且我已经编写了许多具有这种编程风格的汇编程序。我知道它有效。感谢您的回答,但是您仍然没有回答为什么我的汇编代码运行但不执行cmd.exe的问题。
  • @August:You pass "c1\win...." as the path. 搞乱 ESP 肯定会让你的程序慢下来。它与 CPU 中的堆栈引擎混淆;而且它不必要地使您的代码复杂化,就好像汇编还不够复杂一样。
  • 抱歉 31 是错字,应该是 3a... 已修复。我在最后添加了对 _ExitProcess@4 的调用,使其停止死亡。仍然没有执行 cmd.exe...
  • 再一次,我很高兴您分享了您在术语和格式方面的专业知识,但没有人知道为什么我的程序不起作用,或者正在尝试解决这个问题。
  • gcc 默认值(在 x86 Linux 上)是 -fomit-frame-pointer。直接使用 ESP 很好,释放 EBP 以用作帧指针以外的东西,只要您不因异常而中断堆栈展开。唯一的性能问题是直接在 push/pop/call/ret 之后使用 ESP 可能需要堆栈引擎插入额外的堆栈同步 uop(仅限 Intel CPU)。不幸的是,ESP 相对地址总是需要一个 SIB 字节,因此代码大小会受到轻微影响。制作堆栈帧有时并不会降低速度,尤其是在 64 位代码中,您不会那么渴望寄存器。
【解决方案2】:

@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 $16, %esp
       movl %esp, %eax

       #STARTUPINFO...
       subl $68, %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 $68, (%esp)
       movl %esp, %ebx

       #Application name (C:\WINDOWS\system32\cmd.exe)...
       subl $28, %esp
       movb %dl, 27(%esp)
       movb $0x65, 26(%esp)
       movw $0x7865, 24(%esp)
       movl $0x2e646d63, 20(%esp)
       movl $0x5c32336d, 16(%esp)
       movl $0x65747379, 12(%esp)
       movl $0x735c5357, 8(%esp)
       movl $0x4f444e49, 4(%esp)
       movl $0x575c3a43, (%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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 2017-07-23
    相关资源
    最近更新 更多