日期:
来源:看雪学苑收集编辑:ericyudatou
本文为看雪论坛优秀文章
看雪论坛作者ID:ericyudatou
一
准备
CodeMeter.exe Win32 v7.30
IDA Pro
二
初见——反调试
三
初见——从何入手(通信协议部分)
char __thiscall decrypt_package(void *this, int a2, unsigned __int8 a3, int pbuf, _BYTE *plen, int flag){char v6; // dlchar result; // alv6 = 1;if ( a3 == 160 ){if ( (*plen & 0xF) != 0 ) // len 应当是16的倍数return 0;return (*(int (__fastcall **)(void *, char, int, _BYTE *, int))(*(_DWORD *)this + 16))(this, 1, pbuf, plen, flag);// decrypt_telegram}else if ( a3 == 161 || a3 == 163 ){if ( (*plen & 0xF) == 0 ){result = (*(int (__fastcall **)(int, char, int, _BYTE *, _DWORD))(*(_DWORD *)a2 + 16))(a2, 1, pbuf, plen, 0);*(_DWORD *)plen = *(_DWORD *)(*(_DWORD *)plen + pbuf - 4);return result;}return 0;}return v6;}
char __thiscall encrypt_package(struct_communication *this, int a2, unsigned __int8 a3, int buf, int *length, int flag){char result; // alint v8; // ecxint v9; // eaxchar v10; // blint v11; // [esp+10h] [ebp-18h] BYREFint v12[5]; // [esp+14h] [ebp-14h] BYREFv12[0] = a2;result = 1;if ( a3 == 160 ){v12[0] = 0;sub_219A20(dword_800FC4 + 268);v9 = *(_DWORD *)this->gap0;v12[4] = 0;v10 = (*(int (__thiscall **)(struct_communication *, int, int *, int))(v9 + 12))(this, buf, length, flag);// encrypt_telegramsub_219A90(v12);return v10;}else if ( a3 == 161 || a3 == 163 ){v11 = *length;sub_3578E0(buf, length, 0);v8 = *length;*(_DWORD *)(buf + v8 - 8) = v11;v11 = v8 - 4;return (*(int (__thiscall **)(int, int, int *, _DWORD))(*(_DWORD *)v12[0] + 12))(v12[0], buf, &v11, 0);}return result;}
void __thiscall cm_client_encrypt_req(_DWORD *this,_DWORD *message_buf,unsigned __int8 a3,unsigned int final_len,unsigned int a5){int v6; // ecxunsigned int v7; // eaxsize_t v8; // esivoid *v9; // eaxsize_t v10; // ecxsize_t v11; // eaxsize_t v12; // esi_BYTE *buf_1; // esiint v14; // ecxint v15; // ecxsize_t v16; // edxint v17; // eaxint v18; // ecxchar v19; // alint v20; // ecxint v21; // ecx_DWORD *v22; // ecxunsigned int v23; // edx_BYTE *v24; // eaxvoid *p_Block; // edx_DWORD *v26; // eax_DWORD *v27; // esivoid *v28; // eaxint v29; // eaxint v30; // eaxint v31; // eaxint v32; // eaxint v33; // eaxint v34; // eaxint v35; // [esp-10h] [ebp-298h]int v36; // [esp-10h] [ebp-298h]int v37; // [esp-Ch] [ebp-294h]int v38; // [esp-Ch] [ebp-294h]int v39; // [esp-8h] [ebp-290h]int v40; // [esp-8h] [ebp-290h]int v41; // [esp-4h] [ebp-28Ch]int v42; // [esp-4h] [ebp-28Ch]int v43; // [esp-4h] [ebp-28Ch]int v44; // [esp-4h] [ebp-28Ch]int v45; // [esp+0h] [ebp-288h]char pExceptionObject[140]; // [esp+Ch] [ebp-27Ch] BYREFchar *v47; // [esp+98h] [ebp-1F0h]int buf; // [esp+9Ch] [ebp-1ECh]unsigned int v49; // [esp+A4h] [ebp-1E4h]int v50; // [esp+A8h] [ebp-1E0h]size_t v51; // [esp+ACh] [ebp-1DCh]_DWORD *v52; // [esp+B0h] [ebp-1D8h]char v53; // [esp+B7h] [ebp-1D1h]char v54[160]; // [esp+B8h] [ebp-1D0h] BYREFchar v55[160]; // [esp+158h] [ebp-130h] BYREFvoid **v56; // [esp+1F8h] [ebp-90h] BYREF__int128 v57; // [esp+1FCh] [ebp-8Ch]__int128 v58; // [esp+20Ch] [ebp-7Ch]int v59; // [esp+21Ch] [ebp-6Ch]int v60; // [esp+220h] [ebp-68h] BYREFvoid **v61; // [esp+224h] [ebp-64h] BYREFvoid *Block; // [esp+228h] [ebp-60h] BYREFint v63; // [esp+238h] [ebp-50h]unsigned int v64; // [esp+23Ch] [ebp-4Ch]size_t Size[4]; // [esp+240h] [ebp-48h] BYREFint v66; // [esp+250h] [ebp-38h]__int128 v67; // [esp+254h] [ebp-34h]int v68; // [esp+264h] [ebp-24h] BYREFint v69; // [esp+268h] [ebp-20h] BYREFunsigned int len_1; // [esp+26Ch] [ebp-1Ch] BYREFint len; // [esp+270h] [ebp-18h] BYREFchar v72; // [esp+276h] [ebp-12h] BYREFchar v73; // [esp+277h] [ebp-11h] BYREFint v74; // [esp+284h] [ebp-4h]v52 = message_buf;v57 = 0i64;v56 = &YS0076::YS0306::`vftable';v58 = 0i64;v59 = 0;v74 = 0;sub_EB4620(v55);v6 = this[63];LOBYTE(v74) = 1;(*(void (__thiscall **)(int, char *))(*(_DWORD *)v6 + 64))(v6, v55);sub_ECA0E0(v55);sub_ECA3F0(v41);v47 = v55;v7 = a5;HIDWORD(v67) = 0;if ( a5 < 0x1000 )v7 = 4096;*(_OWORD *)Size = 0i64;if ( final_len > v7 )v7 = final_len;Size[0] = (size_t)&YS0073::YS0080<unsigned char>::`vftable';memset(&Size[1], 0, 12);v66 = 1;v49 = ((v7 + 39) & 0xFFFFFFF0) + 1;v8 = ((v7 + 39) & 0xFFFFFFF0) + 17;v51 = v8;v67 = xmmword_126CA30;LOBYTE(v74) = 3;v9 = (void *)unknown_libname_56(v8);Size[3] = v8;v10 = (size_t)v9;Size[1] = (size_t)v9;Size[2] = v8;if ( (_DWORD)v67 == 1 ){memset(v9, 0, v8);v11 = Size[2];v10 = Size[1];}else{v11 = v51;}v12 = 0;LOBYTE(v74) = 4;if ( v11 )v12 = v10;buf_1 = (_BYTE *)(v12 + 15);if ( a3 == 0xA2 )(*(void (__thiscall **)(_DWORD))(*(_DWORD *)this[63] + 20))(this[63]);v51 = 0;v53 = 1;while ( 1 ){if ( !(*(unsigned __int8 (__thiscall **)(_DWORD))(*(_DWORD *)this[63] + 84))(this[63]) ){sub_EB4620(v54);v14 = this[63];LOBYTE(v74) = 5;(*(void (__thiscall **)(int, char *))(*(_DWORD *)v14 + 64))(v14, v54);v15 = this[63];LOBYTE(v50) = a3 != 0xA2;(*(void (__thiscall **)(int))(*(_DWORD *)v15 + 100))(v15);sub_DB90E0(this, v54, 3500, v50, 1);if ( !(*(unsigned __int8 (__thiscall **)(_DWORD))(*(_DWORD *)this[63] + 84))(this[63]) ){v32 = sub_D6E030(v45);v33 = sub_D6E030(v32);v34 = sub_D6E030(v33);v36 = sub_D6E030(v34);sub_D70090(100, v36, v38, v40, v44);goto LABEL_70;}LOBYTE(v74) = 4;sub_EB4790(v54);}v69 = 0;sub_D79A20(this + 1);v16 = 0;len = final_len;if ( Size[2] )v16 = Size[1];len_1 = v49;LOBYTE(v74) = 6;v17 = *v52;buf = v16 + 16;if ( !(*(unsigned __int8 (__stdcall **)(size_t, int *))(v17 + 4))(v16 + 16, &len) || len != final_len ){v52[2] = 100;LABEL_67:LOBYTE(v74) = 4;sub_D79A90(&v69);LABEL_68:v29 = sub_D6E030(v45);v30 = sub_D6E030(v29);v31 = sub_D6E030(v30);v35 = sub_D6E030(v31);sub_D70090(v52[2], v35, v37, v39, v43);LABEL_70:_CxxThrowException(pExceptionObject, (_ThrowInfo *)&_TI2_AVException_wbs__);}if ( !encrypt_package((int *)&v56, (int)(this + 2), a3, buf, &len, 0) ){v52[2] = 302;goto LABEL_67;}++len;*buf_1 = a3;v68 = 0;v63 = 0;v64 = 15;LOBYTE(Block) = 0;v61 = &wbs::StringBase<char>::`vftable';v18 = this[63];LOBYTE(v74) = 7;v19 = (*(int (__thiscall **)(int, _BYTE *, int, _DWORD, int *, void ***))(*(_DWORD *)v18 + 28))(v18,buf_1,len,0,&v68,&v61);if ( v19 == 1 ){if ( len ){*(_QWORD *)(dword_1360FC4 + 520) += (unsigned int)len;++*(_DWORD *)(dword_1360FC4 + 528);}}else if ( !v19 ){if ( v68 ){p_Block = &Block;if ( v64 >= 0x10 )p_Block = Block;(*(void (**)(int, const char *, ...))(*(_DWORD *)dword_13610C4 + 4))(dword_13610C4,"HTTP ERROR %i: %s\n",v68,p_Block);}v52[2] = 102;if ( (*(unsigned __int8 (__thiscall **)(_DWORD))(*(_DWORD *)this[63] + 84))(this[63]) )(*(void (__thiscall **)(_DWORD, int))(*(_DWORD *)this[63] + 16))(this[63], 1);v61 = &wbs::StringBase<char>::`vftable';if ( v64 < 0x10 )goto LABEL_38;v22 = Block;v23 = v64 + 1;v24 = Block;LOBYTE(v74) = 8;goto LABEL_35;}sub_EB82A0(v52);v20 = this[63];v73 = 0;v72 = 0;if ( (*(unsigned __int8 (__thiscall **)(int, size_t *, unsigned int *, char *, char *))(*(_DWORD *)v20 + 40))(v20,Size,&len_1,&v73,&v72) ){break;}LABEL_31:v52[2] = 103;if ( (*(unsigned __int8 (__thiscall **)(_DWORD))(*(_DWORD *)this[63] + 84))(this[63]) )(*(void (__thiscall **)(_DWORD, int))(*(_DWORD *)this[63] + 16))(this[63], 1);v61 = &wbs::StringBase<char>::`vftable';if ( v64 < 0x10 )goto LABEL_38;v22 = Block;v23 = v64 + 1;v24 = Block;LOBYTE(v74) = 9;LABEL_35:if ( v23 >= 0x1000 ){v22 = (_DWORD *)*(v22 - 1);if ( (unsigned int)(v24 - (_BYTE *)v22 - 4) > 0x1F )_invalid_parameter_noinfo_noreturn();}sub_F17EF9(v22);LABEL_38:LOBYTE(v74) = 4;LOBYTE(Block) = 0;v64 = 15;v63 = 0;sub_D79A90(&v69);if ( (int)++v51 >= 2 )goto LABEL_68;}while ( 1 ){if ( (int)len_1 <= 0 )goto LABEL_31;buf_1 = 0;if ( Size[2] )buf_1 = (_BYTE *)Size[1];*(_QWORD *)(dword_1360FC4 + 504) += len_1;++*(_DWORD *)(dword_1360FC4 + 512);if ( !decrypt_package(&v56, (int)(this + 2), a3, (int)buf_1, &len_1, (v73 & 0xF0) == 112) )goto LABEL_64;v60 = 0;if ( !(unsigned __int8)sub_EB8AC0(buf_1, len_1, &v60) )break;v21 = this[63];v73 = 0;v72 = 0;if ( !(*(unsigned __int8 (__thiscall **)(int, size_t *, unsigned int *, char *, char *))(*(_DWORD *)v21 + 40))(v21,Size,&len_1,&v73,&v72) )goto LABEL_31;}if ( len_1 > a5 ){LABEL_64:v52[2] = 302;sub_D63570(&v61);goto LABEL_67;}if ( !(*(unsigned __int8 (__thiscall **)(_DWORD *, _BYTE *, unsigned int))(*v52 + 8))(v52, buf_1, len_1) ){v53 = 0;v52[2] = 100;}sub_D63570(&v61);LOBYTE(v74) = 4;sub_D79A90(&v69);if ( v53 != 1 )goto LABEL_68;v26 = (_DWORD *)DWORD2(v67);v27 = (_DWORD *)DWORD1(v67);LOBYTE(v74) = 10;for ( Size[0] = (size_t)&YS0073::YS0080<unsigned char>::`vftable'; v27 != v26; ++v27 ){if ( *v27 ){(*(void (__thiscall **)(_DWORD, _DWORD))(*(_DWORD *)*v27 + 4))(*v27, 0);v26 = (_DWORD *)DWORD2(v67);}}if ( (_BYTE)v66 ){v28 = (void *)Size[1];if ( Size[1] ){if ( (_DWORD)v67 == 1 ){memset((void *)Size[1], 0, Size[2]);v28 = (void *)Size[1];}j_j__free(v28);}memset(&Size[1], 0, 12);LOBYTE(v66) = 1;}sub_D6CCA0();LOBYTE(v74) = 11;sub_ECA0E0(v55);sub_ECA6B0(v42);sub_EB4790(v55);}
void __thiscall api_cm_access_2_entry(int this){CMTIME *v2; // eaxchar v3; // clCMTIME v4; // xmm0char v5[16]; // [esp+4h] [ebp-2D4h] BYREFCMACCESS2 cmacc; // [esp+14h] [ebp-2C4h] BYREFcmacc.mulReserved1 = 0;cmacc.mulReserved2 = 0;memset(&cmacc.mulLicenseQuantity, 0, 0x88u);memset(cmacc.mabCmActId, 0, 0x110u);memset(&cmacc.mcmCredential.mulCreationTime, 0, 0xE0u);cmacc.mflCtrl = *(_DWORD *)(this + 44);cmacc.mulFirmCode = *(_DWORD *)(this + 48);cmacc.mulProductCode = *(_DWORD *)(this + 52);cmacc.mulFeatureCode = *(_DWORD *)(this + 56);v2 = (CMTIME *)getCMTime(v5, 0);v3 = *(_BYTE *)(this + 72);v4 = *v2;cmacc.mulUsedRuntimeVersion = *(_DWORD *)(this + 60);cmacc.mulProductItemReference = *(unsigned __int16 *)(this + 68);cmacc.mbMinBoxMajorVersion = *(_BYTE *)(this + 76);cmacc.mbMinBoxMinorVersion = *(_BYTE *)(this + 77);cmacc.musBoxMask = *(_WORD *)(this + 78);cmacc.mulSerialNumber = *(_DWORD *)(this + 80);cmacc.mcmCredential.mulPID = *(_DWORD *)(this + 64);cmacc.mcmCredential.mulSession = *(unsigned __int16 *)(this + 70);cmacc.mcmCredential.mulCleanupTime = 0;cmacc.mcmCredential.mulMaxLifeTime = 0;cmacc.mcmReleaseDate = v4;if ( v3 || *(_BYTE *)(this + 73) || *(_BYTE *)(this + 74) || *(_BYTE *)(this + 75) )sub_D9EB30(cmacc.mszServername, 0x80u, 0x80u, "%i.%i.%i.%i", v3);if ( !*(_BYTE *)(dword_1360FC4 + 760) && (cmacc.mflCtrl & 0x200000) != 0 )*(_DWORD *)(this + 20) = 0x80000000;api_cm_access_2__3(*(_DWORD *)(this + 40),&cmacc,(int *)(this + 220),(_DWORD *)(this + 8),*(void ***)(this + 16),0,*(_DWORD *)(this + 28));}
int __thiscall api_handler(_DWORD *this){int v2; // eaxchar v3; // alint api_class; // ecxint v5; // ecxchar v6; // dlint v7; // ecxint v8; // esiint v9; // eaxbool v10; // zf_DWORD v12[8]; // [esp+0h] [ebp-38h] BYREFchar v13; // [esp+23h] [ebp-15h] BYREF_DWORD *v14; // [esp+28h] [ebp-10h]int v15; // [esp+34h] [ebp-4h]v14 = v12;v12[7] = this;v13 = 0;v12[6] = &v13;v15 = 0;do{if ( (*(unsigned __int8 (__thiscall **)(int))(*(_DWORD *)((char *)this + *(_DWORD *)(*this + 4)) + 32))((int)this + *(_DWORD *)(*this + 4)) ){*(_DWORD *)(this[2] + 8) = 0xD0010003;this[1] = 0;v15 = 1;goto LABEL_17;}LOBYTE(v15) = 2;v2 = _Mtx_trylock((_Mtx_t)(dword_1360FC4 + 220));if ( v2 ){if ( v2 != 3 )std::_Throw_C_error(v2);v3 = 0;}else{v3 = 1;}LOBYTE(v15) = 0;}while ( !v3 );v13 = 1;if ( !*(_BYTE *)(dword_1360FC4 + 150) ){*(_DWORD *)(this[2] + 8) = 238;this[1] = 0;v15 = 3;LABEL_17:v10 = v13 == 0;goto LABEL_18;}api_class = this[2];LOBYTE(v15) = 4;(*(void (__thiscall **)(int))(*(_DWORD *)api_class + 16))(api_class);// <==============call apiv15 = 0;_Mtx_unlock((_Mtx_t)(dword_1360FC4 + 220));v5 = this[2];v6 = 0;v13 = 0;if ( *(int *)(v5 + 20) >= 0 ){v7 = *(_DWORD *)(v5 + 8);if ( v7 ){if ( v7 != 112 && v7 != 209 ){v8 = *(_DWORD *)dword_13610C4;v9 = sub_D8CD00(v7);(*(void (**)(int, const char *, ...))(v8 + 4))(dword_13610C4,"API Error %u (%s) occurred!\n",*(_DWORD *)(this[2] + 8),v9);v6 = v13;}}}this[1] = 0;v15 = 6;v10 = v6 == 0;LABEL_18:if ( !v10 )_Mtx_unlock((_Mtx_t)(dword_1360FC4 + 220));return 0;}
(*(void (__thiscall **)(int))(*(_DWORD *)api_class + 16))(api_class);简单的标注一下常用的API
三
初见——服务端的主要加密算法
主要用于通信协议中的校验,和函数签名的校验
仅用于getRandomkey,其余没有调用
用于签名校验,配合ECDSA
用于数据包的加解密,以及license文件的加解密
secp224r1{p = 0xffffffffffffffffffffffffffffffff000000000000000000000001a = 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffeb = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3DGx = 0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21Gy = 0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34}
四
CodeMeter所特有的ECDSA
吐槽一下,FindCrypt貌似不支持ECDSA算法。
其中我们主要关注checkECDSASignature ECDSAEncrypt ECDSASign这几个函数,因为ECDSA算法的原理及其实现论坛上一抓一大把,我这里只说说这些函数在CodeMeter中的用处以及定位方法。
checkECDSASignature
BOOL __cdecl checkECDSASignature(char *ecdsa,unsigned __int8 *pubKey,unsigned __int8 *pbSignature,unsigned __int8 *mabDigest){BOOL result; // eaxvoid *curve_n; // [esp+10h] [ebp-A8h] BYREFvoid *curve_G_y; // [esp+14h] [ebp-A4h] BYREFvoid *curve_G_x; // [esp+18h] [ebp-A0h] BYREF__int128 pSignature_2[2]; // [esp+1Ch] [ebp-9Ch] BYREFchar a2[16]; // [esp+3Ch] [ebp-7Ch] BYREF__int128 v10; // [esp+4Ch] [ebp-6Ch]int pSignature_1[7]; // [esp+5Ch] [ebp-5Ch] BYREFint pubkey[4]; // [esp+78h] [ebp-40h] BYREF__int128 v13; // [esp+88h] [ebp-30h]char plaintext[4]; // [esp+98h] [ebp-20h] BYREFresult = sub_B1C960(ecdsa, (int)pubKey, 32);if ( result ){bignum_copy((int)pSignature_1, pbSignature, 0x1Cu);bignum_copy((int)pSignature_2, pbSignature + 32, 0x1Cu);bignum_copy((int)plaintext, mabDigest, 0x1Cu);get_ecdsa_curve(&curve_n, &curve_G_x, &curve_G_y);result = bignum_compare_int((int)pSignature_1, (int)curve_n, 7);if ( !result ){result = bignum_compare_int((int)pSignature_1, 0, 7);if ( result != 3 ){result = bignum_compare_int((int)pSignature_2, (int)curve_n, 7);if ( !result ){result = bignum_compare_int((int)pSignature_2, 0, 7);if ( result != 3 ){sub_B1FBE0(pSignature_2, (int)a2, curve_n, 7);sub_B1FE90((int)plaintext, (int)a2, curve_n, 7);sub_B1FE90((int)a2, (int)pSignature_1, curve_n, 7);bignum_copy((int)pubkey, pubKey, 0x1Cu);bignum_copy((int)pSignature_2, pubKey + 32, 0x1Cu);result = init_ecdsa_curve_G(ecdsa, a2, 7, pubkey, pSignature_2);if ( result ){*(_OWORD *)a2 = *(_OWORD *)ecdsa;v10 = *((_OWORD *)ecdsa + 1);pSignature_2[0] = *((_OWORD *)ecdsa + 2);pSignature_2[1] = *((_OWORD *)ecdsa + 3);*(_OWORD *)pubkey = *((_OWORD *)ecdsa + 4);v13 = *((_OWORD *)ecdsa + 5);result = init_ecdsa_curve_G(ecdsa, plaintext, 7, curve_G_x, curve_G_y);if ( result ){result = sub_B1BC30(ecdsa, a2, (int)pSignature_2, (int)pubkey);if ( result ){result = bignum_compare_int((int)(ecdsa + 64), 0, 7);if ( result != 3 ){init_ecdsa_curve_p(ecdsa);result = bignum_compare_int((int)ecdsa, (int)pSignature_1, 7);if ( result == 3 )return 1;}}}}}}}}}return 0;}
用处:
client CmValiateSignature验证签名
server License授权校验 Licensor Public Key检查 etc
破解方法:
函数尾xor eax,eax改成mov al,1 就能爆掉证书检查
定位方法:
1、搜索字符串 “Licensor Public Key Signature is invalid.”,串参找引用,只有一个函数。
2、这个便是checkECDSASignature。
看雪ID:ericyudatou
https://bbs.kanxue.com/homepage-786730.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!