2008年9月24日星期三

VeryCD版电驴(eMule)存在封锁

eMule是一个GPL程序,所以VeryCD的改版必须公开源码。今天听说VeryCD版有封锁的现象,所以贝壳抓源码来看看。如果大家认为老调重弹的话,不妨把文章拉到最后。
源码从此处下载:http://www.emule.org.cn/download/
最下方链接:http://download.verycd.com/eMule-VeryCD-src.rar
贝壳下到的文件大小13,703,064字节,打包时间2008-09-11。经过贝壳查找,在eMule-VeryCD-src\src \WordFilter发现两个文件,WordFilter.cpp 2008-03-12 09:57 13374和WordFilter.h
2007-11-20 17:56 1009。仔细阅读里面,发现有以下内容。
void CWordFilter::Init()
{
HANDLE hFile;
DWORD dwRead;
int nLen;
BOOL bResult;
CStringList list;

//m_count = 0;

CString saaa = thePrefs.GetMuleDirectory(EMULE_EXECUTEABLEDIR) + FLITER_FILE;
CString sbbb = thePrefs.GetMuleDirectory(EMULE_CONFIGDIR) + FLITER_FILE;

// 如果文件目录不对,程序移动一下,到config目录下 added by kernel1983 2006.07.31
if (PathFileExists(thePrefs.GetMuleDirectory(EMULE_EXECUTEABLEDIR) + FLITER_FILE))
MoveFile(thePrefs.GetMuleDirectory(EMULE_EXECUTEABLEDIR) + FLITER_FILE, thePrefs.GetMuleDirectory(EMULE_CONFIGDIR) + FLITER_FILE);

if (!PathFileExists(thePrefs.GetMuleDirectory(EMULE_CONFIGDIR) + FLITER_FILE))
{
// 不存在,所有的都过滤 added by kernel1983 2006.08.08
m_filterall = true;
return;
}

// Open file for read
hFile = CreateFile(thePrefs.GetMuleDirectory(EMULE_CONFIGDIR) + FLITER_FILE, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//AddLogLine(false,_T(":%s\n"),thePrefs.GetConfigDir() + FLITER_FILE);
if(hFile == NULL || hFile == INVALID_HANDLE_VALUE)
{
// 读取错误,所有的都过滤 added by kernel1983 2006.08.08
m_filterall = true;
return;
}

DWORD dwSize = GetFileSize(hFile, NULL);

TCHAR * pszData = new TCHAR[(dwSize / sizeof(TCHAR)) + 1]; // 申请空间
bResult = ReadFile(hFile, pszData, dwSize, &dwRead, NULL); // 读入文件1
CloseHandle(hFile);
pszData[(dwSize / sizeof(TCHAR))] = 0;

if(bResult)
{
// 加入解码算法
{
std::string tempstr( (char*)pszData + 1 , ((int)dwSize - 1) > 0 ? dwSize -1 : 0 );

// 查看是否是老格式
char * pszData_a = (char*) pszData;

if( pszData_a[0] != 0x15 ) {
// 老格式,进行转换
CUnicodeToMultiByte wc2mb( thePrefs.GetMuleDirectory(EMULE_CONFIGDIR) + FLITER_FILE );
tempstr.assign( (char*)pszData , dwSize );
InternalBase64::encode2file( tempstr , std::string((LPCSTR)wc2mb , wc2mb.GetLength()) );

delete [] pszData;
// 重新载入
return Init();
}

vector vec = InternalBase64::decode( tempstr );
char * pszt = (char*) pszData;
for( size_t i = 0; i < vec.size() ; i++ ) {
pszt[i] = vec[i];
}
dwSize = vec.size();
}

TCHAR * pszTemp = wcstok(pszData + 1, _T("\r\n"));
while(pszTemp != NULL)
{
nLen = wcslen(pszTemp);
while(pszTemp[nLen - 1] == '\t' || pszTemp[nLen - 1] == ' ')
{
nLen --;
pszTemp[nLen] = 0;
}
while(*pszTemp == '\t' || *pszTemp == ' ')
{
pszTemp ++;
nLen --;
}
//AddLogLine(false,_T("pszTemp:%s"),pszTemp);
//AddLogLine(false,_T("nLen:%d"),nLen);
if(nLen > 0)list.AddTail(pszTemp);
//if(nLen == 8)AddLogLine(false,_T(":%d %d %d %d "),((char*)pszTemp)[0],((char*)pszTemp)[1],((char*)pszTemp)[2],((char*)pszTemp)[3]);
pszTemp = wcstok(NULL, _T("\r\n"));
}
}

delete[] pszData;

m_count = list.GetCount();
//AddLogLine(false,_T("m_count:%d"),m_count);

if(bResult && m_count > 0)
{
m_filterwords = new TCHAR*[m_count+1];
m_kmpvalue = new int*[m_count+1];
ZeroMemory(m_filterwords, sizeof(TCHAR *) * m_count);
ZeroMemory(m_kmpvalue, sizeof(int *) * m_count);
}

for(int i = 0; bResult && (i < m_count); i ++)
{
CString s = list.GetAt(list.FindIndex(i));
s.MakeLower();
nLen = s.GetLength();
//AddLogLine(false,_T("nLen:%d"),nLen);
m_filterwords[i] = new TCHAR[nLen + 1];
m_filterwords[i][nLen] = 0; // 最后一个字节设为0
m_kmpvalue[i] = new int[nLen];
//AddLogLine(false,_T("nLen:%d"),nLen);
_tcscpy(m_filterwords[i],s);
//AddLogLine(false,_T("m_filterwords[i]:%s"),m_filterwords[i]);
KMP_GetNext(m_filterwords[i], m_kmpvalue[i]); // 得到一个与内容有关的数值m_kmpvalue[i]
}

if(m_count == 0 || !bResult)
{
Free();
//m_filterall = true;
}
}


bool CWordFilter::VerifyString(const CString & sString) // 验证字符是否合法
{
bool bIsRm = sString.Right(3)==_T(".rm");
CString sReduceString=sString;
CString sInterpunctionString = _T("(),().。·;:-《》『』~ “”〓!【】★×┇");
try // VC-Huby[2007-03-20]:满足中国国情特色,加强过滤
{
int j=0;
for( int i=0; i< sString.GetLength(); i++ )
{
if( sString.GetAt(i)<=_T('/') && sString.GetAt(i)>=_T(' ') ) //从空格到'/'之间的字符减掉后再过滤
{
continue;
}
else if( sString.GetAt(i)<=_T('@') && sString.GetAt(i)>=_T(':') )
{
continue;
}
else if( sString.GetAt(i)<=_T('`') && sString.GetAt(i)>=_T('[') )
{
continue;
}
else if( sString.GetAt(i)<=_T('~') && sString.GetAt(i)>=_T('{') )
{
continue;
}
else if( sInterpunctionString.Find(sString.GetAt(i))>=0 )
{
continue;
}
else
{
sReduceString.SetAt(j,sString.GetAt(i));
j++;
}
}
if( j< sString.GetLength() )
sReduceString.SetAt(j,_T('\0'));
}
catch (...)
{
}

if(m_filterall){
//AddLogLine(false,_T("m_filterall"));
return true; // 检测不到文件,或者读取错误的情况下放弃过滤
}
if(m_count == 0){
//AddLogLine(false,_T("m_count == 0"));
return true; // 文件是空的时候,放弃过滤功能
}
CString strSearch = ((CString)sReduceString).MakeLower();

//vc-huby: 过滤中文字符超过15字符
//CString sReduceString2=strSearch;
int k=0;
for( int i=0; i< strSearch.GetLength(); i++ )
{
if( strSearch.GetAt(i)<=_T('9') && strSearch.GetAt(i)>=_T('0') )
{
continue;
}
if( strSearch.GetAt(i)<=_T('z') && strSearch.GetAt(i)>=_T('a') )
{
continue;
}
else
{
k++;
}
}

if( k>=20 && bIsRm )
return false;
//int m = sReduceString2.GetLength();
/*
if( k>=60 )
return false;*/


/*if (strSearch.GetLength() > 20)
{
return false;
}*/

for(int i = 0; i < m_count; i ++)
{
if(KMP_Match(strSearch, m_filterwords[i], m_kmpvalue[i]))
{
//AddLogLine(false,_T("KMP_Match"));
return false; // 关键词命中了,被fliter了
}
}
//AddLogLine(false,_T("漏掉的"));
return true;

}

void CWordFilter::Free() //
{
for(int i = 0; i < m_count; i ++)
{
if(m_filterwords[i])
delete[] m_filterwords[i];
if(m_kmpvalue[i])
delete[] m_kmpvalue[i];
}
delete[] m_filterwords;
delete[] m_kmpvalue;
}

CWordFilter::~CWordFilter()
{
Free();
}
其中WordFilter.h的第17行有以下定义。
#define FLITER_FILE _T("wordfilter.txt")
于是贝壳查看了C:\Program Files\eMule\config目录,在下面发现了wordfilter.txt 2007-09-30 12:58 10788。大家有兴趣自己看看里面的内容,贝壳就不贴了,贴出来绝对被封,死1090次。
下面说一点起效方式,也许大家很奇怪,这些内容是可以搜索的。贝壳仔细查看了代码,类在两处被引用了,一个是MFC初始化系统的时候初始化类,载入词典。另外一个是在SearchList.cpp 2007-11-20 17:56 22505,351行AddToList函数,第360行,内容如下。
// WordFilter added by kernel1983 2006.07.31
if(!WordFilter.VerifyString(toadd->GetFileName()))
{
delete toadd;
return false;
}
这个封锁手法尤其狠毒,并非封锁你的搜索,而是如果你的文件信息内有这些关键词,那么文件共享消息就不会被发送到服务器上,如同这个文件没有被共享一样。这样既没有用户会发现被封锁的事实(因为有少量其他客户端的数据会被检索出来),又能达到封锁的目地。
当然,贝壳理解VeryCD这帮人的苦心,毕竟他们还住在中国,不过估计从此后,贝壳和朋友的机器上不会装VeryCD了。

没有评论: