Windows黑客编程之功能技术(下)

描述

  • 利用CreateProcess和匿名管道,获取远程命令执行的结果
  • 使用MoveFileEx和批处理脚本,实现文件自删除

远程CMD

  • 关键在于捕获命令的输出结果
  • 创建匿名管道,一端写,一端读
  • CreateProcess创建进程,并将输出重定向到写端的管道
  • WaitForSingleObject等到主线程和进程执行完毕
  • 将读端的管道的内容读入缓冲区
#include "stdafx.h"
#include "PipeCmd.h"

void ShowError(char *pszText)
{
	char szErr[MAX_PATH] = {0};
	::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
	::MessageBox(NULL, szErr, "ERROR", MB_OK);
}


// 执行 cmd 命令, 并获取执行结果数据
BOOL PipeCmd(char *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)
	{
		ShowError("CreatePipe");
		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 (FALSE == bRet)
	{
		ShowError("CreateProcess");
	}
	// 等待命令执行结束
	::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;
}
  • 调用函数,并将捕获的结果打印出来
// Pipe_CMD_Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "PipeCmd.h"


int _tmain(int argc, _TCHAR* argv[])
{
	char szCmd[] = "ping 127.0.0.1";
	char szResultBuffer[512] = {0};
	DWORD dwResultBufferSize = 512;

	// 执行 cmd 命令, 并获取执行结果数据
	if (FALSE == PipeCmd(szCmd, szResultBuffer, dwResultBufferSize))
	{
		printf("pipe cmd error.\n");
	}
	else
	{
		printf("CMD执行结果为:\n%s\n", szResultBuffer);
	}

	system("pause");
	return 0;
}

文件自删除

利用MoveFileEx函数自删除

  • 利用MoveFileEx实现机器重启删除文件
// MoveFileEx_Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>


BOOL RebootDelete(char *pszFileName)
{
	// 重启删除文件
	char szTemp[MAX_PATH] = "\\\\?\\";
	::lstrcat(szTemp, pszFileName);
	BOOL bRet = ::MoveFileEx(szTemp, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
	return bRet;
}


int _tmain(int argc, _TCHAR* argv[])
{
	if (FALSE == RebootDelete("C:\\Users\\Test\\Desktop\\520.exe"))
	{
		printf("Set Reboot Delete Error.\n");
	}
	else
	{
		printf("Set Reboot Delete OK.\n");
	}

	system("pause");
	return 0;
}

批处理脚本

  • 通过del *.exedel %0删除程序和bat脚本自身
  • 利用ping、choice等命令延迟执行删除指令,保证程序执行完后再删除
  • 写一个生成bat脚本的程序,并用CreateProcess通过cmd调用脚本,创建进程成功后,立即结束进程
// SelfDel_Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>


BOOL CreateChoiceBat(char *pszBatFileName)
{
	int iTime = 5;
	char szBat[MAX_PATH] = { 0 };

	// 构造批处理内容
	/*
		@echo off
		choice /t 5 /d y /n >nul
		del *.exe
		del %0
	*/
	::wsprintf(szBat, "@echo off\nchoice /t %d /d y /n >nul\ndel *.exe\ndel %%0\n", iTime);

	// 生成批处理文件
	FILE *fp = NULL;
	fopen_s(&fp, pszBatFileName, "w+");
	if (NULL == fp)
	{
		return FALSE;
	}
	fwrite(szBat, (1 + ::lstrlen(szBat)), 1, fp);
	fclose(fp);

	return TRUE;
}


BOOL CreatePingBat(char *pszBatFileName)
{
	int iTime = 5;
	char szBat[MAX_PATH] = {0};

	// 构造批处理内容
	/*
		@echo off
		ping 127.0.0.1 -n 5
		del *.exe
		del %0
	*/
	::wsprintf(szBat, "@echo off\nping 127.0.0.1 -n %d\ndel *.exe\ndel %%0\n", iTime);

	// 生成批处理文件
	FILE *fp = NULL;
	fopen_s(&fp, pszBatFileName, "w+");
	if (NULL == fp)
	{
		return FALSE;
	}
	fwrite(szBat, (1 + ::lstrlen(szBat)), 1, fp);
	fclose(fp);

	return TRUE;
}


BOOL DelSelf(int iType)
{
	BOOL bRet = FALSE;
	char szCurrentDirectory[MAX_PATH] = {0};
	char szBatFileName[MAX_PATH] = {0};
	char szCmd[MAX_PATH] = {0};

	// 获取当前程序所在目录
	::GetModuleFileName(NULL, szCurrentDirectory, MAX_PATH);
	char *p = strrchr(szCurrentDirectory, '\\');
	p[0] = '\0';
	// 构造批处理文件路径
	::wsprintf(szBatFileName, "%s\\temp.bat", szCurrentDirectory);
	// 构造调用执行批处理的 CMD 命令行
	::wsprintf(szCmd, "cmd /c call \"%s\"", szBatFileName);

	// 创建自删除的批处理文件
	if (0 == iType)
	{
		// choice 方式
		bRet = CreateChoiceBat(szBatFileName);
	}
	else if (1 == iType)
	{
		// ping 方式
		bRet = CreatePingBat(szBatFileName);
	}

	// 创建新的进程, 以隐藏控制台的方式执行批处理
	if (bRet)
	{
		STARTUPINFO si = { 0 };
		PROCESS_INFORMATION pi;
		si.cb = sizeof(si);
		//指定wShowWindow成员有效
		si.dwFlags = STARTF_USESHOWWINDOW;	
		//此成员设为TRUE的话则显示新建进程的主窗口
		si.wShowWindow = FALSE;					
		BOOL bRet = CreateProcess(
			//不在此指定可执行文件的文件名
			NULL,	
			//命令行参数
			szCmd,				
			//默认进程安全性
			NULL,		
			//默认进程安全性
			NULL,	
			//指定当前进程内句柄不可以被子进程继承
			FALSE,					
			//为新进程创建一个新的控制台窗口
			CREATE_NEW_CONSOLE,		
			//使用本进程的环境变量
			NULL,				
			//使用本进程的驱动器和目录
			NULL,								
			&si,
			&pi);
		if (bRet)
		{
			//不使用的句柄最好关掉
			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);

			// 结束进程
			exit(0);
			::ExitProcess(NULL);
		}
	}

	return bRet;
}


int _tmain(int argc, _TCHAR* argv[])
{
	// 程序自删除
	BOOL bRet = DelSelf( 0 );
	if (FALSE == bRet)
	{
		printf("Selft Delete Error!\n");
	}
	else
	{
		printf("Selft Delete OK!\n");
	}

	system("pause");
	return 0;
}
posted @ 2023-02-26 09:06  z5onk0  阅读(426)  评论(0编辑  收藏  举报