This chapter covers the use of Socket API
and CMD
command line tools to implement local CMD
command execution and pipeless forward CMD
and pipeless reverse CMD
three functions. Execute the local CMD
implementation and use the CreateProcess
function to create a new CMD
process and redirect the standard input, output and error output to the current process Standard input, output and error output. Pipeless forward CMD
and pipeless reverse CMD
use the WSASocket
function to create a TCP
socket and add The standard input, output and error output of the CMD
process are redirected to the socket handle to implement remote command execution through a network connection.
First, implement a CMD
command line running function by using CreatePipe
to create an anonymous pipe, and use the CreateProcess
function to create a new CMD
process, then redirects standard input, output, and error output to the current process’s standard input, output, and error output. In this way, you can execute the CMD
command through the input and output of the current process and obtain the command output results.
CreatePipe function, used to create an anonymous pipe. An anonymous pipe is a mechanism for inter-process communication that allows one process to transfer output data to another process. The prototype of the CreatePipe function is as follows:
BOOL CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize );
The parameters hReadPipe
and hWritePipe
are pointers to the HANDLE
type, used to receive the handles of the read and write ends of the created pipe. The parameter lpPipeAttributes
is a pointer to the SECURITY_ATTRIBUTES
structure, used to set the security of the pipe. The parameter nSize
is a value of type DWORD
, used to specify the buffer size of the pipe. It can usually be set to 0 to use the system default value.
After creating an anonymous pipe, you can use the ReadFile
function to read data from the read end of the pipe and the WriteFile
function to write data to the write end of the pipe. After using the pipe, you should use the CloseHandle
function to close the handle of the pipe to release resources.
The CreateProcess function can create a new process, allocate memory space for the process, initialize environment variables, create the main thread, etc. Among them, the parameter lpApplicationName
is used to specify the name of the executable file to be executed, and the parameter lpCommandLine
is used to specify the command line parameters. If the lpApplicationName
parameter is NULL, the system will automatically use the command line specified by the lpCommandLine
parameter to create a process.
The function prototype is as follows:
BOOL CreateProcess( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
This function creates a process that includes a console window. If you need to use the CreateProcess()
function to create a process without a console window, you need to specify the CREATE_NO_WINDOW
flag in the dwCreationFlags
parameter.
When creating a process, you can set some properties of the process through the STARTUPINFO
structure, such as the redirection of standard input, standard output and standard error output, the display mode of the startup window, etc. At the same time, the CreateProcess()
function will return a PROCESS_INFORMATION
structure, which contains information such as the handle and ID of the new process.
As shown in the RunCommand
function below, this function passes in a string type command parameter and returns a string execution result. Inside the function, use the CreatePipe()
function to create Create an anonymous pipe and use the CreateProcess()
function to start a new CMD
process and redirect its standard output and error output to the writing end of the pipe. Then use the ReadFile()
function to read the output data from the reading end of the pipe and store the read data in a buffer. Finally, it concatenates the contents of the buffer into a complete output result and returns it to the caller.
// Execute CMD command in hidden mode BOOL RunCommand(char* cmdStr, char* message) {<!-- --> DWORD readByte = 0; //Execute command line char command[1024] = {<!-- --> 0 }; // buffer char buf[8192] = {<!-- --> 0 }; HANDLE hRead, hWrite; //Start configuration information STARTUPINFOsi; //Process information PROCESS_INFORMATION pi; // Pipe security properties SECURITY_ATTRIBUTES sa; // Splice CMD commands sprintf(command, "cmd.exe /c %s", cmdStr); // printf("-- CMD command: [%s]n", command); //Configure pipeline security properties sa.nLength = sizeof(sa); // Pipe handles can be inherited sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; //Create an anonymous pipe, the pipe handle can be inherited if (!CreatePipe( & amp;hRead, & amp;hWrite, & amp;sa, 1024)) {<!-- --> // printf("Pipe creation failed %xn", (unsigned int)GetLastError()); return FALSE; } //Configure cmd startup information ZeroMemory( & amp;si, sizeof(si)); si.cb = sizeof(si); // Get compatible size si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; // Standard output, etc. use additional si.wShowWindow = SW_HIDE; //Hide window startup si.hStdOutput = si.hStdError = hWrite; // The output stream and error stream point to the write end of the pipe //Create a child process and run the command. The child process is inheritable if (!CreateProcess( NULL, // Do not pass the program path, use the command line command, // command line command NULL, // Do not inherit process handle (default) NULL, // Do not inherit thread handle (default) TRUE, // inherit handle 0, // No creation flag (default) NULL, // use default environment variables NULL, // use the directory of the parent process & amp;si, // STARTUPINFO structure stores startup information & amp;pi)) // PROCESS_INFORMATION saves process-related information after startup {<!-- --> // printf("Failed to create process %x \ ", (unsigned int)GetLastError()); CloseHandle(hRead); CloseHandle(hWrite); return FALSE; } CloseHandle(hWrite); /* The write end handle of the pipe has been inherited by cmd's output stream and error stream, that is, when cmd outputs, data will be written to the pipe. We can get the output of cmd by reading the read end of the pipe */ while (ReadFile(hRead, buf, 8192, &readByte, NULL)) {<!-- --> strcat(message, buf); ZeroMemory(buf, 8192); } //printf("-- [CMD] Message: [%s] Length:%d n", message, strlen(message) + 1); CloseHandle(hRead); return TRUE; }
The above function is very easy to call. Let’s take the execution of the ipconfig
function as an example. The calling case is RunCommand((char*)"ipconfig", szBuffer)
, and the function executes the command ipconfig
parameters, and store the return value in the szBuffer
variable. The output rendering is as follows;