活跃值:
(46282)
能力值:
(RANK:115 )
|
-
-
2 楼
期待完整版
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
3 楼
0x02 初步分析 

从样本一进行跟踪分析,CmCalculateSignature发现在这里被调用 ……
memset((__m128i *)&cmAuth, 0, sizeof(cmAuth));
v15 = v4[1];
if ( v15 == 512 )
{
mflCtrl = cmAuth.mflCtrl;
cmAuth.mulKeyExtType = 0;
if ( v23 )
mflCtrl = 5;
cmAuth.mflCtrl = mflCtrl;
}
else if ( v15 == 1024 )
{
cmAuth.mflCtrl = 2;
cmAuth.mulKeyExtType = 136;
}
pbPubKey = (unsigned int)(v11 + 8);
memcpy(v21[190], cmAuth.mabDigest, 32);
if ( !sub_25971B0(v4) )
return 0;
v17 = sub_2596C00();
hcmse = v20[1];
memset(pbSignature, 0, sizeof(pbSignature));
if ( !(*(int (__cdecl **)(int, CMAUTHENTICATE *, __m128i *, int))(v17 + 56))(hcmse, &cmAuth, pbSignature, 64) )// cm_calc_signature
{
v4[42] = sub_269E220(v17, hcmse);
return 0;
}
if ( (*(int (__cdecl **)(CMAUTHENTICATE *, __m128i *, int, unsigned int, int))(v17 + 60))(// CmValidateSignature
&cmAuth,
pbSignature,
64,
pbPubKey,
64) )
{
return 0;
}
result = sub_269E220(v17, hcmse);
v4[42] = result;
return result;
} 在通过服务器计算签名后在本地用CmValidateSignature验证签名。根据相关帮助文档易知CmValidateSignature运用SHA256 - ECDSA算法 CmCrypt在这里调用 v40 = a5;
v38 = v16 & 0xFF00FFFF;
if ( sub_108F760((char *)&v26, pvDest_, 16) )
{
CmCrypt = (int (__cdecl *)(int, _DWORD, CMCRYPT2 *, __int128 *, int))this[5];
if ( CmCrypt && len >= 0x41E )
{
memset((__m128i *)&pcmCrypt_40, 0, sizeof(pcmCrypt_40));
pcmCrypt_40.mcmBaseCrypt.mulEncryptionCode = EncryptionCode;
pcmCrypt_40.mcmBaseCrypt.mulEncryptionCodeOptions = v31 ^ v38;
pcmCrypt_40.mcmBaseCrypt.mflCtrl = 0x6000000;
pcmCrypt_40.mcmBaseCrypt.mulFeatureCode = v37 ^ v28;
cbDest = sub_10907A0(&v26);
res = CmCrypt(hcmse, 0, &pcmCrypt_40, pvDest, cbDest);// CM_CRYPT_DIRECT_ENC
}
else
{
if ( !v29 || (cbDest_1 = 56, v33 == 0x3000000) )
cbDest_1 = 40;
*(_QWORD *)&pcmCrypt.mcmBaseCrypt.mflCtrl = 0i64;
pcmCrypt.mcmBaseCrypt.mulEncryptionCode = EncryptionCode;
pcmCrypt.mcmBaseCrypt.mulEncryptionCodeOptions = v31 ^ v38;
memset(&pcmCrypt.mcmBaseCrypt.mulFeatureCode, 0, 24);
pcmCrypt.mcmBaseCrypt.mulFeatureCode = v37 ^ v28;
CmCrypt2 = (int (__cdecl *)(int, _DWORD, CMCRYPT *, __int128 *, int))this[4];
pcmCrypt.mcmBaseCrypt.mflCtrl = 0x6000000;
res = CmCrypt2(hcmse, 0, &pcmCrypt, pvDest, cbDest_1);// CM_CRYPT_DIRECT_ENC
}
res_ = res;
if ( res )
{
sub_FF3DB0((int)aes);
*pvDest_ = pvDest[0];
}
} 让这两个函数在此地不要走动,咱们解决了这些加密API再来找她
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
4 楼
0x03 授权 & 加密 API分析 
这些API,咱一个个来 CmCalculateDigest CODEMETER_API int CMAPIENTRY CmCalculateDigest(const CMBYTE *pbInput, CMUINT cbInput,
CMBYTE *pbDigest, CMUINT cbDigest); 本地实现,不需要服务器。输入一个二进制串,返回唯一对应的32位二进制串。 int __thiscall CmCalculateDigest_0(int *this, BYTE *pbInput, int cbInput, BYTE *pbDigest, unsigned int cbDigest)
{
int v6; // eax
_DWORD v8[5]; // [esp+0h] [ebp-98h] BYREF
int sha256[33]; // [esp+14h] [ebp-84h] BYREF
sha256[29] = (int)v8;
v6 = *this;
v8[4] = this;
(*(void (__thiscall **)(int *, _DWORD))(v6 + 4))(this, 0);
if ( cbDigest >= 0x20 )
{
sha256[32] = 0;
memset(sha256, 0, 112u);
init_sha256((int)sha256);
sha256_update(sha256, pbInput, cbInput);
sha256_final(pbDigest, (int)sha256);
}
else
{
(*(void (__thiscall **)(int *, int))(*this + 4))(this, 112);// 传递给CodeMeter驱动程序的数据段太小, 错误 112.
}
return 32;
} 平淡无奇的sha256套皮,没什么可说的。 CmCalculateSignature 需要用服务器,核心科技在CodeMeter.exe上,咱先分析一下客户端上的
#define CM_DIGEST_LEN 32
typedef struct __CMAUTHENTICATE {
CMULONG mflCtrl;
CMULONG mulKeyExtType;
CMULONG mulFirmCode;
CMULONG mulProductCode;
CMULONG mulEncryptionCodeOptions;
CMULONG mulFeatureCode;
CMBOXINFO mcmBoxInfo;
CMBYTE mabDigest[CM_DIGEST_LEN];
} CMAUTHENTICATE;
CODEMETER_API int CMAPIENTRY CmCalculateSignature(HCMSysEntry hcmse,
const CMAUTHENTICATE *pcmAuth, CMBYTE *pbSignature, CMUINT cbSignature); 功能:通过CmDongle(狗)中的私钥用ECDSA算法对一个32位的二进制串进行签名,返回签名,不唯一,长度64位
客户端: // CODEMETER_API int CMAPIENTRY CmCalculateSignature(HCMSysEntry hcmse,
// const CMAUTHENTICATE *pcmAuth, CMBYTE *pbSignature, CMUINT cbSignature);
int __thiscall CmCalculateSignature_1(
LPCRITICAL_SECTION *this,
HCMSysEntry hcmse,
CMAUTHENTICATE *pcmAuth,
BYTE *pbSignature,
int cbSignature)
{
int cbSignature_1; // eax
_OWORD *v7; // eax
_DWORD *v8; // eax
unsigned int Ticket_2; // eax
int res; // esi
size_t newsize; // [esp+18h] [ebp-120h]
HCMSysEntry hcmse_1; // [esp+20h] [ebp-118h] BYREF
int buf[65]; // [esp+24h] [ebp-114h] BYREF
int v16; // [esp+134h] [ebp-4h]
hcmse_1 = hcmse;
if ( !isBadHandle(this, &hcmse_1) || !isBadAddress(this, pcmAuth, 0xC8u) )
return 0;
if ( (unsigned int)cbSignature < 0x40 || !pbSignature )
{
((void (__thiscall *)(LPCRITICAL_SECTION *, int))(*this)->LockCount)(this, 105);
return 0;
}
cbSignature_1 = 64;
if ( (unsigned int)cbSignature <= 0x40 )
cbSignature_1 = cbSignature;
newsize = cbSignature_1;
if ( !isBadAddress(this, pbSignature, cbSignature_1) )
return 0;
memset(buf, 0, sizeof(buf));
buf[1] = -1;
buf[2] = 0;
LOBYTE(buf[3]) = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = -1;
buf[7] = 0;
LOBYTE(buf[8]) = 0;
v16 = 0;
buf[0] = (int)&YS0039::`vftable';
LOBYTE(buf[9]) = 90;
memset(&buf[10], 0, 0xD8u);
v7 = operator new(0x24u);
LOBYTE(v16) = 1;
if ( v7 )
{
*v7 = 0i64;
v7[1] = 0i64;
*((_DWORD *)v7 + 8) = 0;
v8 = sub_67602DB0(v7, 1u, 0);
}
else
{
v8 = 0;
}
buf[64] = (int)v8;
v16 = 2;
Ticket_2 = CmGetTicket_2(this + 23, (unsigned __int16)hcmse_1);
buf[10] = Ticket_2 | (unsigned int)hcmse_1;
qmemcpy(&buf[11], pcmAuth, 0xC8u);
buf[61] = newsize;
reallocateMem((struct_reallocateMem *)buf[64], newsize);
if ( *(_DWORD *)(buf[64] + 8) )
buf[63] = *(_DWORD *)(buf[64] + 4);
else
buf[63] = 0;
if ( send_cm_socket_Req(this + 6, buf, 0xD4u, newsize + 12, 0) )// 发出请求
{
memmove(pbSignature, (const void *)buf[63], buf[61]);
res = buf[62];
FREE(buf);
return res;
}
else
{
FREE(buf);
return 0;
}
} 也没什么能说的,捣鼓捣鼓参数塞请求包里。结构如下 struct{
int apicode;//90
HCMSysEntry hcmse;
CMAUTHENTICATE *pcmAuth;
CMUINT cbSignature;
} 服务端:(**占位**)
CmGetPublicKey CODEMETER_API int CMAPIENTRY CmGetPublicKey(HCMSysEntry hcmse,
const CMAUTHENTICATE *pcmAuth, CMBYTE *pbPubKey, CMUINT cbPubKey); 从CmContainner中获得公钥,因为CmContainner中只存放私钥故需要通过私钥计算公钥 int __thiscall CmGetPublicKey_1(
LPCRITICAL_SECTION *this,
HCMSysEntry hcmse,
CMAUTHENTICATE *pcmAuth,
char *pbPubKey,
int cbPubKey)
{
int cbPublicKey; // edi
unsigned int v7; // eax
unsigned int keysrc; // ecx
LPCRITICAL_SECTION v9; // ecx
int Ticket_2; // eax
int v12; // esi
void *v13; // ecx
unsigned __int16 mulKeyExtType; // [esp-8h] [ebp-2Ch]
int mulEncryptionCodeOptions; // [esp-4h] [ebp-28h]
HCMSysEntry hcmse_1; // [esp+24h] [ebp+0h] BYREF
int buf[67]; // [esp+28h] [ebp+4h] BYREF
void *Src[2]; // [esp+134h] [ebp+110h] BYREF
int v19; // [esp+13Ch] [ebp+118h]
hcmse_1 = hcmse;
if ( !isBadHandle(this, &hcmse_1) )
return 0;
if ( !isBadAddress(this, pcmAuth, 0xC8u) )
return 0;
cbPublicKey = cbPubKey;
if ( !isBadAddress(this, pbPubKey, cbPubKey) )
return 0;
v7 = 64;
keysrc = pcmAuth->mflCtrl & 7; // Key Source
if ( keysrc == 6 ) // CM_AUTH_UNIVERSALDATA
v7 = 1044;
if ( cbPubKey <= v7 )
{
if ( cbPubKey < v7 )
{
LABEL_22:
((void (__thiscall *)(LPCRITICAL_SECTION *, int))(*this)->LockCount)(this, 105);// Message Text
//
// The specified parameter is invalid, Error 105.
return 0;
}
}
else
{
cbPublicKey = v7;
}
if ( !pbPubKey )
goto LABEL_22;
if ( keysrc == 6 ) // CM_AUTH_UNIVERSALDATA
{
mulEncryptionCodeOptions = pcmAuth->mulEncryptionCodeOptions;
v9 = this[111];
mulKeyExtType = pcmAuth->mulKeyExtType;
*(_QWORD *)Src = 0i64;
v19 = 0;
sub_676388E0(v9, Src, (int)hcmse_1, mulKeyExtType, mulEncryptionCodeOptions); //UVD Get Public Key
if ( Src[0] == Src[1] )
{
free(Src);
return 0;
}
else
{
memmove(pbPubKey, Src[0], Src[1] - Src[0]);
free(Src);
return 1;
}
}
else
{
memset(buf, 0, sizeof(buf));
buf[1] = -1;
buf[2] = 0;
LOBYTE(buf[3]) = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = -1;
buf[7] = 0;
LOBYTE(buf[8]) = 0;
buf[0] = (int)&YS0038::`vftable';
memset(&buf[10], 0, 228);
LOBYTE(buf[9]) = 91;
Ticket_2 = CmGetTicket_2(this + 23, (unsigned __int16)hcmse_1);
sub_67614390(buf, (int)hcmse_1, pcmAuth, cbPublicKey, Ticket_2);
if ( send_cm_socket_Req(this + 6, buf, 0xD4u, cbPublicKey + 12, 0) )
{
memmove(pbPubKey, (const void *)buf[66], buf[64]);
v12 = buf[65];
}
else
{
v12 = 0;
}
v13 = (void *)buf[10];
if ( buf[10] )
{
if ( (unsigned int)(buf[12] - buf[10]) >= 0x1000 )
{
v13 = *(void **)(buf[10] - 4);
if ( (unsigned int)(buf[10] - (_DWORD)v13 - 4) > 0x1F )
_invalid_parameter_noinfo_noreturn();
}
sub_67690A3E(v13);
memset(&buf[10], 0, 12);
}
sub_6763FEC0(buf);
return v12;
}
} 整体上大同小异,数据包跟CmCalculateSignature一样 struct{
int apicode;//91
HCMSysEntry hcmse;
CMAUTHENTICATE *pcmAuth;
CMUINT cbPublicKey;
} 当Key Source 为 Universal Data时会转发到CmGetPublicKeyUVD,处理流程不太一样,后面说CmGetPublicKeyUVD再提 CmValidateSignature CODEMETER_API int CMAPIENTRY CmValidateSignature(const CMAUTHENTICATE *pcmAuth,
const CMBYTE *pbSignature, CMUINT cbSignature,
const CMBYTE *pbPubKey, CMUINT cbPubKey); 本地实现,用ECDSA验证签名,签名由CmCalculateSignature生成,pcmAuth-->mabDigest(被签名的sha256值)必须存在 int __thiscall CmValidateSignature(
int *this,
CMAUTHENTICATE *pcmAuth,
BYTE *pbSignature,
unsigned int cbSignature,
BYTE *pbPubKey,
unsigned int cbPubKey)
{
int v7; // eax
void *v8; // eax
CMBOXINFO *boxinfo_1; // eax
bool res; // al
int mulEncryptionCodeOptions; // [esp-4h] [ebp-20Ch]
int v13; // [esp+0h] [ebp-208h] BYREF
CMBOXINFO boxinfo; // [esp+10h] [ebp-1F8h] BYREF
int *pbPubKey_1; // [esp+A0h] [ebp-168h]
void *v16[65]; // [esp+A4h] [ebp-164h] BYREF
int signature[17]; // [esp+1A8h] [ebp-60h] BYREF
int len; // [esp+1ECh] [ebp-1Ch] BYREF
int key_source[3]; // [esp+1F0h] [ebp-18h] BYREF
int v20; // [esp+204h] [ebp-4h]
key_source[2] = (int)&v13;
pbPubKey_1 = (int *)pbPubKey;
v7 = *this;
boxinfo.mulExtendedSerial = (unsigned int)this;
(*(void (__thiscall **)(int *, _DWORD))(v7 + 4))(this, 0);
if ( cbPubKey < 0x40 || cbSignature < 0x40 )
{
(*(void (__thiscall **)(int *, int))(*this + 4))(this, 105);// 指定了一个无效的参数, 错误 105.
}
else
{
memset(signature, 0, sizeof(signature));
v8 = sub_6760F7E0();
sub_67656310((int)signature, (int)v8);
v20 = 0;
init_this((int)v16);
LOBYTE(v20) = 1;
boxinfo_1 = copy_boxinfo(&boxinfo, &pcmAuth->mcmBoxInfo);
copy_boxinfo_to_this((int)v16, boxinfo_1);
copy_firm_code_to_this((int)v16, pcmAuth->mulFirmCode, 0, 0, 0);
sub_676588C0(signature, (int)v16);
len = 0;
key_source[0] = 0;
if ( explain_mflCtrl(pcmAuth->mflCtrl, &len, key_source) )
{
mulEncryptionCodeOptions = pcmAuth->mulEncryptionCodeOptions;
LOBYTE(v20) = 2;
res = doValidateSignature(
signature,
len,
pcmAuth->mabDigest,
(int)pbSignature,
key_source[0],
pbPubKey_1,
pcmAuth->mulProductCode,
pcmAuth->mulFeatureCode,
mulEncryptionCodeOptions);
v20 = 1;
if ( res )
{
clean_s(v16); // 成功
clean_s_0(signature);
return 1;
}
(*(void (__thiscall **)(int *, int))(*this + 4))(this, 202);// 对该序列的加/解密操作失败, 错误 202.
}
else
{
(*(void (__thiscall **)(int *, int))(*this + 4))(this, 105);// 指定了一个无效的参数, 错误 105.
}
clean_s(v16);
clean_s_0(signature);
}
return 0;
} bool __thiscall doValidateSignature(
int *signature,
int len,
_OWORD *mabDigest,
unsigned __int8 *pbSignature,
int key_source,
int *pbPubKey,
int productCode,
int featureCode,
int mulEncryptionCodeOptions)
{
int *pubKey; // ebx
int v11; // eax
__int128 v12; // xmm0
int v13; // eax
int v15[35]; // [esp+Ch] [ebp-20Ch] BYREF
int arr[31]; // [esp+98h] [ebp-180h] BYREF
int ecdsa[24]; // [esp+114h] [ebp-104h] BYREF
int pubkey[16]; // [esp+174h] [ebp-A4h] BYREF
int mabDigest_1[4]; // [esp+1B4h] [ebp-64h] BYREF
__int128 v20; // [esp+1C4h] [ebp-54h]
int v21[16]; // [esp+1D4h] [ebp-44h] BYREF
pubKey = pbPubKey;
*(_OWORD *)mabDigest_1 = *mabDigest;
v20 = mabDigest[1];
memset(v21, 0, sizeof(v21));
memset(pubkey, 0, sizeof(pubkey));
if ( len == 16 || len == 32 || len == 64 )
{
memset(&arr[1], 0, 0x77u); // 16
v11 = *signature;
arr[0] = 55;
arr[5] = *(_DWORD *)((*(int (__thiscall **)(int *))(v11 + 40))(signature) + 4);
arr[6] = productCode;
*(_OWORD *)&arr[1] = *(_OWORD *)mabDigest_1;
*(_OWORD *)((char *)&arr[10] + 3) = v20;
if ( len == 16 || len == 64 ) // 64
{
arr[7] = featureCode;
arr[9] = mulEncryptionCodeOptions;
calcSHA256((BYTE *)arr, (BYTE *)mabDigest_1);
if ( len == 64 )
{
v12 = *(_OWORD *)pbPubKey;
pubkey[6] = pbPubKey[6];
v13 = pbPubKey[14];
*(_OWORD *)pubkey = v12;
pubkey[13] = v13;
*(_QWORD *)&pubkey[4] = *((_QWORD *)pbPubKey + 2);
*(_OWORD *)&pubkey[7] = *((_OWORD *)pbPubKey + 2);
*(_QWORD *)&pubkey[11] = *((_QWORD *)pbPubKey + 6);
sub_67687130((unsigned int *)ecdsa, (unsigned __int8 *)pubkey, 1, (int)v21);
pubKey = pubkey;
pubkey[6] = v21[6];
*(_OWORD *)pubkey = *(_OWORD *)v21;
pubkey[7] = 0;
*(_QWORD *)&pubkey[4] = *(_QWORD *)&v21[4];
pubkey[14] = v21[13];
pubkey[15] = 0;
*(_OWORD *)&pubkey[8] = *(_OWORD *)&v21[7];
*(_QWORD *)&pubkey[12] = *(_QWORD *)&v21[11];
}
}
else
{
qmemcpy(v15, (const void *)(*(int (__thiscall **)(int *))(*signature + 44))(signature), sizeof(v15));// 32
arr[7] = v15[0];
LOWORD(arr[8]) = v15[1];
arr[9] = mulEncryptionCodeOptions;
calcSHA256((BYTE *)arr, (BYTE *)mabDigest_1);
}
}
return checkECDSASignature((char *)ecdsa, (unsigned __int8 *)pubKey, pbSignature, (unsigned __int8 *)mabDigest_1);
} 逻辑很简单,爆掉checkECDSASignature即可
最后于 2023-1-3 19:04
被ericyudatou编辑
,原因:
|
活跃值:
(1141)
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
高手,明白一下大神
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
6 楼
CmCrypt加密相关
在我们干掉Axprotector的CmValiateSignature校验之后,程序在进行一次CmCrypt2请求之后紫砂,请求如下

