maxism 发表于 2021-1-5 11:23:17

dota2 局域网联机软件开发过程中遇到了 一个逆向难题 请求帮助

本帖最后由 maxism 于 2021-2-16 20:39 编辑

大家好,最近几个朋友在开发dota2局域网联机的软件,但是遇到了一个难题,特向大佬们请教。
dota2中,当一个用户建立房间,另一个用户进行连接的时候,dota会请求一个“证书”,验证通过后,两台电脑才能开始联机,使用软件进行转储后得到的信息如下:
cert = 080112202B39DF35AAB3E009269D5FBF57A0AC8D8059BAFA7C4E1001EE8D54062DAAEAEF2108E41494763F4001453518F75F4D35BBF95F50BA045A0A810108E41494763F40016219737465616D69643A3930313431373731303730343937383030
ca_key_id = 18220590129359924542
ca_signature = E1FA9B6E43521BDA3DA6F5C579AB10A31913AA538D6FAFE4C813CF6321E43F66D2C3D913C96A86423DC8A2A24B73F237D4E30A5BE6A85536B1E042938B1A450B


目前想到的办法是对steamnetworkingsockets.dll进行逆向,动态调试,将证书验证的函数修改了,或者是发送一个自签名的证书,但是这些我们都不会,希望各位大佬不吝指教,万分感谢。下面是搜到的一个相关的帖子,希望有用。

dll文件地址

https://wwa.lanzous.com/i7Z7Tlq6zdg



V社source游戏现在似乎使用steamnetworkingsockets.dll进行客户端/服务器通信。它需要一个“证书”,该“证书”实际上是一个已签名的协议,
由应用程序通过使用EMsgClientNetworkingCertRequest通过蒸汽向cmserver请求,并响应EMsgClientNetworkingCertRequestResponse
,游戏会发送一个appid和一个“密钥”,服务器返回一个“证书” “,由CA签名(由ID标识)


      response->body_cert.set_key_type(CMsgSteamDatagramCertificate_EKeyType_ED25519);
      response->body_cert.set_key_data(msg->body.key_data());
      response->body_cert.set_steam_id(connection->getSteamGlobalId());
      response->body_cert.set_time_created(now);
      response->body_cert.set_time_expiry(now+2*24*60*60); // 2 days
      response->body_cert.set_app_id(msg->body.app_id());

      response->body.set_ca_key_id(1234);
      response->body.set_ca_signature(64 bytes signature);




证书似乎存储在userdata / steamid / config / localconfig.vdf中,在“ nettickets”部分中,服务器似乎可以发送任何东西,它将被缓存,无论如何,当证书/ ca /​​签名被验证时,游戏服务器/客户端在steamnetworkingsockets.dll中进行连接:


