我想创建一个批处理文件,该文件将使一个程序运行7秒钟,而与其他程序的执行完成无关。我还希望该程序接受输入并将输出保存在外部文件中。这是我尝试的:
start program.exe
ping 1.1.1.1 -n 1 -w 7000 > nul
taskkill /im program.exe /f
rem continue here
上面的工作正常,但当我将第1行替换为:
start program.exe < in.txt > out.txt
那么从文件中输入和在文件中输出将不起作用。
cmd不会设置结构的STARTF_USESTDHANDLES
标志CreateProcess
STARTUPINFO
。相反,它临时重定向其自己的标准句柄并依赖于继承。即使cmd必须调用ShellExecuteEx
,该方法仍然有效,而该方法缺少显式设置标准句柄的方法。
但是,当CREATE_NEW_CONSOLE
在进程创建标志中设置了重定向时,重定向其自己的标准句柄将不起作用,这是该start
命令的默认设置。为避免此问题,请使用该/b
选项阻止创建新控制台。
您可能还需要将stderr重定向到stdout或文件。这样可以防止将错误写入控制台。例如:
start /b program.exe <in.txt >out.txt 2>&1
start /b program.exe <in.txt >out.txt 2>err.txt
start /b program.exe <in.txt >out.txt 2>nul
(test) C:\>cdb -Goxi ld cmd
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: cmd
Symbol search path is: symsrv*symsrv.dll*
C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(ed0.1770): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc int 3
0:000> .reload /f
Reloading current modules
.....
0:000> bp CreateProcessW
0:000> g
在新控制台中运行where.exe。
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
(test) C:\>start /w where.exe <nul >nul
Breakpoint 0 hit
kernel32!CreateProcessW:
00000000`775a0660 4883ec68 sub rsp,68h
请注意,cmd.exeStandardOutput
在调用前将其重定向CreateProcess
:
0:000> ?? ((ntdll!_PEB *)@$peb)->ProcessParameters->StandardOutput
void * 0x00000000`00000060
0:000> !handle 60 3
Handle 60
Type File
Attributes 0
GrantedAccess 0x120196:
ReadControl,Synch
Write/Add,Append/SubDir/CreatePipe,WriteEA,ReadAttr,WriteAttr
HandleCount 2
PointerCount 3
流程创建标志,即dwCreationFlags
第六个参数:
0:000> dd (@rsp + 6*8) l1
00000000`00182c58 00080410
作为0x80410传递,它是以下标志的按位或:
EXTENDED_STARTUPINFO_PRESENT
CREATE_UNICODE_ENVIRONMENT
CREATE_NEW_CONSOLE
因为创建了新控制台,所以where.exe不会继承cmd的标准句柄:
0:000> g
Symbol search path is: symsrv*symsrv.dll*
C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(1550.1a80): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc int 3
1:001> ?? ((ntdll!_PEB *)@$peb)->ProcessParameters->StandardOutput
void * 0x00000000`00000007
注意:在Windows 8+中,控制台句柄只是常规文件句柄,因此您必须更深入地研究。
在此示例中,我使用Windows 7,因此控制台句柄是通过设置低2位(例如3、7、11 => 0b0011、0b0111、0b1011)标记的假句柄。“假”是指它们不在用于内核对象句柄的进程句柄表中。因此,例如,您不能使用debugger!handle
命令检查句柄7:
1:001> !handle 7 f
Could not duplicate handle 7, error 87
在Windows 7中,控制台句柄由控制台主机进程conhost.exe分配和管理。它们被标记为Windows基本功能可以通过进行对conhost.exe的必需LPC调用NtRequestWaitReplyPort
。
上面的示例演示了如何创建新的控制台来覆盖继承cmd的重定向标准句柄。现在,让我们添加该/b
选项以防止创建新的控制台。
1:001> g
(test) C:\>start /b /w where.exe <nul >nul
Breakpoint 0 hit
kernel32!CreateProcessW:
00000000`775a0660 4883ec68 sub rsp,68h
dwCreationFlags
是0x80600:
0:000> dd (@rsp + 6*8) l1
00000000`00182c58 00080600
这是以下创建标志的按位或:
EXTENDED_STARTUPINFO_PRESENT
CREATE_UNICODE_ENVIRONMENT
CREATE_NEW_PROCESS_GROUP
(指定的副作用/b
是将流程创建为新流程组的领导者。如果是控制台流程,则允许生成以该组为目标的Ctrl + Break事件。)
在这种情况下,where.exe确实从cmd.exe继承了重定向的标准句柄:
0:000> g
Symbol search path is: symsrv*symsrv.dll*
C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(1508.1534): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc int 3
1:001> ?? ((ntdll!_PEB *)@$peb)->ProcessParameters->StandardOutput
void * 0x00000000`00000064
1:001> !handle 64 3
Handle 64
Type File
Attributes 0
GrantedAccess 0x120196:
ReadControl,Synch
Write/Add,Append/SubDir/CreatePipe,WriteEA,ReadAttr,WriteAttr
HandleCount 3
PointerCount 4
同样,在Windows 7中,很容易发现控制台伪句柄,因为它是通过将句柄值的低2位设置来进行标记的。对于Windows 8+,快速检查是查看文件的授予访问权限的低半字节(4位),其读取数据访问权限为1,写入数据访问权限为2,附加数据访问权限为4。控制台缓冲区具有读取和写入访问权限,而cmd的重定向使用read(<
)或write(>
),但不能同时使用。上面是重定向的输出,您可以看到该文件已通过写入和追加访问(2 + 4)打开,但没有读取访问权限。这是一个快速检查,但是如果要确定可以使用内核调试器(例如kd.exe)或工具(例如Sysinternals Process Explorer或handle.exe)。这些可以向您显示NT内核对象路径,例如\Device\ConDrv\Input
Windows 8+控制台输入句柄。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句