Hacking Diablo II之D2HACKIT技术详解
趁著圣誕又歇了幾天,沒博,倒是主動被動的看了不少片子。我發現我的觀影口味挺雜,什么都看,還什么都能看的津津有味。這些片中,有肥皂劇型的“Ally McBeal”(甜心俏佳人),柯恩兄弟的黑幫型的”Miller’s Crossing”,悶騷型的“Country Life”,一直想看的“北京樂與路”,還有成龍大叔的“神話”。
前幾天有博友留言希望我多談點兒d2hackit,那我就隨便說說。
D2中的外掛,比較有代表性的大致可以分為三類:以maphack為代表的輔助型,以幫助玩家更有效的玩游戲為目的;以D2JSP為代表的BOT型,用于在無人值守的狀態下自動進行游戲;還有一類就是以d2hackit為代表的全能型,bot、pickit、dupe、pk hack、packet sniffer、trade hack、drop hack什么都能做,D2中dupe泛濫有一部分原因要歸功于它,比較有代表性的基于d2hackit的插件外掛有09時期的pickit、PindleBot,和1.10時期的zPickit。
從結果上看,d2hackit無疑是成功的,然而從軟件設計角度看,它當初的部分設計目標并沒有達到。d2hackit的設計意圖,是要實現一個外掛的開發平臺,其他開發者只需用這個平臺提供的基礎設施,不必具備逆向工程,甚至匯編語言的能力就能夠做出外掛。按照d2hackit原作者thohell的設想,d2hackit甚至不必局限于D2,而是一個通用的外掛開發平臺,可以用于其他游戲。
降低外掛開發的難度這一點d2hackit是做到了,d2hackit插件泛濫就說明了它的成功。通用平臺這一目標它顯然沒有達到,別說用于其它游戲,在09補丁上能用的插件,在1.10上都用不了,必須重新編譯甚至修改源代碼。
d2hackit的基本工作原理,跟我以前寫的一篇
介紹外掛工作原理的文章里說的大致相同:d2hackit的加載、卸載,地址(旁路點、游戲內部函數和全局變量)的定位,以及旁路點被觸發時的處理等幾部份。不同的是d2hackit做為一個外掛平臺,還需要加載它的插件,并在適當時刻(收、發數據包,進入、退出游戲等)通知插件。下面逐一分析。
1,d2hackit的加載和卸載。 d2hackit在本質上就是一個windows的DLL,因此任何能在游戲進程加載、卸載DLL的方法都適用于d2hackit。d2hackit 自帶的loader用的是遠程DLL注入的方法,另外d2hackit本身也可以做為d2loader的插件在游戲程序運行時自動加載。
2,地址的定位。d2hackit對地址的定位是比較有特色的,它除了支持基址+偏移量的通常做法,還支持指紋式的內存數據匹配搜索,也就是說它可以通過搜索特定模式的字節序列來定位內存地址。這樣設計的意圖是在游戲補丁升級時只需更新指紋數據就可以讓d2hackit工作于新版本補?。ó斎淮蠹叶贾肋@個目標沒有達到)。指紋模式在配置文件中指定(d2hackit.ini),格式如下:
;
Name
=
Module
,
patchsize
,
offset
,
fingerprint
GamePacketReceivedIntercept
=
D2Client
.
dll
,
7
,
13
,
8B5C2410xxxxxxxxxxxx8D145B8B0495
上面這行指定了接收數據包的旁路點地址的匹配模式:在d2client.dll中搜索8B5C2410xxxxxxxxxxxx8D145B8B0495特征數據,每xx匹配任意1字節數據。7為patch長度,13為距離匹配地址的偏移。
3,旁路點的事件處理。以接收游戲數據包的處理為例。在安裝了GamePacketReceivedIntercept旁路點以后,每當收到游戲內數據包時,d2hackit的相應旁路點處理例程就會先獲取控制權。為了不破壞原先的寄存器內容,旁路點處理例程必須先保存必要的寄存器然后再做真正的處理。因此處理例程分為兩部分,用匯編寫的GamePacketReceivedInterceptSTUB函數和C函數GamePacketReceivedIntercept。
DWORD__fastcallGamePacketReceivedIntercept(BYTE
*
aPacket,DWORDaLength)
{
//
Passpackettoallclientswhowantstosnoop
LinkedItem
*
li
=
ClientModules.GetFirstItem();
while
(li)
{
PCISpCIS
=
ClientModules.GetCIS(li);
if
(pCIS
&&
pCIS
->
OnGamePacketBeforeReceived)
{
aLength
=
pCIS
->
OnGamePacketBeforeReceived(aPacket,aLength);
if
(
!
aLength)
break
;
}
li
=
ClientModules.GetNextItem(li);
}
return
aLength;
}
上面是d2hackit的收到數據包時的處理代碼,很簡單,就是遍歷加載的插件模塊,挨個調用插件模塊中的
OnGamePacketBeforeReceived函數進行進一步的分析。
4,d2hackit插件模塊。d2hackit的插件以d2h為后綴,其實也是普通的DLL。做為d2hackit的插件,d2h必須提供一些回調入口點(即DLL的導出函數),供d2hackit在必要的時刻調用。這些入口點有:
BOOLEXPORTOnClientStart
();
BOOLEXPORTOnClientStop
();
DWORDEXPORTOnGameTimerTick
();
BOOLEXPORTOnGameCommandLine
(
char**argv
,
intargc
);
DWORDEXPORTOnBnetPacketBeforeSent
(
BYTE*aPacket
,
DWORDaLen
);
DWORDEXPORTOnBnetPacketBeforeReceived
(
BYTE*aPacket
,
DWORDaLen
);
DWORDEXPORTOnRealmPacketBeforeSent
(
BYTE*aPacket
,
DWORDaLen
);
DWORDEXPORTOnRealmPacketBeforeReceived
(
BYTE*aPacket
,
DWORDaLen
);
DWORDEXPORTOnGamePacketBeforeSent
(
BYTE*aPacket
,
DWORDaLen
);
DWORDEXPORTOnGamePacketBeforeReceived
(
BYTE*aPacket
,
DWORDaLen
);
LPCSTREXPORTGetModuleAuthor
();
LPCSTREXPORTGetModuleWebsite
();
LPCSTREXPORTGetModuleEmail
();
LPCSTREXPORTGetModuleDescription
();
DWORDEXPORTGetModuleVersion
();
VOIDEXPORTOnGameJoin
(
THISGAMESTRUCT*thisgame
);
VOIDEXPORTOnGameLeave
(
THISGAMESTRUCT*thisgame
);
通過名字你就能猜出它們在什么時候會被d2hackit調用,比如說收到數據包時就是
OnGamePacketBeforeReceived
。
d2hackit插件的加載有兩種方法,一種是在d2hackit.ini里設定隨著d2hackit本身加載時自動加載,另一種可以由玩家在進入游戲后在聊天輸入框中以特定的命令加載(d2hackit截獲了聊天輸入框的處理)。
5,d2hackit也給插件模塊提供了一組接口(API),供插件模塊使用。比如在OnGamePacketBeforeReceived函數中,插件可以直接修改數據包buffer的數據,但有的時候你需要向玩家顯示分析結果或者向服務器發送一些定制數據包,這時候就得調用d2hackit提供的API?;镜腁PI大概有這些:
DWORDEXPORTGameSendPacketToServer(LPBYTEbuf,DWORDlen);
DWORDEXPORTBnetSendPacketToServer(LPBYTEbuf,DWORDlen);
DWORDEXPORTRealmSendPacketToServer(LPBYTEbuf,DWORDlen);
BOOLEXPORTGameSendMessageToChat(LPSTRmsg);
DWORDEXPORTGameSendPacketToGame(LPBYTEbuf,DWORDlen);
BOOLEXPORTGameInsertPacketToGame(LPBYTEbuf,DWORDlen);
BOOLEXPORTGamePrintInfo(LPCSTRbuf);
BOOLEXPORTGamePrintError(LPCSTRbuf);
BOOLEXPORTGamePrintVerbose(LPCSTRbuf);
BOOLEXPORTGamePrintString(LPCSTRbuf);
DWORDEXPORTGameSendPacketToServer(LPBYTEbuf,DWORDlen);
PTHISGAMESTRUCTEXPORTGetThisgameStruct(
void
);
PSERVERINFOEXPORTGetServerInfo(DWORDdwVersion,LPCSTRszModule);
BOOLEXPORTGameSaveAndExit();
這樣,d2hackit的插件通過處理特定的事件和調用d2hackit提供的API就可以實現它想要的功能,無須匯編和逆向工程知識。由于網絡游戲的功能實現非常依賴于數據包,因此通過截獲數據包的收發來分析、篡改、偽造數據包可以完成絕大部分外掛的功能。
6,d2hackit的升級。由于d2hackit利用游戲的特定函數和數據進行工作,每次D2升級補丁d2hackit本身也必須重定位這些地址。做一個可以用于1.11b補丁的d2hackit其實也主要就是這個工作。比起d2hackmap來,d2hackit用的的地址很少(10個),難度小多了。要定位的地址有:
GamePacketReceivedIntercept=D2Client.dll,7,13,8B5C2410xxxxxxxxxxxx8D145B8B0495
GamePacketReceivedIntercept2=D2Client.dll,7,18,85C9894C24xx0F8FxxxxxxxxFF05xxxxxxxx5F5E5D
GamePacketSentIntercept=D2Net.dll,5,0,!10005
GamePlayerInfoIntercept=D2Client.dll,6,10,E8xxxxxxxxE8xxxxxxxx8935xxxxxxxx5EC3
pPlayerInfoStruct=D2Client.dll,0,12,E8xxxxxxxxE8xxxxxxxx8935xxxxxxxx5EC3
GamePrintStringLocation=D2Client.dll,0,0,81ECxxxxxxxx53558BE956578A45xx84C0
LoaderStruct=Game.exe,0,0,1d10abd1
GameKeyDownIntercept=D2Client.dll,5,5,8B770833D2xxxxxxxxxxxxC0668B41043BC6
GameSendPacketToGameLocation=d2net.dll,0,21,81EC0C010000538B1Dxxxxxxxx5556
GameSaveAndExit=D2client.dll,0,0,33c9e8xxxxxxxxc705xxxxxxxxxxxxxxxxe8xxxxxxxxc705
GameSendMessageToChat=bnclient.dll,0,15,C390909090909090909090909090908BD1
pGameInfoStruct=d2client.dll,0,0,#6FAA1C5A
第二個要做的工作是修改旁路點的入口代碼,因為不同的d2補丁具體代碼可能有變化,對寄存器的利用也有所不同。具體的說就是要改這幾個函數:
void
GamePacketReceivedInterceptSTUB();
void
GamePacketReceivedIntercept2STUB();
void
BnetPacketReceivedSaveSTUB();
void
BnetPacketReceivedInterceptSTUB();
void
GamePacketSentInterceptSTUB();
void
BnetPacketSentInterceptSTUB();
void
GamePlayerInfoInterceptSTUB();
第三步是修正兩個游戲內部的數據結構:
typedef
struct
playerinfostruct_t_110
…
{
BYTEUnitType;//+0x00
DWORDCharacterClass;//+0x04
DWORDunknown1;//+0x08
DWORDPlayerID;//+0x0c
DWORDPlayerLocation;//+0x10(defineslocationsomehowinoroutoftownandmaybeotherlocations(0x05=intown,0x01=outoftown)
LPCSTRPlayerName;//+0x14pointertoLPSZplayername
BYTEAct;//+0x18
BYTEunknown2[0x73];//+0x19
WORDPlayerPositionX;//+0x8c
WORDPlayerPositionY;//+0x8e
}
PLAYERINFOSTRUCT_110,
*
PPLAYERINFOSTRUCT_110;
typedef
struct
gamestruct_t_110
…
{
charUnknown1[0x1a];
charGameName[0x10];
charUnknown2[0x08];
charServerIP[0x10];
charUnknown3[0x46];
charAccountName[0x10];
charUnknown4[0x20];
charCharacterName[0x10];
charUnknown5[0x08];
charRealmName[0x10];
charUnknown6[0x147];
charRealmName2[0x10];
charUnknown7[0x08];
charGamePassword[0x10];
}
GAMESTRUCT_110,
*
PGAMESTRUCT_110;
總結
以上是生活随笔為你收集整理的Hacking Diablo II之D2HACKIT技术详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jtable mysql数据库_使用My
- 下一篇: mysql 记录更新 内部_MySQL