http://www.hack50.com/stu/sort092/sort0105/27683.html
我们在下载一些网络资源的时候,常常会见到类似于如下的链接地址:
thunder://QUFodHRwOi8vaGkuYmFpZHUuY29tL3lqc3dvcmQvWlo=
在Windows中如果安装了迅雷,就可以正确解析这样的地址,其实这样一串字符就是用BASE64算法经加密后得到的,下面我用“http://hi.baidu.com/yjsword/”为例说明一下整个加密和解密的过程(当然,我这个例子不是一个合法的可下载的资源)!
加密:
在完整的下载链接前冠以“AA”,后缀以“ZZ”:
AAhttp://hi.baidu.com/yjsword/ZZ
用BASE64算法进行加密,得到:
QUFodHRwOi8vaGkuYmFpZHUuY29tL3lqc3dvcmQvWlo=
在前面加上迅雷自己的协议头:
thunder://QUFodHRwOi8vaGkuYmFpZHUuY29tL3lqc3dvcmQvWlo=
大功告成!
解密:
把以上过程“倒行逆施”一下即可:
去掉迅雷协议头;用BASE64算法解密;去掉“AA”、“ZZ”!
// thunderprotocol.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <winsock2.h>
#include "aes.h"
#pragma comment(lib, "Ws2_32.lib")
bool MakePackage(const char *address, const char *id, unsigned char *package)
{
size_t len = strlen(address);
if (len > 0x3C)
{
return false;
}
memset(package, 0, 0x7C);
unsigned char *p = package;
*p = 0x29;//固定的头
p += 4;
*p = 0x05;//命令标示
p += 4;
*p = 0x70;//长度
p += 4;
*p = 0x05;
p += 4;
memcpy(p, "QUERY", 6);
p += 6;
*p = len;//地址长度
p += 4;
memcpy(p, address, len);//地址
p += len;
*p = 0x10;
p += 4;
memcpy(p, id, 0x10);
p += 17;
*p = 0x14;
p += 4;
*p = 0x14;
p += 12;
unsigned char temp = package+0x7C - p;
for (; p!=package+0x7C; ++p)
{
*p = temp;
}
AES aes;
unsigned char key[16] = { 0x4C, 0xBA, 0xCF, 0xF2, 0xD4, 0x5F, 0x8F, 0x28, 0xBE,
0xD4, 0xDD, 0x26, 0x08, 0x36, 0x0E, 0xE1 };
const unsigned char *plainText;
for (int i=0xC; i<0x7C; i+=16)
{
p = (unsigned char*)package + i;
plainText = aes.Cipher(p, key, 16);
memcpy(p, plainText, 16);
}
return true;
}
unsigned char *MemSearch(const unsigned char *mem, const int memSize, const
unsigned char *patt, const int pattSize)
{
if (memSize <= 0 || pattSize <= 0)
{
return 0;
}
int i;
int td[256];
for (int c=0; c<256; ++c)
{
td[c] = pattSize + 1;
}
const unsigned char *p;
for (p=patt, i=0; i<pattSize; ++p, ++i)
{
td[*p] = pattSize - (p - patt);
}
const unsigned char *t, *tx = mem;
while (tx + pattSize <= mem + memSize)
{
for (p=patt, t=tx, i=0; i<pattSize; ++p, ++t, ++i)
{
if (*p != *t)
{
break;
}
}
if (i == pattSize)
{
return (unsigned char*)tx;
}
tx += td[tx[pattSize]];
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
cout << "please input full address:" << endl;
char address[0x5c];
cin >> address;
cout << endl;
unsigned char package[0x7C];
if(!MakePackage(address, "0004618F9B760000", package))
{
return;
}
AES aes;
unsigned char key[16] = { 0x4C, 0xBA, 0xCF, 0xF2, 0xD4, 0x5F, 0x8F, 0x28, 0xBE,
0xD4, 0xDD, 0x26, 0x08, 0x36, 0x0E, 0xE1 };
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
{
printf("Error at WSAStartup()/n");
return false;
}
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Error at socket(): %ld/n", WSAGetLastError());
WSACleanup();
return false;
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "210.22.14.6" );
clientService.sin_port = htons( 3076 );
if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService)
) == SOCKET_ERROR)
{
printf( "Failed to connect./n" );
WSACleanup();
return false;
}
int bytesSent;
int bytesRecv = 0;
char recvbuf[0xB00] = "";
bytesSent = send( ConnectSocket, (const char*)package, 124, 0 );
bytesRecv = recv( ConnectSocket, recvbuf, 0xB00, 0 );
if (bytesRecv == 0)
{
return false;
}
const unsigned char *plainText;
unsigned char *p;
size_t *pSize = (size_t*)(recvbuf+8);
for (size_t i=0; i<*pSize; i+=16)
{
p = (unsigned char*)recvbuf + i + 12;
plainText = aes.InvCipher(p, key, 16);
memcpy(p, plainText, 16);
}
const unsigned char *string = (const unsigned char*)(recvbuf+12);
while(1)
{
string = MemSearch(string+1, p-string+1, (const unsigned char*)"http://", 7);
if (string == 0)
{
break;
}
cout << string << endl;
}
string = (const unsigned char*)(recvbuf+12);
while(1)
{
string = MemSearch(string+1, p-string+1, (const unsigned char*)"ftp://", 6);
if (string == 0)
{
break;
}
cout << string << endl;
}
system("pause");
return 0;
}