
ãµã€ã¯ã«ã®æåŸã®èšäºãæãè峿·±ããæãããªã¥ãŒã ã®ãããã®ïŒ
ãã®èšäºã§ã¯ãããŸããŸãªãµãŒããŒãšã®Steamã¯ã©ã€ã¢ã³ãããŒã¿äº€æãããã³ã«ã«ã€ããŠèª¬æããŸãã
ç¹°ãè¿ããŸãããåé¡ã®ãããã³ã«ã¯å€ããçŸåšäœ¿çšãããŠããŸããïŒäºææ§ã®ããã«GDSãšConfigãé€ãïŒã
ãã¹ãŠã®ã¢ã«ãŽãªãºã ã¯ç§ã®
ãªããžããªã«è¡šç€ºãã
ãŸã ã
ãããã³ã«å
šäœã¯ãœã±ããã«åºã¥ããŠãããããWireSharkã¯ã»ãŒãã¹ãŠã®å Žæã§è§£æã§ããŸããã ãããã³ã«ã®èª¬æå
šäœãã¯ã©ã€ã¢ã³ãã«ãã£ãŠæ€èšãããŸãïŒDelphiã§ïŒã å Žæã«ã¯ãC ++ã®ãµãŒããŒã³ãŒãã®ã»ã¯ã·ã§ã³ãäžããããŸãã
ã»ãšãã©ãã¹ãŠã®ãªã¯ãšã¹ãã«ã¯å
±éã®ã¢ã«ãŽãªãºã ããããŸãfunction TSteamNetwork.ConectToServer(Addr: TSockAddr; const QUERY; QSize: uint32; Command: pByte; CSize: uint32; var ReplySize: uint32; IsConfigServer: boolean = false): pByte; var Accept: boolean; DestIP: uint32; Sock: CSocket; begin result:=nil; Sock:=CSocket.Create(SOCKET_IP); if not Sock.Connect(Addr) then Exit; Sock.SetTimeOut(3000); if not Sock.Send(QUERY, QSize) then Exit; if not Sock.recv(Accept, 1) then Exit; if IsConfigServer then if not Sock.recv(DestIP, 4) then Exit; if not Accept then Exit; CSize:=htonl(CSize); if not Sock.send(CSize, 4) then Exit; CSize:=htonl(CSize); if not Sock.send(Command^, CSize) then Exit; Sock.OnLoadingProc:=OnLoadingProc; result:=Sock.RecvFromLen(ReplySize); Sock.Free; end;
ãã®ãããã³ã«ã¯ããã¹ãŠã®ãªã¹ããµãŒããŒïŒGDãConfigãContentListïŒãžã®ã¯ãšãªã«äœ¿çšãããŸãã QUERYãã©ã¡ãŒã¿ãŒã§ã¯ãèŠæ±ã®ã¿ã€ãã衚ããã€ãã®é
åãžã®ãã€ã³ã¿ãŒãæž¡ãããQSizeã§ã¯ãã®é
åã®ãµã€ãºãæž¡ãããŸãã Commandãã©ã¡ãŒã¿ãŒã§ã¯ãã³ãã³ãèªäœãå«ããã€ãé
åãžã®ãã€ã³ã¿ãŒãæž¡ãããCSizeã§ã¯ãã®é
åã®ãµã€ãºãæž¡ãããŸãã ReplySize倿°ã«ã¯ãèŠæ±ãããå¿çã®ãµã€ãºãå«ãŸããåŒã³åºãåŸãå®éã«åä¿¡ããããŒã¿ã®éãšçãããªããŸãã äžèšã®ã³ãŒãã¯ãæ¬¡ã®æ¬äŒŒã³ãŒãã§è¡šãããšãã§ããŸãã
IP-, Config Server' ,
å Žåã«ãã£ãŠã¯ã次ã®ã¢ã«ãŽãªãºã ã«ãã£ãŠååŸãããRSA眲åã䜿çšãããŸãã
SteamããŒã¿ãããã¯çœ²å char *RSASign(RSA *key, char *Mess, UINT32 size, UINT32 sign_size) { char *sign = new char[sign_size]; memset(sign, 0, sign_size); sign[0] = '\x00'; sign[1] = '\x01'; memset(&sign[2], 0xff, sign_size-38); memcpy(&sign[sign_size-36], "\x00\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", 0x10); void *hash = HashSHA1(Mess, size); memcpy((void*)&sign[sign_size-20], hash, 20); delete hash; RSA_public_encrypt(sign_size, (UCHAR*)sign, (UCHAR*)sign, key, RSA_NO_PADDING); return sign; } char *RSASignMessage(RSA *key, char *Mess, UINT32 size) { return RSASign(key, Mess, size, 128); } char *RSASignMessage1024(RSA *key, char *Mess, UINT32 size) { return RSASign(key, Mess, size, 256); }
以åã«çœ²åã«äœ¿çšããã㌠// MainKeySign #define MainKeySign_n #define MainKeySign_e #define MainKeySign_d // NetworkKey #define NetworkKey_n #define NetworkKey_e #define NetworkKey_d
æ±çšãã£ã¬ã¯ããªãµãŒããŒ
ã€ã³ãã©ã¹ãã©ã¯ãã£å
šäœã®ã«ãŒãã§ãããä»ã®ãµãŒããŒã®ã¢ãã¬ã¹ã®ã¿ãä¿åããŸãã èŠæ±ã¿ã€ãã¯0x02000000ã§ãïŒConectToServerãåŒã³åºããšãã«äœ¿çšãããŸãïŒã çãã¯ãèŠæ±ããããµãŒããŒIPã¢ãã¬ã¹ã®ãªã¹ãã§ãã
- 4ãã€ãã®ãªã¹ãã®é·ãã
- IPïŒportïŒ4 + 2ãã€ãïŒã®åœ¢åŒã®Nåã®ãªã¹ãé
ç®ã
æ¢ç¥ã®ã¯ãšãªãšãã®ã³ãã³ãïŒ
- æ§æãµãŒããŒã®ãªã¹ã-\ x00;
- èªèšŒãµãŒããŒã®ãªã¹ã-\ x00 \ xC4 \ x1D \ x1A \ x00;
- ã«ãŒãã³ã³ãã³ããµãŒããŒã®ãªã¹ã-\ x06;
- CSERãµãŒããŒã®ãªã¹ãã¯\ x14ã§ãã
ã©ã®ãããªCSERãµãŒããŒãçè§£ããŠããªãã£ãã®ã§ãä»ã®å Žæã§ã¯èšåããŸããã
æ§æãµãŒããŒ
èŠæ±ã¿ã€ãã¯0x03000000ã§ãã æ¢ç¥ã®ã¯ãšãªïŒ
- CDR ;
- ã¯ã©ã€ã¢ã³ãããŒãžã§ã³ã
- ãããã¯ãŒã¯ããŒ;
- äžæãªãªã¯ãšã¹ãã
CDRãšããŒãžã§ã³ã¯
BLOBãã¡ã€ã«ãšããŠæäŸãããŸãã
CDR
ã³ãã³ãã¯ããã¡ã€ã«ãåä¿¡ããå Žåã¯0x02ãæŽæ°ã確èªããå Žåã¯0x09ã§ãã æŽæ°ã®å ŽåãèŠæ±åŸãSHA-1ããã·ã¥ã®20ãã€ãã¯æ¢åã®ãã¡ã€ã«çšã§ãïŒããã§ãªãå Žåã¯0x00ïŒã çãã¯ããã£ã¹ã¯ã«ä¿åãããåŸã§ã¯ã©ã€ã¢ã³ãã«ãã£ãŠäœ¿çšãããCDRãå«ããçã®ããã¡ã€ã«ã§ãã
ã¯ã©ã€ã¢ã³ãããŒãžã§ã³
ããŒã ã¯0x01ã§ãã
ãµãŒããŒåŽã§ã®BLOB'aã®åœ¢æ case ACTION_GET_VERSIONS_BLOB: #ifdef LOG Log(Client->ServerName, "Client %s - Sending Versions Blob", ClientAddr); #endif blob = new CBLOBFile(); rootNode = blob->RootNode(); rootNode->AddString("\x00\x00\x00\x00", 4, "\x00\x00\x00\x00", 4); rootNode->AddData("\x01\x00\x00\x00", 4, (char*)&SteamVersion, 4); rootNode->AddData("\x02\x00\x00\x00", 4, (char*)&SteamUIVersion, 4); rootNode->AddString("\x03\x00\x00\x00", 4, "\x00\x00\x00\x00", 4); rootNode->AddString("\x04\x00\x00\x00", 4, "\x14\x00\x00\x00", 4); rootNode->AddString("\x05\x00\x00\x00", 4, "\x17\x00\x00\x00", 4); rootNode->AddString("\x06\x00\x00\x00", 4, "\x0e\x00\x00\x00", 4); rootNode->AddString("\x07\x00\x00\x00", 4, "boo\x00", 4); //rootNode->AddString("\x08\x00\x00\x00", 4, "\x5c\x01\x00\x00", 4); rootNode->AddString("\x09\x00\x00\x00", 4, "foo\x00", 4); rootNode->AddString("\x0a\x00\x00\x00", 4, "\x11\x00\x00\x00", 4); rootNode->AddString("\x0b\x00\x00\x00", 4, "bar\x00", 4); rootNode->AddString("\x0c\x00\x00\x00", 4, "\x12\x00\x00\x00", 4); rootNode->AddString("\x0d\x00\x00\x00", 4, "foo\x00", 4); rootNode->AddString("\x0e\x00\x00\x00", 4, "", 0); rootNode->AddString("\x0f\x00\x00\x00", 4, "\x50\x01\x00\x00", 4); ReplySize = blob->SaveToMem(&reply, false); delete blob; Socket->SendInt32(ReplySize, true); Socket->Send(reply, ReplySize); break;
ãã®ã³ãŒããããããããã«ãã¬ã³ãŒãã«ã¯å€ãã®ãªãŒããŒããããå«ãŸããŠããããã®ç®çã¯æç¢ºã§ã¯ãããŸããããé·ãéäžå®ã§ããã ã¯ã©ã€ã¢ã³ãã®ææ°ããŒãžã§ã³ãšãã®UIããã±ãŒãžãå«ãæååã¯ã倿°ãã転éãããŸãã
ãããã¯ãŒã¯ããŒ
ããŒã ã¯0x04ã§ãã ããã¯ããéæšæºã®ããŒã¿äº€æãããã³ã«ãåããŠããŸã-ãµãŒããŒããã®å¿çã®ãµã€ãºã¯ãæ®ãã®å¿çã®4ãã€ãã§ã¯ãªã2ãã€ãã§ãã ãµãŒããŒå¿çã«ã¯ä»¥äžãå«ãŸããŸãã
- ã¿ã€ãã«-\ x30 \ x81 \ x9d \ x30 \ x0d \ x06 \ x09 \ x2a \ x86 \ x48 \ x86 \ xf7 \ x0d \ x01 \ x01 \ x01 \ x05 \ x00 \ x03 \ x81 \ x8b \ x00 \ x30 \ x81 \ x87 \ x02 \ x81 \ x81 \ x00;
- NetworkKeyã®éåžžã®éšåã
- Data \ x02 \ x01 \ x11ïŒæåŸã®ãã€ãã¯ãæããã«NetworkKeyã®ææ°éšã§ãã
- MainKeySignã䜿çšãã256ãã€ãã®RSA眲åã 眲åã®ãµã€ãºã¯å«ãŸããŠããŸããããããã±ãŒãžã®ãµã€ãºã§ãïŒ
äžæãªãªã¯ãšã¹ã
ã³ãã³ã0x07ã ãµãŒããŒå¿çã«ã¯ã9ãã€ãã®å®æ°ãå«ãŸããŸã-\ x00 \ x01 \ x31 \ x2d \ x00 \ x00 \ x00 \ x01 \ x2c
èªèšŒãµãŒããŒ
ãããã³ã«ãéãããã®æãé¢çœããŠé£ãããµãŒããŒã äž»ãªæ©èœã¯ã
PXããã®ããç§åäœã®éåžžã«éæšæºã®æé枬å®ã·ã¹ãã ã®äœ¿çšã§ãã ãœãŒã¹ããŒã¿ïŒ
- ãŠãŒã¶ãŒå
- ãŠãŒã¶ãŒãã¹ã¯ãŒã
ãŠãŒã¶ãŒå
ã«ãã£ãŠãJenkins Hash颿°ãã³ã³ãã€ã«ãããŸãïŒ
颿°ãœãŒã¹ã³ãŒã procedure mix(var a, b, c: uint32); inline; begin dec(a, b); dec(a, c); a:=a xor (c shr 13); dec(b, c); dec(b, a); b:=b xor (a shl 8); dec(c, a); dec(c, b); c:=c xor (b shr 13); dec(a, b); dec(a, c); a:=a xor (c shr 12); dec(b, c); dec(b, a); b:=b xor (a shl 16); dec(c, a); dec(c, b); c:=c xor (b shr 5); dec(a, b); dec(a, c); a:=a xor (c shr 3); dec(b, c); dec(b, a); b:=b xor (a shl 10); dec(c, a); dec(c, b); c:=c xor (b shr 15); end; function jenkinsLookupHash2(Data: pByte; Length: integer; InitVal: uint32): uint32; var a, b, c, len: uint32; begin len:=Length; a:=$9e3779b9; b:=a; c:=InitVal; while (len>=12) do begin inc(a, Data[0] + (Data[1] shl 8) + (Data[2] shl 16) + (Data[3] shl 24)); inc(b, Data[4] + (Data[5] shl 8) + (Data[6] shl 16) + (Data[7] shl 24)); inc(c, Data[8] + (Data[9] shl 8) + (Data[10] shl 16) + (Data[11] shl 24)); mix(a, b, c); Data:=pByte(@Data[12]); dec(len, 12); end; inc(c, length); if len>=11 then inc(c, Data[10] shl 24); if len>=10 then inc(c, Data[9] shl 16); if len>=9 then inc(c, Data[8] shl 8); if len>=8 then inc(b, Data[7] shl 24); if len>=7 then inc(b, Data[6] shl 16); if len>=6 then inc(b, Data[5] shl 8); if len>=5 then inc(b, Data[4]); if len>=4 then inc(a, Data[3] shl 24); if len>=3 then inc(a, Data[2] shl 16); if len>=2 then inc(a, Data[1] shl 8); if len>=1 then inc(a, Data[0]); mix(a, b, c); result:=c; end;
äžè¬çãªãµãŒããŒçžäºäœçšã¢ã«ãŽãªãºã ïŒ
- èªèšŒãªã¯ãšã¹ããéä¿¡ããŸã-5ãã€ã\ x00 \ x00 \ x00 \ x00 \ x04;
- ããŒã«ã«IPã¢ãã¬ã¹ãéä¿¡ããŸãã
- ãŠãŒã¶ãŒåã®ããã·ã¥ãéä¿¡ããŸãã
- æ¥ç¶ç¢ºèªãã©ã°ãåãå
¥ããŸãã ãã®ãããªååã®ããã·ã¥ãæã€ãŠãŒã¶ãŒããµãŒããŒããŒã¿ããŒã¹ã«ååšããªãå Žåã¯falseã§ãã
- ã¯ã©ã€ã¢ã³ãã®å€éšIPã¢ãã¬ã¹ãåãå
¥ããŸãã
- ãŠãŒã¶ãŒåãå«ãããã±ãŒãžãéä¿¡ããŸãïŒæ§æã«ã€ããŠã¯åŸã§èª¬æããŸãïŒã
- æå·åã«ã¯ãå¡©ãã䜿çšã§ããŸãïŒ8ãã€ãïŒã
- èªèšŒããã±ãŒãžãäœæããŸãïŒããã«æ€èšããŸãïŒã
- èªèšŒç¢ºèªãã€ããåãå
¥ããŸãã
- 8ãã€ãã®ãµãŒããŒæéãåãå
¥ããŸãïŒPXã§ã¯ããç§ãå¿ããªãã§ãã ããïŒïŒã
- 8ãã€ãã®ãã±ããæå¹æéãåãå
¥ããŸãã
èªèšŒç¢ºèªãã€ãã¯ã次ã®ç¶æ
ãåãããšãã§ããŸãã
0x00-ãã°ã€ã³ã¯æ£åžžã«å®äºããŸããã
0x01-ã¢ã«ãŠã³ãã¯ååšããŸããã
0x02-ã¢ã«ãŠã³ããååšããªããããã¹ã¯ãŒããæ£ãããããŸããã
0x03-ã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®æéå·®ã倧ããããã
0x04-ã¢ã«ãŠã³ãã¯ãããã¯ãããŠããŸãã
ãã°ã€ã³ãè¡ãããå ŽåããŠãŒã¶ãŒããŒã¿ãå«ããã±ããããµãŒããŒããåä¿¡ãããŸãïŒããã«æ€èšããŸãïŒã ãŠãŒã¶ãŒåãæã€ããã±ãŒãžã¯ã次ã®ãã£ãŒã«ãã§æ§æãããŸãã
- ãã±ãããµã€ãºïŒ4ãã€ãïŒ;
- 1ãã€ã0x02;
- ååã®é·ãïŒ2ãã€ãïŒ;
- ãŠãŒã¶ãŒå
- ååã®é·ãïŒ2ãã€ãïŒ;
- ãŠãŒã¶ãŒå
èªèšŒããã±ãŒãžã®ããŒã¿ã®æºåïŒ
- ãsaltãã®æåã®4ãã€ãããŠãŒã¶ãŒã®ãã¹ã¯ãŒããããã³ãsaltãã®æåŸã®4ãã€ãã§è¡šãããããŒã¿ãããã¯ã®ããã·ã¥ãèšç®ããŸãã
- ã¯ã©ã€ã¢ã³ãã®å€éšããã³ããŒã«ã«IPã¢ãã¬ã¹ããããŒã¿ãããã¯ã®ããã·ã¥ãèšç®ããŸãã
- çŸåšã®æéïŒPXã§ns !!!ïŒãããŒã«ã«IPã¢ãã¬ã¹ãããã³4ãã€ãã®ããŒã¿ãããã¯\ x04 \ x04 \ x04 \ x04ã圢æããŸãã
- é
ç®3 xorãŸãã¯é
ç®2ã®ããŒã¿ãå«ããã±ããã®æåã®8ãã€ãã
- ããŒïŒè«æ±é
1ã®ããŒã¿ïŒãšåæåãã¯ãã«ïŒä»»æã®ããŒã¿ïŒã䜿çšããAES-CBCã¢ã«ãŽãªãºã ã䜿çšããŠãè«æ±é
4ã®ããŒã¿ãããã¯ãæå·åããŸãã
èªèšŒããã±ãŒãžã®æ§æïŒ
- ããã±ãŒãžãµã€ãº-宿°ã0x00000036;
- åæåãã¯ãã«ïŒããŒã¿çæäžïŒ;
- 4ãã€ãã®å®æ°-\ x00 \ x0C \ x00 \ x10ã å€ãã倿ãããšããããã¯16ãããã®ããŒã¿ãµã€ãºïŒIVããã³æå·åãããéšåïŒã§ãã
- æå·åãããããŒã¿ã
ãããã®ãŠãŒã¶ãŒã䜿çšãããµãŒããŒã®å¿çã®åœ¢åŒã¯æ¬¡ã®ãšããã§ãã
- ã¿ã€ãã«TTicket_SubHeader;
- ã¿ã€ãã«TTicketHeader;
- åæåãã¯ãã«firstIV ;
- ãµã€ãºTTicketHeader.SZ2ã®ããŒã¿ãããã¯ã
- 2çªç®ã®ããããŒTTicketHeaderïŒ2ïŒ;
- ãµã€ãºTTicketHeaderïŒ2ïŒ.SZ2ã®2çªç®ã®ããŒã¿ãããã¯ã
- ã¿ã€ãã«TTicket_TestData;
- TicketSignããŒã¿ã
- ã¿ã€ãã«TTicket_BLOBHeader;
- blobèªäœã¯TTicket_BLOBHeader.Len2-20-sizeofïŒTTicket_BLOBHeaderïŒã§ãã
- ããã±ãŒãžã®çœ²åã
䜿çšãããæ§é ãšãã®ãã£ãŒã«ããèæ
®ããŠãã ããã
TTicket_SubHeader = packed record nullData1: uint16; outerIV: array[0..15] of byte; nullData2: uint16; nullData3: uint16; EncrData: array[0..63] of byte; TicketLen: uint16; end;
EncrDataãã£ãŒã«ãã«ã¯ãããŒïŒèªèšŒããŒã¿ã®æºåããã®é
ç®1ïŒãšåæåãã¯ãã«TTicket_SubHeader.outerIVã䜿çšããŠãAES-CBCã¢ã«ãŽãªãºã ã«ãã£ãŠåŸ©å·åããå¿
èŠãããããŒã¿ãå«ãŸããŠããŸãã åºåã¯ã
TTicket_UserHeaderåã®UserHeaderããããŒã«ãªããŸãã
TTicket_UserHeader = packed record InnerKey: array[0..15] of byte; Dummy1: uint16; SteamID: uint64; Servers: packed record IP1: uint32; Port1: uint16; IP2: uint32; Port2: uint16; end; CurrentTime: uint64; ExpiredTime: uint64; Dummy2: array[0..9] of byte; end;
ãã¹ãŠã®åéã®ç®çã¯ååããæããã§ãããç§ãšç§ã«ã¯çè§£äžå¯èœã§ãã æçµçã«ããããã®ããŒã¿ã®ã»ãšãã©ã¯ããããã®ãããªãçšéã«åºã¥ããŠãçŽç²ã«çŽæçã«åœåãããŸãã
InnerKeyãã£ãŒã«ãã¯åŸã§äœ¿çšãããŸãã
TTicketHeader = record SZ1, SZ2: uint16; end;
TTicket_TestData = packed record len: uint16;
TTicket_BLOBHeader = packed record NodeHeader: uint16; Len2: uint32; ZerosSize: uint32; BLOBLen: uint32; InnerIV: array[0..15] of byte; end;
åè¿°ã®ããã«ããã®ããããŒã®åŸã«ã¯ãæå·åãããBLOBãã¡ã€ã«ãæã€ããŒã¿ãããã¯ããããŸãã
UserHeader.InnerKeyããŒãš
TTicket_BLOBHeader.InnerIVåæå
ãã¯ãã«ã䜿çšããŠãAES-CBCã¢ã«ãŽãªãºã ã§æå·åãããŸãã
ã³ã³ãã³ããªã¹ããµãŒããŒ
ããŸããŸãªãã¡ã€ã«ã®ã³ã³ãã³ããµãŒããŒãªã¹ããæ ŒçŽããŸãã èŠæ±ã¿ã€ãã¯0x0200000000ã§ãã 2ã€ã®ãªã¯ãšã¹ãããããŸãã ã³ãã³ãã®2çªç®ãš3çªç®ã®ãã€ãã®ã¿ãç°ãªãïŒ
- ã¢ãŒã«ã€ãã®ãµãŒããŒã®ãªã¹ã-0x0000;
- ãµãŒãã¹ã¢ãŒã«ã€ãã®ãµãŒããŒã®ãªã¹ãã¯0x0100ã§ãã
ãã®ãµãŒããŒã®äžè¬çãªã³ãã³ã圢åŒã¯æ¬¡ã®ãšããã§ãã
- 1ãã€ã-0x00;
- 2ãã€ãã®ã³ãã³ãã®æ¹è¯ïŒ\ x00 \ x00ãŸãã¯\ x0100ïŒ;
- 4ãã€ã-èŠæ±ãããã¢ãŒã«ã€ãã®IDã
- 4ãã€ã-èŠæ±ãããã¢ãŒã«ã€ãã®ããŒãžã§ã³ã
- 2ãã€ã-å¿çå
ã®ãµãŒããŒã®æå€§æ°ã
- 4ãã€ã-ãªãŒãžã§ã³ã
- 4ãã€ã-0xFFã
ãµãŒããŒå¿çã«ã¯ã次ã®èŠçŽ ã®ãªã¹ããå«ãŸããŸãã
TContentListEntry = packed record ID: uint32;
åããµãŒããŒã®
IDãã£ãŒã«ãã倿Žããããããããããã®ãµãŒããŒã®è² è·ã§ãããšçµè«ä»ããŸããã æ¬¡ã«ã2çµã®IPïŒããŒãããããŸãããããã¯ã»ãšãã©åžžã«äžèŽããŠããŸãã ãªã2ãã¢-ããããªãã
ã³ã³ãã³ããµãŒããŒ
ã²ãŒã ã®ã³ã³ãã³ããšSteamèªäœã®ãã¡ã€ã«ãçŽæ¥ä¿åããçžäºäœçšãæãé£ãããµãŒããŒã ç¬èªã®ãããã³ã«ãæã¡ã2ã€ã®èŠæ±ãåŠçããŸãã
- ãµãŒãã¹ã¢ãŒã«ã€ãïŒã¯ã©ã€ã¢ã³ããã¡ã€ã«ïŒãããŠã³ããŒãããŸãã
- ã²ãŒã ã¢ãŒã«ã€ããããŠã³ããŒãããŸãã
ãµãŒãã¹ã¢ãŒã«ã€ãã®èªã¿èŸŒã¿ãæ€èšããŠãã ããã
- ã³ãã³ããéä¿¡ããŸã-\ x03 \ x00 \ x00 \ x00;
- æ¥ç¶ãã©ã°ãåãå
¥ããŸãã
- èŠæ±ããããã¡ã€ã«ãåãå
¥ããŸãã
- ãã¡ã€ã«ã®RSA眲åãåãå
¥ããŸãã
ãã¡ã€ã«ãšçœ²åã®èŠæ±ã¯ããã¡ã€ã«ã®ååã«ãã£ãŠè¡ãããŸãïŒçœ²åã®å Žåã¯ã<ãã¡ã€ã«å> _rsa_signatureããååŸãããŸãïŒã
- 4ãã€ã-ãã±ãããµã€ãºïŒãã¡ã€ã«åã®é·ã+ 16ïŒ;
- 4ãã€ã-ã³ãã³ã\ x00 \ x00 \ x00 \ x00;
- 4ãã€ã-\ x00 \ x00 \ x00 \ x00;
- 4ãã€ã-ãã¡ã€ã«åã®é·ãã
- ãã¡ã€ã«åèªäœã
ãã®ãããªåèŠæ±ã«å¯Ÿããçãã¯ãèŠæ±ããããã¡ã€ã«ã§ãã
説æãããŠããã¢ã«ãŽãªãºã ã®ãœãŒã¹ã³ãŒã function TSteamNetwork.Content_DownloadPackage(Name: AnsiString; FileName: string): ENetWorkResult; var Accepted: boolean; Sock: CSocket; PacketSize, Request, MessSize: uint32; Data, Mess: pByte; str: TStream; Addr: TSockAddr; procedure ProcPackage(N, FN: AnsiString); begin PacketSize:=htonl(4+8+Length(N)+4); if not Sock.Send(PacketSize, 4) then Exit; if not Sock.Send(CS_PACKAGE_GET_FILE, 4) then Exit; Request:=0; if not Sock.Send(Request, 4) then Exit; Request:=htonl(Length(N)); if not Sock.Send(Request, 4) then Exit; if not Sock.Send(N[1], Length(N)) then Exit; Request:=0; if not Sock.Send(Request, 4) then Exit; if not Sock.Recv(PacketSize, 4) then Exit; Data:=Sock.RecvFromLen(PacketSize); end; begin result:=eConnectionError; Addr:=ContentList_GetContentServer(); if Addr.sin_addr.S_addr=0 then Exit; Sock:=CSocket.Create(SOCKET_IP); Sock.SetTimeOut(3000); if (Sock=nil) or (not Sock.Connect(Addr)) then Exit; if not Sock.Send(CS_PACKAGE_QUERY, 4) then Exit; if not Sock.Recv(Accepted, 1) then Exit; if not Accepted then begin result:=eServerReset; Exit; end; ProcPackage(Name, Wide2Ansi(FileName)); MessSize:=PacketSize; Mess:=Data; ProcPackage(Name+'_rsa_signature', ''); Sock.Free; if RSACheckSign(NetWorkKeySign, Data, Mess, MessSize, 128) then begin str:=TStream.CreateWriteFileStream(FileName); str.Write(Mess^, MessSize); str.Free; result:=eOK; end else result:=eSignError; FreeMem(Mess, MessSize); FreeMem(Data, 128); end;
ã²ãŒã ã¢ãŒã«ã€ãã®ããŠã³ããŒãã¯ã¯ããã«è€éã§ãå€ãã®æ®µéãçµãŸãã
- ã³ãã³ã\ x07 \ x00 \ x00 \ x00ãéä¿¡ããŸãã
- æ¥ç¶ãã©ã°ãåãå
¥ããŸãã
- ãããŒãåä¿¡ããããã«ã³ãã³ãã®5ãã€ããéä¿¡ããŸã-\ x00 \ x00 \ x00 \ x00 \ x00;
- 確èªãã©ã°ãååŸããŸãã
- æååã®é·ããåãå
¥ããŸãã
- ãªã³ã¯ã®ããè¡ãåãå
¥ããŸãã
- ã¢ãŒã«ã€ããéãã³ãã³ããéä¿¡ããŸã-\ x09;
- 8ãã€ã\ x00ãéä¿¡ããŸãã
- èŠæ±ãããã¢ãŒã«ã€ãã®4ãã€ãã®IDãéä¿¡ããŸãã
- èŠæ±ãããã¢ãŒã«ã€ãã®ããŒãžã§ã³ã®4ãã€ããéä¿¡ããŸãã
- 4ãã€ãã®æ¥ç¶IDãåãå
¥ããŸã ã
- 4ãã€ãã®MessageIDãåãå
¥ããŸã ã
- 確èªãã©ã°ãåãå
¥ããŸãã
- 4ãã€ãã®CacheIDãåãå
¥ããŸãã
- 4ãã€ãã®ManifestCheckãåãå
¥ããŸãã
- ãããã§ã¹ããåä¿¡ããã³ãã³ããéä¿¡ããŸã-\ x04;
- 4ãã€ãã®CacheIDãéä¿¡ããŸãã
- 4ãã€ãã®MessageIDãéä¿¡ããŸã ã
- ãããã§ã¹ãïŒ GCF / NCFã¢ãŒã«ã€ãã®ããããŒã®äžéšïŒãæã€ããŒã¿ãããã¯ãåãå
¥ããŸãã
- ãã§ãã¯ãµã ãåãåãã³ãã³ããéä¿¡ããŸã-\ x06;
- 4ãã€ãã®CacheIDãéä¿¡ããŸãã
- 4ãã€ãã®MessageIDãéä¿¡ããŸã ã
- ãã§ãã¯ãµã ïŒ GCF / NCFã¢ãŒã«ã€ãã®ããããŒã®äžéšïŒãå«ãããŒã¿ãããã¯ãåãå
¥ããŸãã
- ãã¡ã€ã«ãåä¿¡ããã³ãã³ããéä¿¡ããŸã-\ x07;
- 4ãã€ãã®CacheIDãéä¿¡ããŸãã
- 4ãã€ãã®MessageIDãéä¿¡ããŸã ã
- 4ãã€ããéä¿¡ããŸã-ã¢ãŒã«ã€ãå
ã®ãã¡ã€ã«ã®ã€ã³ããã¯ã¹ïŒ0ããå§ãŸããŸãïŒ;
- 4ãã€ããéä¿¡ããŸã-æåã«å¿
èŠãªéšåã®æ°ïŒ1ã€ã®éšåã®ãµã€ãºã¯0x00002000ã§ã- åè¿°ã®ã»ã¯ã¿ãŒãµã€ãºã«åŸã£ãŠïŒ;
- 4ãã€ã-èŠæ±ãããããŒãã®æ°ãéä¿¡ããŸãã
- 4ãã€ãã®CacheIDãåãå
¥ããŸãã
- 4ãã€ãã®MessageIDãåãå
¥ããŸã ã
- 確èªãã©ã°ãåãå
¥ããŸãã
- ãŠãŒã¶ãŒã«éãããéšåã®æ°ãåãå
¥ããŸãã
- æå®ãããæ°ã®éšåãåãå
¥ããŸãïŒããã«æ€èšããŸãïŒã
- ãã¡ã€ã«ãéããã³ãã³ããéä¿¡ããŸã-\ x03;
- 4ãã€ãã®CacheIDãåãå
¥ããŸãã
- 4ãã€ãã®MessageIDãåãå
¥ããŸã ã
- 確èªãã©ã°ãåãå
¥ããŸãã
- æ¥ç¶ãéããŸãã
ãã¡ã€ã«ã®äžéšã®åä¿¡ïŒ
- 4ãã€ãã®CacheIDãåãå
¥ããŸãã
- 4ãã€ãã®MessageIDãåãå
¥ããŸã ã
- 4ãã€ãã®ããŒããµã€ãºãåãå
¥ããŸãã
- 4ãã€ãã®CacheIDãåãå
¥ããŸãã
- 4ãã€ãã®MessageIDãåãå
¥ããŸã ã
- 4ãã€ãã®ãããã¯ãµã€ãºãåãå
¥ããŸãã
- æå®ããããµã€ãºã®ãããã¯ãåãå
¥ããŸãã
- ã¹ããã4ã«é²ã¿ãåä¿¡ãããããã¯ã®ãµã€ãºãããŒãã®ãµã€ãºããå°ãããªã£ãŠããŸãã
説æãããŠããã¢ã«ãŽãªãºã ã®ãœãŒã¹ã³ãŒã function TSteamNetwork.Content_DownloadGCF(AppID, Version: uint32): ENetWorkResult; var Accepted: boolean; Sock: CSocket; i: integer; ConnID, MessageID, MsgID, BlockSize, CacheID, ManifestCheck: uint32; ManifestSize, ChecksumSize, PS: uint32; Manifest, Checksum: pByte; UpdateList: puint32; str: TStream; GCF: TGCFFile; q: array[0..HL_GCF_CHECKSUM_LENGTH*2] of byte; Addr: TSockAddr; function RecvPacket(var Size: uint32): pByte; var Pos, recived: uint32; begin result:=nil; if not Sock.Recv(CacheID, 4) then Exit; if not Sock.Recv(MsgID, 4) then Exit; if not Sock.Recv(Accepted, 1) then Exit; if Accepted then Exit; if not Sock.Recv(Size, 4) then Exit; if not Sock.Recv(CacheID, 4) then Exit; if not Sock.Recv( MsgID, 4) then Exit; if not Sock.Recv(BlockSize, 4) then Exit; Pos:=0; Size:=htonl(Size); BlockSize:=htonl(BlockSize); GetMem(result, Size); repeat recived:=Sock.Recvi(pByte(result+Pos)^, BlockSize); inc(Pos, recived); until (Pos>=Size) or (recived=0); end; function GetBannerURL(): boolean; var URL: pAnsiChar; Len: uint16; begin result:=false; FillChar(Q[0], 9, 0); Q[0]:=CS_STORAGE_BANNER_URL; Sock.SendFromLen(5, @Q[0]); if not Sock.Recv(Accepted, 1) then Exit; URL:=pAnsiChar(Sock.RecvFromLenShort(Len));
ãããã«
ãã®ãããSteamã®æä»£é
ãã®éšåã«é¢ããèšäºã®ãµã€ã¯ã«ã¯çµãããŸããã ãŸã ç©æ¥µçã«äœ¿çšãããŠããå¯äžã®ãã®ã¯VDFã¢ãŒã«ã€ãã§ãã
次ã®èšäºã§ã¯ãããé¢é£æ§ã®é«ãæ
å ±-SteamAPIïŒsteam.dllïŒããã³SteamClienAPIïŒsteamclient.dllïŒã«è§ŠããŸãããããŠã2çªç®ãèš±å¯ãããç¯å²å
ã§ãŠãŒã¶ãŒã«é¢ããæ
å ±ãååŸããåŽããèæ
®ãããå Žåã1çªç®ã¯ãã®APIã®æãåçŽãªãšãã¥ã¬ãŒã¿ãŒåŽããèæ
®ãããŸããããã«ã€ããŠæžããã©ããã®æ±ºå®ã¯ã³ãã¥ããã£æ¬¡ç¬¬ã§ãã