聲明:本人只講技術實現,因為本文引起其他的后果與本人無關。
目前,網絡游戲的外掛從程序角度主要分為輔助型的動作外掛和內核型的協議型外掛。動作外掛主要幫助玩家進行一些重復性的勞動量,網絡上有許多介紹這方面的程序,按鍵精靈就是一個很好的例子。協議型外掛則給人一個很神秘的感覺,這方面在網絡游戲上最多的恐怕是傳奇的脫機外掛,這也是因為傳奇最受歡迎而已。
在具體的講解前,我很想扯點別的事情,畢竟學院不是我的風格,我更喜歡自由一點的。既然我們主要是針對協議型外掛的制作教程,就先扯扯網絡游戲的流程和一些亂其八糟的事情,如果有冒犯你們的地方本人則不勝感激。如果你感到煩的話可以直接跳到你感興趣的地方。
我玩網游的歷史很短,剛開始玩得是魔力寶貝,總是在免費的時候玩,在一個服務器里面呆的最長的就是在四川臥龍了,現在服務器大概早就該名或者并組了吧,在里面我的名字叫Bluerose,名字前面帶的是我的職業(yè),小號一大堆,不過名字都是一樣的。用這個名字是因為朋友說我很憂郁,但卻總抱著希望,所以就用這個名字了。后來玩的是大話西游II,是朋友拉著玩的,現在雖然上了班,但偶爾還玩,里面的名字叫星淚,用的是女性玩家,因為這個名字太女性化了。在剛開始玩得時候,我覺得自己好孤獨(那時候在大學雖然旁邊都是同學朋友,但內心仍然孤獨),朋友拉我玩大話的時候,那天晚上星光倒不錯,灑下的星光讓我想起了眼淚的感覺,所以就叫獨孤星淚了,不過感覺這個名字太裸露,就將獨孤二字去掉了。
由于玩大話西游II的歷史比較長,而且對大話西游的游戲也比較熟悉,所以這次的教程就用大話西游II做為目標了,但教程盡可能考慮通用性。不過提前聲明,本人對網絡游戲并不熟悉,因此請勿和本人談論網絡游戲的前因后果和發(fā)展以及網游外掛對網絡游戲的沖擊等亂其八糟的事情。我對網絡編程也是一知半解,因此我盡可能的避免含有網絡的代碼,同時,由于協議型的外掛需要發(fā)送數據,但可以通過其它的辦法來進行(比如通過網游客戶端來代理)。
先說說服務器和客戶端的通訊,由于服務器和本地的客戶端不在同一個地理位置,相距比較遙遠,因此數據的傳輸就需要一定的時間,這就決定了在網游中數據只能進行采樣的收集處理而不能進行真正實時的數據處理。舉例來說,局域網C-S(反恐精英)的數據處理,當你移動的時候,必須告知別的電腦玩家自己的移動,這個數據的傳輸由于在局域網內部,數據的傳輸比較快,量也比較小,電腦可以進行快速的采樣和數據處理來進行判斷是否打中或者移動是否違反規(guī)則(比如凌空徐步)等等,但在網絡上進行玩的時候,對數據的采樣就不像本地局域網那么快了,以大話西游II(以后簡稱大話吧,少打幾個字)為例,在移動的時候,并不是將每一步的數據一個一個傳送給服務器,而是將本次移動規(guī)則打成數據包提交給服務器,讓后客戶端開始播放動畫,當服務器處理完數據之后,就會將位置回傳給客戶端,客戶端以這個位置數據為基點,進行人物的下次移動,這個數據的采集需要隔一段時間來能進行一次采集,相對于CS來說,這個采集密度要比CS采集密度小。
當服務器和客戶端進行通訊的時候,數據包是至關重要的。數據包中數據的規(guī)則則是協議型外掛最重要的基礎之一。由于網絡數據可以進行攔截,為了防止數據被修改,數據包中的數據都是加密進行,至于如何加密,這由服務器和客戶端通過一定的算法來執(zhí)行。因此,服務器和客戶端的通訊大概就是下面這個樣子:
客戶端進行數據的采集===〉數據打包==〉數據加密==〉發(fā)送數據到服務器==〉服務器進行數據解密====〉服務器處理數據包==(處理完畢回傳數據)==〉回傳數據打包==〉回傳數據加密==〉數據回傳==〉客戶端接收數據==〉客戶端解密數據==〉客戶端數據處理
我們的目標就是數據包,即攔截游戲通訊間的數據來進行相應的修改或者進行發(fā)送偽數據包。我大概定了一個計劃,不過這一節(jié)肯定不能全部講完,我只能在下班之后寫上一點,時間有限,能寫多少就寫多少吧。
目標程序:大話西游II客戶端。(你手上有服務器端嗎?有的話我也想要)
目標:數據包
目的:數據包攔截,修改,偽發(fā)送
編程軟件:這個無所謂吧,不過我這里用的是C++ Builder 6,前段時間做CB 6相關的項目,而且CB 對于程序界面的編寫是最方便不過的了,就是編譯的有點慢和生成的程序有點大。(旁白:又不是做手機項目,擔心容量嗎?)我做受限程序做慣了,養(yǎng)成了不良習慣,沒辦法了。
思路:我們的程序要干擾別的程序的運行,最好的辦法是使用debug的辦法,不過,我并沒有打算使用debug的辦法,我對程序的debug并不太熟悉,而且討厭編寫沒用的代碼。我準備采用線程注入的辦法,至于線程注入,和為什么要線程注入才能干預,這方面的知識最好自己看看《Windows 核心編程》里面講的,否則這個教程要沒完沒了了。當我們的線程注入到目標程序之后就方便多了,就可以為所欲為了。因此我們的第一目的是將線程注入到目標程序中。
預備活動:
線程注入最簡單的莫過于hook了,如果連這都不知道的話,最好趕快到網上查查或者翻翻《Windows核心編程》。為了防止游戲內部存在反hook的存在和外掛的檢測,我將用自己的程序來啟動目標程序。由于網游的不定期更新,因此在啟動程序的時候最好將升級跳過去,至少在大話這樣的程序中我是這樣做的,因為頻繁升級和版本檢測總讓我等的時間太長。
下面來進行具體的做法,我盡可能的弄出詳細的步驟,如果你用的是VC或者其它的話,只要注意核心的代碼就可以了。
新建一個工程,在窗體上添加兩個按鈕(TButton或者其它類型的按鈕),一個將標題改為啟動游戲,另一個標題改為啟動外掛。再添加一個TOpenDialog。對于默認的窗體那么大的界面有點浪費,因此將窗體弄得小點,別大大的怪嚇人的。
雙點啟動游戲的按鈕就可以進行編寫該按鈕的事件了,默認的是OnClick事件。下面就是事件的代碼:
if(FileExists(ExtractFileDir(Application->ExeName)+"\\path.ini")==FALSE)
{ /*我將目標程序的路徑保存到了當前程序目錄中的path.ini文件中,但如果當前程序第一次運行的話,
是不存在這個文件的,所以就可以用TOpdnDialog來打開了,
做這點只是為了方便,不用每次都得點目標程序*/
if(OpenFile->Execute())
{
AnsiString AppPath="path="+ExtractFilePath(OpenFile->FileName);
WritePrivateProfileSection("XY2PATH",AppPath.c_str(),(ExtractFileDir(Application->ExeName)+
"\\path.ini").c_str());//將目標程序的路徑存到path.ini文件中。
}else
{
return;
}
}
//下面的代碼開始啟動目標程序
PROCESS_INFORMATION pi;
STARTUPINFO si;
si.cb=sizeof(si);
si.lpReserved=NULL;
si.lpDesktop=NULL;
si.lpTitle=NULL;
si.cbReserved2=0;
si.lpReserved2=NULL;
si.dwFlags=STARTF_USEPOSITION;
si.dwX=0;
si.dwY=0;
char Appname[300];
GetPrivateProfileString("XY2PATH","path","",Appname,250,(ExtractFileDir(Application->ExeName)+
"\\path.ini").c_str());
strcat(Appname,"\\xy2.exe");
/*以上都在構建目標程序的環(huán)境設置,下面調用CreateProcess來啟動目標程序,
注意將倒數第3個參數要填為目標程序的路徑,
第6個參數為CREATE_SUSPENDED是為了將程序加載到內存中之后可以進行一些修改,
以更好的配合外掛程序的運行*/
if(CreateProcess(Appname,NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,ExtractFileDir(Appname).
c_str(),&si,&pi)==0)
{
//啟動目標程序失敗
showMessage("error open exe file");
return;
}
gamehandle=pi.hProcess;
/*在本節(jié)中要執(zhí)行程序的話,最好將這個條件注釋掉,我將在以后的教程中進行講解,這里大概說一下功能,
第一個Write是為了跳過Update,第二個是為了退出的時候不打開網頁,
我的電腦要是退出大話的時候打開網頁的話,中間的時間可以抽上幾根煙了,所以將程序改了*/
if(WriteProcessMemory(gamehandle,(void*)0x0042BC13,No_Update,1,NULL)==false
||WriteProcessMemory(gamehandle,(void*)0x00430a80,No_HTML,2,NULL)==false
)
return;
threadhand=pi.hThread;
gamethreadid=pi.dwThreadId;
//恢復程序,讓程序執(zhí)行
ResumeThread(pi.hThread);
/*下面的代碼也是本節(jié)中不需要的,我將物品的有關信息存到了當前目錄(外掛啟動程序目錄)中的item.ini文件中,
但目標程序中并不知道外掛啟動程序的路徑,因此我在目標程序文件夾中建立了一個名字叫path.ini文件,里面包含了item.ini的路徑*/
String inipath= "path="+ExtractFileDir(Application->ExeName)+"\\item.ini";
WritePrivateProfileSection("ITEM",inipath.c_str(),(ExtractFileDir(OpenFile->FileName)+
"\\path.ini").c_str());
啟動程序中將啟動屬性設置為CREATE_SUSPENDED屬性是為了考慮到程序的通用性和穩(wěn)定性,在該函數之后,如果目標程序中存在有必要修改的代碼的話,可以在這里進行修改,也可以對目標程序進行反反外掛的處理。其實,debug形式的外掛就可以在這里進行debug環(huán)境的建立,以及在目標程序中插入Int 3指令來進行攔截處理了(我怎么越來越感覺到自己在寫調試器的教程??)。
這節(jié)就講到這里,如果再晚的話,我就沒辦法趕上公交車了,然后還得走回家,天哪,這么冷的天~~~~趕緊上傳回家吧。
請勿將文章用于任何商業(yè)場合,如果因為本教程引起其他的后果的話,則與本人無關,本人只講技術實現。如果要轉貼的話,請注明出處,如果有疑問或者商議的話,請發(fā)E-Mail到zeze0556@sina.com或者QQ:23033206留言,MSN:zeze0556@msn.com。另外請勿給我信箱發(fā)垃圾郵件,在添加好友的時候一定要寫好附言,我已經被莫名其妙的廣告信件和流言蜚語嚇得沒有膽了。算是我求各位大蝦了。

