paralin / Dota2

[Deprecated] A plugin for SteamKit that interfaces with the DOTA 2 game coordinator and game servers.
https://github.com/paralin/go-dota2
115 stars 32 forks source link

Update the GameClient to work with Source 2 #14

Open paralin opened 8 years ago

paralin commented 8 years ago

The game client is a massive amount of work, mostly put in by @dschleck originally.

I'd like to update it for Source 2 (which significantly changed the networking protocol) and clean up the code a bit.

alanz85 commented 8 years ago

the sample project need game client lib to make the bot working, another other sample for latest version ?

paralin commented 8 years ago

this issue is regarding the Dota2.GameClient library which was able to connect into Source 1 servers completely, and perform normal game actions. this was all using reverse engineered protocols. needs to be updated for Source2.

studentworksl3 commented 8 years ago

Are there any news on how to connect to a Source 2 server? I still can join a lobby, but it blocks when I try to start a game...

paralin commented 7 years ago

This is probably never going to happen, it's a lot of work and I don't have the time or reason to do it.

luxalpa commented 7 years ago

I'm currently trying to work on it but I don't really know how to reverse engineer it well. Currently I'm just decompiling and debugging, but that takes ages and neither nethook nor MS Network Monitor/Wireshark have been of great help. It seems the community has access to a lot more things than I do :/

paralin commented 7 years ago

Reverse engineering this probably would require some static and runtime analysis with a tool like IDA Pro as well as extensive packet level analysis.

luxalpa commented 7 years ago

Yes, that's what I'm currently doing. I was able to find out how to generate the Ready_up_key last week, however, this one looks more difficult.

Do you happen to know if these strings that look like .?AVCMsgSteamDatagramConnectionStatsRouterToServer@@ (all those strings that start with .?AV and end with @@) are somehow backtraceable to the methods that they describe? That would be a huge help. I'm a little lost inbetween all these unlabled functions.

Also I'm not receiving the ClientTicketAuthComplete message from the server even though my ClientAuthList call looks perfectly fine :S

paralin commented 7 years ago

@SmaugTheGreat good work. I'm curious how you're generating ready_up_key. I wouldn't publicly publish your work on that particular bit, though. Maybe shoot me an email at christian@paral.in?

That looks like the protobuf message here: https://github.com/SteamRE/SteamKit/blob/master/Resources/Protobufs/tf/steamdatagram_messages.proto#L194

Are you comparing your auth process with the official Dota client's? Are you sure it looks nearly the same / explain-ably different?

luxalpa commented 7 years ago

I figured out that apparently the ClientTicketAuthComplete isn't being sent as an immediate response to ClientAuthList (The game establishes connection to the game server between these messages). The only two things that aren't created exactly like the game client are h_steam_pipe and the tick part of the auth ticket although I think those don't really matter at all.

I'm currently deep into networksystem.dll's Steam Datagram Protocol and trying to find out how it works, however it looks very difficult (I'm only making slow progress).

paralin commented 7 years ago

@SmaugTheGreat If you can figure out the rest of it, I can help you with datagram. I had mapped out how all of that works in detail before, and can probably help you with the rest of the way now. If you are as far along as it sounds you are, you're pretty close to breaking step 1 of building this thing. Step 2 of course is to figure out how the Source 2 in-band, out-of-band, channels, etc are structured, and if they're similar to Source 1 at all.

luxalpa commented 7 years ago

It took me a while but I found out most of the things. But I'm stuck and I don't think I will be able to finish the work. Maybe you got some ideas. If you want to, I can send you the code (typescript) that I've got so far.

Basically I send the gc messages until (excluding) ClientAuthList, then I need to connect to the relay using a seperate UDP Socket. The way the GameClient does it is by pinging 32 different relays that it gets from some cached .json file using RouterPingRequest. The format for that is a bit crazy and involves some undefined values (I checked in the code and it's literally using 200 bytes of random memory data) and doesn't really seem to use protobuf for this message. However, the replies do indeed use pbuf.

The reply is a RouterPingReply message which contains the challenge that you need in order to create a session. You get 1 of those for each request, however the client only uses 1 or occasionally 2 of those to actually create a session. For that it sends a GameserverSessionRequest using the challenge. Also all of these messages are using a client_cookie which is completely randomly generated (also verified that one in code). The session request then results in a GameserverSessionEstablished message, at which point the client sends a CMsgSteamDatagramConnectionStatsClientToRouter, however, this message has a special form again (only part of it is protobuf).

The thing looks a bit like this:

 let bb = new ByteBuffer()
            .writeUInt8(0x81)
            .writeUInt16(this.seqNum) // seq nums
            .writeUInt16(this.seqNum) // seq nums
            .writeUInt16(this.sessionId)
            .writeUInt16(this.clientCookie & 0xffff)
            .writeUInt8(StatsMessage.length)
            .append(StatsMessage) // this is a protobuf message
            .append(Buffer.from([0x02, 0x01, 0xFF, 0xFF, 0xFF, 0xFF]))
            .append("qconnect0x00000000")
            .writeUInt8(0);

Sometimes it appears to send this message twice in a 1s interval.

My problem is now that the Router / Gameserver should be replying to this message, however it simply doesn't when I try to send it.

The reason why I followed this path for so long is that I would really like to build a webservice to host custom games for Dota 2 like an Inhouse League, as Valve's way to work with custom games isn't really satisfying. Unfortunately I don't really have much time now to work on things like that, but maybe if you want to you can find a way or we can do it together or something like that.

Anyway, if you're interested in the code just write me and I'll email it to you.

Good luck further!

xanf commented 7 years ago

Hey, @SmaugTheGreat, any chance to see the code? (if you don't want to publish it email is in my github profile). I'm digging exactly the same task you were researching - just want to see if it is possible to take a shortcut and use your findings. Of course sharing back my results in case of success.

JS (+ Flow) / TS are the primary languages of me and my company so that should be not an issue at all. My "high level" task is to have a fully working spectator logic there

ur0 commented 6 years ago

I was watching this issue for quite some time and wanted to give some updates regarding this.

The entirety of packet encryption/decryption when the client is connected to SDR happens in steamnetworkingsockets.dll. As far as I can tell, it uses AES-256-CBC (see .text+0x4cdd0). The key and IV are initialized when the client first connects to the relay (haven't looked into that yet).

Setting up hooks in a couple of places reveals perfectly serialized messages, implying that there's no further encryption applied to the packets beyond what I've mentioned above.

paralin commented 6 years ago

@ur0 that's very exciting, I will have a look at this in the coming days.

paralin commented 6 years ago

@ur0 can you please drop me a mail at christian@paral.in? thanks.

herenickname commented 5 years ago

Any news from 2017? :)