windows黑客编程系列(十二):远程CMD

文章目录

    • 功能技术模块
      • 远程CMD
      • WINAPI
        • CreatePipe
      • 实现原理
      • 编码实现
      • 执行效果

功能技术模块

病毒木马的入侵并潜伏在用户计算机上总是有着某种目的,例如获取用户隐私的办公文件或是账号密码,或是控制肉鸡,或是进行加密磁盘文件然后进行勒索。

远程CMD

对于大部分读者来说,CMD可能稍微有些陌生,但大家应该都用过CMD来执行一些基础命令,如ipconfig查看ip信息,dir列出文件信息,shutdown关机命令等等,如下图调用ipconfig所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9SMLmQY-1588932688953)(https://xiaoming-1253385810.cos.ap-shanghai.myqcloud.com/20200508160920.png)]

但我相信,如果读者有使用过linux操作系统,如ubuntu、deepin或者center os等,都至少熟悉terminal机制。

可以说linux核心就在于terminal机制,或者说shell机制。linux下的shell与winows中的CMD极其类似。

本文中所介绍的远程CMD是指病毒木马获取控制端发送过来的CMD命令,在用户计算机上执行该CMD命令并将执行结果回传给控制端,以此实现远程CMD的功能。

WINAPI

CreatePipe

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

函数声明:

BOOL WINAPI CreatePipe(
    _Out_ PHANDLE hReadPipe,
    _Out_ PHANDLE hWritePipe,
    _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
    _In_ DWORD nSize
    );

参数说明:

  • hReadPipe:返回一个可读管道数据的文件句柄。
  • hWritePipe:返回一个可写管道数据的文件句柄。
  • lpPipeAttributes:传入一个SECURITY_ATTRIBUTES结构的指针,该结构决定此函数返回的句柄是否可由子进程继承。如果传入为NULL,则表示不可继承。
  • nSize:指向管道的缓冲区大小,但是这仅是一个理想值,系统根据这个值创建大小相近的缓冲区。如果传入0,那么系统将使用一个默认的缓冲区大小。

返回值:

  • 函数成功,返回值不为0
  • 函数失败,返回0

实现原理

管道是一种在进程间共享数据的机制,其实质是一段共享内存,Windows系统为这段共享内存设计使用数据流I/O的方式来访问,一个进程读,一个进程写,这类似于一个管道的两端,因此这种进程间通信的方式称为管道。

管道分为:

  • 匿名管道:只能在父子进程间进行通信,不能在网络间通信,而且数据传输是单向的,只能一端写,一端读。
  • 命名管道:可以在任意进程间通信,通信是双向的,任何一端都可读可写,但是在同一时间只能有一端读一端写。

思路:

  1. 首先初始化SECURITY_ATTRIBUTES结构体,使用匿名管道默认的缓冲区大小,并调用函数CreatePipe创建匿名管道,获取管道数据读取句柄和写入句柄。
//SECURITY_ATTRIBUTES结构体声明:
typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
  1. 对即将创建的进程结构体STARTUPINFO进行初始化,隐藏进程窗口,并把上面的管道数据写入句柄赋值给新进程控制台窗口的缓存句柄,这样,新进程就会把窗口缓存的输出数据写入匿名管道中。
  2. 调用CreateProcess函数创建新进程,执行CMD命令,并调用函数WaitForSingleObject函数等待命令执行完毕,否则立刻获取执行结果就会获得不完整的执行结果
  3. 执行完毕后,调用ReadFile函数根据匿名管道的数据读取句柄从匿名管道的缓冲区中读取数据。

编码实现

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include 
#include "resource.h"
#include "ConsoleApplication1.h"
#include 
#include 
#include 
#include 
#include 
#define AddVKey(VK, VKName) { (VK), (VKName) }

BOOL PipeCmd(LPWSTR pszCmd, char* pszResultBuffer, DWORD dwResultBufferSize)
{
	HANDLE hReadPipe = NULL;
	HANDLE hWritePipe = NULL;
	SECURITY_ATTRIBUTES securityAttributes = { 0 };
	BOOL bRet = FALSE;
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };

	securityAttributes.bInheritHandle = TRUE;
	securityAttributes.nLength = sizeof(securityAttributes);
	securityAttributes.lpSecurityDescriptor = NULL;
	bRet = CreatePipe(&hReadPipe, &hWritePipe, &securityAttributes, 0);
	if (FALSE == bRet)
	{
		printf("create pipe error!\n");
		return FALSE;
	}
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdError = hWritePipe;
	si.hStdOutput = hWritePipe;
	bRet = CreateProcess(NULL, pszCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
	if (bRet == FALSE)
	{
		printf("CreateProcess error!\n");
		return FALSE;
	}
	WaitForSingleObject(pi.hThread, INFINITE);
	WaitForSingleObject(pi.hProcess, INFINITE);
	RtlZeroMemory(pszResultBuffer, dwResultBufferSize);
	ReadFile(hReadPipe, pszResultBuffer, dwResultBufferSize, NULL, NULL);
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
	CloseHandle(hWritePipe);
	CloseHandle(hReadPipe);

	return TRUE;
}

int main()
{
	wchar_t szCmd[] = L"cmd /k ping 127.0.0.1";
	char szResultBuffer[512] = { 0 };
	DWORD dwResultBufferSize = 512;

	if (FALSE == PipeCmd(szCmd, szResultBuffer, dwResultBufferSize))
	{
		printf("pipe cmd error.\n");
	}
	else
	{
		printf("%s\n", szResultBuffer);
	}
	system("pause");
	return 0;
}

执行效果

windows黑客编程系列(十二):远程CMD_第1张图片

你可能感兴趣的:(windows编程)