大家过年好,
最近几个朋友在开发dota2局域网联机的软件,但是遇到了一个难题,特向大佬们请教。
dota2中,当一个用户建立房间,另一个用户进行连接的时候,dota会请求一个“证书”,验证通过后,两台电脑才能开始联机,使用软件进行转储后得到的信息如下:
cert = 080112202B39DF35AAB3E009269D5FBF57A0AC8D8059BAFA7C4E1001EE8D54062DAAEAEF2108E41494763F4001453518F75F4D35BBF95F50BA045A0A810108E41494763F40016219737465616D69643A3930313431373731303730343937383030
ca_key_id = 18220590129359924542
ca_signature = E1FA9B6E43521BDA3DA6F5C579AB10A31913AA538D6FAFE4C813CF6321E43F66D2C3D913C96A86423DC8A2A24B73F237D4E30A5BE6A85536B1E042938B1A450B
现在的问题是,我们无法还原这个加密的算法,但是dota本身是要进行验证的,目前想到的办法是对steamnetworkingsockets.dll进行逆向,将证书验证的函数修改了,或者是发送一个自签名的证书,但是这些我们都不会,希望各位大佬不吝指教,万分感谢。下面是搜到的一个相关的帖子,希望有用。
大家好,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; // [sp+4h] [bp-290h]@58
char v53; // [sp+104h] [bp-190h]@26
char v54; // [sp+184h] [bp-110h]@82
char v55; // [sp+1A4h] [bp-F0h]@80
char v56; // [sp+1C4h] [bp-D0h]@94
char v57; // [sp+1E4h] [bp-B0h]@95
void *v58; // [sp+1E8h] [bp-ACh]@86
int v59; // [sp+1F8h] [bp-9Ch]@86
int v60; // [sp+20Ch] [bp-88h]@39
int v61; // [sp+210h] [bp-84h]@39
int v62; // [sp+214h] [bp-80h]@38
int v63; // [sp+218h] [bp-7Ch]@38
int v64; // [sp+21Ch] [bp-78h]@7
int v65; // [sp+220h] [bp-74h]@7
int v66; // [sp+224h] [bp-70h]@7
char v67; // [sp+228h] [bp-6Ch]@7
int v68; // [sp+22Ch] [bp-68h]@1
int v69; // [sp+230h] [bp-64h]@69
int v70; // [sp+234h] [bp-60h]@69
int v71; // [sp+238h] [bp-5Ch]@69
char v72; // [sp+23Ch] [bp-58h]@69
int v73; // [sp+240h] [bp-54h]@84
int v74; // [sp+244h] [bp-50h]@84
int v75; // [sp+248h] [bp-4Ch]@84
int v76; // [sp+24Ch] [bp-48h]@84
size_t v77; // [sp+250h] [bp-44h]@84
int v78; // [sp+254h] [bp-40h]@84
int v79; // [sp+258h] [bp-3Ch]@84
int v80; // [sp+25Ch] [bp-38h]@84
int v81; // [sp+260h] [bp-34h]@80
int v82; // [sp+264h] [bp-30h]@80
int v83; // [sp+268h] [bp-2Ch]@80
int v84; // [sp+26Ch] [bp-28h]@80
void *v85; // [sp+270h] [bp-24h]@84
char *v86; // [sp+274h] [bp-20h]@84
_BYTE *v87; // [sp+278h] [bp-1Ch]@84
_BYTE *v88; // [sp+27Ch] [bp-18h]@84
int v89; // [sp+280h] [bp-14h]@84
int v90; // [sp+284h] [bp-10h]@84
int v91; // [sp+290h] [bp-4h]@7
char *v92; // [sp+2A4h] [bp+10h]@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[4]) )
goto LABEL_42;
v60 = v4->dword3220;
v61 = v4->dword3224;
v12 = sub_10086E60(&v4->gap2C[4]);
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[4]);
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[1] )
{
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[31];
v88 = &v4->gap330A[47];
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[47];
v88 = &v4->gap330A[31];
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;
}
我被信任的CA证书列表或签名验证所吸引,所以由于我真的没有时间,有人已经扭转了这一点吗? 感谢您的见解!
原帖地址(请注册登录查看):https://cs.rin.ru/forum/viewtopic.php?f=20&t=85859
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-2-16 15:57
被cloverlove编辑
,原因: