本文最后更新于:2021-08-30 下午
远程CMD
CMD,提示进行命令输入的一种工作提示符,在windows系统下,相当于在windows窗口使用的DOS系统,简单来讲,CMD就是通过命令行实现键鼠的操作。
现在介绍的远程CMD是指病毒木马获取控制端发送过来的CMD命令,执行后将结果回传给控制端。
有许多的API都可以实现CMD命令,比如WinExec,CreateProcess但是这些函数不能获取执行后的操作结果。所以实现远程CMD的关键是获取CMD的执行结果,接下来介绍如何执行CMD,并通过匿名管道的方法获取执行结果,实现远程CMD。
函数介绍
CreatePipe
创建一个匿名管道,并从中得到读写管道的句柄。
| BOOL CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize );
|
参数
hReadPipe:返回一个刻度管道数据的文件句柄。
hWritePipe:返回一个可写管道数据的文件句柄。
lpPipeAttributes:传入一个SECURITY_ATTRIBUTES结构的指针,该结构决定此函数返回的句柄是否可由子进程继承。如果传入为NUL,则不可进程。
nSize:指向管道的缓冲区大小。但是这仅仅是一个理想值,系统根据这个值创建大小相近的缓冲区。如果传入0,那么系统将使用一个默认的缓冲区大小。
返回值
如果函数成功,则返回值不为0;
如果函数失败,则返回值为0。
实现原理
管道是一种在进程间共享数据的机制,其实质是一段共享内存。windows系统为这段共享的内存设计使用数据流I/O的方式来访问。一个进程读,另一个进程写,这类似一个管道的两端。实现远程CMD的流程如下:
首先初始化匿名管道的安全属性结构SECURITY_ATTRIBUTES,调用CreatePipe函数创建匿名管道,获取管道数据读取句柄和管道数据写入句柄。
对即将创建的进程结构体STARTUPINFO进行初始化,隐藏进程窗口,并把上面的管道数据写入句柄赋值给新进程控制台窗口的缓存句柄,这样,新进程会把窗口缓存的输出数据写入到匿名管道中。
调用CreateProcess函数创建新的进程,执行CMD命令,并调用WaitForSingleObject等待命令执行完毕。执行完毕后,就调用ReadFile函数根据匿名管道的数据读取句柄从匿名管道的缓冲区中读取数据,这个数据就是命令的返回结果。
最后便可以关闭句柄,释放资源。
编码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include <Windows.h> #include <stdio.h> BOOL PipeCmd(char* pszCmd, char* pszResultBuffer, DWORD dwBufferSize); int main() { char pszCmd[] = "ping www.baidu.com"; char pszResultBuffer[1024] = { 0 }; DWORD dwBufferSize = 1024; if (PipeCmd(pszCmd, pszResultBuffer, dwBufferSize) == TRUE) { printf("执行成功:\n%s\n",pszResultBuffer); } else { printf("执行失败\n"); } system("pause"); return 0; } BOOL PipeCmd(char* pszCmd, char* pszResultBuffer, DWORD dwBufferSize) { HANDLE hReadPipe = NULL; HANDLE hWritePipe = NULL; SECURITY_ATTRIBUTES SEA = { 0 }; BOOL bRet = FALSE; STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; SEA.bInheritHandle = TRUE; SEA.nLength = sizeof(SEA); SEA.lpSecurityDescriptor = NULL; bRet = CreatePipe(&hReadPipe, &hWritePipe, &SEA, 0); if (bRet == FALSE) { printf("创建管道失败\n"); return bRet; } si.cb = sizeof(si); si.hStdError = hWritePipe; si.hStdOutput = hWritePipe; si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; //创建新进程执行CMD命令 bRet = CreateProcess(NULL, pszCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (bRet == FALSE) { printf("创建进失败\n"); return bRet; } //等待执行结束 WaitForSingleObject(pi.hThread, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE); //从匿名管道中读取结果到输出缓冲区 RtlZeroMemory(pszResultBuffer, dwBufferSize); ReadFile(hReadPipe, pszResultBuffer, dwBufferSize, NULL, NULL);
//关闭句柄 CloseHandle(pi.hThread); CloseHandle(pi.hProcess); CloseHandle(hWritePipe); CloseHandle(hReadPipe);
return bRet; }
|
测试
执行Ping baidu的命令,查看效果