能力值:
(RANK:135 )
|
-
-
2 楼
期待完整版
|
能力值:
( 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再来找她
|
能力值:
( 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编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
高手,明白一下大神
|
能力值:
( 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编辑
,原因:
|
能力值:
( 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编辑
,原因:
|
能力值:
( 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编辑
,原因:
|
能力值:
( 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编辑
,原因:
|
能力值:
( 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编辑
,原因:
|
能力值:
( LV7,RANK:100 )
|
-
-
11 楼
吃羊杂去了,晚上更过自校验
|
能力值:
( 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
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
硬件狗内的授权可以提取吗?实现脱狗行。
|
能力值:
( LV7,RANK:100 )
|
-
-
14 楼
CHYX
硬件狗内的授权可以提取吗?实现脱狗行。
理论上可行 我手头没狗做不了测试 但有那两组秘钥就应该能做
|
能力值:
( LV2,RANK:10 )
|
-
-
15 楼
是checkECDSASignature的密钥,还是,我感觉这里可以伪造一个,暴破checkECDSASignature应该就可以过了。对于后面的自校验,感觉应该是针对调试器而引起的软件不能正常开启吧。
|
能力值:
( LV7,RANK:100 )
|
-
-
16 楼
CHYX
是checkECDSASignature的密钥,还是,我感觉这里可以伪造一个,暴破checkECDSASignature应该就可以过了。对于后面的自校验,感觉应该是针对调试器而引起的软件不能正常开启吧 ...
对,理论上把checkECDSASignature这个函数伪造了就可以无补丁运行,但我是懒狗,实现有、麻烦
|
能力值:
( LV7,RANK:100 )
|
-
-
17 楼
调试器不下断点就没事,下了断点解完密就自杀
|
能力值:
( LV2,RANK:10 )
|
-
-
18 楼
大神,能否分享一下您修改的Wireshark
|
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
谢谢,估计如果脱壳的话,还有很常的路要走。
|
能力值:
( LV7,RANK:100 )
|
-
-
20 楼
|
能力值:
( LV7,RANK:100 )
|
-
-
21 楼
2023年2月5日更新
上文的方法只适用于CmActLicense,即firm code 5000xxxx的,而对于用狗的CmDongle则是另外一套的授权系统 CmDongle所对应的CmCrypt2 0x6000000算法跟CmActLicense有所不同,提供一下目前的线索 没有调用func2,致使第一组key没有暴露在内存中(暂时未发现) 在func1讲参数传递给狗,狗的结果解密后便是pbDest 第二组私钥key会在CmCalculateSignature时暴露在内存中 因为AxProtector壳在解密中只有一套算法,没有区分CmDongle和CmActLicense,所以可以大胆推测狗里头的算法跟上文提到的func2中的算法大差不差
|
能力值:
( LV7,RANK:100 )
|
-
-
22 楼
对于用AxProtector保护的.exe .dll(不是.NET)程序的完整dump方法 在源程序未用IxProtector保护的情况下,所有被加密的部分全都在启动后解密完成 过掉反调试 a.ScyllaHide全开即可 b.下任何断点都需要下成硬件断点,AxProtector没有对硬件断点所需要的寄存器进行检查,但是会对软件断点进行检查,用硬件断点即可完美解决这一问题 c.关于AxProtector杀狗 只要不瞎搞,这个保护也形同虚设
已知的两种会杀狗的可能 1.CmCrypt2 0x6000000未返回正确的授权 2.调试器被查到 杀狗则是通过CmControl这个API进行的这个API没有进行文档化,对此知之甚少,可以通过tcp环路过滤掉这个API(TODO) Dump exe 找到壳的入口点 axengine_entry,从入口点开始找,找到最大的一个函数即可,可以通过壳的数据段解密的key和api来进行定位,确认 有两处代码会识别不出来
__wibu04:00475EA5 jnz short loc_475ED1
__wibu04:00475EA7 mov eax, ds:dword_623B60
__wibu04:00475EAC add eax, 0F8h
__wibu04:00475EB1 mov ecx, eax
__wibu04:00475EB3 mov [ebp+var_58C], eax
__wibu04:00475EB9 call sub_45E1A0
__wibu04:00475EB9 ; ---------------------------------------------------------------------------
__wibu04:00475EBE db 0FFh ;<----------此处
__wibu04:00475EBF db 0FFh
__wibu04:00475EC0 db 8Bh
__wibu04:00475EC1 db 8Dh
__wibu04:00475EC2 db 74h ; t
__wibu04:00475EC3 db 0FAh
__wibu04:00475EC4 db 0FFh
__wibu04:00475EC5 db 0FFh
__wibu04:00475EC6 ; ---------------------------------------------------------------------------
__wibu04:00475EC6 call sub_45E230
__wibu04:00475ECB mov edi, [ebp+var_598]
__wibu04:00475ED1
__wibu04:00475ED1 loc_475ED1: ; CODE XREF: axengine_entry+4D5↑j
__wibu04:00475ED1 push offset Address
__wibu04:00475ED6 mov ecx, edi
__wibu04:00475ED8 call sub_46D490
__wibu04:00475EDD test al, al
__wibu04:00475EDF jnz loc_475FD2
.........
__wibu04:00475EA7 mov eax, ds:dword_623B60
__wibu04:00475EAC add eax, 0F8h
__wibu04:00475EB1 mov ecx, eax
__wibu04:00475EB3 mov [ebp+var_58C], eax
__wibu04:00475EB9 call sub_45E1A0
__wibu04:00475EB9 ; ---------------------------------------------------------------------------
__wibu04:00475EBE db 0FFh ;<----------此处
__wibu04:00475EBF db 0FFh
__wibu04:00475EC0 db 8Bh
__wibu04:00475EC1 db 8Dh
__wibu04:00475EC2 db 74h ; t
__wibu04:00475EC3 db 0FAh
__wibu04:00475EC4 db 0FFh
__wibu04:00475EC5 db 0FFh
__wibu04:00475EC6 ; ---------------------------------------------------------------------------
__wibu04:00475EC6 call sub_45E230
__wibu04:00475ECB mov edi, [ebp+var_598] 那两个0xFF是用不可识别指令异常来反调试的,调试的时候爆这两处的异常必须交由应用程序处理 从axengine_entry往下找,找到in ax, 64h 在此处下硬件断点。在这里执行特权指令,通过SEH跳到程序真正的入口点。断下之后就可以对源程序进行dump
|
能力值:
( LV2,RANK:10 )
|
-
-
23 楼
楼主可以提供下,壳的程序?
|
能力值:
( LV2,RANK:10 )
|
-
-
24 楼
狗壳的CmCrypt2 0x6000000 有没有办法计算出正确的cbDest,或者壳内有没有可以Patch的地方呢 00 00 00 06 00 00 00 00 37 13 00 00 68 e6 02 b5 6c 0e 0b e5 00 00 00 00 00 00 00 00 pvDest= bc 8d bc 56 55 6c 71 76 b5 78 11 ea 2a 3a b9 7e 26 e0 cd 0e b5 ff dd ce f6 09 3f b7 53 c5 78 e4 a3 71 30 36 e5 8c e3 ab cbDest= a9 13 33 07 53 b1 35 24 9e d2 ef 02 8c 2d 4e c8 26 e0 cd 0e b5 ff dd ce f6 09 3f b7 53 c5 78 e4 a3 71 30 36 e5 8c e3 ab 计算结果是前10,不过,转了几次,都没有找到大佬说的解码的玩意,还没玩懂
|
能力值:
( LV1,RANK:0 )
|
-
-
25 楼
大神,找到壳的入口点 axengine_entry呢?
|
|
|