- == Research ==
- Every address from here on applies to 3.0.3 client on windows.
- 0x57 parsing function can be found at 00442B60.
- Following data gets pushed onto stack:
- * (dword) packet+24 (IP address)
- * (word) packet+10 (max clients)
- * (word) packet+6 (flag that seems to indicate if this is a payed server)
- * (word) packet+8 (port)
- * (dword) packet+24 (ip address) after it has gone through ntohl
- Then function 0046DE70 is called.
- If segment of IP address starts with:
- * 127
- * 10
- * 12
- the function will return prematurely (no further checking needs to be done).
- Then, the data is copied into a structure, below is the simplified disasembly:
- {{{
- 0046DEB5 |. 8951 1C MOV DWORD PTR DS:[ECX+1C],EDX ; ECX+1C = server ip
- 0046DEBD |. 66:8941 20 MOV WORD PTR DS:[ECX+20],AX ; ECX+20 = port
- 0046DEC6 |. 66:8951 22 MOV WORD PTR DS:[ECX+22],DX ; ECX+22 = flag
- 0046DECE |. 66:8941 24 MOV WORD PTR DS:[ECX+24],AX ; ECX+24 = max clients
- 0046DED2 |. 8951 28 MOV DWORD PTR DS:[ECX+28],EDX ; ECX+28 = server ip
- }}}
- It then seems to spawn a thread with ECX as argument to function 0046DE20.
- The pointer to the structure is retrieved from the stack and stored in ECX again:
- {{{
- 0046DE21 . 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+8]
- 0046DE25 . 8BCE MOV ECX,ESI
- }}}
- Function 0046DAF0 is called, which does a poor attempt at trying to obfuscate the verifcation's server address:
- {{{
- 0046DB21 |. 8D4424 04 LEA EAX,DWORD PTR SS:[ESP+4]
- 0046DB25 |. 50 PUSH EAX ; /Name
- 0046DB26 |. C64424 08 70 MOV BYTE PTR SS:[ESP+8],70 ; |
- 0046DB2B |. C64424 09 72 MOV BYTE PTR SS:[ESP+9],72 ; |
- ... ETC ...
- 0046DB77 |. FF15 74A75100 CALL DWORD PTR DS:[<&WS2_32.#52>] ; \get proinfo.ventrilo.com host by name
- }}}
- Then the thread sleeps for 10 seconds.
- Function 0046DFC0 is called:
- * A new socket gets created. (after closing previous socket)
- * setsockopt on the socket is called with option SO_BROADCAST making the socket ready for transmitting and receiving UDP packets.
- * the socket is bound to the address through bind()
- Function 0046DBF0:
- * 804 bytes are allocated
- * These bytes are partially set to 00. (some remnant of F00DBAAD exist as 0xADBA)
- Data is copied into a buffer in this format:
- * buffer+0 = (dword) port
- * buffer+4 = (word) flag
- * buffer+6 = (word) max clients
- * buffer+8 = (dword) ip
- * buffer+12 = (dword) ip
- This is the data section for our packet.
- An 18-byte header will be attached in front of it, with another 2 bytes in front of that which will act as encryption seed.
- Example header:
- {{{
- 84 e1 // encryption seed
- 00 00 00 06
- 00 29
- 00 10
- 00 10
- 00 01
- 00 00
- 23 be 64 c6
- }}}
- There is no need for me to reinvent the wheel, if you are curious about the encryption technique you can have a look at Luigi Auriemma's C code; http://aluigi.altervista.org/papers/vent5000dec.zip
- After attaching the header and encrypting the packet, its sent to the proinfo.ventrilo.com server for verification purposes.
- After that, a call is made to close the socket (at 0046DBC0), and the structure is cleaned up so that next time 0x57 is received, the verification process starts over again:
- {{{
- 0046DE33 . 33C0 XOR EAX,EAX
- 0046DE35 . 33C9 XOR ECX,ECX
- 0046DE37 . 33D2 XOR EDX,EDX
- 0046DE39 . 8946 1C MOV DWORD PTR DS:[ESI+1C],EAX
- 0046DE3C . 66:894E 20 MOV WORD PTR DS:[ESI+20],CX
- 0046DE40 . 66:8956 24 MOV WORD PTR DS:[ESI+24],DX
- 0046DE44 . 8946 28 MOV DWORD PTR DS:[ESI+28],EAX
- }}}