功能技术远程CMD

本文最后更新于:2021-08-30 下午

远程CMD

CMD,提示进行命令输入的一种工作提示符,在windows系统下,相当于在windows窗口使用的DOS系统,简单来讲,CMD就是通过命令行实现键鼠的操作。

现在介绍的远程CMD是指病毒木马获取控制端发送过来的CMD命令,执行后将结果回传给控制端。

有许多的API都可以实现CMD命令,比如WinExec,CreateProcess但是这些函数不能获取执行后的操作结果。所以实现远程CMD的关键是获取CMD的执行结果,接下来介绍如何执行CMD,并通过匿名管道的方法获取执行结果,实现远程CMD。

函数介绍

CreatePipe

创建一个匿名管道,并从中得到读写管道的句柄。

1
2
3
4
5
6
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()
{
//执行的CMD命令
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的命令,查看效果