能力值:
( LV7,RANK:100 )
|
-
-
5 楼
0x07 send_cm_socket_Req初探二——参数协议 char __thiscall send_cm_socket_Req(
LPCRITICAL_SECTION *this,
_DWORD *buf, //发送的数据报内容
unsigned int final_length,//长度
unsigned int len2, //长度final_length,len2取最长
char flag) //数据发送失败是否尝试重启Codemeter服务 显而易见,需要重点分析buf的结构,从wibucm32.dll中可以通过调用以及编译残留的字符串可以发现各个Cm api调用send_cm_socket_Req的参数。初步分析如下(完整版见附件): 通过归类可知,这些Cm Api分为三大类 1.超短型:不需要传递太多的参数,如CmGetVersion CmGetInfoExt CmRelease CmGetBoxes等 2.本地实现型:通过调用其他Cm Api或者直接本地解决,如CmCryptEcies CmCalculateDigest等 3.超长型:1.传递巨量参数 2.buf[9]=0 3.buf[1]~buf[8]={-1,0,0,0,0,-1,0,0}这个特定的开头 如CmGetContainerInfo CmGetAccountInfo CmWriteSettings 等 (黄色标出),不是研究的重点 4.一般型:1.传递一定参数 2.buf[9]≠0 3.buf[1]~buf[8]={-1,0,0,0,0,-1,0,0}这个特定的开头 如CmAccess CmAccess2 CmGetInfo等,为研究重点 通过分析我们可以发现一些未公开的Cm Api如CmControl CmCreateLicenseFile等,其中CmControl非常值得我们分析研究(挖坑) 0x08 send_cm_socket_Req初探三——我们需要再深入一些send_cm_req_encrypt char __thiscall send_cm_socket_req(int this, _DWORD *buf, int final_length, unsigned int len2, char flag)
{
_DWORD *buf_1; // edi
int v7; // eax
int err_4; // eax
int function_table_006F8A58; // eax
char result; // al
int v11; // eax
int v12; // ebx
char err; // cl
int v14; // eax
int err_2; // eax
int v16; // eax
unsigned __int64 v17; // kr10_8
int v18; // eax
int v19; // eax
int v20; // eax
int v21; // eax
int err_3; // [esp+10h] [ebp-38h]
int v23; // [esp+14h] [ebp-34h]
int v24; // [esp+1Ch] [ebp-2Ch]
char err_1; // [esp+23h] [ebp-25h]
int v26[2]; // [esp+24h] [ebp-24h] BYREF
int time1[2]; // [esp+2Ch] [ebp-1Ch] BYREF
LPCRITICAL_SECTION *v28[5]; // [esp+34h] [ebp-14h] BYREF
buf_1 = buf;
v7 = sub_553BC0(); // 多线程相关
err_4 = sub_554DF0(v7, 0); // should ret 1 Codemeter服务器检测 没启动的话挂起服务
err_3 = err_4;
if ( err_4 != 1 )
{
switch ( err_4 )
{
case 0:
case 2:
case 3:
function_table_006F8A58 = get_function_table_006F8A58();
(*(void (__thiscall **)(int, int))(*(_DWORD *)function_table_006F8A58 + 4))(function_table_006F8A58, 101);// 未找到CodeMeter服务器, 错误 101.
result = 0;
break;
case 4:
v11 = get_function_table_006F8A58();
(*(void (__thiscall **)(int, int))(*(_DWORD *)v11 + 4))(v11, 308);// 该数据无法写入安全区, 错误 308.
goto LABEL_5;
default:
LABEL_5:
result = 0;
break;
}
return result;
}
v28[0] = 0;
sub_4FE310(v28, (LPCRITICAL_SECTION *)(this + 60));
v28[4] = 0;
v12 = 0;
v24 = 3;
v23 = 0;
while ( 1 )
{
get_time(time1);
err = send_cm_req_encrypt((struct_this_2 *)this, buf_1, final_length, len2);// should ret 0 加密数据包并发送
err_1 = err;
if ( err && buf_1[2] == 238 ) // CodeMeter 许可服务器启动仍旧在待定中,错误238.
{
sleep(1000u);
v14 = 20;
v24 = 20;
goto LABEL_24; // try again
}
err_2 = *(_DWORD *)(*(_DWORD *)(this + 40) + 12);// getlasterror
if ( err_2 == 309 ) // CodeMeter许可服务器超载, 访问请求已超时,该请求已被拒绝, 错误309.
{
sleep(1000 * (v23 + 1));
v12 = v23;
v24 = 20;
v14 = 20;
goto LABEL_24; // try again
}
if ( err )
{
LABEL_31:
v21 = get_function_table_006F8A58();
(*(void (__thiscall **)(int, _DWORD))(*(_DWORD *)v21 + 4))(v21, *(_DWORD *)(*(_DWORD *)(this + 40) + 12));// cm_set_error
goto LABEL_32;
}
if ( flag && (err_2 == 101 || err_2 == 102) )// 无法将请求发送至其他CodeMeter服务器, 错误 102.
// 未找到CodeMeter服务器, 错误 101.
{
v16 = sub_553BC0();
err_3 = sub_554DF0(v16, 1);
}
get_time(v26);
v17 = v26[1] + 1000000 * (v26[0] - (__int64)time1[0]) - time1[1];
if ( v17 >= 950
* (unsigned __int64)(unsigned int)(*(int (__thiscall **)(_DWORD))(**(_DWORD **)(this + 40) + 96))(*(_DWORD *)(this + 40)) )
break; // 超时检测(网络,反调试)
v12 = v23;
if ( v23 != 2 || *(_DWORD *)(this + 56) != 1 )
{
buf_1 = buf;
LABEL_23:
v14 = v24;
goto LABEL_24;
}
buf_1 = buf;
if ( (*(_BYTE *)(sub_5269C0() + 132) & 2) == 0 )
goto LABEL_23;
*(_DWORD *)(this + 40) = *(_DWORD *)(this + 48);
v14 = v24 + 1;
*(_DWORD *)(this + 56) = 2;
++v24;
LABEL_24:
v23 = ++v12;
if ( v12 >= v14 )
goto LABEL_28;
}
v18 = *(_DWORD *)(this + 40);
if ( !*(_DWORD *)(v18 + 12) )
*(_DWORD *)(v18 + 12) = 100;
LABEL_28:
switch ( err_3 )
{
case 0:
case 1:
goto LABEL_31;
case 2:
case 3:
v19 = get_function_table_006F8A58();
(*(void (__thiscall **)(int, int))(*(_DWORD *)v19 + 4))(v19, 0x65);// 未找到CodeMeter服务器, 错误 101
break;
case 4:
v20 = get_function_table_006F8A58();
(*(void (__thiscall **)(int, int))(*(_DWORD *)v20 + 4))(v20, 0x134);// 该数据无法写入安全区, 错误 308.
break;
default:
break;
}
LABEL_32:
sub_4FE380(v28);
return err_1;
} 分析可知send_cm_socket_Req的主要功能是判断服务器状态以及错误处理,实际上转发给send_cm_req_encrypt
最后于 2022-12-24 23:18
被ericyudatou编辑
,原因:
|
能力值:
( LV7,RANK:100 )
|
-
-
6 楼
0x09 通信协议初探 Codemeter在通信上除了使用一个私有的算法进行加密并与系统时间挂钩以外并没有别的门槛,只是一个简单的winsock通信框架,Wireshark能抓包。这里观察一下通信上的行为。 可以发现端口50777的客户端与端口22350的Codemeter服务器间的通信行为: 客户端对服务端的通信行为可以概括如下 首先发送一个长度为16字节的明文握手包package01结构为如下,length为下一个加密数据包的长度 struct handshake_package{ char magic[4] = "samc"; dword length; byte flag; char gap[7] = {00,01,00,00,00,00,00,00}; } 发送一个长度为length的加密包package02,内容全部为加密后的数据,没有长度等信息 (更正)
第二个加密数据包第一个字节是固定的,0xA0,之后才是被加密的数据 等待服务器回话
但服务端对客户端的通信行为却有点不同 服务器对客户端倒像一个高冷御姐,没有了单独的握手包,但是却把握手包与数据杂合到一块。 服务器返回的数据包前16字节是跟客户端handshake_package的结构一样,后面就是长度为length的加密后的数据。 0x10 send_cm_req_encrypt,func_10_send_message, func_6_recv_telegram char __thiscall send_cm_req_encrypt(struct_this_2 *this, _DWORD *buf, int final_length, unsigned int definelength)
{
unsigned int len2; // edx
_DWORD *buf_1; // edi
SIZE_T len1; // eax
unsigned int lenbuf_2; // ecx
__m128i *buf_2; // eax
__int8 *v10; // ecx
struct_name_3 *arr; // eax
char err; // al
int dword28; // edx
int final_length_2; // ecx
_DWORD *buf_4; // eax
unsigned int len_1; // ecx
_DWORD *calltb; // edx
_DWORD *buf_3; // edi
char v19; // al
int v20; // ecx
char *v21; // esi
int v22; // eax
char flag; // [esp+Ch] [ebp-58h]
unsigned int len1_; // [esp+10h] [ebp-54h]
int *plaintext; // [esp+10h] [ebp-54h]
char err_1; // [esp+1Bh] [ebp-49h]
unsigned int v28; // [esp+1Ch] [ebp-48h] BYREF
int flag_1; // [esp+20h] [ebp-44h] BYREF
struct_reallocateMem lpMem; // [esp+24h] [ebp-40h] OVERLAPPED BYREF
char *v31; // [esp+3Ch] [ebp-28h] BYREF
int v32; // [esp+40h] [ebp-24h]
int v33; // [esp+44h] [ebp-20h]
int len; // [esp+48h] [ebp-1Ch] BYREF
int final_length_1; // [esp+4Ch] [ebp-18h] BYREF
char gapshould1; // [esp+53h] [ebp-11h] BYREF
int issuccess; // [esp+60h] [ebp-4h]
len2 = 0x1000; // 准备:确定长度
buf_1 = buf; // buf + 0 ??_7YS0061@@6B@
if ( definelength > 0x1000 )
len2 = definelength;
len1 = final_length + 56;
v33 = 0;
*(_OWORD *)&lpMem.dword0 = 0i64;
if ( len2 > final_length + 56 )
len1 = len2;
lenbuf_2 = 0; // len1取最大长度
final_length_1 = 0;
*(_DWORD *)&lpMem.isReallocated = 1;
len = len2;
LOBYTE(flag_1) = 0;
gapshould1 = 0;
v28 = 0;
len1_ = len1;
lpMem.dword0 = &YS0073::YS0080<unsigned char>::`vftable';
memset(&lpMem.pBuf, 0, 12);
*(_OWORD *)&lpMem.doInit0 = 0i64;
issuccess = 0;
if ( len1 ) // 准备:分配内存
{
buf_2 = (__m128i *)allocmem(len1);
lenbuf_2 = len1_;
lpMem.pBuf = buf_2->m128i_i32; // buf
lpMem.size = len1_; // len
lpMem.used_size = len1_; // len
if ( lpMem.doInit0 == 1 )
{
memset(buf_2, 0, len1_);
lenbuf_2 = lpMem.used_size;
buf_2 = (__m128i *)lpMem.pBuf;
}
}
else
{
buf_2 = 0;
}
lpMem.pBuf = buf_2->m128i_i32;
issuccess = 1;
if ( lenbuf_2 )
{
v10 = &buf_2->m128i_i8[lenbuf_2]; // wtf?
}
else
{
v10 = 0;
buf_2 = 0;
}
memset(buf_2, 0, v10 - (__int8 *)buf_2); // 准备发送
err_1 = prepareNetwork((int)this); // 网络连接ret 1
if ( err_1 )
{
final_length_1 = final_length;
arr = 0;
if ( lpMem.used_size )
arr = (struct_name_3 *)lpMem.pBuf;
plaintext = &arr->buf_new;
err_1 = (*(int (__thiscall **)(_DWORD *, int *, int *))(*buf + 4))(buf, &arr->buf_new, &final_length_1);// expand_plaintext 将buf中的原文进行操作转换成v11+16数据包
if ( err_1 && final_length_1 == final_length )
{
flag = (*(int (__thiscall **)(_DWORD *))(*buf + 24))(buf);// ret 0 NTI
if ( flag )
{
final_length_2 = final_length_1;
}
else
{
err = (*(int (__thiscall **)(struct_this_2 *, int *, int *, _DWORD))(this->dword0 + 12))(// encrypt_telegram
this,
plaintext,
&final_length_1,
this->unsigned___int840);
dword28 = this->dword28;
err_1 = err;
if ( !err )
{
*(_DWORD *)(dword28 + 12) = 301; // 对CodeMeter Runtime Server的访问操作无法被加密, 错误 301.
goto LABEL_45;
}
final_length_2 = final_length_1;
if ( (unsigned int)final_length_1 > *(_DWORD *)(dword28 + 16) )
{
*(_DWORD *)(dword28 + 12) = 112; // 传递给CodeMeter驱动程序的数据段太小, 错误 112.
goto LABEL_45;
}
}
buf_4 = 0;
if ( lpMem.used_size )
buf_4 = lpMem.pBuf;
len_1 = final_length_2 + 1;
*((_BYTE *)buf_4 + 15) = 0xA0;
calltb = (_DWORD *)this->dword28;
if ( len_1 < calltb[4] )
{
err_1 = (*(int (__thiscall **)(_DWORD *, int, unsigned int, char))(*calltb + 24))(
calltb,
(int)buf_4 + 15,
len_1,
flag); // func_10_send_message 网络:发送数据
if ( err_1 )
{
sub_56E3D0(buf); // buf[6]=-1
while ( 1 )
{
err_1 = (*(int (__thiscall **)(_DWORD, struct_reallocateMem *, int *, int *, char *, _DWORD))(*(_DWORD *)this->dword28 + 32))(// char __thiscall func_5_recv_message(struct_this_1 *this, struct_reallocateMem *buf, int pLen, _BYTE *flag, int gapshould1, int a6)
// 网络,接受服务器返回数据
this->dword28,
&lpMem,
&len,
&flag_1,
&gapshould1,
0);
if ( !err_1 )
break;
(*(void (__thiscall **)(_DWORD *, int))(*buf_1 + 28))(buf_1, flag_1);
buf_3 = 0;
if ( lpMem.used_size )
buf_3 = lpMem.pBuf;
if ( !flag )
{
if ( len == 1 )
goto LABEL_40;
err_1 = (*(int (__thiscall **)(struct_this_2 *, _DWORD *, int *, _DWORD))(this->dword0 + 16))(
this,
buf_3,
&len,
this->unsigned___int840);// decrypt_telegram
if ( !err_1 )
{
*(_DWORD *)(this->dword28 + 12) = 302;// 通讯加解密出错, 错误 302.
break;
}
}
v28 = 0;
if ( !sub_56F180(buf, buf_3, len, &v28) )
{
if ( sub_56E240(buf_3, len) )
{
*(_DWORD *)(this->dword28 + 12) = 309;// CodeMeter许可服务器超载, 访问请求已超时,该请求已被拒绝, 错误309.
LABEL_40:
err_1 = 0;
break;
}
v19 = (*(int (__thiscall **)(_DWORD *, _DWORD *, int))(*buf + 8))(buf, buf_3, len);
v20 = this->dword28;
err_1 = v19;
if ( v19 )
*(_DWORD *)(v20 + 12) = buf[2];
else
*(_DWORD *)(v20 + 12) = 100; // 发生网络错误, 错误 100.
break;
}
buf_1 = buf;
}
}
}
else
{
calltb[3] = 112;
err_1 = 0;
}
}
else
{
*(_DWORD *)(this->dword28 + 12) = 100; // 发生网络错误, 错误 100.
}
}
LABEL_45:
v21 = v31;
v22 = v32;
issuccess = 2;
for ( lpMem.dword0 = &YS0073::YS0080<unsigned char>::`vftable'; v21 != (char *)v22; v21 += 4 )
{
if ( *(_DWORD *)v21 )
{
(*(void (__thiscall **)(_DWORD, _DWORD))(**(_DWORD **)v21 + 4))(*(_DWORD *)v21, 0);// good
v22 = v32;
}
}
if ( lpMem.isReallocated )
{
if ( lpMem.pBuf )
{
if ( lpMem.doInit0 == 1 )
memset((__m128i *)lpMem.pBuf, 0, lpMem.used_size);
free(lpMem.pBuf); // realease
}
memset(&lpMem.pBuf, 0, 12);
lpMem.isReallocated = 1;
}
release(&v31); // release
return err_1;
}
char __userpurge func_10_send_message@<al>(
_DWORD *this@<ecx>,
int a2@<ebx>,
int a3@<edi>,
char *buf,
unsigned int len,
int a6)
{
unsigned int i; // edi
int len_1; // eax
int v12; // [esp-8h] [ebp-10h]
int v14; // [esp-4h] [ebp-Ch]
if ( (this[2] & 2) == 0 )
{
this[3] = 100; // 发生网络错误, 错误 100.
return 0;
}
if ( (*(unsigned __int8 (__thiscall **)(_DWORD *, unsigned int, int))(*this + 112))(this, len, a6) )// func_9_send_handshake
// 握手,发送密文的长度
{
i = 0;
if ( !len )
return 1;
while ( 1 )
{
len_1 = send(this[5], buf, len - i, 0); // 发送加密报文
if ( len_1 < 0 )
break;
i += len_1;
buf += len_1;
if ( i >= len )
return 1;
}
if ( (*(unsigned __int8 (__thiscall **)(_DWORD *, int, int))(*this + 80))(this, a3, a2) )
send(this[5], Default, 0, 0);
if ( (*(unsigned __int8 (__thiscall **)(_DWORD *, int, int))(*this + 80))(this, v12, v14) )
{
shutdown(this[5], 2);
if ( closesocket(this[5]) < 0 )
this[3] = 100; // 发生网络错误, 错误 100.
this[2] &= ~2u;
this[5] = -1;
}
sub_4FE2C0();
this[3] = 102; // 无法将请求发送至其他CodeMeter服务器, 错误 102.
}
return 0;
}
bool __thiscall func_9_send_handshake(_DWORD *this, int len, char a3)
{
char buf[16]; // [esp+4h] [ebp-14h] BYREF
constractHandshake((int)buf, len, a3); // 73 61 6D 63 D1 00 00 00 41 00 01 00 00 00 00 00
//
// 73 61 6D 63 len 00 00 00 a3|1 00 01 00 00 00 00 00
return send_handshake(this, this[5], buf, 16) == 16;// this[5] socket
}
handshake_package *__cdecl constractHandshake(handshake_package *buf, int len, char a3)
{
*buf = 0i64;
buf->len = len;
*(_DWORD *)buf->magic = 'cmas';
buf->gap[1] = 1;
if ( a3 )
buf->flag = a3 | 1;
else
buf->flag = 65;
return buf;
}
char __thiscall func_5_recv_message(
struct_this_1 *this,
struct_reallocateMem *buf,
int pLen,
_BYTE *flag,
int gapshould1,
int a6)
{
SOCKET fd; // edi
*flag = 0;
fd = this->fd;
if ( (this->dword8 & 2) != 0 )
{
if ( (*(unsigned __int8 (__thiscall **)(struct_this_1 *, SOCKET, struct_reallocateMem *, int, _BYTE *, int))(this->dword0 + 36))(
this,
this->fd,
buf,
pLen,
flag,
gapshould1) ) // bool __thiscall func_6_recv_telegram(_DWORD *this, SOCKET fd, struct_reallocateMem *buf_2, int *plen, char *flag_1, _BYTE *gapshould1)
{
return 1;
}
else
{
if ( fd == this->fd )
{
this->dword8 &= ~2u;
this->fd = -1;
}
return 0;
}
}
else
{
this->errcode = 100;
return 0;
}
}
bool __thiscall func_6_recv_telegram(
struct_this_1 *this,
SOCKET fd,
struct_reallocateMem *buf_2,
int *plen,
char *flag_1,
_BYTE *gapshould1)
{
int v6; // esi
int len; // ebx
char flag; // bl
int len_1; // ecx
struct_this_1 *v10; // edx
unsigned int used_size; // eax
SIZE_T newsize; // eax
int v13; // eax
__m128i *buf; // edi
int v15; // eax
unsigned int v17; // eax
__m128i *pBuf; // edi
int recvlen; // eax
handshake_package buf_1; // [esp+1Ch] [ebp-14h] BYREF
*flag_1 = 0;
v6 = 0;
*gapshould1 = 0;
if ( !*plen )
return 0;
buf_1 = 0i64;
len = recv_message((int)this, fd, buf_1.magic, 16);
if ( !(*(unsigned __int8 (__thiscall **)(struct_this_1 *, int, int *))(this->dword0 + 108))(this, len, plen) )
return 0;
if ( len == 16 )
{
if ( *(_DWORD *)buf_1.magic == 'cmas' ) // handshake len and magic check
{
flag = buf_1.flag; // a3 | 1
len_1 = buf_1.len; // len
if ( (buf_1.flag & 1) == 0 && buf_1.len >= 0x20000u )// 握手包参数检查
return 0;
v10 = this;
if ( buf_1.len >= *(_DWORD *)this->gap10 )
return 0;
used_size = buf_2->used_size;
if ( used_size < buf_1.len )
{
newsize = 0x1000;
if ( buf_1.len > 0x1000u )
newsize = buf_1.len;
reallocateMem(buf_2, newsize);
v13 = buf_2->used_size;
if ( !v13 )
return 0;
flag = buf_1.flag;
len_1 = buf_1.len;
v10 = this;
*plen = v13;
used_size = buf_2->used_size;
}
if ( used_size )
buf = buf_2->pBuf;
else
buf = 0;
*flag_1 = flag;
*gapshould1 = buf_1.gap[1];
if ( len_1 > 0 )
{
while ( 1 )
{
v15 = recv_message((int)v10, fd, buf->m128i_i8, len_1 - v6);
if ( v15 < 0 )
break;
if ( !v15 )
goto LABEL_34;
len_1 = buf_1.len;
v6 += v15;
v10 = this;
buf = (__m128i *)((char *)buf + v15);
if ( v6 >= buf_1.len )
{
*plen = v6;
return v6 != 0;
}
}
if ( v15 == -2 )
v6 = -1;
goto LABEL_23;
}
goto LABEL_34;
}
}
else if ( len < 16 )
{
goto LABEL_34;
}
v17 = buf_2->used_size;
if ( v17 < 0x1000 )
{
reallocateMem(buf_2, 0x1000u);
v17 = buf_2->used_size;
}
if ( v17 )
pBuf = buf_2->pBuf;
else
pBuf = 0;
memmove((unsigned int)pBuf, (unsigned int)&buf_1, len);
v6 = len;
recvlen = recv_message((int)this, fd, &pBuf->m128i_i8[len], *plen - len);
if ( recvlen < 0 )
{
LABEL_23:
*plen = v6;
return 0;
}
if ( recvlen )
v6 = recvlen + len;
LABEL_34:
*plen = v6;
return v6 != 0;
} 对Codemeter的逆向的感受有别于flexlm,最突出也是最蛋疼的就是codemeter运用了大量的虚函数,虚表。使得有很多程序逻辑不能直接了当的呈现出来,而是必须通过动态调试才能知悉。 因为这个send_cm_req_encrypt很长所以直接呈上分析结果,验证后发现func_10_send_message,func_6_recv_telegram的逻辑与wireshark抓包的结果相符,可以认为分析是正确的 0x11 伪造服务端 通过调试可知encrypt_telegram,decrypt_telegram,expand_plaintext等加解密函数在服务端也被复用,因此我们可以通过对wibucm32.dll的魔改,导出这些重要的函数以减少工作量,不用复现那些加解密算法 encrypt_telegram
decrypt_telegram 通过实践发现只需要这两个函数笑ψ(`∇´)ψ
最后于 2022-12-28 15:33
被ericyudatou编辑
,原因:
|
能力值:
( LV7,RANK:100 )
|
-
-
7 楼
0x11 伪造服务端 帖子被加精了,新人第一回,有点受宠若惊(❁´◡`❁)
记于2022年12月28日: 经过几天摸爬滚打,Fake server已经初见雏形。已经能够解密客户端发送的加密数据包了 简单的记录一下过程中遇到的问题和发现 1.让人摸不着头脑的错误 一开始通过GetProcAddress获得函数的地址进行访问,但总是离奇出错,出错原因各不相同。后来排查发现 typedef char(* Type_encrypt_telegram)(struct_communication*, char* buf, int* length, char flag); 这样编译出来的和这么编译出来的
typedef char(__thiscall* Type_encrypt_telegram)(struct_communication*, char* buf, int* length, char flag); 生成出的汇编代码不同,前一种报错而后一种则正常运行。也算是涨经验了。
2.客户端对服务端的请求格式 struct PKG
{
char APICODE;
FUNCTION_ARGS
};
//举个例子 对于 CODEMETER_API HCMSysEntry CMAPIENTRY CmAccess2(CMULONG flCtrl, CMACCESS2 *pcmAcc);
//请求包的结构就是这样
struct PKG_CMACCESS2
{
char APICODE;
CMULONG flCtrl;
CMACCESS2 pcmAcc;
}; 举个例子
[*]Client 127.0.0.1:13794 login,time=63479375
[*]Valid Handeshake
[*]Recieved handshake package,length=737,magic=samc?
[*]Encrypted package decrypt:SUCCESS,len:712
[*]Function Request:CmAccess2
[*][CmAccess2] flctrl=0x10000000,mflCtrl=0x00000100,firmcode=1000,productcode=114514,featurecode=1919810
[*]Printing Decrypted Request:
[*]-------------------------------------------PRINT HEX---------------------------------------------------
[*]00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[*]-------------------------------------------------------------------------------------------------------
[*]64 00 00 00 00 00 00 10 00 01 00 00 ffffffe8 03 00 00
[*]52 ffffffbf 01 00 42 4b 1d 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 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 65 64 61 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 00 00 00 00 00 00 fffffff8 45 00 00 3d ffffffc0 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 00 00 00 00 00 00 00 73 68 65 6e 77 65 6e 68
[*]75 61 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 01 00 00 00 00 00
[*]00 00 00 00 45 44 41 00 00 00 00 00 00 00 00 00
[*]00 00 00 00 ffffffd4 12 1e 07
[*]----------------------------------------------END------------------------------------------------------
[*]Client 127.0.0.1:13794 out 之后需要做的就是 完成服务器对客户端的回复这一行为的函数 优先实现cmaccess cmaccess2 cmrelease等函数的模拟 实现其他函数 做个GUI
附件为更新过的各个API所对应的API Code
|