客户端CmCrypt2下断 int __thiscall func_0(
_DWORD *this,
void *hcmse,
unsigned int a3,
_DWORD *key,
int a5,
unsigned int a6,
int a7,
int a8,
int a9,
_OWORD *a10,
int mulEncryptionCode_1,
char a12)
{
_DWORD *v12; // edi
int v13; // esi
int v14; // edi
__int128 v15; // xmm0
unsigned int v16; // esi
int (__cdecl *cmcrypt2)(HCMSysEntry, int, CMCRYPT2 *, void *, int); // esi
int cbDest; // eax
int len; // eax
int v20; // ecx
int (__cdecl *v21)(void *, _DWORD, CMCRYPT *, __int128 *, int); // eax
int len_1; // esi
int (__cdecl *v23)(void *, unsigned int, int *, _OWORD *, int); // eax
_BYTE *v26; // [esp+24h] [ebp-29Ch] BYREF
__m128i v27[19]; // [esp+28h] [ebp-298h] BYREF
int v28; // [esp+158h] [ebp-168h]
int v29; // [esp+15Ch] [ebp-164h]
int v30; // [esp+160h] [ebp-160h]
int v31; // [esp+164h] [ebp-15Ch]
unsigned int v32; // [esp+168h] [ebp-158h]
unsigned int v33; // [esp+16Ch] [ebp-154h]
int v34; // [esp+170h] [ebp-150h]
int v35; // [esp+174h] [ebp-14Ch]
unsigned int mulEncryptionCode; // [esp+178h] [ebp-148h]
unsigned int v37; // [esp+17Ch] [ebp-144h]
unsigned int v38; // [esp+180h] [ebp-140h]
__int128 v39; // [esp+184h] [ebp-13Ch]
int v40; // [esp+194h] [ebp-12Ch]
CMCRYPT v41; // [esp+198h] [ebp-128h] BYREF
CMCRYPT2 pmacc; // [esp+1C0h] [ebp-100h] BYREF
__int128 pbDest[3]; // [esp+250h] [ebp-70h] BYREF
int v44[5]; // [esp+288h] [ebp-38h] BYREF
__int64 v45; // [esp+29Ch] [ebp-24h]
__int64 v46; // [esp+2A4h] [ebp-1Ch]
int v47; // [esp+2ACh] [ebp-14h]
int v48; // [esp+2BCh] [ebp-4h]
v12 = this;
if ( a12 )
{
memset((__m128i *)&v26, 0, 0x264u);
LOBYTE(v26) = 0;
v13 = key[6];
v14 = key[5];
memset(v27, 0, 0x128u);
init_aes(v27, 0);
sub_269EAB0((int)&v26, v14, v13);
v12 = this;
v15 = *(_OWORD *)(mulEncryptionCode_1 + 4);
mulEncryptionCode = *(_DWORD *)mulEncryptionCode_1;
v28 = a7;
v48 = 0;
v39 = v15;
v34 = 0;
v29 = key[8];
v30 = a8 ^ this[21];
v31 = a9;
v32 = a3 & 1;
v33 = ((a3 >> 8) & 1) << 26;
v35 = 0;
v16 = sub_25FA190(a5, -1);
v37 = sub_25FA190(a5, -1);
v40 = a5;
v38 = v16 & 0xFF00FFFF;
if ( sub_269DE30((char *)&v26, a10, 16) )
{
cmcrypt2 = (int (__cdecl *)(HCMSysEntry, int, CMCRYPT2 *, void *, int))this[5];
if ( cmcrypt2 && a6 >= 0x41E )
{
memset((__m128i *)&pmacc, 0, sizeof(pmacc));
pmacc.mcmBaseCrypt.mulEncryptionCode = mulEncryptionCode;
pmacc.mcmBaseCrypt.mulEncryptionCodeOptions = v31 ^ v38;
pmacc.mcmBaseCrypt.mflCtrl = 0x6000000;
pmacc.mcmBaseCrypt.mulFeatureCode = v37 ^ v28;
cbDest = sub_269EE70(&v26);
len = cmcrypt2(hcmse, 0, &pmacc, pbDest, cbDest);// cmcrypt2
}
else
{
if ( !v29 || (v20 = 56, v33 == 0x3000000) )
v20 = 40;
*(_QWORD *)&v41.mcmBaseCrypt.mflCtrl = 0i64;
v41.mcmBaseCrypt.mulEncryptionCode = mulEncryptionCode;
v41.mcmBaseCrypt.mulEncryptionCodeOptions = v31 ^ v38;
memset(&v41.mcmBaseCrypt.mulFeatureCode, 0, 24);
v41.mcmBaseCrypt.mulFeatureCode = v37 ^ v28;
v21 = (int (__cdecl *)(void *, _DWORD, CMCRYPT *, __int128 *, int))this[4];
v41.mcmBaseCrypt.mflCtrl = 100663296;
len = v21(hcmse, 0, &v41, pbDest, v20);
}
len_1 = len;
if ( len )
{
sub_25F97F0((int)v27); // success
*a10 = pbDest[0]; // pDest
}
}
else
{
len_1 = 0;
}
sub_269EAB0((int)&v26, 0, 0);
v48 = 1;
aes_final((int)v27);
v48 = -1;
}
else
{
v44[2] = a8 ^ this[21];
v44[3] = a9;
v44[4] = a7;
v23 = (int (__cdecl *)(void *, unsigned int, int *, _OWORD *, int))this[4];
v44[1] = 0;
v45 = 0i64;
v46 = 0i64;
v47 = 0;
v44[0] = ((a3 >> 8) & 1) << 26;
len_1 = v23(hcmse, a3 & 1, v44, a10, 16);
}
if ( !len_1 )
return sub_269E220((int)v12, (int)hcmse);
*(_BYTE *)a10 ^= *((_BYTE *)v12 + 84);
return 0;
} 发现是在 len = cmcrypt2(hcmse, 0, &pmacc, pbDest, cbDest); 处调用,观察CmCrypt2函数的参数会发现有几个疑点(这几个疑点将在服务端分析上揭晓) mcmBaseCrypt.mflCtrl = 0x6000000; 查看手册发现Wibu并未开放这个算法,姑且称之为AxProtector解密算法 mcmBaseCrypt.mulEncryptionCodeOptions mcmBaseCrypt.mulFeatureCode并未传入相应数据,推测为AxProtector解密算法的私有参数 IV key,AES Decrypt Key均未设置,cbDest长度恒为40,mcmBaseCrypt.mulEncryptionCode为固定值0x1337
现在有两个方向,向上去找对func_0的调用过程,向下通过CmCrypt2去服务端上找实现的算法 实际运行抓包发现 这是壳启动阶段最后两次调用Codemeter API,在调用完两次CmCrypt2之后程序即可启动,胜利就在眼前 CmCrypt2请求时附加了长度为0x28的待加密数据,服务器返回长度0x10的加密后的数据,加密后的数据覆盖在之前的数据上
最后于 2023-1-9 00:08
被ericyudatou编辑
,原因:
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
7 楼
AxProtectot所特有的0x600000Cmcrypt在服务器上的行为分析 参见Wibu Codemeter 7.3学习笔记——Codemeter服务端在api_cm_crypt处下断
void __cdecl api_cm_crypt2(
int flctrl,
CMCRYPT2 *cmcrypt2,
HCMSysEntry hcmse,
size_t cbDest,
size_t *a5,
void *pbDest,
void *pbDest_1,
int *a8,
char a9)
{
unsigned int len_1; // esi
int v10; // ecx
unsigned int v11; // edx
int v12; // eax
int *v13; // ecx
int mulKeyExtType; // esi
int *v15; // eax
int *v16; // esi
struct_cmcrypt *v17; // eax
bool v18; // zf
int v19; // ecx
int v20; // eax
__m128d v21; // xmm1
void *v22; // eax
_DWORD *v23; // eax
__int128 v24; // xmm0
void (__thiscall ***v25)(_DWORD, int); // ecx
_BYTE *v26; // ecx
size_t v27; // esi
void *v28; // eax
_DWORD *v29; // eax
void *v30; // edi
void ***v31; // eax
void ***v32; // eax
void ***v33; // eax
void ***v34; // eax
void ***v35; // eax
void ***v36; // eax
void ***v37; // eax
void ***v38; // esi
void ***v39; // edi
void ***v40; // eax
int errcode; // eax
void ***v42; // eax
HCMSysEntry hcmse_1; // [esp-10h] [ebp-794h]
int v44; // [esp-10h] [ebp-794h]
int v45; // [esp-Ch] [ebp-790h]
void *v46; // [esp-Ch] [ebp-790h]
void *v47; // [esp-Ch] [ebp-790h]
void ***v48; // [esp-Ch] [ebp-790h]
void ***v49; // [esp-Ch] [ebp-790h]
void ***v50; // [esp-Ch] [ebp-790h]
void ***v51; // [esp-Ch] [ebp-790h]
void ***v52; // [esp-Ch] [ebp-790h]
void ***v53; // [esp-Ch] [ebp-790h]
void ***v54; // [esp-Ch] [ebp-790h]
int v55; // [esp-Ch] [ebp-790h]
void ***v56; // [esp-Ch] [ebp-790h]
const void *v57; // [esp-8h] [ebp-78Ch]
const void *v58; // [esp-8h] [ebp-78Ch]
void ***v59; // [esp-8h] [ebp-78Ch]
void ***v60; // [esp-8h] [ebp-78Ch]
void ***v61; // [esp-8h] [ebp-78Ch]
void ***v62; // [esp-8h] [ebp-78Ch]
void ***v63; // [esp-8h] [ebp-78Ch]
void ***v64; // [esp-8h] [ebp-78Ch]
void ***v65; // [esp-8h] [ebp-78Ch]
void ***v66; // [esp-8h] [ebp-78Ch]
size_t v67; // [esp-4h] [ebp-788h]
size_t v68; // [esp-4h] [ebp-788h]
void ***v69; // [esp-4h] [ebp-788h]
void ***v70; // [esp-4h] [ebp-788h]
void ***v71; // [esp-4h] [ebp-788h]
void ***v72; // [esp-4h] [ebp-788h]
void ***v73; // [esp-4h] [ebp-788h]
void ***v74; // [esp-4h] [ebp-788h]
void ***v75; // [esp-4h] [ebp-788h]
void ***v76; // [esp-4h] [ebp-788h]
int v77; // [esp+0h] [ebp-784h] BYREF
char pExceptionObject[140]; // [esp+10h] [ebp-774h] BYREF
char v79[140]; // [esp+128h] [ebp-65Ch] BYREF
char v80[140]; // [esp+1B4h] [ebp-5D0h] BYREF
char v81[140]; // [esp+240h] [ebp-544h] BYREF
char v82[140]; // [esp+2CCh] [ebp-4B8h] BYREF
char v83[140]; // [esp+358h] [ebp-42Ch] BYREF
char v84[140]; // [esp+3E4h] [ebp-3A0h] BYREF
char v85[140]; // [esp+470h] [ebp-314h] BYREF
char v86[140]; // [esp+4FCh] [ebp-288h] BYREF
__int128 v87; // [esp+58Ch] [ebp-1F8h] BYREF
char v88[24]; // [esp+59Ch] [ebp-1E8h]
size_t len; // [esp+5B4h] [ebp-1D0h]
void *pbDest_3; // [esp+5B8h] [ebp-1CCh]
int v91; // [esp+5BCh] [ebp-1C8h]
int flctrl_1; // [esp+5C0h] [ebp-1C4h]
int *v93; // [esp+5C4h] [ebp-1C0h]
size_t *v94; // [esp+5C8h] [ebp-1BCh]
_DWORD *hcmse_2; // [esp+5CCh] [ebp-1B8h]
int v96; // [esp+5D0h] [ebp-1B4h]
_BYTE v97[356]; // [esp+5D4h] [ebp-1B0h] BYREF
struct_cmcrypt algorithms; // [esp+738h] [ebp-4Ch] BYREF
void *v99[2]; // [esp+75Ch] [ebp-28h] BYREF
void *pbDest_2; // [esp+764h] [ebp-20h] BYREF
void *encrypt_option; // [esp+768h] [ebp-1Ch] BYREF
unsigned int hcmse_3[3]; // [esp+76Ch] [ebp-18h] BYREF
int v103; // [esp+780h] [ebp-4h]
hcmse_3[2] = (unsigned int)&v77;
len_1 = cbDest;
flctrl_1 = flctrl;
hcmse_1 = *(HCMSysEntry *)hcmse;
hcmse_2 = hcmse;
v94 = a5;
pbDest_2 = pbDest;
v10 = *(_DWORD *)(global_1360FC4 + 196);
pbDest_3 = pbDest_1;
encrypt_option = cmcrypt2;
len = cbDest;
v93 = a8;
v11 = check_hcmse_handle(v10, hcmse_1, 0x10000, 1, 1);
hcmse_3[0] = v11;
if ( a9 )
++*(_DWORD *)(global_1360FC4 + 460);
else
++*(_DWORD *)(global_1360FC4 + 456);
*v94 = 0;
if ( (unsigned __int8)isReleaseMode(v11 + 328) )
{
if ( cbDest < 0x10 ) // 指定了一个无效的参数, 错误 105.cbDest太短
{
v70 = sub_BDE030();
v60 = sub_BDE030();
v49 = sub_BDE030();
v32 = sub_BDE030();
construct_Exception(v86, 105, (int)v32, (int)v49, (int)v60, (int)v70);
_CxxThrowException(v86, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
v91 = sub_BDB5A0((_DWORD *)(hcmse_3[0] + 328));
sub_C0EC70((_BYTE *)(hcmse_3[0] + 328));
v12 = v91;
if ( v91 )
{
v13 = *(int **)(v91 + 380);
v93 = v13;
v96 = 0;
hcmse_2 = v13;
if ( v13 )
{
v96 = v13[21];
v93 = v13;
hcmse_2 = v13;
}
}
else
{
v93 = 0;
hcmse_2 = 0;
v96 = 0;
v12 = 0;
}
if ( (*(_DWORD *)(v12 + 56) & 0x200) != 0
&& !sub_BFEE40((_BYTE *)global_1360FC4)
&& (*(_DWORD *)(hcmse_3[0] + 644) & 0x10000) != 0 )// TMP许可不支持此命令, 错误134.
{
v71 = sub_BDE030();
v61 = sub_BDE030();
v50 = sub_BDE030();
v33 = sub_BDE030();
construct_Exception(v85, 134, (int)v33, (int)v50, (int)v61, (int)v71);
_CxxThrowException(v85, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
if ( (cmcrypt2->mcmBaseCrypt.mflCtrl & 0xF) == 8 )// CM_CRYPT_UNIVERSALDATA
{ // UVD加密,不是研究的重点,忽略即可
/*
resolve_crypt_alg((unsigned int *)&encrypt_option, cmcrypt2->mcmBaseCrypt.mflCtrl & 0xFF000000);
mulKeyExtType = cmcrypt2->mcmBaseCrypt.mulKeyExtType;
sub_C59B10(v91, v99);
v103 = 0;
v15 = sub_D46E60((int ***)v99, mulKeyExtType);
v16 = v15;
if ( !v15 ) // 无法找到要求的产品码选项, 错误 26.
{
v72 = sub_BDE030();
v62 = sub_BDE030();
v51 = sub_BDE030();
v34 = sub_BDE030();
construct_Exception(v84, 26, (int)v34, (int)v51, (int)v62, (int)v72);
_CxxThrowException(v84, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
if ( !sub_D478C0((int)v15, (int)encrypt_option) )// 指定的产品码选项参数错误, 错误 25.
{
v73 = sub_BDE030();
v63 = sub_BDE030();
v52 = sub_BDE030();
v35 = sub_BDE030();
construct_Exception(v83, 25, (int)v35, (int)v52, (int)v63, (int)v73);
_CxxThrowException(v83, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
v45 = (int)v16;
len_1 = len;
v17 = sub_D46EB0(
(struct_cmcrypt *)((char *)&v87 + 4),
flctrl_1,
cmcrypt2,
len,
*(_DWORD *)(*(_DWORD *)(v96 + 244) + 832),
v45,
0,
0);
v103 = -1;
algorithms = *v17;
sub_BF8660(v99);
*/
}
else
{
//非UVD正常获取加密算法
algorithms = *(struct_cmcrypt *)cm_crypt_get_alg(
(int)&v87 + 4,
flctrl_1,
cmcrypt2,
cbDest,
*(_DWORD *)(*(_DWORD *)(v96 + 244) + 832),
0,
0);
}
hcmse_3[0] = sub_C0EC30((_DWORD *)(hcmse_3[0] + 328), 0x700);
encrypt_option = (void *)(cmcrypt2->mcmBaseCrypt.mulEncryptionCodeOptions & 0xF0000);
if ( sub_BFEE40((_BYTE *)global_1360FC4) )
goto LABEL_27;
if ( encrypt_option == (void *)0x20000 ) // CM_CRYPT_SASTATIONSHARE
{
v18 = hcmse_3[0] == 768;
}
else
{
if ( encrypt_option != (void *)0x40000 )
{
if ( encrypt_option == (void *)0x80000 )
{
v18 = hcmse_3[0] == 512;
goto LABEL_26;
}
LABEL_27:
if ( (cmcrypt2->mcmBaseCrypt.mflCtrl & 0x20000) != 0 )// calc crc
{
init_crc(hcmse_3);
crc32(hcmse_3, (char *)pbDest_3, algorithms.cbDest_);
cmcrypt2->mcmBaseCrypt.mulCrc = bit_negration(hcmse_3);
}
if ( (flctrl_1 & 0xF) == 2 )
{
v19 = *(_DWORD *)(v96 + 20);
if ( !v19 || v19 != v93[1] )
{
v75 = sub_BDE030();
v65 = sub_BDE030();
v54 = sub_BDE030();
v37 = sub_BDE030();
construct_Exception(v81, 123, (int)v37, (int)v54, (int)v65, (int)v75);// CmDongle没有CTSB功能模块, 错误 123.
_CxxThrowException(v81, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
}
v103 = 1;
if ( !do_crypt_job(v96, v91, &algorithms, pbDest_2, pbDest_2) ) //进行加解密
{
v38 = sub_BDE030();
v39 = sub_BDE030();
encrypt_option = sub_BDE030();
v40 = sub_BDE030();
v55 = (int)encrypt_option;
v44 = (int)v40;
errcode = sub_C4B310(*(_DWORD **)(v96 + 244));
construct_Exception(v80, errcode, v44, v55, (int)v39, (int)v38);
_CxxThrowException(v80, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
v103 = -1;
if ( algorithms.algorithms == 2 || algorithms.algorithms == 3 )
*v94 = len_1;
else
*v94 = algorithms.cbDest_;
if ( (cmcrypt2->mcmBaseCrypt.mflCtrl & 0x10000) != 0 )// CM_CRYPT_CHKCRC
{
init_crc(&pbDest_2);
crc32((unsigned int *)&pbDest_2, (char *)pbDest_3, len_1);
if ( cmcrypt2->mcmBaseCrypt.mulCrc != bit_negration(&pbDest_2) )
{
*v94 = 0;
v76 = sub_BDE030();
v66 = sub_BDE030();
v56 = sub_BDE030();
v42 = sub_BDE030();
construct_Exception(v79, 203, (int)v42, (int)v56, (int)v66, (int)v76);// 校验数据检测失败, 错误 203.
_CxxThrowException(v79, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
}
return;
}
if ( !hcmse_3[0] )
goto LABEL_27;
v18 = hcmse_3[0] == 1024;
}
LABEL_26:
if ( !v18 )
{
v74 = sub_BDE030();
v64 = sub_BDE030();
v53 = sub_BDE030();
v36 = sub_BDE030();
construct_Exception(v82, 223, (int)v36, (int)v53, (int)v64, (int)v74);// 所使用的访问模式与EncryptionCodeOption集冲突, 错误 223.
_CxxThrowException(v82, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
goto LABEL_27;
}
if ( !sub_C0ED00((_DWORD *)(hcmse_3[0] + 328)) )
{
v69 = sub_BDE030();
v59 = sub_BDE030();
v48 = sub_BDE030();
v31 = sub_BDE030();
construct_Exception(pExceptionObject, 116, (int)v31, (int)v48, (int)v59, (int)v69);// 给出的句柄指向了一个未定义的子系统, 错误 116.
_CxxThrowException(pExceptionObject, (_ThrowInfo *)&_TI2_AVException_wbs__);
}
v20 = sub_C0EC20((_DWORD *)(hcmse_3[0] + 328));
*hcmse_2 = v20;
//Wubu Codemeter内部调试时用的代码,忽略
/*
if ( a9 )
{
memset(v97, 0, sizeof(v97));
sub_CCC4F0(v97);
v103 = 4;
*(_DWORD *)&v97[40] = *hcmse_2;
*(_DWORD *)&v97[44] = flctrl_1;
qmemcpy(&v97[48], cmcrypt2, 0x90u);
v27 = len;
*(_DWORD *)&v97[192] = len;
sub_C37B30(*(int *)&v97[352], len);
if ( *(_DWORD *)(*(_DWORD *)&v97[352] + 8) )
v28 = *(void **)(*(_DWORD *)&v97[352] + 4);
else
v28 = 0;
*(_DWORD *)&v97[196] = v28;
memmove(v28, pbDest_2, *(size_t *)&v97[192]);
*(_DWORD *)&v97[348] = *(_DWORD *)&v97[196];
v29 = (_DWORD *)sub_C0EC10((_DWORD *)(hcmse_3[0] + 328));
cm_client_encrypt_req(v29, v97, 0xA1u, v27 + 164, v27 + 156);
v68 = *(_DWORD *)&v97[192];
v58 = *(const void **)&v97[348];
v30 = encrypt_option;
v47 = pbDest_3;
*v93 = *(_DWORD *)&v97[8];
qmemcpy(v30, &v97[204], 0x90u);
memmove(v47, v58, v68);
*(_DWORD *)&v97[348] = 0;
*(_DWORD *)v97 = &YS0534::`vftable';
*v94 = *(_DWORD *)&v97[200];
if ( *(_DWORD *)&v97[352] )
(***(void (__thiscall ****)(_DWORD, int))&v97[352])(*(_DWORD *)&v97[352], 1);
*(_DWORD *)&v97[348] = 0;
v26 = v97;
}
else
{
memset(&v97[208], 0, 0x94u);
sub_CCC160();
v21 = *(__m128d *)cmcrypt2->mabInitKey;
LODWORD(v87) = cmcrypt2->mcmBaseCrypt.mflCtrl;
*(_DWORD *)&v88[4] = cmcrypt2->mcmBaseCrypt.mulCrc;
*((_QWORD *)&v87 + 1) = *(_QWORD *)&cmcrypt2->mcmBaseCrypt.mulEncryptionCode;
*(_DWORD *)v88 = cmcrypt2->mcmBaseCrypt.mulFeatureCode;
DWORD1(v87) = cmcrypt2->mcmBaseCrypt.mulKeyExtType;
*(__m128d *)&v88[8] = v21;
*(_OWORD *)&v97[256] = v87;
*(_DWORD *)&v97[248] = *hcmse_2;
v103 = 3;
*(_DWORD *)&v97[252] = flctrl_1;
*(_OWORD *)&v97[272] = *(_OWORD *)v88;
*(_DWORD *)&v97[296] = cbDest;
*(_QWORD *)&v97[288] = *(_OWORD *)&_mm_unpackhi_pd(v21, v21);
sub_C37B30(*(int *)&v97[352], cbDest);
if ( *(_DWORD *)(*(_DWORD *)&v97[352] + 8) )
v22 = *(void **)(*(_DWORD *)&v97[352] + 4);
else
v22 = 0;
*(_DWORD *)&v97[300] = v22;
memmove(v22, pbDest_2, *(size_t *)&v97[296]);
*(_DWORD *)&v97[348] = *(_DWORD *)&v97[300];
v23 = (_DWORD *)sub_C0EC10((_DWORD *)(hcmse_3[0] + 328));
cm_client_encrypt_req(v23, &v97[208], 0xA1u, cbDest + 60, cbDest + 52);
v67 = *(_DWORD *)&v97[296];
v57 = *(const void **)&v97[348];
v46 = pbDest_3;
*v93 = *(_DWORD *)&v97[216];
memmove(v46, v57, v67);
v24 = *(_OWORD *)&v97[332];
*(_DWORD *)&v97[348] = 0;
*v94 = *(_DWORD *)&v97[304];
v25 = *(void (__thiscall ****)(_DWORD, int))&v97[352];
cmcrypt2->mcmBaseCrypt.mflCtrl = *(_DWORD *)&v97[308];
cmcrypt2->mcmBaseCrypt.mulCrc = *(_DWORD *)&v97[328];
cmcrypt2->mcmBaseCrypt.mulEncryptionCode = *(_DWORD *)&v97[316];
cmcrypt2->mcmBaseCrypt.mulEncryptionCodeOptions = *(_DWORD *)&v97[320];
cmcrypt2->mcmBaseCrypt.mulFeatureCode = *(_DWORD *)&v97[324];
cmcrypt2->mcmBaseCrypt.mulKeyExtType = *(_DWORD *)&v97[312];
*(_DWORD *)&v97[208] = &YS0059::`vftable';
*(_OWORD *)cmcrypt2->mabInitKey = v24;
if ( v25 )
(**v25)(v25, 1);
*(_DWORD *)&v97[348] = 0;
v26 = &v97[208];
}
*/
sub_D28150(v26);
}
/* Orphan comments:
Key Source FIRMKEY HIDDENDATA SECRETDATA
*/ 参数等经过经过简单的处理后被传入do_crypt_job中 int __thiscall do_crypt_job(int this, int a2, struct_cmcrypt *algorithms, void *len, void *pdest_1)
{
__int16 *v7; // ebp
int v8; // ebp
int v10; // [esp+14h] [ebp-4h]
int v11; // [esp+1Ch] [ebp+4h]
if ( a2 )
v7 = *(__int16 **)(a2 + 380);
else
v7 = 0;
v11 = sub_CAFC00(a2, (unsigned __int8 (__thiscall *)(int))sub_C5B150);
sub_CAFC00(a2, (unsigned __int8 (__thiscall *)(int))sub_C5B140);
v10 = *(_DWORD *)(v11 + 16);
v8 = do_crypt_job_0(
*(void **)(this + 244),
*v7,
*(_WORD *)(a2 + 4),
algorithms,
len,
pdest_1,
v7 + 8,
(_DWORD *)(v11 + 16));
if ( !v8 )
return v8;
sub_C58C50(v11);
sub_C589C0();
sub_C80590(a2, algorithms, this);
if ( v10 != *(_DWORD *)(v11 + 16) )
sub_C0DE40(2048);
if ( !*(_BYTE *)(this + 241) && !*(_BYTE *)(this + 240) )
return v8;
if ( len )
*(_WORD *)len = 0;
*(_DWORD *)(*(_DWORD *)(this + 244) + 908) = 21;
return 0;
}
int __thiscall do_crypt_job_0(
void *this,
__int16 a2,
__int16 a3,
struct_cmcrypt *algorithms,
void *len,
void *pdest_1,
_WORD *a7,
_DWORD *a8)
{
int algorithms_1; // eax
int v9; // esi
struct_v18 *v10; // ecx
unsigned int v11; // eax
__int16 v12; // si
__int16 v13; // cx
__int16 cbDest; // ax
unsigned int v15; // ecx
struct_v18 *Block; // [esp+1Ch] [ebp-60h]
struct_v18 *v18; // [esp+24h] [ebp-58h]
unsigned int v19; // [esp+28h] [ebp-54h]
int v21; // [esp+2Ch] [ebp-50h]
void *Src; // [esp+34h] [ebp-48h]
char v23; // [esp+3Bh] [ebp-41h]
v23 = 0;
(*(void (__thiscall **)(void *))(*(_DWORD *)this + 56))(this);
algorithms_1 = algorithms->algorithms;
v9 = algorithms->cbDest + 27;
if ( (!algorithms->algorithms || algorithms_1 == 1 || algorithms_1 == 5)
&& (algorithms->mulSecondsSince01_01_2000 || (algorithms->mulEncryptionCodeOptions & 0xF00000) == 0x100000) )
{
v9 = algorithms->cbDest + 31;
v23 = 1;
}
v19 = (v9 + 19) & 0xFFFFFFF0;
if ( v19 )
{
v10 = (struct_v18 *)operator new[]((v9 + 19) & 0xFFFFFFF0);
v11 = (v9 + 19) & 0xFFFFFFF0;
}
else
{
v10 = 0;
v11 = 0;
}
Block = v10;
if ( !v11 )
v10 = 0;
v18 = v10;
*(_WORD *)v10->gap0 = v9;
v12 = 1;
v10->gap0[4] = 2;
v13 = 1;
if ( !BYTE2(algorithms->mulKeyExtType) )
v13 = a3;
if ( !BYTE2(algorithms->mulKeyExtType) )
v12 = a2;
v18->word5 = v12;
v18->word7 = v13;
v18->keySource = algorithms->keySource;
if ( BYTE1(algorithms->mulKeyExtType) )
v18->keySource |= 0x8000u;
v18->mulKeyExtType = algorithms->mulKeyExtType;
v18->algorithms = algorithms->algorithms;
v18->mulFeatureCode = algorithms->mulFeatureCode;
v18->mulEncryptionCode = algorithms->mulEncryptionCode;
v18->mulEncryptionCodeOptions = algorithms->mulEncryptionCodeOptions;
cbDest = algorithms->cbDest;
v18->cbDest = cbDest;
if ( v23 )
{
v18->keySource |= 0x4000u;
v18->cbDest = cbDest + 4;
*(_DWORD *)&v18->pbDest = algorithms->mulSecondsSince01_01_2000;
memmove(&v18->pbDest1, pdest_1, algorithms->cbDest);
}
else
{
memmove(&v18->pbDest, pdest_1, algorithms->cbDest);
}
v15 = (algorithms->cbDest_ + 29) & 0xFFFFFFF0;
Src = (void *)v15;
if ( v15 )
{
if ( v15 > 0x7FFFFFFF )
sub_BD9DE0();
sub_BED070(v15);
memset(0, 0, (size_t)Src);
v15 = (unsigned int)Src;
}
if ( (*(int (__thiscall **)(void *, struct_v18 *, unsigned int, _DWORD, unsigned int, int, _DWORD, _DWORD, _DWORD, _DWORD))(*(_DWORD *)this + 12))(// cm_encrypt_alg
// func_interested
this,
v18,
v19,
0,
v15,
0x400000,
0,
0,
0,
0) )
{
*a7 = MEMORY[6];
*a8 = MEMORY[2];
memmove(len, (const void *)0xA, algorithms->cbDest_);
v21 = MEMORY[8];
}
else
{
v21 = 0;
}
if ( Block )
j_j__free(Block);
sub_BDCCA0();
return v21;
} do_crypt_job中做事不多,转交给do_crypt_job_0,再由do_crypt_job_0进行转发至相应的算法。 值得注意的是,在正常的请求下(mflCtrl为CM_CRYPT_AES,CM_CRYPT_ECIES等),会被转发到cm_encrypt_alg。服务端大多数注意安全性的算法都转发到这个函数进行加解密操作。这种正常的CmCrypt之后会在Wibu Codemeter 7.3学习笔记——Codemeter服务端上说 而对于mfCtrl = 0x6000000这个AxProtector壳特有的则被转发到func_interested(暂且这么命名)进行处理。 unsigned int __thiscall func_interested(
_BYTE *this,
struct_v18 *a2,
size_t a3,
void *a4,
int a5,
unsigned int a6,
int a7,
char a8,
int a9,
char a10)
{
int v11; // eax
unsigned int v12; // esi
int v14; // [esp+0h] [ebp-3Ch] BYREF
struct_v18 *v15; // [esp+10h] [ebp-2Ch]
void *v16; // [esp+14h] [ebp-28h]
int v17; // [esp+18h] [ebp-24h]
_BYTE *v18; // [esp+1Ch] [ebp-20h]
int v19; // [esp+20h] [ebp-1Ch] BYREF
int v20[3]; // [esp+24h] [ebp-18h] BYREF
int v21; // [esp+38h] [ebp-4h]
v20[2] = (int)&v14;
v15 = a2;
v16 = a4;
v18 = this;
v17 = a9;
if ( !a8 && !this[964] && !(*(unsigned __int8 (__thiscall **)(_BYTE *))(*(_DWORD *)this + 48))(this) )
{
v20[0] = 0;
v11 = *(_DWORD *)this;
v21 = 0;
LOBYTE(v19) = 0;
(*(void (__thiscall **)(_BYTE *, int *))(v11 + 32))(this, &v19);
sub_D51FD0(v19);
this[964] = 1;
v21 = -1;
}
v20[0] = 0;
sub_BE9A20((int)(this + 904));
v21 = 2;
v12 = func_1(this, v15, a3, v16, a5, a6, a7, a8, v17, a10);
sub_BE9A90(v20);
return v12;
} 而func_interested又转发到func_1(暂且这么命名),这个func_1便是真正做事的地方
(func_1挺大的,过几天更)
最后于 2023-1-9 00:47
被ericyudatou编辑
,原因:
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
8 楼
func_1 
大工程,慢慢更 对传入的pbDest下内存断点,断下三次后在对func_1复制过的pbDest下内存断点,跟踪,运行,这里显示的值是pbDest的第一位 
在这次运行中,原始传入的40字节pbDest如下图蓝框中,第一位为0x6E

加密后的pbDest如下图,前是16为加密后的结果(红框),后面的则是原始pbDest填充,第一位为0x55

一眼丁真的发现(其实是经历很多测试),加密前后的pbDest是跟内存断点跟踪的结果是相同的,并且是有个这样的过程 0x6E(原始)-->0x64 --->0x59 -->0x55(结果) 大概这个算法分为三个阶段,并且不太可能使用太过复杂的算法
(未完待续)
最后于 2023-1-10 00:37
被ericyudatou编辑
,原因:
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
9 楼
书接上回,通过内存断点发现真正做事的函数func_2,对于func_1和func_1是怎么调用到func_2不必深究,只需要知道ecx+399是pbDest,ecx+397是cbDest即可。整个函数挺大的,不方便贴伪代码贴全。分析可得,整个加密过程分为两轮。因为我也不是专业做逆向的,找不到趁手的跟踪方法,故只能边录屏边F8,视频放最后。 第一轮
case 7: // axprotector 0x6000000 round 1
p_pbDest_1 = pbDest;
sub_7FA840(this, 0, 0);
sub_753900(this->pvoid5E4, this->dword13E);
sub_753800(this->pvoid5E4, this->arr.mulEncryptionCode);
sub_753870(this->pvoid5E4, 2);
nullsub_1(this->pvoid5E4);
sub_753B00(this->pvoid5E4);
nullsub_1(this->pvoid5E4);
arg_interested = sub_7536C0(this->pvoid5E4);
pbDest_1_1 = p_pbDest;
*arg_interested = *p_pbDest;
*(arg_interested + 1) = *(pbDest_1_1 + 4);
*(arg_interested + 2) = this->dword144;
*(arg_interested + 3) = this->dword13E;
sub_7533E0(this->pvoid5E4, arg_interested);
nullsub_1(this->pvoid5E4);
nullsub_1(this->pvoid5E4);
sub_7537E0(arg_interested); // aes job
sub_753720(this->pvoid5E4);
crypt_job_1(this->pvoid5E4, p_pbDest + 8, len_4 - 8);// crypt job 1,进行加密 change round 1 9~40
nullsub_1(this->pvoid5E4);
pbDest_4 = p_pbDest;
this->arr.keySource = *(p_pbDest + 4); //准备下一轮参数
this->arr.mulKeyExtType = *(pbDest_4 + 10);
this->arr.algorithms = *(pbDest_4 + 11);
this->arr.mulFeatureCode ^= *(pbDest_4 + 12);
this->arr.mulEncryptionCode = *(pbDest_4 + 16);
this->arr.mulEncryptionCodeOptions ^= *(pbDest_4 + 20);// init arg for round 2
len_3 = cbDest_1;
if ( v116 )
{
pbDest = &this->arr.pbDest1;
cbDest_1 += 65496;
memmove(&this->arr.pbDest1, (pbDest_4 + 40), (len_3 - 40));
pbDest_5 = p_pbDest;
p_pbDest = &this->arr.pbDest1;
*&this->arr.pbDest = pbDest_5[6];
}
else
{
pbDest = &this->arr.pbDest; // here
cbDest_1 += 65512;
p_pbDest = &this->arr.pbDest;
memmove(&this->arr.pbDest, p_pbDest_1 + 24, (len_3 - 24));// changed 2 0~15
// 把后16位复制到前16位
}
v131 = -1; // changed_1
nullsub_1(&v121);
v6 = cbDest_1;
continue; // to round 2 简单的分析可知,round 1做的事就是通过crypt_job_1加密pbDest的9~40位,然后再将操作后的最后16位复制到前16位。并且准备下一轮的参数。 对于其中第一轮加密,首先对一个结构体(暂称之为round1aes1)前55位求SHA256散列值的前16位作为AES加密的密钥,再将pDest前8位拼接Firm Code,Product Code作为明文,进行AES_CBC_128的加密(iv = 0),其结果的前16位作为参数参与到crypt_job_1中
struct round1aes1{
DWORD constant1 = 0x77****E5;//<-----------与firm code相关
DWORD constant2 = 0xB5****9F;
DWORD constant3 = 0x66****C0;
DWORD constant4 = 0x52****66;
DWORD FirmCode = 0;
DWORD ProductCode = 0;
DWORD gap1 = 0;
DWORD EncryptionCode = 0x1337;
DWORD gap2 = 0;
DWORD constant_round = 2;
DWORD gap3 = 0;
DWORD gap4 = 0;
DWORD gap5 = 0;
DWORD gap6 = 0x00000000;
}round1aes1; 值得注意的是,对于同一个公司的产品(Firm Code相同),所对应的constant1~4相同,不随机器特征码改变,为常量。且不与Firm Code存在关系,为公司指定的(随机生成的)数据。不存在与客户端AxProtector程序上,只存在服务器Codemeter上。因此,对AxProtector保护的程序脱壳必须有一个合法的授权才能对程序进行解密 第一轮:crypt_job_1void __thiscall crypt_job_1(void *this, _OWORD *pBuf, int len)
{
char *v3; // ebp
unsigned int v5; // ebx
char *v6; // esi
int v7; // ecx
int v8; // edx
char v9; // al
char *lena; // [esp+Ch] [ebp+8h]
if ( len )
{
v3 = this + 320;
v5 = ((len - 1) >> 4) + 1;
lena = this + 2422;
do
{
v6 = sub_5A8310(v3);
*v6 = *pBuf;
sub_5A8350(v3);
v7 = 16;
v8 = lena - v6;
do
{
v9 = (v6++)[v8];
*(v6 - 1) ^= v9;
v6[v8 - 1] = *pBuf;
*pBuf = *(v6 - 1);
pBuf = (pBuf + 1);
--v7;
}
while ( v7 );
--v5;
}
while ( v5 );
}
} crypt_job_1这个函数比较简单,不多赘述。传入pDest 9~40位(32)和上一步AES加密出来的前16位,简单的位运算,然后准备下一轮的参数,并将pDest最后16位复制到前16位。 this->arr.keySource = *(p_pbDest + 4); //准备下一轮参数
this->arr.mulKeyExtType = *(pbDest_4 + 10);
this->arr.algorithms = *(pbDest_4 + 11);
this->arr.mulFeatureCode ^= *(pbDest_4 + 12);
this->arr.mulEncryptionCode = *(pbDest_4 + 16);
this->arr.mulEncryptionCodeOptions ^= *(pbDest_4 + 20);// init arg for round 1
最后于 2023-1-25 03:13
被ericyudatou编辑
,原因:
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
10 楼
第二轮 ……
if ( !gen_firm_product_code(this, this->arr.word7, this->arr.keySource) )// set seed1 seed2
//
// seed1 4C4D0Eh 来自firm item
// seed2 100000h
……
LABEL_101:
gen_aes_constant(this, 0, flag_sd_b_1 ? 59 : 0);// round 2
set_aes_productcode(*(void **)((char *)&this->aes_job + 2), this->produccode);// product code
set_aes_featurcode(
*(void **)((char *)&this->aes_job + 2),
*(_DWORD *)((char *)&this->arr.mulFeatureCode + 2));
set_aes_encryptioncode(
*(void **)((char *)&this->aes_job + 2),
*(_DWORD *)((char *)&this->mulEncryptionCode + 2));
set_aes_encryptioncodeoption(
*(void **)((char *)&this->aes_job + 2),
*(_DWORD *)((char *)&this->mulEncryptionCodeOptions + 2));
if ( flag_sd_b_1 ) // round2 0
sub_C33950(*(int **)((char *)&this->aes_job + 2), *(_DWORD *)&this->arr.gap1C[1]);
if ( this->algorithms == 5 )
set_aes_type_constant(*(void **)((char *)&this->aes_job + 2), 1);
v32 = *(void **)((char *)&this->aes_job + 2);
if ( *(__int16 *)&this->arr.mulKeyExtType >= 0 )
{
nullsub_1(v32);
aes_job_1 = *(BYTE **)((char *)&this->aes_job + 2);
if ( algorithms_3 )
{
if ( this->algorithms == 5 )
doAesKeySHA_0(aes_job_1, this->constant_round2aes1);
else
doAesKeySHA(aes_job_1);
}
else
{
doAesKey(aes_job_1);
}
if ( (*(_DWORD *)((_BYTE *)&this->mulEncryptionCodeOptions + 2) & 0x200000) != 0 )
{
v35 = *(void **)((char *)&this->aes_job + 2);
this->word4E = 40;
nullsub_1(v35);
nullsub_1(&v122);
return;
}
if ( this->algorithms == 5 && func_key_changed_3(pbDest, (int)this->constant_round2aes1, 16) )
{
*(_WORD *)this->gap166 = 0;
gen_rand_arr(pbDest, 0x10u); // fuck up
}
func2_aes_encrypt(*(char **)((char *)&this->aes_job + 2), pbDest);
nullsub_1(*(void **)((char *)&this->aes_job + 2));
}
else
{
nullsub_1(v32);
aes_job_2 = *(int (__cdecl ***)(int, int, int, int, int))((char *)&this->aes_job + 2);
if ( algorithms_3 )
{
if ( this->algorithms == 5 )
doAesKeySHA_2((int)aes_job_2, this->constant_round2aes1);// here
else
doAesKeySHA_1((int)aes_job_2);
}
else
{
sub_C33AC0(aes_job_2);
}
func_key_changed_2(*(char **)((char *)&this->aes_job + 2), pbDest);// round2 key change 1 前16位
nullsub_1(*(void **)((char *)&this->aes_job + 2));
if ( this->algorithms == 5 && func_key_changed_3(pbDest, (int)this->constant_round2aes1, 16) )
{
*(_WORD *)this->gap166 = 0;
gen_rand_arr(pbDest, 0x10u); // fuck up
}
}
if ( algorithms_org == 7 )
{
key2 = sub_C336C0(*(char **)((char *)&this->aes_job + 2));// final
nullsub_1(*(void **)((char *)&this->aes_job + 2));
set_aes_key(*(int (__cdecl ***)(int, int, int, int, int))((char *)&this->aes_job + 2), (int)key2);
nullsub_1(*(void **)((char *)&this->aes_job + 2));
pbDest = p_pbDest;
func_key_changed_2(*(char **)((char *)&this->aes_job + 2), p_pbDest);// round2 key change 2
nullsub_1(*(void **)((char *)&this->aes_job + 2));
}
crypt_job_2(this, pbDest, *(unsigned __int16 *)len_5);
sub_CD8B20(this);
LOBYTE(this->aes_job) = 0;
return; crypt_job_2并没有参与到加密数据的加密过程中,故不研究 首先还是声明一个结构体round2aes1,对其前55位求SHA256散列值,取散列值前16位作为第一次AES解密的密钥 接着是对pDest前16位进行第一次AES_CBC_128解密(iv=0),密钥为散列值前16位。 坠吼是对pDest前16位进行第一次AES_CBC_128解密(iv=0),密钥为第一轮第一次AES加密所生成的密文的前16位。 此时pDest的前16位就是我们想要的数据了。 struct round2aes1 {
DWORD constant1 = 0x4E****74; //CmAct私钥
DWORD constant2 = 0x4E****7C;
DWORD constant3 = 0x78****C1;
DWORD constant4 = 0xFE****22;
DWORD FirmCode = 0;
DWORD ProductCode = 0;
DWORD FeatureCode = 0;
DWORD EncryptionCode = 0;
DWORD EncryptionCodeOption = 0;
DWORD constant_round = 1;
DWORD gap3 = 0;
DWORD gap4 = 0;
DWORD gap5 = 0;
DWORD gap6 = 0x80000000;
}round2aes1; 需要注意的是这里的FirmCode,Product Code等参数都是经过第一轮加密变换的。 值得注意的是,对于同一个公司的同一个产品(Firm Code,Product Code相同),所对应的constant1~4相同,为这个产品的ECDSA私钥前16位。 AxProtectot-Codemeter保护系统的强度不体现在其纸老虎似的ECDSA,唬人的反调试,哈人的"毁狗",还是那略显迷惑的通信算法,而是在于公司的私钥和产品的私钥。 这两个私钥不仅仅参与到他们所对应的非对称加密算法(ECDSA),还参与到普通的对称加密算法,可执行文件的解密过程中,使得没有可用授权的破解变为不可能,破解这个AxProtectot-Codemeter保护系统必须得有一个可用的授权 附加一份加密过程的日志 [*]Client encrypted package
[*]Encrypted package decrypt:SUCCESS,len:204,time:47754
[*]Function Request:CmCrypt2
[*]HCMSE 2,flCtrl 0,mflCtrl 06000000,feature code 2924a1dd,crc 0,mulEncryptionCode 00001337 mulEncryptionCodeOptions 51023a51
[*]pDest:(40)
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc2 ffffffe1 ffffffd4 34 30 47 ffffffa9 ffffff94 ffffff99 40 ffffffe2 26 ffffffd3 ffffffcd 75 ffffffcb
[*]ffffffe3 ffffff96 ffffffe0 67 0d ffffffc2 21 ffffffba 23 44 fffffff6 ffffff95 0b 7c ffffffa2 ffffffb4
[*]3f ffffff91 72 25 4b 7a 28 ffffffd1
[*]----------------------------------------------END------------------------------------------------------
[*]InitKey:(16)
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*]DirectAesKey:(16)
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*]Mode:Direct encryption
[*]Key Source: Firmware Key
[*]Encryption Algorithm: Unknown 100663296
[*][CmCrypt2]AxProtectot CmCrypt 0x6000000 function start,Firm Code 5000462,Product Code 3
[*][CmCrypt2]AxProtectot C6F Round 1 AES JOB 1 Start
[*][CmCrypt2]AxProtectot C6F Round 1 AES JOB 1 SHA256
[*][CmCrypt2]AxProtectot C6F Round 1 AES JOB 1 AES key:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]3e fffffffb 7d 2e ffffff95 21 ffffff96 7d ffffffa5 1e ffffff82 ffffffa5 ffffffdc 5a 5f 4b
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 AES JOB 1 AES plain text:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc2 ffffffe1 ffffffd4 34 30 47 ffffffa9 ffffff94 0e 4d 4c 00 03 00 00 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 AES JOB 1 AES result(Also Round 1 AES JOB 2 Key):
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc0 69 ffffffe1 ffffffa2 ffffffd1 ffffffa6 51 ffffffc9 16 ffffffb2 68 58 41 ffffffa4 0c 59
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 start
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Start
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffff99 40 ffffffe2 26 ffffffd3 ffffffcd 75 ffffffcb ffffffe3 ffffff96 ffffffe0 67 0d ffffffc2 21 ffffffba
[*]23 44 fffffff6 ffffff95 0b 7c ffffffa2 ffffffb4 3f ffffff91 72 25 4b 7a 28 ffffffd1
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 1 AES reslut->pplaintext
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 ffffff80 00 05 ffffffdd ffffffa3 24 29 11 ffffff84 6b 36 51 3a 00 51
[*]00 ffffff80 00 05 ffffffdd ffffffa3 24 29 11 ffffff84 6b 36 51 3a 00 51
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 1 Result->pInBufOrg
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 ffffff80 00 05 ffffffdd ffffffa3 24 29 11 ffffff84 6b 36 51 3a 00 51
[*]23 44 fffffff6 ffffff95 0b 7c ffffffa2 ffffffb4 3f ffffff91 72 25 4b 7a 28 ffffffd1
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 1 Result->pplaintext
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 ffffff80 00 05 ffffffdd ffffffa3 24 29 11 ffffff84 6b 36 51 3a 00 51
[*]45 ffffffe8 ffffff9b ffffffd6 08 fffffffb 2c 03 ffffffd5 ffffff83 1d 00 fffffff4 fffffffa 2c 03
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 1 Result->pbuf
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffff99 40 ffffffe2 26 ffffffd3 ffffffcd 75 ffffffcb ffffffe3 ffffff96 ffffffe0 67 0d ffffffc2 21 ffffffba
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 2 AES reslut->pplaintext
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc9 0b 32 ffffff92 27 47 71 54 ffffffd4 ffffffc0 26 ffffff8a 7a 78 ffffffc6 46
[*]ffffffc9 0b 32 ffffff92 27 47 71 54 ffffffd4 ffffffc0 26 ffffff8a 7a 78 ffffffc6 46
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 2 Result->pInBufOrg
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 ffffff80 00 05 ffffffdd ffffffa3 24 29 11 ffffff84 6b 36 51 3a 00 51
[*]50 4b ffffffd0 ffffffb4 fffffff4 ffffff8a 04 ffffff9f 37 56 ffffffc6 ffffffed 77 ffffffba ffffffe7 fffffffc
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 2 Result->pplaintext
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]45 ffffffe8 ffffff9b ffffffd6 08 fffffffb 2c 03 ffffffd5 ffffff83 1d 00 fffffff4 fffffffa 2c 03
[*]7c fffffff2 2c 03 20 00 00 00 10 41 1d 00 10 41 1d 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 Round 2 Result->pbuf
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]23 44 fffffff6 ffffff95 0b 7c ffffffa2 ffffffb4 3f ffffff91 72 25 4b 7a 28 ffffffd1
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 crypt_job_1 done!result:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc2 ffffffe1 ffffffd4 34 30 47 ffffffa9 ffffff94 00 ffffff80 00 05 ffffffdd ffffffa3 24 29
[*]11 ffffff84 6b 36 51 3a 00 51 50 4b ffffffd0 ffffffb4 fffffff4 ffffff8a 04 ffffff9f
[*]37 56 ffffffc6 ffffffed 77 ffffffba ffffffe7 fffffffc
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 1 result:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]50 4b ffffffd0 ffffffb4 fffffff4 ffffff8a 04 ffffff9f 37 56 ffffffc6 ffffffed 77 ffffffba ffffffe7 fffffffc
[*]11 ffffff84 6b 36 51 3a 00 51 50 4b ffffffd0 ffffffb4 fffffff4 ffffff8a 04 ffffff9f
[*]37 56 ffffffc6 ffffffed 77 ffffffba ffffffe7 fffffffc
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 Start,keySource 8000 KeyExtType 00 FeatureCode 200 EncryptionCode 366b8411 EncryptionCodeOptions 20000 alogrithm 05
[*][CmCrypt2]AxProtectot C6F Round 2 Serving Gasturb Smooth C
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 1 SHA256
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffcc ffffff8e 62 60 ffffffae ffffff8c ffffffad ffffff91 ffffffca 3b ffffffbd ffffffa8 fffffff4 7d 31 ffffffa5
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 1 pDest (16):
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]50 4b ffffffd0 ffffffb4 fffffff4 ffffff8a 04 ffffff9f 37 56 ffffffc6 ffffffed 77 ffffffba ffffffe7 fffffffc
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 1 Result:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]17 fffffff0 7c ffffff99 ffffffca ffffffca ffffffbf 25 10 54 ffffffd0 46 ffffffe4 ffffffa2 63 ffffff94
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 2 Key:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffc0 69 ffffffe1 ffffffa2 ffffffd1 ffffffa6 51 ffffffc9 16 ffffffb2 68 58 41 ffffffa4 0c 59
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 2 pDest (16):
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]17 fffffff0 7c ffffff99 ffffffca ffffffca ffffffbf 25 10 54 ffffffd0 46 ffffffe4 ffffffa2 63 ffffff94
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmCrypt2]AxProtectot C6F Round 2 AES JOB 2 Result (16),AxProtectot C6F END,16 byte payload:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]ffffffd8 ffffffc9 2c 56 61 ffffff90 ffffffbd ffffff94 0f 1c 64 4c 5f ffffff80 21 ffffffa2
[*]
[*]----------------------------------------------END------------------------------------------------------
[*][CmSendMessage]ENCRYPT SUCCESS
[*][CmSendMessage]Message send(196):
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 00 00 00 00 ffffffd8 ffffffc9 2c 56 61 ffffff90 ffffffbd ffffff94
[*]0f 1c 64 4c 5f ffffff80 21 ffffffa2 ffffffe3 ffffff96 ffffffe0 67 0d ffffffc2 21 ffffffba
[*]23 44 fffffff6 ffffff95 0b 7c ffffffa2 ffffffb4 3f ffffff91 72 25 4b 7a 28 ffffffd1
[*]00 00 00 00
[*]----------------------------------------------END------------------------------------------------------
最后于 2023-1-25 09:20
被ericyudatou编辑
,原因:
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
11 楼
吃羊杂去了,晚上更过自校验
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
12 楼
自校验 在实现了CmCrypt2 Axprotector 0x6000000之后,理论上程序可以运行。但一旦设了(软)断点或者是修改了代码,程序就跑不起来,报错说代码完整性检查失败。 随便在代码段设个硬件断点 发现断在memmove,简单的看了一下,发现调用链如下 doMemCheck->memcheck_doSha_0->memcheck_doSha->sha256_update->memmove bool __thiscall doMemCheck(int this, int a2, unsigned __int8 *a3, int a4, int a5, int a6, int a7)
{
unsigned __int8 *v7; // esi
_DWORD *v10; // edx
unsigned int v11; // esi
int *v12; // ecx
bool v13; // cf
bool v14; // bl
_DWORD *v15; // [esp+Ch] [ebp-90h]
int v16[4]; // [esp+18h] [ebp-84h] BYREF
__int128 v17; // [esp+28h] [ebp-74h]
char v18[96]; // [esp+38h] [ebp-64h] BYREF
v7 = a3;
if ( !a4 || !(unsigned __int8)sub_A01D00(a2, a4) )
return 0;
v15 = (_DWORD *)(this + 88);
if ( (unsigned __int8)memcheck_doSha_0(a5, a6, this + 88) )
{
*(_OWORD *)v16 = 0i64;
v17 = 0i64;
sub_B13040(this + 88, v16);
*(_DWORD *)(this + 92) = *(_DWORD *)(this + 88);
if ( *(_BYTE *)(this + 4) )
{
memset(v18, 0, sizeof(v18));
if ( !a3 )
v7 = (unsigned __int8 *)(this + 5);
v14 = checkECDSASignature(v18, v7, (unsigned __int8 *)(a4 + 64), (unsigned __int8 *)v16);
}
else
{
v10 = (_DWORD *)(a4 + 128);
v11 = 28;
v12 = v16;
while ( *v12 == *v10 )
{
++v12;
++v10;
v13 = v11 < 4;
v11 -= 4;
if ( v13 )
{
v14 = 1;
goto LABEL_15;
}
}
v14 = 0;
}
LABEL_15:
LOBYTE(v15) = v14;
nullsub_6(a7, a5, a6, v15, a4 + 128, v16);
return v14;
}
else
{
*(_DWORD *)(this + 92) = *v15;
return 0;
}
}
char __thiscall memcheck_doSha_0(_DWORD *this, int a2, int a3, _DWORD *a4)
{
int v5; // ebx
unsigned int v6; // ecx
unsigned int v7; // eax
int v8; // edi
_OWORD *v9; // eax
__int128 v11; // [esp+18h] [ebp-94h] BYREF
__int128 v12; // [esp+28h] [ebp-84h]
char v13[112]; // [esp+38h] [ebp-74h] BYREF
memset(v13, 0, sizeof(v13));
init_sha256((int)v13);
v5 = this[4];
v6 = (v5 - this[3]) >> 4;
v7 = (a4[2] - *a4) >> 5;
v11 = 0i64;
v12 = 0i64;
if ( v6 > v7 )
{
if ( v6 > 0x7FFFFFF )
sub_9FAD60();
sub_9FA900(v6);
v5 = this[4];
}
v8 = this[3];
if ( v8 == v5 )
return 1;
while ( 1 )
{
init_sha256((int)v13);
if ( !(*(unsigned __int8 (__thiscall **)(_DWORD *, int, int, int, char *, _DWORD, _DWORD))(*this + 28))(
this,
v8,
a2,
a3,
v13,
0,
0) )
break;
sha256_final((BYTE *)&v11, (int)v13);
v9 = (_OWORD *)a4[1];
if ( v9 == (_OWORD *)a4[2] )
{
sub_B12D10(v9, &v11);
}
else
{
*v9 = v11;
v9[1] = v12;
a4[1] += 32;
}
v8 += 16;
if ( v8 == v5 )
return 1;
}
return 0;
}
char __thiscall memcheck_doSha(_DWORD *this, int a2, __int64 a3, int *a4, int a5, int a6)
{
int *v7; // ecx
int v8; // ebp
unsigned int v9; // edi
int (__thiscall *v10)(_DWORD *); // esi
unsigned int v11; // ebx
unsigned int v12; // edi
_QWORD *v13; // esi
unsigned int v14; // ebx
unsigned int v15; // edx
unsigned int v16; // ebp
int (__thiscall *v17)(_DWORD *); // edi
int v18; // eax
int (__thiscall *v19)(_DWORD *); // edi
int (__thiscall *v20)(_DWORD *); // edi
int v21; // eax
int (__thiscall *v22)(_DWORD *); // edi
unsigned int v23; // edi
int (__thiscall *v24)(_DWORD *); // esi
BYTE *v25; // eax
char result; // al
int (__thiscall *v27)(_DWORD *); // esi
BYTE *v28; // [esp-10h] [ebp-3Ch]
unsigned int v29; // [esp-Ch] [ebp-38h]
unsigned int v30; // [esp+8h] [ebp-24h]
_DWORD *v31; // [esp+Ch] [ebp-20h]
int *v32; // [esp+18h] [ebp-14h]
int v33; // [esp+1Ch] [ebp-10h] BYREF
__int64 v34; // [esp+20h] [ebp-Ch] BYREF
v7 = &dword_B92C80;
v8 = a2;
if ( this[14] )
v7 = (int *)this[14];
v31 = this;
v32 = v7;
if ( *v7 == v7[1] )
{
v9 = *(_DWORD *)(a2 + 12);
v10 = *(int (__thiscall **)(_DWORD *))(*this + 8);
nullsub_1();
v28 = (BYTE *)(*(_DWORD *)(a2 + 4) + v10(v31));
sha256_update(a4, v28, v9);
return 1;
}
v11 = *(_DWORD *)(a2 + 4);
v33 = 0;
v12 = v11;
v34 = 0i64;
v13 = (_QWORD *)*v7;
v30 = v11;
if ( *v7 == v7[1] )
{
LABEL_15:
v23 = *(_DWORD *)(v8 + 12) + v12;
if ( v23 <= v11 )
return 1;
v24 = *(int (__thiscall **)(_DWORD *))(*this + 8);
nullsub_1();
v25 = (BYTE *)(v11 + v24(v31));
v29 = v23 - v11;
LABEL_17:
sha256_update(a4, v25, v29);
return 1;
}
while ( 1 )
{
v14 = (*v13 >> 4) ^ ((unsigned __int16)*(_DWORD *)v13 ^ (unsigned __int16)(*v13 >> 4)) & 0xFFF;
v15 = *(_DWORD *)(v8 + 4);
if ( v14 >= v15 )
break;
LABEL_12:
v11 = v30;
LABEL_13:
if ( ++v13 == (_QWORD *)v32[1] )
{
v12 = *(_DWORD *)(v8 + 4);
this = v31;
goto LABEL_15;
}
}
v16 = v15 + *(_DWORD *)(v8 + 12);
if ( v14 >= v16 )
{
if ( v16 <= v30 )
return 1;
v27 = *(int (__thiscall **)(_DWORD *))(*v31 + 8);
nullsub_1();
v25 = (BYTE *)(v30 + v27(v31));
v29 = v16 - v30;
goto LABEL_17;
}
switch ( (*v13 >> 12) & 0xF )
{
case 0i64:
case 1i64:
case 2i64:
case 4i64:
case 9i64:
v8 = a2;
goto LABEL_12;
case 3i64:
v17 = *(int (__thiscall **)(_DWORD *))(*v31 + 8);
nullsub_1();
v18 = v17(v31);
sha256_update(a4, (BYTE *)(v30 + v18), v14 - v30);
v19 = *(int (__thiscall **)(_DWORD *))(*v31 + 8);
nullsub_1();
v33 = a3 + *(_DWORD *)(v19(v31) + v14);
sha256_update(a4, (BYTE *)&v33, 4u);
v8 = a2;
v11 = v14 + 4;
v30 = v11;
goto LABEL_13;
case 0xAi64:
v20 = *(int (__thiscall **)(_DWORD *))(*v31 + 8);
nullsub_1();
v21 = v20(v31);
sha256_update(a4, (BYTE *)(v30 + v21), v14 - v30);
v22 = *(int (__thiscall **)(_DWORD *))(*v31 + 8);
nullsub_1();
v34 = *(_QWORD *)(v22(v31) + v14) + a3;
sha256_update(a4, (BYTE *)&v34, 8u);
v8 = a2;
v11 = v14 + 8;
v30 = v11;
goto LABEL_13;
default:
result = 0;
break;
}
return result;
} 发现其对代码段分段求SHA256散列值,再将上一步的散列值再进行一次SHA256,然后用ECDSA验证签名 定位方法: 查看checkECDSASignature串式参考,就两个引用。除开CmValiateSignature以为另外一个就是doMemCheck 和谐方法: 把最后的堆栈检查函数改成mov eax,1
|
活跃值:
(61)
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
硬件狗内的授权可以提取吗?实现脱狗行。
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
14 楼
CHYX
硬件狗内的授权可以提取吗?实现脱狗行。
理论上可行 我手头没狗做不了测试 但有那两组秘钥就应该能做
|
活跃值:
(61)
能力值:
( LV2,RANK:10 )
|
-
-
15 楼
是checkECDSASignature的密钥,还是,我感觉这里可以伪造一个,暴破checkECDSASignature应该就可以过了。对于后面的自校验,感觉应该是针对调试器而引起的软件不能正常开启吧。
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
16 楼
CHYX
是checkECDSASignature的密钥,还是,我感觉这里可以伪造一个,暴破checkECDSASignature应该就可以过了。对于后面的自校验,感觉应该是针对调试器而引起的软件不能正常开启吧 ...
对,理论上把checkECDSASignature这个函数伪造了就可以无补丁运行,但我是懒狗,实现有、麻烦
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
17 楼
调试器不下断点就没事,下了断点解完密就自杀
|
活跃值:
(150)
能力值:
( LV2,RANK:10 )
|
-
-
18 楼
大神,能否分享一下您修改的Wireshark
|
活跃值:
(61)
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
谢谢,估计如果脱壳的话,还有很常的路要走。
|
活跃值:
(3235)
能力值:
( LV7,RANK:100 )
|
-
-
20 楼
|
|
|