char __thiscall sub_10088EF0(int this, struct_a2 *a2, struct_a3 *a3, void *a4)
{
struct_v4 *v4; // edi@1
bool v6; // zf@7
int v7; // eax@9
size_t v8; // ecx@9
int v9; // ecx@25
int v10; // eax@31
int v11; // eax@38
int v12; // ST28_4@39
int v13; // eax@39
HANDLE *v14; // esi@43
int v15; // eax@46
int v16; // ecx@49
int v17; // edx@49
int v18; // ecx@57
int v19; // eax@58
int v20; // esi@59
int v21; // eax@59
int v22; // eax@71
size_t v23; // ecx@71
char v24; // cl@75
int v25; // edx@80
int v26; // esi@80
int v27; // eax@80
int v28; // ecx@80
char *v29; // eax@82
signed int v30; // ecx@82
int v31; // edx@84
int v32; // esi@84
int v33; // ebx@84
int v34; // ecx@84
int v35; // eax@85
int v36; // eax@85
int v37; // eax@85
int *v38; // esi@89
signed int v39; // ebx@89
void *v40; // eax@90
char *v41; // edi@93
void *v42; // esi@93
int v43; // eax@95
_BYTE *v44; // ecx@95
int i; // edi@95
signed int v46; // ecx@97
char *v47; // eax@97
signed int v48; // ecx@99
char *v49; // eax@99
signed int v50; // ecx@101
char *v51; // eax@101
char v52; // @58
char v53; // @26
char v54; // @82
char v55; // @80
char v56; // @94
char v57; // @95
void *v58; // @86
int v59; // @86
int v60; // @39
int v61; // @39
int v62; // @38
int v63; // @38
int v64; // @7
int v65; // @7
int v66; // @7
char v67; // @7
int v68; // @1
int v69; // @69
int v70; // @69
int v71; // @69
char v72; // @69
int v73; // @84
int v74; // @84
int v75; // @84
int v76; // @84
size_t v77; // @84
int v78; // @84
int v79; // @84
int v80; // @84
int v81; // @80
int v82; // @80
int v83; // @80
int v84; // @80
void *v85; // @84
char *v86; // @84
_BYTE *v87; // @84
_BYTE *v88; // @84
int v89; // @84
int v90; // @84
int v91; // @7
char *v92; // @86

v4 = (struct_v4 *)this;
v68 = this;
if ( *(_BYTE *)(this + 13032) )
    return 1;
if ( !(a2->byte8 & 1) || !(a3->byte8 & 1) )
{
    sub_1008A650(4002, "Crypto handshake missing cert or session data");
    return 0;
}
if ( !(unsigned __int8)sub_100C3130(a2->dword10) )
{
    sub_1008A650(4002, "Cert failed protobuf decode");
    return 0;
}
v64 = 3;
v66 = 0;
v65 = 0;
v67 = 0;
v6 = v4->key_type == 1;
v91 = 0;
if ( !v6 )
{
    sub_1008A650(4002, "Unsupported identity key type");
LABEL_107:
    sub_10022270(&v64);
    return 0;
}
v7 = v4->dword3218;
v8 = *(_DWORD *)(v7 + 16);
if ( *(_DWORD *)(v7 + 20) >= 0x10u )
    v7 = *(_DWORD *)v7;
if ( !(unsigned __int8)sub_10021860((void *)v7, v8) || !(unsigned __int8)sub_10021170(&v64) )
{
    sub_1008A650(4002, "Cert has invalid identity key");
    goto LABEL_107;
}
if ( v4->byte32C8 & 1 )
{
    if ( !((v4->fields_maps >> 2) & 1) )
      sub_1001CDE0(
      (int)"Assertion Failed: m_msgCryptLocal.has_nonce()",
      0,
      "steamnetworkingsockets_connections.cpp",
      802);
    if ( !((v4->fields_maps >> 1) & 1) )
      sub_1001CDE0(
      (int)"Assertion Failed: m_msgCryptLocal.has_key_data()",
      0,
      "steamnetworkingsockets_connections.cpp",
      803);
    if ( !(v4->fields_maps & 1) )
      sub_1001CDE0(
      (int)"Assertion Failed: m_msgCryptLocal.has_key_type()",
      0,
      "steamnetworkingsockets_connections.cpp",
      804);
}
else
{
    if ( !(unsigned __int8)(*(int (__thiscall **)(struct_v4 *))(v4->dword0 + 56))(v4) && dword_10271D84 >= 4 )
      sprintf(
      (char *)4,
      "We don't have cert, and unsigned certs are not supposed to be allowed here.Continuing anyway temporarily.");
    sub_1008B330(v4);
}
if ( (v4->dword3210 >> 6) & 1 )
{
    v9 = v4->app_id;
    if ( v9 != v4->dword28->dword78 )
    {
      sub_10077AE0((int)&v53, "Cert is for AppID %u instead of %u", v9, v4->dword28->dword78);
      if ( dword_10271D84 >= 4 )
      sprintf((char *)4, "Cert failure: %s\n", &v53);
    }
}
if ( v4->steam_id <= 0 || !((*(_DWORD *)&a2->byte8 >> 2) & 1) )
{
    if ( !((v4->dword3210 >> 2) & 1) && dword_10271D84 >= 4 )
      sprintf((char *)4, "Cert failure: %s\n", "Cert must be bound to a SteamID.");
    if ( !((v4->dword3210 >> 6) & 1) && dword_10271D84 >= 4 )
      sprintf((char *)4, "Cert failure: %s\n", "Cert must be bound to an AppID.");
    v11 = v4->dword3220;
    v63 = v4->dword3224;
    v62 = v11;
    if ( !(unsigned __int8)sub_10087AA0(&v4->gap2C) )
      goto LABEL_42;
    v60 = v4->dword3220;
    v61 = v4->dword3224;
    v12 = sub_10086E60(&v4->gap2C);
    v13 = sub_10086E60(&v60);
    sub_10077AE0((int)&v53, "Cert was issued to %s, not %s", v13, v12);
    goto LABEL_40;
}
if ( (v4->dword34 & 0xF00000) != 0x400000 )
{
    v10 = sub_10086E60(&v4->gap2C);
    sub_10077AE0((int)&v53, "Certs restricted data center are for anon GS only.Not %s", v10);
LABEL_40:
    if ( dword_10271D84 >= 4 )
      sprintf((char *)4, "Cert failure: %s\n", &v53);
}
LABEL_42:
if ( (*(_DWORD *)&a2->byte8 >> 2) & 1 )
{
    v14 = (HANDLE *)&unk_102562E0;
    do
    {
      if ( a2->ca_key_1 == *v14 && a2->ca_key_2 == v14 )
      {
      v15 = a2->dword20;
      if ( *(_DWORD *)(v15 + 16) == 64 )
      {
          if ( *(_DWORD *)(v15 + 20) >= 0x10u )
            v15 = *(_DWORD *)v15;
          v16 = a2->dword10;
          v17 = *(_DWORD *)(v16 + 16);
          if ( *(_DWORD *)(v16 + 20) >= 0x10u )
            v16 = *(_DWORD *)v16;
          if ( sub_100221F0(v16, v17, (int)(v14 + 2), v15) )
            goto LABEL_57;
      }
      if ( dword_10271D84 >= 4 )
          sprintf((char *)4, "Cert failure: %s\n", "Invalid cert signature");
      }
      v14 += 6;
    }
    while ( v14 != &hEvent );
    sub_10077AE0((int)&v53, "Cert signed with key %llu; not in trusted list", a2->ca_key_1, a2->ca_key_2);
    if ( dword_10271D84 >= 4 )
      sprintf((char *)4, "Cert failure: %s\n", &v53);
LABEL_57:
    v18 = v4->dword28->dword6C;
    if ( v18 )
    {
      v20 = v4->dword323C;
      v21 = (*(int (**)(void))(*(_DWORD *)v18 + 12))();
      if ( v21 > v20 )
      {
      sub_10077AE0((int)&v53, "Cert expired %ld secs ago at %ld", v21 - v20, v20);
      if ( dword_10271D84 >= 4 )
          sprintf((char *)4, "Cert failure: %s\n", &v53);
      }
    }
    else
    {
      v19 = sub_1001D440(&v52, "Assertion Failed: %s", "No ISteamUtils?Cannot check if cert expired!");
      sub_1001CDE0(v19, 0, "steamnetworkingsockets_connections.cpp", 899);
    }
    if ( !(unsigned __int8)(*(int (__thiscall **)(struct_v4 *))(v4->dword0 + 60))(v4) )
    {
      if ( v4->dword334C != 5 )
      {
      sub_1001CDE0(
          (int)"Assertion Failed: GetState() == k_ESteamNetworkingConnectionState_ProblemDetectedLocally",
          0,
          "steamnetworkingsockets_connections.cpp",
          920);
      sub_10022270(&v64);
      return 0;
      }
      goto LABEL_107;
    }
}
else if ( dword_10271D84 >= 5 )
{
    sprintf((char *)5, "Remote host is using an unsigned cert.Allowing connection, but it's not secure!\n");
}
if ( !(unsigned __int8)sub_100C3130(a3->dword10) )
{
    sub_1008A650(4002, "Crypt info failed protobuf decode");
    goto LABEL_107;
}
v69 = 5;
v71 = 0;
v70 = 0;
v72 = 0;
v6 = v4->dword325C == 1;
LOBYTE(v91) = 1;
if ( !v6 )
{
    sub_1008A650(4002, "Unsupported DH key type");
LABEL_105:
    sub_10022270(&v69);
    sub_10022270(&v64);
    return 0;
}
v22 = v4->dword3258;
v23 = *(_DWORD *)(v22 + 16);
if ( *(_DWORD *)(v22 + 20) >= 0x10u )
    v22 = *(_DWORD *)v22;
if ( !(unsigned __int8)sub_10021860((void *)v22, v23) || !(unsigned __int8)sub_10021130(&v69) )
{
    sub_1008A650(4002, "Invalid DH key");
    goto LABEL_105;
}
v24 = v4->byte3260;
if ( !v24 )
    goto LABEL_112;
if ( !dword_10264930 )
{
LABEL_79:
    sub_1008A650(4002, "Incompatible protocol format (SNP)");
    goto LABEL_105;
}
if ( !v24 )
{
LABEL_112:
    if ( dword_10264930 )
      goto LABEL_79;
}
LOBYTE(v91) = 2;
sub_10021640(v4->gap3270, &v69, &v55);
sub_10022270(v4->gap3270);
v25 = v4->dword3268;
v26 = v4->dword326C;
v27 = v4->dword32A0;
v28 = v4->dword32A4;
v81 = v4->dword3268;
v82 = v26;
v83 = v27;
v84 = v28;
if ( (_BYTE)a4 )
{
    v81 = v27;
    v82 = v28;
    v83 = v25;
    v84 = v26;
}
LOBYTE(v91) = 3;
sub_10020940(&v81, 0x10u, &v55, 0x20u, &v54);
v29 = &v55;
v30 = 32;
do
{
    *v29++ = 0;
    --v30;
}
while ( v30 );
v31 = a2->dword10;
v32 = v4->dword32D0;
v33 = v4->dword32B8;
v85 = &v4->char32E9;
v86 = &v4->char3309;
v87 = &v4->gap330A;
v88 = &v4->gap330A;
v77 = 32;
v78 = 32;
v34 = a3->dword10;
v89 = v4->dword50;
v90 = v4->dword54;
v79 = 16;
v80 = 16;
v73 = v31;
v74 = v32;
v75 = v34;
v76 = v33;
if ( (_BYTE)a4 )
{
    v85 = &v4->char3309;
    v86 = &v4->char32E9;
    v87 = &v4->gap330A;
    v88 = &v4->gap330A;
    v35 = v31;
    v31 = v32;
    v77 = 32;
    v32 = v35;
    v78 = 32;
    v36 = v34;
    v79 = 16;
    v34 = v33;
    v80 = 16;
    v33 = v36;
    v73 = v31;
    v89 = v4->dword54;
    v37 = v4->dword50;
    v74 = v32;
    v75 = v34;
    v76 = v33;
    v90 = v37;
}
sub_1001E020(
    0,
    *(_DWORD *)(v31 + 16) + *(_DWORD *)(v32 + 16) + *(_DWORD *)(v34 + 16) + 104 + *(_DWORD *)(v33 + 16),
    0);
LOBYTE(v91) = 4;
sub_1001EFD0(0, 32);
v92 = (char *)v58 + v59;
if ( v4->dword60 < 3u )
    sub_1001EAE0(&v89, 4u);
else
    sub_1001EAE0(&v89, 8u);
sub_1001EAE0("Steam datagram", 0xEu);
v38 = &v73;
v39 = 4;
do
{
    v40 = (void *)*v38;
    if ( *(_DWORD *)(*v38 + 20) >= 0x10u )
      v40 = *(void **)v40;
    sub_1001EAE0(v40, *(_DWORD *)(*v38 + 16));
    ++v38;
    --v39;
}
while ( v39 );
v41 = (char *)v58 + v59;
v42 = v92;
do
{
    *v41 = v39 + 1;
    sub_10020940(v42, v41 - (_BYTE *)v42 + 1, &v54, 0x20u, &v56);
    memmove_0(*(&v85 + v39), &v56, *(&v77 + v39));
    v42 = v58;
    memmove_0(v58, &v56, 0x20u);
    ++v39;
}
while ( v39 < 4 );
v43 = sub_100B09D0(&v57);
v44 = v58;
for ( i = v68; v43; --v43 )
    *v44++ = 0;
v46 = 32;
v47 = &v56;
do
{
    *v47++ = 0;
    --v46;
}
while ( v46 );
*(_BYTE *)(i + 13032) = 1;
LOBYTE(v91) = 3;
sub_1001F470(&v57);
v48 = 32;
v49 = &v54;
do
{
    *v49++ = 0;
    --v48;
}
while ( v48 );
v50 = 32;
v51 = &v55;
do
{
    *v51++ = 0;
    --v50;
}
while ( v50 );
sub_10022270(&v69);
sub_10022270(&v64);
return 1;
}









飘云 发表于 2021-1-6 10:35:58

"服务器似乎可以发送狗屎"

啥玩意?

xie83544109 发表于 2021-1-6 12:03:29

{:lol:}
可能是打错字了吧

七色九天 发表于 2021-1-9 19:47:50

不懂这个,来围观一下啊

maxism 发表于 2021-2-16 20:44:34

飘云 发表于 2021-1-6 10:35
"服务器似乎可以发送狗屎"

啥玩意?

难得大哥回复
能不能帮忙看看、、、、、、、、

钢铁侠dhluser 发表于 2021-5-7 20:38:41

maxism 发表于 2021-2-16 20:44
难得大哥回复
能不能帮忙看看、、、、、、、、

大哥不想理你,i并向你扔了一坨**{:call:}
页: [1]
查看完整版本: dota2 局域网联机软件开发过程中遇到了 一个逆向难题 请求帮助