I'm not assuming that this info is 100% correct, if you have something to add or found something that i completely missed, don't hesitate to say about it
To study dekaron.exe in disassembler you'll need to unpack it first (remove y0da+ASProtect). I'm not going for details on how to do that, there's already been even video tutorials for that, and you can get unpacked expedition client exe here [Only registered and activated users can see links. Click Here To Register...]. In future minor updates to game offsets in code might change.
Typical communication between client and server at connection to map server (when you're at character selection screen, selected char/server channel and pressed "connect" button) looks like this.
[Only registered and activated users can see links. Click Here To Register...]
In case someone forgot, this is general packet structure in all dekaron games:
[Only registered and activated users can see links. Click Here To Register...]
Offset:
0 - Packet CRC (calculated/checked by upon encryption/decryption)
4 - Number (starts from 0; synchronization,GG’s CSA are not counted)
6 - Size (header+data => 16bytes minimum )
8 - Timestamp (used to distinguish between requests/responces in some commnads)12 - Command (Describes what action to take)
16 - Data (optional; varies in size and not all areas of it are always used)
The packets with command 4000010 and 4000011 are exclusive to Expedition and weren't in BMR version of the game.
Number 0x4000011 can be easily found in disassembled client code.
Number 0x4000010 can't be found directly because it calculated in big switch-like structure in a function that handles all login commands
Now with 0x4000011:
Lets' look more deeper what happens when client receives 4000010 command.
And here's goes the most interesting part - CRC calculation itself.
I have no idea what does these 4 parameters mean, they seem to be different each time client connects to map-erver even if the same server channel is selected.However i found following pattern:
P1 = 0 ~ 10h
P2 = 10h ~ 20h (usually > P1)
P3 = 000FXXXX
P4 = totally random
Obviously you need to calculate CRC value each time based on valid files with parameters given by server, otherwise server won't let you connect (it will be famouse "invalid client" error. Possible ways to bypass CRC checks that comes to my mind:
1.Do not modify files on disk, let the client calculate correct CRC and then make changes directly in memory.Using GG killer + UCE/Rev for example, or write new program that will be injected into client process at startup and do all the work.
2.Modify client code so it will load valid files only for CRC calculation from other location, not from pak.d04.Files in pack.d04 then can freely modified. (GG Killer will be required to run such exectauble)
3.Intercept packets 4000010, store parameters from it,calculate CRC based on valid files and then modify packet 4000011 with correct CRC. WPE will NOT work here even if GG is bypassed, need a specific packet sniffer/editor capable of decrypting packets
Here's a little program with source code that will calculate correct CRC value with given parameters. Necessary client files including list.csv must be located in CRC\ subfolder.
For the first screenshot with packets:
[Only registered and activated users can see links. Click Here To Register...]
To study dekaron.exe in disassembler you'll need to unpack it first (remove y0da+ASProtect). I'm not going for details on how to do that, there's already been even video tutorials for that, and you can get unpacked expedition client exe here [Only registered and activated users can see links. Click Here To Register...]. In future minor updates to game offsets in code might change.
Typical communication between client and server at connection to map server (when you're at character selection screen, selected char/server channel and pressed "connect" button) looks like this.
[Only registered and activated users can see links. Click Here To Register...]
In case someone forgot, this is general packet structure in all dekaron games:
[Only registered and activated users can see links. Click Here To Register...]
Offset:
0 - Packet CRC (calculated/checked by upon encryption/decryption)
4 - Number (starts from 0; synchronization,GG’s CSA are not counted)
6 - Size (header+data => 16bytes minimum )
8 - Timestamp (used to distinguish between requests/responces in some commnads)12 - Command (Describes what action to take)
16 - Data (optional; varies in size and not all areas of it are always used)
The packets with command 4000010 and 4000011 are exclusive to Expedition and weren't in BMR version of the game.
Number 0x4000011 can be easily found in disassembled client code.
Number 0x4000010 can't be found directly because it calculated in big switch-like structure in a function that handles all login commands
So, when client receives packet with command = 4000010 it calls function located at 0x0051C2D0 (On_4000010_Receive).Quote:
.text:0051C370 ; int __thiscall LoginPacketHandler(void *pObject,void *pPacketObject, int)
.text:0051C370 LoginPacketHandler proc near ; CODE XREF: sub_51C6F0+25p
.text:0051C370
.text:0051C370 pPacketObject = dword ptr 4
.text:0051C370 arg_4 = dword ptr 8
.text:0051C370
.text:0051C370 push esi
.text:0051C371 push edi
.text:0051C372 mov edi, [esp+8+pPacketObject]
.text:0051C376 mov esi, ecx
.text:0051C378 mov ecx, [edi+0Ch]
.text:0051C37B call sub_428180 ; Get Command
.text:0051C380 cmp eax, 2040018h
.text:0051C385 ja loc_51C4EF ; 4000010 > 2040018 --> jump taken
.text:0051C38B jz loc_51C4D8
.text:0051C391 sub eax, 2040000h
.text:0051C396 cmp eax, 17h ; switch 24 cases
.text:0051C399 ja loc_51C60C ; default
.text:0051C399 ; jumptable 0051C3A6 cases 4-14
.text:0051C399 ; jumptable 0051C50E cases 33816606-33816611
.text:0051C39F movzx eax, ds:byte_51C690[eax]
.text:0051C3A6 jmp ds:off_51C658[eax*4] ; switch jump
.....................switch cases..............
.text:0051C4EF loc_51C4EF: ; CODE XREF: LoginPacketHandler+15j
.text:0051C4EF cmp eax, 2060002h
.text:0051C4F4 ja loc_51C5FB ; 4000010 > 2060002 --> jump taken
.text:0051C4FA jz loc_51C5E4
.text:0051C500 sub eax, 2040019h ; switch 15 cases
.text:0051C505 cmp eax, 0Eh
.text:0051C508 ja loc_51C60C ; default
.text:0051C508 ; jumptable 0051C3A6 cases 4-14
.text:0051C508 ; jumptable 0051C50E cases 33816606-33816611
.text:0051C50E jmp ds:off_51C6A8[eax*4] ; switch jump
..................... more switch cases..............
.text:0051C5FB loc_51C5FB: ; CODE XREF: LoginPacketHandler+184j
.text:0051C5FB sub eax, 4000002h
.text:0051C600 jz short loc_51C641
.text:0051C602 sub eax, 1
.text:0051C605 jz short loc_51C62A
.text:0051C607 sub eax, 0Dh
.text:0051C60A jz short loc_51C613 ;4000010 - 4000002 - 1 - 0D = 0 jump taken
.................................................. .........
.text:0051C613 loc_51C613: ; CODE XREF: LoginPacketHandler+29Aj
.text:0051C613 mov ecx, [esp+8+arg_4]
.text:0051C617 mov edx, [edi+0Ch]
.text:0051C61A push ecx ; int
.text:0051C61B push edx ; pRecvPacket
.text:0051C61C mov ecx, esi
.text:0051C61E call On_4000010_Receive ; <--- called upon CRC request from server
.text:0051C623 pop edi
.text:0051C624 mov al, 1
.text:0051C626 pop esi
.text:0051C627 retn 8
Now with 0x4000011:
Here packet with command = 4000011 and CRC value as data is formed. Function-method of CRC object at [this+4] (called at 51BCFA and 51BD14) retreives CRC value.But it's calculated somewhere else.Note that value is retreived from [this+10h] offsetQuote:
.text:0051BCA0 ; int __thiscall SendPacket_4000011(void *pObject)
.text:0051BCA0 SendPacket_4000011 proc near ; CODE XREF: sub_51C0B0+3p
.text:0051BCA0 ; sub_51C6F0+35p
.text:0051BCA0
.text:0051BCA0 var_24 = dword ptr -24h
.text:0051BCA0 var_20 = dword ptr -20h
.text:0051BCA0 var_1C = dword ptr -1Ch
.text:0051BCA0 var_18 = dword ptr -18h
.text:0051BCA0 var_4 = dword ptr -4
.text:0051BCA0
.text:0051BCA0 sub esp, 24h
.text:0051BCA3 push ebx
.text:0051BCA4 push esi
.text:0051BCA5 mov esi, ecx
.text:0051BCA7 xor ebx, ebx
.text:0051BCA9 cmp [esi+20h], bl
.text:0051BCAC push edi
.text:0051BCAD jz loc_51BE5A
.text:0051BCB3 mov eax, [esi+14h]
.text:0051BCB6 cmp eax, ebx
.text:0051BCB8 jz short loc_51BCCC
.text:0051BCBA mov ecx, [esi+18h]
.text:0051BCBD sub ecx, eax
.text:0051BCBF sar ecx, 2
.text:0051BCC2 mov [esp+30h+var_24], ecx
.text:0051BCC6 jnz loc_51BD80
.text:0051BCCC
.text:0051BCCC loc_51BCCC: ; CODE XREF: SendPacket_4000011+18j
.text:0051BCCC push 400h ; size_t
.text:0051BCD1 call ??2@YAPAXI@Z ; operator new(uint)
.text:0051BCD6 add esp, 4
.text:0051BCD9 mov ecx, eax
.text:0051BCDB mov [eax+8], ebx
.text:0051BCDE mov dword ptr [eax+0Ch], 4000011h ;<--- command 4000011
.text:0051BCE5 mov word ptr [eax+6], 14h ;<-- packet length (header+4bytes)
.text:0051BCEB call sub_428150
.text:0051BCF0 mov ecx, ds:pCRCObject
.text:0051BCF6 mov edx, [ecx]
.text:0051BCF8 mov edi, eax
.text:0051BCFA call dword ptr [edx+4] ; <--- pCRC->Get_CRC()
.text:0051BCFD mov [edi+16], eax
.text:0051BD00 mov ecx, ds:dword_BF785C
.text:0051BD06 push edi
.text:0051BD07 call sub_4E2C50 ; <--- Send packet (encrypt+send)
.text:0051BD0C mov ecx, ds:pCRCObject
.text:0051BD12 mov eax, [ecx]
.text:0051BD14 call dword ptr [eax+4] ; <--- pCRC->Get_CRC()
.text:0051BD17 push eax ; char
.text:0051BD18 sub esp, 1Ch
.text:0051BD1B mov ecx, esp ; lpszFormat
.text:0051BD1D push 13h ; int
.text:0051BD1F mov dword ptr [ecx+18h], 0Fh
.text:0051BD26 mov [ecx+14h], ebx
.text:0051BD29 push offset aCrccheckSendU ; "[CRCCHECK send %u "
.text:0051BD2E mov [ecx+4], bl
.text:0051BD31 call sub_401740 ; CString::Format() ??
.text:0051BD36 lea ecx, [esp+50h+var_1C] ; int
.text:0051BD3A push ecx ; char
.text:0051BD3B call sub_404280 ; CString::ReleaseBuffer() ??
.text:0051BD40 push eax
.text:0051BD41 call nullsub_1
.text:0051BD46 add esp, 28h
.text:0051BD49 cmp [esp+30h+var_4], 10h
.text:0051BD4E jb short loc_51BD5D
.text:0051BD50 mov edx, [esp+30h+var_18]
.text:0051BD54 push edx ; void *
.text:0051BD55 call j__free_0
.text:0051BD5A add esp, 4
Note that nullsub_1 at 51BD41 and string "[CRCCHECK send %u " above it.There's alot of such debug text messages at client but their results usually aren't printed anywhere. I beleive that instead of nullsub_1 (it contains only "ret" instruction) originally there was debug output function which was removed in release build.I wonder if it's possible to patch it to send these strings to console for example, there's would be alot of useful information from client itself.Well, that's a side noteQuote:
.text:0063BD50 Get_CRC proc near ; DATA XREF: .data:00A48AECo
.text:0063BD50 mov eax, [ecx+10h]
.text:0063BD53 retn
.text:0063BD53 Get_CRC endp
Lets' look more deeper what happens when client receives 4000010 command.
pCRCObject is variable that holds address of object (C++ class) that is used to store CRC and it's parameters & address of functions to manipulate with it.If you load it in debugger you can get address of list of that class member functions (it lies at offset '0' at memory address stored pCRCObject variable) in this case it's A48AE8.So CRC object has 4 methods, sub_63C030 is probably destructor but it's not interesting.Here contents of received packet are stored in memory via Load_params method.There are 4 values 2 words(P1,P2 - 16bit integers) and 2 double words (P3,P4 - 32bit integer) which are taken from packet's data consequently. I'm not sure what exactly Load_ListCSV (51C120) does, but it contains strings "list.csv","share\\" so i assume it loads share\list.csv file from pack.d04Quote:
.text:0051C2D0 ; int __thiscall On_4000010_Receive(void *pObject, void *pRecvPacket, int)
.text:0051C2D0 On_4000010_Receive proc near ; CODE XREF: LoginPacketHandler+2AEp
.text:0051C2D0
.text:0051C2D0 var_1C = dword ptr -1Ch
.text:0051C2D0 var_18 = dword ptr -18h
.text:0051C2D0 var_4 = dword ptr -4
.text:0051C2D0 pRecvPacket = dword ptr 4
.text:0051C2D0 arg_4 = dword ptr 8
.text:0051C2D0
.text:0051C2D0 sub esp, 1Ch
.text:0051C2D3 push esi
.text:0051C2D4 mov esi, [esp+20h+pRecvPacket]
.text:0051C2D8 mov edx, [esi+24] ;<--- P4 (dword)
.text:0051C2DB push edi
.text:0051C2DC push edx
.text:0051C2DD mov edx, [esi+20] ;<--- P3 (dword)
.text:0051C2E0 push edx
.text:0051C2E1 mov dx, [esi+18] ;<--- P2 (word)
.text:0051C2E5 mov edi, ecx
.text:0051C2E7 mov ecx, ds:pCRCObject
.text:0051C2ED mov eax, [ecx] ; eax = A48AE8 <---address of member functions list
.text:0051C2EF push edx
.text:0051C2F0 mov dx, [esi+16] ;<--- P1 (word)
.text:0051C2F4 push edx
.text:0051C2F5 call dword ptr [eax+0Ch] ; .data:00A48AE8 + 0C -> pCRC->Load_params(...)
.text:0051C2F8 mov eax, [esi+24]
.text:0051C2FB mov ecx, [esi+20]
.text:0051C2FE movzx edx, word ptr [esi+18]
.text:0051C302 push eax
.text:0051C303 movzx eax, word ptr [esi+16]
.text:0051C307 push ecx
.text:0051C308 push edx
.text:0051C309 push eax ; char
.text:0051C30A sub esp, 1Ch
.text:0051C30D mov ecx, esp ; lpszFormat
.text:0051C30F xor eax, eax
.text:0051C311 push 1Fh ; int
.text:0051C313 mov dword ptr [ecx+24], 0Fh
.text:0051C31A mov [ecx+14h], eax
.text:0051C31D push offset aCrccheckRecvUU ; "[CRCCHECK recv %u, %u, %u, %u "
.text:0051C322 mov [ecx+4], al
.text:0051C325 call sub_401740 ; CString::Format() ??
.text:0051C32A lea ecx, [esp+50h+var_1C] ; int
.text:0051C32E push ecx ; char
.text:0051C32F call sub_404280 ; CString::ReleaseBuffer() ??
.text:0051C334 push eax
.text:0051C335 call nullsub_1
.text:0051C33A add esp, 34h
.text:0051C33D cmp [esp+24h+var_4], 10h
.text:0051C342 jb short loc_51C351
.text:0051C344 mov edx, [esp+24h+var_18]
.text:0051C348 push edx ; void *
.text:0051C349 call j__free_0
.text:0051C34E add esp, 4
.text:0051C351
.text:0051C351 loc_51C351: ; CODE XREF: On_4000010_Receive+72j
.text:0051C351 mov ecx, edi
.text:0051C353 call Load_ListCSV
.text:0051C358 mov byte ptr [edi+20h], 1
.text:0051C35C pop edi
.text:0051C35D pop esi
.text:0051C35E add esp, 1Ch
.text:0051C361 retn 8
.text:0051C361 On_4000010_Receive endp
Function-member used to store 4 parameters from packet 4000010:Quote:
.data:00A48AE8 off_A48AE8 dd offset sub_63C030 ; DATA XREF: new_CRCObject+Ao
.data:00A48AEC dd offset Get_CRC
.data:00A48AF0 dd offset Calc_CRC
.data:00A48AF4 dd offset Load_params
So P1 (word) is sroted at offset 4, P2 (word) -> 6, P3 (dword) -> 8, P4 -> 12 (that are offsets from "this" pointer for CRC object).At offset 16(=10h) is stored '-1' - this initial value for CRC, and it will be used later in calculations.Quote:
.text:0063BD60 ; void __thiscall Load_params(void *pCRCObject, int p1, int p2, int p3, int p4)
.text:0063BD60 Load_params proc near ; DATA XREF: .data:00A48AF4o
.text:0063BD60
.text:0063BD60 p1 = dword ptr 4
.text:0063BD60 p2 = dword ptr 8
.text:0063BD60 p3 = dword ptr 0Ch
.text:0063BD60 p4 = dword ptr 10h
.text:0063BD60
.text:0063BD60 mov eax, [esp+p4]
.text:0063BD64 mov dx, word ptr [esp+p1]
.text:0063BD69 mov [ecx+0Ch], eax
.text:0063BD6C mov ax, word ptr [esp+p2]
.text:0063BD71 mov [ecx+4], dx
.text:0063BD75 mov edx, [esp+p3]
.text:0063BD79 mov [ecx+6], ax
.text:0063BD7D mov [ecx+8], edx
.text:0063BD80 mov dword ptr [ecx+10h], 0FFFFFFFFh
.text:0063BD87 retn 10h
.text:0063BD87 Load_params endp
And here's goes the most interesting part - CRC calculation itself.
Quote:
.text:0063BEA0 ; void __thiscall Calc_CRC(void *pCRCObject, void *pFileObject)
.text:0063BEA0 Calc_CRC proc near ; DATA XREF: .data:00A48AF0o
.text:0063BEA0
.text:0063BEA0 dwOutput = byte ptr -308h
.text:0063BEA0 var_304 = dword ptr -304h
.text:0063BEA0 var_300 = byte ptr -300h
.text:0063BEA0 var_200 = byte ptr -200h
.text:0063BEA0 var_100 = byte ptr -100h
.text:0063BEA0 pFileObject = dword ptr 8
.text:0063BEA0
.text:0063BEA0 push ebp
.text:0063BEA1 mov ebp, esp
.text:0063BEA3 and esp, 0FFFFFFF8h
.text:0063BEA6 sub esp, 30Ch
.text:0063BEAC push ebx
.text:0063BEAD push esi
.text:0063BEAE push edi
.text:0063BEAF push 500000h ; size_t
.text:0063BEB4 mov ebx, ecx
.text:0063BEB6 call ??2@YAPAXI@Z ; operator new(uint)
.text:0063BEBB mov ecx, [ebp+pFileObject]
.text:0063BEBE mov esi, eax
.text:0063BEC0 mov eax, [ecx]
.text:0063BEC2 add esp, 4
.text:0063BEC5 push esi
.text:0063BEC6 push 500000h
.text:0063BECB mov [esp+320h+var_304], esi
.text:0063BECF call dword ptr [eax+8] ; -> 88E6C0 load file into buffer
.text:0063BED2 push eax ; SourceLen
.text:0063BED3 lea ecx, [esp+31Ch+dwOutput]
.text:0063BED7 push ecx ; dwOutput
.text:0063BED8 push esi ; pSource
.text:0063BED9 mov ecx, ebx ; pCRCObject
.text:0063BEDB call CalcFileCRC
.text:0063BEE0 mov edx, dword ptr [esp+318h+dwOutput]
.text:0063BEE4 mov ecx, [ebx+10h]
.text:0063BEE7 movzx eax, dl
.text:0063BEEA and eax, 800000FFh
.text:0063BEEF jns short loc_63BEF8
.text:0063BEF1 dec eax
.text:0063BEF2 or eax, 0FFFFFF00h
.text:0063BEF7 inc eax
.text:0063BEF8
.text:0063BEF8 loc_63BEF8: ; CODE XREF: Calc_CRC+4Fj
.text:0063BEF8 mov esi, ecx
.text:0063BEFA movzx eax, al
.text:0063BEFD and esi, 0FFh
.text:0063BF03 xor eax, esi
.text:0063BF05 mov eax, ds:dword_BAE660[eax*4]
.text:0063BF0C shr ecx, 8
.text:0063BF0F xor eax, ecx
.text:0063BF11 mov ecx, edx
.text:0063BF13 shr ecx, 8
.text:0063BF16 movzx ecx, cl
.text:0063BF19 and ecx, 800000FFh
.text:0063BF1F mov [ebx+10h], eax
.text:0063BF22 jns short loc_63BF2C
.text:0063BF24 dec ecx
.text:0063BF25 or ecx, 0FFFFFF00h
.text:0063BF2B inc ecx
.text:0063BF2C
.text:0063BF2C loc_63BF2C: ; CODE XREF: Calc_CRC+82j
.text:0063BF2C mov esi, eax
.text:0063BF2E movzx ecx, cl
.text:0063BF31 and esi, 0FFh
.text:0063BF37 xor ecx, esi
.text:0063BF39 mov ecx, ds:dword_BAE660[ecx*4]
.text:0063BF40 shr eax, 8
.text:0063BF43 xor ecx, eax
.text:0063BF45 mov eax, edx
.text:0063BF47 shr eax, 10h
.text:0063BF4A movzx eax, al
.text:0063BF4D and eax, 800000FFh
.text:0063BF52 mov [ebx+10h], ecx
.text:0063BF55 jns short loc_63BF5E
.text:0063BF57 dec eax
.text:0063BF58 or eax, 0FFFFFF00h
.text:0063BF5D inc eax
.text:0063BF5E
.text:0063BF5E loc_63BF5E: ; CODE XREF: Calc_CRC+B5j
.text:0063BF5E mov esi, ecx
.text:0063BF60 movzx eax, al
.text:0063BF63 and esi, 0FFh
.text:0063BF69 xor eax, esi
.text:0063BF6B mov eax, ds:dword_BAE660[eax*4]
.text:0063BF72 shr ecx, 8
.text:0063BF75 xor eax, ecx
.text:0063BF77 mov ecx, edx
.text:0063BF79 shr ecx, 18h
.text:0063BF7C and ecx, 800000FFh
.text:0063BF82 mov [ebx+10h], eax
.text:0063BF85 jns short loc_63BF8F
.text:0063BF87 dec ecx
.text:0063BF88 or ecx, 0FFFFFF00h
.text:0063BF8E inc ecx
.text:0063BF8F
.text:0063BF8F loc_63BF8F: ; CODE XREF: Calc_CRC+E5j
.text:0063BF8F mov esi, eax
.text:0063BF91 movzx ecx, cl
.text:0063BF94 push edx ; char
.text:0063BF95 and esi, 0FFh
.text:0063BF9B xor ecx, esi
.text:0063BF9D shr eax, 8
.text:0063BFA0 xor eax, ds:dword_BAE660[ecx*4]
.text:0063BFA7 lea edx, [esp+31Ch+var_300]
.text:0063BFAB push offset aCrc32U ; "[CRC32] : %u "
.text:0063BFB0 push edx ; char *
.text:0063BFB1 mov [ebx+10h], eax
.text:0063BFB4 mov [esp+324h+var_300], 0
.text:0063BFB9 call sub_412B00
.text:0063BFBE mov esi, eax
.text:0063BFC0 mov eax, [ebx+10h]
.text:0063BFC3 push eax ; char
.text:0063BFC4 mov ecx, 40h
.text:0063BFC9 lea edi, [esp+328h+var_200]
.text:0063BFD0 rep movsd
.text:0063BFD2 lea ecx, [esp+328h+var_300]
.text:0063BFD6 push offset aCrc32TotalU ; "[CRC32] Total: %u "
.text:0063BFDB push ecx ; char *
.text:0063BFDC mov [esp+330h+var_300], 0
.text:0063BFE1 call sub_412B00
.text:0063BFE6 lea edx, [esp+330h+var_200]
.text:0063BFED mov esi, eax
.text:0063BFEF mov ecx, 40h
.text:0063BFF4 lea edi, [esp+330h+var_100]
.text:0063BFFB push edx
.text:0063BFFC rep movsd
.text:0063BFFE call sub_8090D0
.text:0063C003 lea eax, [esp+334h+var_100]
.text:0063C00A push eax
.text:0063C00B call sub_8090D0
.text:0063C010 mov ecx, [esp+338h+var_304]
.text:0063C014 push ecx ; void *
.text:0063C015 call j__free_0
.text:0063C01A add esp, 24h
.text:0063C01D pop edi
.text:0063C01E pop esi
.text:0063C01F pop ebx
.text:0063C020 mov esp, ebp
.text:0063C022 pop ebp
.text:0063C023 retn 4
.text:0063C023 Calc_CRC endp
This function is called for each file in list.csv (there are totally 85 files from share/ folder and it's subfolders, and while this folder contains much more files,i beleive these listed files is critical ones, you can affect game client-side by changing them so they are protected by CRC).Files are loaded somewhere else, call to function at 0063BECF only copies particular file content to newly allocated buffer. Then CRC of that file is calculated in function CalcFileCRC.All 4 parameters form packet 4000010 participate in CRC calculation.After that, total CRC value is updated, based on the result and previous CRC value. At BAE660 lies table of 1024 bytes, it's used both in file and total CRC calculation.(Btw, the same table of values is used for encrypting/decrypting packets - obviously game developers were too lazy to add different one). Fully reversed algortihm of CRC calculation you can find with attached archive (it's in C-langauge).Two strings "[CRC32] : %u " and "[CRC32] Total: %u " means calculated CRC values for particular file form list and resulting CRC for all files.Quote:
.text:0063BE20 ; void __thiscall CalcFileCRC(void *pCRCObject, void *pSource, DWORD *dwOutput, int SourceLen)
.text:0063BE20 CalcFileCRC proc near ; CODE XREF: Calc_CRC+3Bp
.text:0063BE20
.text:0063BE20 pSource = dword ptr 4
.text:0063BE20 dwOutput = dword ptr 8
.text:0063BE20 SourceLen = dword ptr 0Ch
.text:0063BE20
.text:0063BE20 push ebx
.text:0063BE21 mov ebx, [esp+4+SourceLen]
.text:0063BE25 test ebx, ebx
.text:0063BE27 mov edx, ecx
.text:0063BE29 mov eax, [edx+0Ch]
.text:0063BE2C push esi
.text:0063BE2D mov esi, [esp+8+dwOutput]
.text:0063BE31 mov [esi], eax
.text:0063BE33 jz short loc_63BE71
.text:0063BE35 push ebp
.text:0063BE36 push edi
.text:0063BE37 mov edi, [esp+10h+pSource]
.text:0063BE3B jmp short loc_63BE40
.text:0063BE3B ; ---------------------------------------------------------------------------
.text:0063BE3D align 10h
.text:0063BE40
.text:0063BE40 loc_63BE40: ; CODE XREF: CalcFileCRC+1Bj
.text:0063BE40 ; CalcFileCRC+4Dj
.text:0063BE40 mov eax, [esi]
.text:0063BE42 movzx ecx, byte ptr [edx+6]
.text:0063BE46 mov ebp, eax
.text:0063BE48 shr ebp, cl
.text:0063BE4A movzx ecx, byte ptr [edi]
.text:0063BE4D and ebp, 0FFh
.text:0063BE53 xor ebp, ecx
.text:0063BE55 movzx ecx, byte ptr [edx+4]
.text:0063BE59 shr eax, cl
.text:0063BE5B add edi, 1
.text:0063BE5E and eax, [edx+8]
.text:0063BE61 xor eax, ds:dword_BAE660[ebp*4]
.text:0063BE68 sub ebx, 1
.text:0063BE6B mov [esi], eax
.text:0063BE6D jnz short loc_63BE40
.text:0063BE6F pop edi
.text:0063BE70 pop ebp
.text:0063BE71
.text:0063BE71 loc_63BE71: ; CODE XREF: CalcFileCRC+13j
.text:0063BE71 mov edx, [esi]
.text:0063BE73 not edx
.text:0063BE75 mov [esi], edx
.text:0063BE77 pop esi
.text:0063BE78 pop ebx
.text:0063BE79 retn 0Ch
.text:0063BE79 CalcFileCRC endp
I have no idea what does these 4 parameters mean, they seem to be different each time client connects to map-erver even if the same server channel is selected.However i found following pattern:
P1 = 0 ~ 10h
P2 = 10h ~ 20h (usually > P1)
P3 = 000FXXXX
P4 = totally random
Obviously you need to calculate CRC value each time based on valid files with parameters given by server, otherwise server won't let you connect (it will be famouse "invalid client" error. Possible ways to bypass CRC checks that comes to my mind:
1.Do not modify files on disk, let the client calculate correct CRC and then make changes directly in memory.Using GG killer + UCE/Rev for example, or write new program that will be injected into client process at startup and do all the work.
2.Modify client code so it will load valid files only for CRC calculation from other location, not from pak.d04.Files in pack.d04 then can freely modified. (GG Killer will be required to run such exectauble)
3.Intercept packets 4000010, store parameters from it,calculate CRC based on valid files and then modify packet 4000011 with correct CRC. WPE will NOT work here even if GG is bypassed, need a specific packet sniffer/editor capable of decrypting packets
Here's a little program with source code that will calculate correct CRC value with given parameters. Necessary client files including list.csv must be located in CRC\ subfolder.
For the first screenshot with packets:
[Only registered and activated users can see links. Click Here To Register...]