I reversed D2GS decompression a long time ago, haven't really cared about D2 for a while. Here's the code to (re)compress D2GS packets. I hope someone finds it useful.
/* Packet compression table */
unsigned int CompTable[] = {
0x80010000, 0x70040000, 0x5C060000, 0x3E070000, 0x40070000, 0x60060000, 0x42070000, 0x44070000,
0x46070000, 0x30080000, 0x48070000, 0x31080000, 0x32080000, 0x4A070000, 0x23080100, 0x33080000,
0x34080000, 0x35080000, 0x4C070000, 0x64060000, 0x68060000, 0x4E070000, 0x36080000, 0x37080000,
0x38080000, 0x23080101, 0x24080100, 0x0D070306, 0x0D070307, 0x39080000, 0x50070000, 0x3A080000,
0x3B080000, 0x0E080200, 0x0E080201, 0x0E080202, 0x0E080203, 0x24080101, 0x0F080200, 0x0F080201,
0x25080100, 0x0F080202, 0x0F080203, 0x10080200, 0x10080201, 0x10080202, 0x10080203, 0x00080300,
0x25080101, 0x26080100, 0x11080200, 0x11080201, 0x11080202, 0x11080203, 0x12080200, 0x12080201,
0x12080202, 0x12080203, 0x13080200, 0x26080101, 0x13080201, 0x13080202, 0x13080203, 0x14080200,
0x27080100, 0x14080201, 0x14080202, 0x27080101, 0x14080203, 0x28080100, 0x15080200, 0x15080201,
0x15080202, 0x15080203, 0x16080200, 0x16080201, 0x28080101, 0x29080100, 0x16080202, 0x00080301,
0x29080101, 0x3C080000, 0x2A080100, 0x16080203, 0x00080302, 0x2A080101, 0x2B080100, 0x17080200,
0x2B080101, 0x17080201, 0x17080202, 0x17080203, 0x00080303, 0x18080200, 0x18080201, 0x18080202,
0x18080203, 0x19080200, 0x2C080100, 0x2C080101, 0x2D080100, 0x19080201, 0x19080202, 0x52070000,
0x54070000, 0x56070000, 0x19080203, 0x2D080101, 0x3D080000, 0x58070000, 0x1A080200, 0x1A080201,
0x1A080202, 0x00080304, 0x1A080203, 0x1B080200, 0x1B080201, 0x1B080202, 0x1B080203, 0x1C080200,
0x1C080201, 0x1C080202, 0x1C080203, 0x00080305, 0x1D080200, 0x1D080201, 0x1D080202, 0x1D080203,
0x5A070000, 0x1E080200, 0x1E080201, 0x1E080202, 0x00080306, 0x00080307, 0x01080300, 0x01080301,
0x01080302, 0x1E080203, 0x1F080200, 0x01080303, 0x01080304, 0x01080305, 0x01080306, 0x1F080201,
0x2E080100, 0x01080307, 0x02080300, 0x1F080202, 0x02080301, 0x2E080101, 0x2F080100, 0x2F080101,
0x1F080203, 0x02080302, 0x02080303, 0x02080304, 0x02080305, 0x02080306, 0x02080307, 0x03080300,
0x20080200, 0x03080301, 0x20080201, 0x03080302, 0x03080303, 0x03080304, 0x03080305, 0x03080306,
0x03080307, 0x04080300, 0x04080301, 0x04080302, 0x04080303, 0x04080304, 0x04080305, 0x04080306,
0x20080202, 0x04080307, 0x05080300, 0x05080301, 0x05080302, 0x05080303, 0x05080304, 0x05080305,
0x20080203, 0x05080306, 0x05080307, 0x06080300, 0x06080301, 0x06080302, 0x06080303, 0x06080304,
0x21080200, 0x06080305, 0x21080201, 0x06080306, 0x06080307, 0x07080300, 0x07080301, 0x07080302,
0x07080303, 0x07080304, 0x07080305, 0x07080306, 0x07080307, 0x08080300, 0x21080202, 0x08080301,
0x08080302, 0x08080303, 0x08080304, 0x08080305, 0x08080306, 0x08080307, 0x09080300, 0x09080301,
0x09080302, 0x09080303, 0x09080304, 0x09080305, 0x09080306, 0x09080307, 0x0A080300, 0x0A080301,
0x21080203, 0x0A080302, 0x22080200, 0x0A080303, 0x0A080304, 0x0A080305, 0x0A080306, 0x0A080307,
0x22080201, 0x0B080300, 0x0B080301, 0x0B080302, 0x0B080303, 0x0B080304, 0x0B080305, 0x0B080306,
0x22080202, 0x0B080307, 0x0C080300, 0x0C080301, 0x0C080302, 0x0C080303, 0x0C080304, 0x0C080305,
0x22080203, 0x0C080306, 0x0C080307, 0x0D080300, 0x0D080301, 0x0D080302, 0x0D080303, 0x6C060000,
};
/* Creates the size header for raw data */
unsigned int GamePacketHeader(unsigned int size, unsigned char* out){
if(size > 238){
size += 2;
size |= 0xF000;
out[0] = (unsigned char) (size >> 8);
out[1] = (unsigned char) (size & 0xFF);
return 2;
} else {
out[0] = (unsigned char) size + 1;
return 1;
}
}
/* D2gs compression routine, by mantralord */
unsigned int GamePacketEncode(unsigned char* indata, unsigned int inlen, unsigned char* outdata) {
unsigned int a, e, buf = 0;
int cnt = 0;
unsigned char* tmp = outdata;
while(inlen--){
a = CompTable[*indata++];
e = (a & 0xFF00) >> 8;
buf |= (a >> 24) << (24 - cnt);
cnt += (a & 0xFF0000) >> 16;
if(e) {
buf |= ((a & 0xFF) << (8 - e)) << (24 - cnt);
cnt += e;
}
while(cnt > 8){
*outdata++ = buf >> 24;
cnt -= 8;
buf <<= 8;
}
}
while(cnt > 0){
*outdata++ = buf >> 24;
buf <<= 8;
cnt -= 8;
}
return (unsigned int) (outdata - tmp);
}
Wow... VERY nice. Thanks much.
great work....
w00t!
*hugs mantralord*
Quote from: Joe on January 12, 2006, 07:09 PM
Ported some of it to VB:
Heh i just modifyed my post >_<
I'll repost it, please help! :P
[EDIT]
Thanks mantralord!
Im having some problems useing it tho, due to not knowing C++ :(
Is that in C or C++? i cant compile it with dev (nore the decompression code for some reassion)
After tinking around for hours, i decided to try and port it to VB6, but im lost by how it works :(
Can somone who can read C/C++ please explain what the following mean and how the are handled through out the function?
Im right looking faward to useing this :D
While inlen = inlen - 1? :(
while(inlen--){
If indata is a string of the raw data to be compressed, what character in "indata" does *indata++ point to?
a = CompTable[*indata++];If E = 0?
if(e) {
Im lost by how this builds up outdata (which is a null buffer to start with?) and how in/out data is used. :(
*outdata++ = b >> 24;
And is this some how trimming the null buffer to fit the message in?
return (unsigned int) (outdata - tmp)
This is what i have at the moment (Not even tested yet).
Could anyone please help finish it off and/or explain what im not getting?
Thanks in advance!
Public CompTable() As Long
Public Sub LoadCompTables()
Call FillCompTable(CompTable, &H80010000, &H70040000, &H5C060000, &H3E070000, &H40070000, &H60060000, &H42070000, &H44070000, &H46070000, &H30080000, &H48070000, &H31080000, &H32080000, &H4A070000, &H23080100, &H33080000, _
&H34080000, &H35080000, &H4C070000, &H64060000, &H68060000, &H4E070000, &H36080000, &H37080000, &H38080000, &H23080101, &H24080100, &HD070306, &HD070307, &H39080000, &H50070000, &H3A080000, _
&H3B080000, &HE080200, &HE080201, &HE080202, &HE080203, &H24080101, &HF080200, &HF080201, &H25080100, &HF080202, &HF080203, &H10080200, &H10080201, &H10080202, &H10080203, &H80300, _
&H25080101, &H26080100, &H11080200, &H11080201, &H11080202, &H11080203, &H12080200, &H12080201, &H12080202, &H12080203, &H13080200, &H26080101, &H13080201, &H13080202, &H13080203, &H14080200, _
&H27080100, &H14080201, &H14080202, &H27080101, &H14080203, &H28080100, &H15080200, &H15080201, &H15080202, &H15080203, &H16080200, &H16080201, &H28080101, &H29080100, &H16080202, &H80301, _
&H29080101, &H3C080000, &H2A080100, &H16080203, &H80302, &H2A080101, &H2B080100, &H17080200, &H2B080101, &H17080201, &H17080202, &H17080203, &H80303, &H18080200, &H18080201, &H18080202, _
&H18080203, &H19080200, &H2C080100, &H2C080101, &H2D080100, &H19080201, &H19080202, &H52070000, &H54070000, &H56070000, &H19080203, &H2D080101, &H3D080000, &H58070000, &H1A080200, &H1A080201, _
&H1A080202, &H80304, &H1A080203, &H1B080200, &H1B080201, &H1B080202, &H1B080203, &H1C080200, &H1C080201, &H1C080202, &H1C080203, &H80305, &H1D080200, &H1D080201, &H1D080202, &H1D080203, _
&H5A070000, &H1E080200, &H1E080201, &H1E080202, &H80306, &H80307, &H1080300, &H1080301, &H1080302, &H1E080203, &H1F080200, &H1080303, &H1080304, &H1080305, &H1080306, &H1F080201, _
&H2E080100, &H1080307, &H2080300, &H1F080202, &H2080301, &H2E080101, &H2F080100, &H2F080101, &H1F080203, &H2080302, &H2080303, &H2080304, &H2080305, &H2080306, &H2080307, &H3080300, _
&H20080200, &H3080301, &H20080201, &H3080302, &H3080303, &H3080304, &H3080305, &H3080306, &H3080307, &H4080300, &H4080301, &H4080302, &H4080303, &H4080304, &H4080305, &H4080306, _
&H20080202, &H4080307, &H5080300, &H5080301, &H5080302, &H5080303, &H5080304, &H5080305, &H20080203, &H5080306, &H5080307, &H6080300, &H6080301, &H6080302, &H6080303, &H6080304, _
&H21080200, &H6080305, &H21080201, &H6080306, &H6080307, &H7080300, &H7080301, &H7080302, &H7080303, &H7080304, &H7080305, &H7080306, &H7080307, &H8080300, &H21080202, &H8080301, _
&H8080302, &H8080303, &H8080304, &H8080305, &H8080306, &H8080307, &H9080300, &H9080301, &H9080302, &H9080303, &H9080304, &H9080305, &H9080306, &H9080307, &HA080300, &HA080301, _
&H21080203, &HA080302, &H22080200, &HA080303, &HA080304, &HA080305, &HA080306, &HA080307, &H22080201, &HB080300, &HB080301, &HB080302, &HB080303, &HB080304, &HB080305, &HB080306, _
&H22080202, &HB080307, &HC080300, &HC080301, &HC080302, &HC080303, &HC080304, &HC080305, &H22080203, &HC080306, &HC080307, &HD080300, &HD080301, &HD080302, &HD080303, &H6C060000)
End Sub
Public Sub FillCompTable(RetArray() As Long, ParamArray lng() As Variant)
Dim i%
ReDim RetArray(UBound(lng))
For i = 0 To UBound(lng)
RetArray(i) = CLng(lng(i))
Next i
End Sub
Public Function RightShift(ByVal Value As Long, ByVal Shift As Long) As Double
RightShift = CDbl(Value \ (2 ^ Shift))
End Function
Public Function LeftShift(ByVal Value As Long, ByVal Shift As Long) As Double
LeftShift = CDbl(Value * (2 ^ Shift))
End Function
Public Function GPHeader&(ByVal s&, ByRef d$)
'//if(size > 238){
'// size += 2;
'// size |= 0xF000;
'// out[0] = (unsigned char) (size >> 8);
'// out[1] = (unsigned char) (size & 0xFF);
'// return 2;
'//} else {
'// out[0] = (unsigned char) size + 1;
'// return 1;
'//}
Dim a%, b&, c$
b = Size
If b > 238 Then
b = b + 2
b = b Or &HF000
c = Chr(RightShift(b, 8))
c = c & Chr(b And &HFF)
GPHeader = 2
Else
c = Chr(Size + 1)
GPHeader = 1
End If
d = c
End Function
Public Function GPEncode&(ByVal InData$, ByVal InSize&, ByRef OutData$)
'//unsigned int a, e, b = 0;
'//int cnt = 0;
'//unsigned char* tmp = outdata;
'//while(inlen--){
'// a = CompTable[*indata++];
'// e = (a & 0xFF00) >> 8;
'// b |= (a >> 24) << (24 - cnt);
'// cnt += (a & 0xFF0000) >> 16;
'// if(e) {
'// b |= ((a & 0xFF) << (8 - e)) << (24 - cnt);
'// cnt += e;
'// }
'// while(cnt > 8){
'// *outdata++ = b >> 24;
'// cnt -= 8;
'// b <<= 8;
'// }
'//}
'//while(cnt > 0){
'// *outdata++ = b >> 24;
'// b <<= 8;
'// cnt -= 8;
'//}
'//return (unsigned int) (outdata - tmp);
Dim a&, e&, b&
Dim cnt%
Dim tmp$
cnt = 0
b = 0
tmp = OutData
While InSize = InSize - 1
a = CompTable(InData + 1)
e = RightShift(a And &HFF00, 8)
b = b Or LeftShift(RightShift(a, 24), 24 - cnt)
cnt = cnt + RightShift((a And &HFF0000), 16)
If e Then
b = b Or LeftShift(LeftShift(a And &HFF, 8 - e), 24 - cnt)
cnt = cnt + e
End If
While cnt > 8
OutData = OutData & RightShift(b, 24)
cnt = cnt - 8
b = LeftShift(b, 8)
Wend
Wend
While cnt > 0
OutData = OutData & Chr(RightShift(b, 24))
b = LeftShift(b, 8)
cnt = cnt - 8
Wend
End Function
His code is in C. I see nothing C++ specific in it.
You guys ported (or began to) it to VB6 and made it look ugly...
I haven't even tested this, but I I've made fixes to the VB code:
Public CompTable() As Long
Public Sub LoadCompTables()
Call FillCompTable(CompTable, &H80010000, &H70040000, &H5C060000, &H3E070000, &H40070000, &H60060000, &H42070000, &H44070000, &H46070000, &H30080000, &H48070000, &H31080000, &H32080000, &H4A070000, &H23080100, &H33080000, _
&H34080000, &H35080000, &H4C070000, &H64060000, &H68060000, &H4E070000, &H36080000, &H37080000, &H38080000, &H23080101, &H24080100, &HD070306, &HD070307, &H39080000, &H50070000, &H3A080000, _
&H3B080000, &HE080200, &HE080201, &HE080202, &HE080203, &H24080101, &HF080200, &HF080201, &H25080100, &HF080202, &HF080203, &H10080200, &H10080201, &H10080202, &H10080203, &H80300, _
&H25080101, &H26080100, &H11080200, &H11080201, &H11080202, &H11080203, &H12080200, &H12080201, &H12080202, &H12080203, &H13080200, &H26080101, &H13080201, &H13080202, &H13080203, &H14080200, _
&H27080100, &H14080201, &H14080202, &H27080101, &H14080203, &H28080100, &H15080200, &H15080201, &H15080202, &H15080203, &H16080200, &H16080201, &H28080101, &H29080100, &H16080202, &H80301, _
&H29080101, &H3C080000, &H2A080100, &H16080203, &H80302, &H2A080101, &H2B080100, &H17080200, &H2B080101, &H17080201, &H17080202, &H17080203, &H80303, &H18080200, &H18080201, &H18080202, _
&H18080203, &H19080200, &H2C080100, &H2C080101, &H2D080100, &H19080201, &H19080202, &H52070000, &H54070000, &H56070000, &H19080203, &H2D080101, &H3D080000, &H58070000, &H1A080200, &H1A080201, _
&H1A080202, &H80304, &H1A080203, &H1B080200, &H1B080201, &H1B080202, &H1B080203, &H1C080200, &H1C080201, &H1C080202, &H1C080203, &H80305, &H1D080200, &H1D080201, &H1D080202, &H1D080203, _
&H5A070000, &H1E080200, &H1E080201, &H1E080202, &H80306, &H80307, &H1080300, &H1080301, &H1080302, &H1E080203, &H1F080200, &H1080303, &H1080304, &H1080305, &H1080306, &H1F080201, _
&H2E080100, &H1080307, &H2080300, &H1F080202, &H2080301, &H2E080101, &H2F080100, &H2F080101, &H1F080203, &H2080302, &H2080303, &H2080304, &H2080305, &H2080306, &H2080307, &H3080300, _
&H20080200, &H3080301, &H20080201, &H3080302, &H3080303, &H3080304, &H3080305, &H3080306, &H3080307, &H4080300, &H4080301, &H4080302, &H4080303, &H4080304, &H4080305, &H4080306, _
&H20080202, &H4080307, &H5080300, &H5080301, &H5080302, &H5080303, &H5080304, &H5080305, &H20080203, &H5080306, &H5080307, &H6080300, &H6080301, &H6080302, &H6080303, &H6080304, _
&H21080200, &H6080305, &H21080201, &H6080306, &H6080307, &H7080300, &H7080301, &H7080302, &H7080303, &H7080304, &H7080305, &H7080306, &H7080307, &H8080300, &H21080202, &H8080301, _
&H8080302, &H8080303, &H8080304, &H8080305, &H8080306, &H8080307, &H9080300, &H9080301, &H9080302, &H9080303, &H9080304, &H9080305, &H9080306, &H9080307, &HA080300, &HA080301, _
&H21080203, &HA080302, &H22080200, &HA080303, &HA080304, &HA080305, &HA080306, &HA080307, &H22080201, &HB080300, &HB080301, &HB080302, &HB080303, &HB080304, &HB080305, &HB080306, _
&H22080202, &HB080307, &HC080300, &HC080301, &HC080302, &HC080303, &HC080304, &HC080305, &H22080203, &HC080306, &HC080307, &HD080300, &HD080301, &HD080302, &HD080303, &H6C060000)
End Sub
Public Sub FillCompTable(RetArray() As Long, ParamArray lng() As Variant)
Dim i%
ReDim RetArray(UBound(lng))
For i = 0 To UBound(lng)
RetArray(i) = CLng(lng(i))
Next i
End Sub
Public Function RightShift(ByVal Value As Long, ByVal Shift As Long) As Double
RightShift = CDbl(Value \ (2 ^ Shift))
End Function
Public Function LeftShift(ByVal Value As Long, ByVal Shift As Long) As Double
LeftShift = CDbl(Value * (2 ^ Shift))
End Function
Public Function GPHeader(s as long, ByRef d as string) as long
Dim b as long: b = s
If b > 238 Then
b = b + 2
b = b Or &HF000
d = Chr(RightShift(b, 8))
d = d & Chr(b And &HFF)
GPHeader = 2
Else
d = Chr(Size + 1)
GPHeader = 1
End If
GPHeader = len(d)
End Function
Public Function GPEncode(InData as string,ByRef OutData as String) as long
dim InSize as long
dim CurPos as long
Dim a&, e&, b&
Dim cnt%
Dim tmp$
InSize = len(InData)
While InSize <> 0
InSize = InSize - 1
a = CompTable(asc(mid(InData, len(InData) - InSize, 1)))
e = RightShift(a And &HFF00, 8)
b = b Or LeftShift(RightShift(a, 24), 24 - cnt)
cnt = cnt + RightShift((a And &HFF0000), 16)
If e <> 0 Then
b = b Or LeftShift(LeftShift(a And &HFF, 8 - e), 24 - cnt)
cnt = cnt + e
End If
While cnt > 8
OutData = OutData & RightShift(b, 24)
cnt = cnt - 8
b = LeftShift(b, 8)
Wend
Wend
While cnt > 0
OutData = OutData & Chr(RightShift(b, 24))
b = LeftShift(b, 8)
cnt = cnt - 8
Wend
GPEncode = len(OutData)
End Function
Wow. Nice
Quote from: mantralord on January 13, 2006, 12:02 AM
I haven't even tested this, but I I've made fixes to the VB code:
Awsome, Thanks!
I have put your code into D2GS.dll along with Brand.X's decompression code, if thats alright.
The DLL can be downloaded from Here (D2GS.dll.zip) (http://www.geocities.com/ringomail711/D2GS.dll.zip) and comes with a txt with links to the relating topics, the exports and an example of how to use them.
Declare Sub GamePacketSize Lib "D2GS.dll" (ByVal Data$, ByRef Size&, ByRef OffSet&)
Declare Function GamePacketDecode& Lib "D2GS.dll" (ByVal InData$, ByVal InSize&, ByVal OutData$, ByVal OutMax&, ByRef OutSize&)
Declare Function GamePacketEncode& Lib "D2GS.dll" (ByVal InData$, ByVal InSize&, ByVal OutData$)
Declare Function GamePacketHeader& Lib "D2GS.dll" (ByVal Size&, ByVal Out$)
Public Sub MakePacketHeader(Data$)
'Adds header to "Data"
Dim tmpData$, tmpHdl&, InSize&
tmpData = String(2, 0)
InSize = Len(Data)
intHdl = GamePacketHeader(InSize, tmpData)
Data = Left(tmpData, intHdl) & Data
End Sub
Public Sub EncodePacket(Data$)
'Converts raw "Data" to compressed "Data"
Dim OutData$, tmpData$, InSize&, tmpLng&
OutData = String(1024, 0)
tmpData = Data
InSize = Len(tmpData)
tmpLng = GamePacketEncode(tmpData, InSize, OutData)
Data = Left(OutData, tmpLng)
End Sub
Public Function GetPacketSize&(Data$)
'Returns the compressed packet lengh and removes the header from "Data"
Dim tmpData$, RetSize&, OffSet&
tmpData = Data
Call GamePacketSize(tmpData, RetSize, OffSet)
Data = Mid(Data, 1 + OffSet)'Remove Lengh header
GetPacketSize = RetSize
End Function
Public Function DecodePacket&(Data$, ByVal pSize&, OutData$)
'Takes compressed data from "Data" annd returns the decompressed data in "OutData"
Dim SizeReturn&, OutBuf$, tmpData$
OutBuf = String(pSize * 3 + 250, 0)
tmpData = Left(Data, pSize)
DecodePacket = GamePacketDecode(tmpData, Len(tmpData), OutBuf, Len(OutBuf), SizeReturn)
OutData = Left(OutBuf, SizeReturn)
End Function
Thanks again!
I'm totally oblivious to how one goes about reversing something like this. I'm especially curious as to how one goes about figuring out what each individual value in the compression table is.
Quote from: Sorc.Polgara on January 27, 2006, 09:30 AM
I'm totally oblivious to how one goes about reversing something like this. I'm especially curious as to how one goes about figuring out what each individual value in the compression table is.
Disassembling the file
Quote from: l2k-Shadow on January 27, 2006, 05:05 PM
Quote from: Sorc.Polgara on January 27, 2006, 09:30 AM
I'm totally oblivious to how one goes about reversing something like this. I'm especially curious as to how one goes about figuring out what each individual value in the compression table is.
Disassembling the file
Aight.
Mind giving me a hint as to what DLL it is found in?
What does the GS in D2GS stand for? Game Socket? Game Server? Because I'm thinking that knowing what the GS stands for might help me narrow down which of the DLLs to look in.
What does MCP stand for? Multi Connection Protocol? Multi Character Protocol?
D2GS: Diablo 2 Game Server
MCP: Master Control Protocol(?)
Note that MCP isn't the official name.
MCP officially stands for Master Control Program.
I am having a lot of problems running your code. I can't seem to get the header part working, mind posting an example?
Thanks.
Quote from: Skywing on January 29, 2006, 12:00 AM
MCP officially stands for Master Control Program.
Got to love how the electornical world revolves around [ TRON ] :)
Quote from: LordNevar on June 06, 2006, 10:58 AM
Quote from: Skywing on January 29, 2006, 12:00 AM
MCP officially stands for Master Control Program.
Got to love how the electornical world revolves around [ TRON ] :)
What?
Quote from: Topaz on June 06, 2006, 05:26 PM
Quote from: LordNevar on June 06, 2006, 10:58 AM
Quote from: Skywing on January 29, 2006, 12:00 AM
MCP officially stands for Master Control Program.
Got to love how the electornical world revolves around [ TRON ] :)
What?
Master Control Program (Tron) (http://en.wikipedia.org/wiki/Master_Control_Program_(Tron))