[调试逆向]
[原创]RTX(腾讯通)本地保存密码TEA变形算法及还原器
-11-11 12:35
16367
[调试逆向]
[原创]RTX(腾讯通)本地保存密码TEA变形算法及还原器
-11-11 12:35
16367
上月在研究RTX本地保存密码还原,发现是变形的TEA,伪代码如下:
//TEA test program written by HappyTown [-10-10]
#include
#include
#include "winsock2.h"
#pragma comment(lib,"WS2_32.LIB")
#include "tea.h"
//变形TEADec
void myDecrypt(unsigned char *data,unsigned char *key,unsigned char *out);
//变形TEAEnc
void myEncrypt(unsigned char *data,unsigned char *key,unsigned char *out);
//Ecnrypt
void myEncrypt(unsigned char *data,unsigned char *key,unsigned char *out)
{
int i;
unsigned int y=0,z=0,a,b,c,d;
int e = 0;
unsigned int sum = 0x61C88647;
//设置y和z
// printf("%08X\n",*(DWORD*)data);
// printf("%08X\n",*(DWORD*)(data+4));
y =ntohl(*(DWORD*)data);
z =ntohl(*(DWORD*)(data+4));
// printf("y=%08X z=%08X\n",y,z);
//变形key设置a,b,c,d值
a = ntohl(*(DWORD*)(key+0));
b = ntohl(*(DWORD*)(key+4));
c = ntohl(*(DWORD*)(key+8));
d = ntohl(*(DWORD*)(key+12));
// printf("a=%08X,b=%08X,c=%08X,d=%08X\n",a,b,c,d);
// printf("%08X %08X %08X\n",(c+(y<<4)),(d+(y>>5)),(c+(y<<4))^(d+(y>>5)));
// printf("%08X %08X %08X\n",(delta+y),(delta+y) ^ (c+(y<<4))^(d+(y>>5)),z-((delta+y) ^ (c+(y<<4))^(d+(y>>5))));
//Decrypt
for(i=0; i<16; i++)
{
e -= sum;
y += (e+z) ^ (a+(z<<4)) ^ (b+(z>>5));
z += (e+y) ^ (c+(y<<4)) ^ (d+(y>>5));
}
// printf("y=%08X z=%08X \n",y,z);
//output y
*(DWORD*)out =ntohl(y);
//output z
*(DWORD*)(out+4) = ntohl(z);
return;
}
//Decrypt
void myDecrypt(unsigned char *data,unsigned char *key,unsigned char *out)
{
int i;
unsigned int y=0,z=0,a,b,c,d;
int e = 0;
unsigned int sum = 0x61C88647;
unsigned delta = 0xE3779B90;
//设置y和z
// printf("%08X\n",*(DWORD*)data);
// printf("%08X\n",*(DWORD*)(data+4));
y =ntohl(*(DWORD*)data);
z =ntohl(*(DWORD*)(data+4));
// printf("y=%08X\n",y);
// printf("z=%08X\n",z);
// printf("a=%08X,b=%08X,c=%08X,d=%08X\n",a,b,c,d);
//变形key设置a,b,c,d值
a = ntohl(*(DWORD*)(key));
b = ntohl(*(DWORD*)(key+4));
c = ntohl(*(DWORD*)(key+8));
d = ntohl(*(DWORD*)(key+12));
// printf("%08X %08X %08X\n",(c+(y<<4)),(d+(y>>5)),(c+(y<<4))^(d+(y>>5)));
// printf("%08X %08X %08X\n",(delta+y),(delta+y) ^ (c+(y<<4))^(d+(y>>5)),z-((delta+y) ^ (c+(y<<4))^(d+(y>>5))));
//Decrypt
for(i=0; i<16; i++)
{
z -= (delta+y) ^ (c+(y<<4)) ^ (d+(y>>5));
e = (delta+z) ^ (a+(z<<4)) ^ (b+(z>>5));
delta += sum;
y -= e;
}
// printf("y=%08X z=%08X \n",y,z);
//output y
*(DWORD*)out =ntohl(y);
//output z
*(DWORD*)(out+4) = ntohl(z);
return;
}
int main()
{
int i;
int runnum = 0;
int keylen = 40;//暂定密文长40
unsigned char k[16] = {0x52,0x00,0x54,0x00,0x58,0x00,0x21,0x00,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//128bits key
//变形密钥
unsigned char k2[16] = {0x00, 0x54, 0x00, 0x52, 0x00, 0x21, 0x00, 0x58, 0x00, 0x00,
0x00, 0x33, 0x00, 0x00, 0x00, 0x00};//128bits key
unsigned char data[128] = {0x95, 0x8D, 0x23, 0x06, 0x74, 0xBB, 0x15, 0xDA, 0xC2, 0x6B,
0x0E, 0xFF, 0xE7, 0x0F, 0x6D, 0xE6, 0x88, 0x26, 0x91, 0x1F,
0xBE, 0x68, 0xBE, 0xF0, 0x3E, 0x24, 0x65, 0xBB, 0x53, 0xF0,
0x89, 0x8D, 0xB3, 0xBE, 0xE2, 0xAC, 0xC1, 0x81, 0xBA, 0x17,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};//plaintext
unsigned char outEn[128] = {0}; //cipher
unsigned char temp[128] = {0};
unsigned char testdata[]={0xD2,0x90,0x2d,0x48,0xd3,0x73,0x00,0x68};
//以十六进制输出密钥k
printf("Key is:");
for (i=0; i<16; i++)
{
printf("%02X", k[i]);
}
//以十六进制输出密钥k
printf("\ndata is:");
for (i=0; i<8; i++)
{
printf("%02X", data[i]);
}
printf("\n数据解密为:\n");
/*
//加密明文data,并输出密文
TEA_Encrypt(outEn, data, k);
printf("TEA(");
for (i=0; i<16;i++)
{
printf("%02X ", data[i]);
}
printf(") is:");
for (i=0; i<8; i++)
{
printf("%02X", outEn[i]);
}
printf("\n");
*/
//解密上一步的密文outEn,并输出明文
myDecrypt(data, k,outEn);//第一次解密
for (i=0; i<8;i++)
{
printf("%02X ", outEn[i]);
}//加密
//开始加密
printf("\n数据加密为:\n");
myEncrypt(outEn,k,outEn);
for (i=0; i<8;i++)
{
printf("%02X ", outEn[i]);
}
//再解密
printf("\n数据再解密为:\n");
myDecrypt(outEn,k,outEn);
for (i=0; i<8;i++)
{
printf("%02X ", outEn[i]);
}
if(!(outEn[0] & 7))
return 0;
// runnum = (40-(outEn[0] & 7) -10);
// printf("次数:%d %d",runnum,(outEn[0] & 7));
printf("\n\n");
system("pause");
return 0;
}
RTX对本地代码用了随机数填充,多次加密,造成相同密码,密文不一致(密钥用的是“RTX!3”)。另外处理步骤过于复杂,还原密码就直接调用了RTX的Crypt.Dll,还原和加密代码如下(好像和QQ有些算法一致),加解密代码用到了上面的变形算法:
//自定义TEA解密
typedef BOOL (*oi_symmetry_decrypt2) (char *mw,int Len,char *key,char *ret,int *num);
oi_symmetry_decrypt2 mydecrypt2;
//自定义TEA加密
//data 是宽字符
//key 是宽字符
//ret 应该是宽字符,长64位
//num 指向长64位的宽字符
typedef BOOL (*oi_symmetry_encrypt2) (wchar_t *data,int Len,char *key,unsigned char *ret,int *num);
oi_symmetry_encrypt2 myencrypt2;
//查找函数地址
mydecrypt2 = (oi_symmetry_decrypt2)::GetProcAddress(::LoadLibrary("Crypt.dll"), "oi_symmetry_decrypt2");
myencrypt2 = (oi_symmetry_encrypt2)::GetProcAddress(::LoadLibrary("Crypt.dll"), "oi_symmetry_encrypt2");
还原密码:
void CRtxPwDlg::OnRead()
{
// TODO: Add your control notification handler code here
char key[]={0x52, 0x00, 0x54, 0x00, 0x58, 0x00, 0x21, 0x00, 0x33, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char ret[1024]={0};
char buff[1024]={0};
char filekey[]="strPassword";
int keylen = 0;
int num = 1024;
::GetPrivateProfileStruct("Default","strPassword",buff,
64,
"D:\\rtx.cfg");//注意rtx.cfg在RTX的安装目录下,这里是本机未安装RTX将CFG文件COPY到D盘测试用
if (2 * wcslen((unsigned short*)buff) >= 64 )
keylen = 64;
else
keylen = 2*wcslen((unsigned short*)buff);
CString msg;
msg.Empty();
//解密
mydecrypt2(buff,keylen,key,ret,&num);
for(int j=0;j<64;j++)
{
CString temp;
if(ret[j]!=0x00)
{
temp.Format("%c",ret[j]);
msg+=temp;
}
}
AfxMessageBox(msg);
}
//加密密码
void CRtxPwDlg::OnWrite()
{
// TODO: Add your control notification handler code here
char key[]={0x52, 0x00, 0x54, 0x00, 0x58, 0x00, 0x21, 0x00, 0x33, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char buff[64] = "123456";
unsigned char ret[64] = {0};
int temp = 0;
// AfxMessageBox(msg);
//第四个参数为-1时,取得转换需要的大小
int nLen = MultiByteToWideChar(CP_ACP, 0,buff, -1, NULL, NULL);
//分配空间
wchar_t *pwText;
pwText = new wchar_t[nLen];
if(!pwText)
delete[]pwText;
//转换
MultiByteToWideChar(CP_ACP,0,buff,-1,pwText,nLen);
CString msg,ls;
m_Show.Empty();
// for(int k=1;k
{
myencrypt2(pwText,nLen*2-2,key,ret,&temp);
msg.Empty();
for(int i=0;i<64;i++)
{
ls.Format("%02X",ret[i]);
m_Show += ls;
}
// AfxMessageBox(m_Show);
}
delete[]pwText;
UpdateData(FALSE);
}