分类:
2008-10-13 16:31:39
近来感觉在VCKBASE上有点手脚不勤,有些惭愧!有人问到关于cmd.exe的问题,希望能够对它的输入命令进行过滤。个人觉得如果从深度考虑还是有些难度的,毕竟在windows下,命令行窗口的消息流是不可访问的。所以也不可以用钩子等类似的机制进行处理。其实对于一般要求不高的实现来说,完全可以通过对cmd.exe的输入输入进行控制,实在对输入进行过滤同时还保留住cmd.exe的大部分功能。今天是周未,睡醒之后,觉得回问题应该用点心,所以花了个把小时写下了下面这段例子代码,顺便改掉手脚不勤的坏习惯^_^!
//=======================================
// Description: A sample to show how to filter cmd.exe
// Author : Hercules Zeng
// Emailto :
#include "stdafx.h"
#include
#include
#define BUFF_SIZE 16384 //16K
HANDLE g_hCmdStdinRead;
HANDLE g_hCmdStdinWrite;
HANDLE g_hCmdStdinWriteDup;
HANDLE g_hChildStdoutRead;
HANDLE g_hChildStdoutWrite;
HANDLE g_hChildStdoutReadDup;
HANDLE g_hInputHandle;
HANDLE g_hBackupStdin;
HANDLE g_hBackupStdout;
//----------------------------------------------------------------------------
void ErrorExit (LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}
//----------------------------------------------------------------------------
BOOL CheckCmd(char* pBuffer)
{
if(strcmp(pBuffer, "exit\r\n") == 0)
{
ExitProcess(0);
}
return TRUE;
}
//----------------------------------------------------------------------------
int EnterInfoCMD(void)
{
DWORD dwReadCnt;
DWORD dwWriteCnt;
CHAR cBuffer[BUFF_SIZE];
int nCmdLen;
memset(cBuffer, 0, BUFF_SIZE);
if (! WriteFile(g_hCmdStdinWriteDup, cBuffer, strlen(cBuffer),
&dwWriteCnt, NULL))
return -1;
Sleep(300);
if( !ReadFile( g_hChildStdoutReadDup, cBuffer, BUFF_SIZE, &dwReadCnt,
NULL) || dwReadCnt == 0) return -1;
if (! WriteFile(g_hBackupStdout, cBuffer, dwReadCnt, &dwWriteCnt, NULL))
return -1;
// Read from a file and write its contents to a pipe.
for (;;)
{
memset(cBuffer, 0, BUFF_SIZE);
if (! ReadFile(g_hInputHandle, cBuffer, BUFF_SIZE, &dwReadCnt, NULL) ||
dwReadCnt == 0)
break;
// Add check-method here
CheckCmd(cBuffer);
nCmdLen = strlen(cBuffer);
if (! WriteFile(g_hCmdStdinWriteDup, cBuffer, dwReadCnt,
&dwWriteCnt, NULL)) break;
BOOL bStripCmd = TRUE;
for(;;)
{
Sleep(300);
memset(cBuffer, 0, BUFF_SIZE);
if( !ReadFile( g_hChildStdoutReadDup, cBuffer, BUFF_SIZE, &dwReadCnt,
NULL) || dwReadCnt == 0) break;
if(bStripCmd)
{
if (! WriteFile(g_hBackupStdout, cBuffer + nCmdLen, dwReadCnt - nCmdLen, &dwWriteCnt, NULL))
break;
}
else
{
if (! WriteFile(g_hBackupStdout, cBuffer, dwReadCnt, &dwWriteCnt, NULL))
break;
}
bStripCmd = FALSE;
if(cBuffer[dwReadCnt - 1] == '>')
break;
}
}
// Close the pipe handle so the child process stops reading.
if (! CloseHandle(g_hCmdStdinWriteDup))
ErrorExit("Close pipe failed\n");
return 0;
}
//----------------------------------------------------------------------------
BOOL CreateCMDProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bRtn = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
// Create the child process.
TCHAR tcsExename[MAX_PATH];
TCHAR tcsParam[MAX_PATH * 2];
TCHAR tcsCmd[MAX_PATH];
if( 0 == GetModuleFileName(NULL, tcsExename, MAX_PATH)
|| 0 == GetEnvironmentVariable(_T("COMSPEC"), tcsCmd, MAX_PATH))
return FALSE;
// get short filename for command shell program
if( 0 == GetShortPathName(tcsExename, tcsExename, MAX_PATH))
return FALSE;
bRtn = CreateProcess(NULL,
tcsCmd, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (bRtn == 0)
{
ErrorExit("CreateProcess failed\n");
return FALSE;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bRtn;
}
}
//----------------------------------------------------------------------------
DWORD main()
{
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// The steps for redirecting child process's STDOUT:
// 1. Save current STDOUT, to be restored later.
// 2. Create anonymous pipe to be STDOUT for child process.
// 3. Set STDOUT of the parent process to be write handle to
// the pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the read handle and
// close the inheritable read handle.
// Save the handle to the current STDOUT.
g_hBackupStdout = GetStdHandle(STD_OUTPUT_HANDLE);
// Create a pipe for the child process's STDOUT.
if (! CreatePipe(&g_hChildStdoutRead, &g_hChildStdoutWrite, &saAttr, 0))
ErrorExit("Stdout pipe creation failed\n");
// Set a write handle to the pipe to be STDOUT.
if (! SetStdHandle(STD_OUTPUT_HANDLE, g_hChildStdoutWrite))
ErrorExit("Redirecting STDOUT failed");
// Create noninheritable read handle and close the inheritable read
// handle.
fSuccess = DuplicateHandle(GetCurrentProcess(), g_hChildStdoutRead,
GetCurrentProcess(), &g_hChildStdoutReadDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if( !fSuccess )
ErrorExit("DuplicateHandle failed");
CloseHandle(g_hChildStdoutRead);
// The steps for redirecting child process's STDIN:
// 1. Save current STDIN, to be restored later.
// 2. Create anonymous pipe to be STDIN for child process.
// 3. Set STDIN of the parent to be the read handle to the
// pipe, so it is inherited by the child process.
// 4. Create a noninheritable duplicate of the write handle,
// and close the inheritable write handle.
// Save the handle to the current STDIN.
g_hBackupStdin = GetStdHandle(STD_INPUT_HANDLE);
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&g_hCmdStdinRead, &g_hCmdStdinWrite, &saAttr, 0))
ErrorExit("Stdin pipe creation failed\n");
// Set a read handle to the pipe to be STDIN.
if (! SetStdHandle(STD_INPUT_HANDLE, g_hCmdStdinRead))
ErrorExit("Redirecting Stdin failed");
// Duplicate the write handle to the pipe so it is not inherited.
fSuccess = DuplicateHandle(GetCurrentProcess(), g_hCmdStdinWrite,
GetCurrentProcess(), &g_hCmdStdinWriteDup, 0,
FALSE, // not inherited
DUPLICATE_SAME_ACCESS);
if (! fSuccess)
ErrorExit("DuplicateHandle failed");
CloseHandle(g_hCmdStdinWrite);
// Now create the child process.
fSuccess = CreateCMDProcess();
if (! fSuccess)
ErrorExit("Create process failed");
// After process creation, restore the saved STDIN and STDOUT.
if (! SetStdHandle(STD_INPUT_HANDLE, g_hBackupStdin))
ErrorExit("Re-redirecting Stdin failed\n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, g_hBackupStdout))
ErrorExit("Re-redirecting Stdout failed\n");
// Get a handle to the parent's input file.
g_hInputHandle = g_hBackupStdin;
if (g_hInputHandle == INVALID_HANDLE_VALUE)
ErrorExit("no input file\n");
EnterInfoCMD();
return 0;
}