After a smooth connection to the main terminal, according to a program of execution logic, the host will be on the local to reflect the local state of a message sent to the main terminal, this process actually involves the control side and the main control end of the interaction between the information process.
*******************************************************************************
We need to start with the Sendlogininfo function. Let's take a look at the implementation of this function
Explain this function, we have to know a structure, this structure is the legend of the online package, a lot of killing soft now has been intercepted this online package, in the installation of the machine on the killing soft if there is this online packet data in the outward transmission, then kill the soft will think it is controlled by the remote control your computer, therefore, The kill soft will intercept the transmission of this on-line package. So, if we want our remote control to work, we have to make a modification to the online package so that we can't match it when the kill is soft enough to match our online package. In this way, you will avoid anti-virus software to prevent black wall interception.
The structure of this online package is shown in the following figure:
A complete set of operations for this function is to populate the values in this data structure.
First, declare that the type of the online package is the online package
Logininfo.btoken = Token_login;
Then get the version information of the operating system
BOOL GetVersionEx (lposversioninfoLpversioninformation);TheGetVersionExfunction obtains extended information about the version of the operating system, which is currently running. Call this function to get the currently running Extended version information for the system. Get host Nameint GetHostName (char FAR *Name, intNamelen);The Windows SocketsGetHostNamefunction returns the standard host name is the local machine. Call this function to return the standard host name for this machine. Get the IP address of the connectionint getsockname (SOCKETS, struct sockaddr far*Name, int far*Namelen);The Windows Socketsgetsocknamefunction retrieves the local name for a socket. This function returns a native IP address for the specified socket used for the connection. Get the CPU FrequencyLogininfo.cpuclockmhz = Cpuclockmhz ();We take a look at the CPU frequency, the CPU frequency is obtained by querying the registry key values to obtain.
Get the number of CPUsVOID getsysteminfo (lpsystem_infoLpsysteminfo);TheGetSystemInfofunction returns information about the current system.Calling this function returns some information about the current system. Get video Information Logininfo.biswebcam = Iswebcam (); The process of obtaining video information is judged by traversing the existence of at least one of the 10 video drivers.BOOL Vfwapi capgetdriverdescription (WORDWdriverindex, LPSTRLpszName, INTCBName, LPSTRLpszver, INTCbver );Thecapgetdriverdescriptionfunction retrieves the version description of the capture driver.Index of the capture driver. The index can range from 0 through 9. Call this function to return the video-driven version information and return FALSE if it does not exist. Get CPU processing speed, this parameter is considered by a time period. Logininfo.dwspeed = GetTickCount () _1-gettickcount () _2 Gets a comment information, which is stored in the registry of the controlled side to obtain a version of information, version information, version information is self-filled. lstrcpy (Logininfo.ver, "0.2"); Make a summary of the above process
After organizing the above data, we start to send the online package to the main control side, and then we look at the process of sending the data. cclientsocket::send This function is the process of organizing the packets to be sent, and we'll look at the process of organizing the data in detail next. First, the data to be sent is in the parameter: lpdata, and the size of the data to be sent is specified by the parameter: nsize. first, the buffer that will need to host the sending data is emptied first: M_writebuffer.clearbuffer (); then compresses the data. This place to note: Before compression, this value is calculated as: unsigned long Destlen = (double) nSize * 1.001 + 12; this one is fixed. Because, in memory, the data is compressed to a certain size of the work space, so according to this formula to calculate the amount of space required for work, and then request a memory space of this size as the compressed data storage space. Then use compress for compression processing:int nret = Compress (PDest, &destlen, lpdata, NSize) Note that when this function is completed, a size after which the data has been compressed is returned in the parameter Destlen. Next, start organizing the data to send in the send buffer long Nbuflen = Destlen + hdr_size; m_writebuffer.write (m_ Bpacketflag, sizeof (M_bpacketflag)), m_writebuffer.write ((pbyte) &nbuflen, sizeof (Nbuflen)); m_ Writebuffer.write ((pbyte) &nsize, sizeof (nSize)), m_writebuffer.write (PDest, Destlen); packet send tag + The size of the entire packet + uncompressed before the packet size + compressed data Then, back up the data to be sent to M_resThe Endwritebuffer buffer. of course, there is a small function in the data sent by this Organization, that is, when the data is received, if something goes wrong, you can alert the host to resend the data. The code described above shows the following: When the managed side receives the data, it calls the Cclientsocket::onread function, and in the execution of this function, the following action is performed when an error occurs: when a send (NULL, 0) This call will execute m_writebuffer.write (m_bpacketflag, sizeof (M_bpacketflag)); m_ Resendwritebuffer.clearbuffer (); m_resendwritebuffer.write (M_bpacketflag, sizeof (M_bpacketflag)); Only send a transmission flag packet to the main terminal, when the host receives this special data, there will be a logical process to resend the data. about this sending process, here we simply describe the: first in a large loop to send nsplitsize*n packets, after sending these packets, Either there are less than nsplitsize packets, or a packet of size 0 is left, and then the packet is sent in the following loop. The above process is complete, which completes the process of sending data from the controlled end to the main control side. Next, we need to look at how the main terminal receives these data and processes it. at the main control, we notice that the Iocpserver::onaccpet function, at the end of this function, made a call to the command: POSTRECV (pContext); Here we look again at the implementation of this function: if you know a little bit about IOCP high-performance server, you will feel familiar with this operation. For example, when associating the completion port with a handle unique numeric--cllientcontext, such as overlappedplus why this structure to design: Class Overlappedplus {public:overlapped M_OL;IOTYPE    &Nbsp; M_iotype;overlappedplus (Iotype iotype) {ZeroMemory (this, sizeof (Overlappedplus)); m_ Iotype = Iotype;}};o verlapped M_ol After this variable m_iotype is the legendary Per-io data, according to this data, we can know, exactly what kind of request is delivered to the completion port, and can be processed. Here is a request to the completion port to read the data, when there is data to reach the completion port, waiting on the completion port, the thread function for the completion port service will be awakened, continue to execute down. Here, we analyze the thread function that completes the port service, and the number of worker threads is related to the number of CPU cores in the system. Next, we analyze the execution logic of the worker thread.
in front of the function is the definition of some variables, the meanings of which we have already explained in the previous course, so we will not repeat them here. Let's focus on the invocation of two commands: InterlockedIncrement (&pthis->m_ncurrentthreads); InterlockedIncrement (&pthis->m_ Nbusythreads); In this case, the variable: M_ncurrentthread and M_nbusythreads in an atomic way to add 1 operations. The role of these two variables is what we look at some of the places that reference these two variables below. 1: In the Ciocpserver::ciocpserver constructor m_ncurrentthreads= 0;m_nbusythreads = 0; 2: in Ciocpserver:: Threadpoolfunc start part, that is, just enter the function of the worker thread interlockedincrement (&pthis->m_ncurrentthreads); Nterlockedincrement (&pthis->m_nbusythreads); 3: At the end of the Ciocpserver::threadpoolfunc, the time to leave the work thread function InterlockedIncrement (&pthis->m_ncurrentthreads); InterlockedIncrement (&pthis->m_ Nbusythreads); Therefore, these two variables are a value that records the number of worker threads in the current process that are completing the port service, except that m_ncurrentthreads is used to log all the number of worker threads for that completion port service, while another m_ Nbusythreads is used to record the number of threads that are awake in the number of threads that are working on the completion port, not the blocked state, and here is a reference to M_nbusythreads, which can be seen in action. This value is decremented before entering the GetQueuedCompletionStatus function to wait for a request to complete on the port: InterlockedDecrement (&pthis->m_ Nbusythreads), and when a thread waits for a request to occur, the GetqueueDcompletionstatus This function returns, an incremental operation is performed on the value of the variable: interlockedincrement (&pthis->m_nbusythreads). Then the program enters an infinite loop in which the incoming request for delivery is awaited and processed.
The theme of this loop is the GetQueuedCompletionStatus function, which is waiting on the completion port to wait for the completion port to arrive on the request. The two parameters used by this function are particularly important for understanding this code, one is Lpclientcontext and the other is lpoverlapped. Here we discuss the importance of these two parameters. First: Lpclientcontext This parameter is set in the Ciocpserver::associatesocketwithcompletionport function: HANDLE h = createiocompletionport ((HANDLE) socket, Hcompletionport, Dwcompletionkey, 0) The third parameter of this is Lpclientcontext. When an event occurs on this completion port, the value returned with the third parameter of GetQueuedCompletionStatus and CreaThe value of the third parameter of Teiocompletionport is relative, or they mean the same clientcontext. Second: lpoverlapped This parameter is set position has three, respectively is the control end just on-line, and the host side interacts with the control end of the socket has been associated with the completion port, will send a ioinitialize as additional data overlapped. overlappedplus *poverlap = new Overlappedplus (ioinitialize); BOOL bsuccess = postqueuedcompletionstatus (m_hcompletionport, 0, (DWORD) PContext, &poverlap->m_ol); when the data needs to be received, the first to send a request to receive data, This time a ioread is delivered as an additional data overlappedoverlappedplus * Poverlap = new Overlappedplus (ioread); ulong ulflags= msg_partial;dword DWNUMBEROFBYTESRECVD; UINT nretval = WSARecv (Pcontext->m_socket, &pContext->m_wsaInBuffer, 1, &DWNUMBEROFBYTESRECVD, &ulFlags, &poverlap->m_ol, NULL); In addition to knowing that a ioread type of request has been posted here, here is a point where the wsarecv indicates that when data arrives, the data is received into the clientcontext::m_wsainbuffer buffer. When the data needs to be sent, the first to send a request for data, this time will be posted a iowrite as additional data overlappedoverlappedplus * Poverlap = new Overlappedplus ( Iowrite); PostQueuedCompletionStatus (M_hcompletionport, 0, (DWORD PContext, &poverlap->m_ol); Where is the use of additional data? Look at the processing of additional data in this loop: Poverlapplus = Containing_record (lpoverlapped, Overlappedplus, M_ol); this containing_ A record is an enlargement of the pointer's scope, pointing to the entire definition structure, so that it can point to the entire Overlappedplus type with additional data, and is processed differently depending on the m_iotype domain of the attached data: processiomessage (Poverlapplus->m_iotype, Lpclientcontext, dwiosize); Next is a judgment on the return value of the GetQueuedCompletionStatus function, which is divided into the following cases. The first case: the other side closed off the communication socket, that is, the end of the control line off, this time the processing plan is to directly the data structure of the control end removed, and from the list box deleted. The second case is that the design in this program is not simply a processing of the return value of the GetQueuedCompletionStatus function. This is an adjustment of the worker thread based on one load capacity of the current CPU: If the current worker thread is busy, and the current CPUThere is also the ability to run a new thread, then open a new thread for the completion port service. If the load capacity of the current CPU is not enough, then kill the self-threading function appropriately. I thought there should be a logical branch that handles the active end of its own thread in this place of adjustment, because when the socket is closed, there are the following operations while (M_NWORKERCNT) { postqueuedcompletionstatus (m_hcompletionport, 0, (DWORD) null, NULL); Sleep (100);} In fact, this loop is a process that requires threads that work on the completion port to voluntarily end themselves.
3: Is the transmission of the correct situation, different requests for different processing, this differentiated processing function is processiomessage the implementation of this process we have in GH0ST Communication Protocol analysis (2) has a special description. And here we go back to the last drop request: sent by Ciocpserver::P rocessiomessage This function to complete the, about the definition of the function, have to look at a set of macro definitions: Enum iotype { ioinitialize, ioread, iowrite, ioidle }; #define BEGIN_IO_MSG_ MAP () \ public: \ bool processiomessage (Iotype clientio, clientcontext* pContext, DWORD dwsize = 0) \ {\&N Bsp;bool BRet = false; #define Io_message_handler (MSG, func) \ if (msg = = Clientio) \ & nbsp; BRet = func (PContext, dwsize); #define END_IO_MSG_MAP () \ return BRet; \ } Next, we need to look at the definition of where this macro is used: begin_io_msg_map () Io_message_handler (Ioread, onclientreading) Io_ Message_handler (Iowrite, onclientwriting) Io_message_ HANDLER (IoinitiaLize, onclientinitializing) end_io_msg_map () Macro expansion for this set of macro calls, when expanded: public: bool Processiomessage (Iotype clientio, clientcontext* pContext, DWORD dwsize = 0) \ { bool BRet = false; if (IOR EAD = = clientio) \ BRet = onclientreading (PContext, dwsize); if ( Iowrite = = clientio) \ BRet = onclientwriting (PContext, dwSize); if (ioinitialize = = clientio) \ BRet = OnClientInitializing ( PContext, dwsize); return bret; } therefore, This time by the accused end of the delivery of the package should be handled by the onclientreadling to deal with, we need to look at this function of the implementation process. At the beginning, a critical section was added to the code to make the code accessible in a multithreaded environment in an exclusive manner. This code should be accessed exclusively, because the caller of this function is called for the thread that is working on the port, and we know more than one thread is working on the completion port. The next step is some coding to reflect the speed of the transfer, where the only thing that needs our attention is a use of static variables. static DWORD Nlasttick = GetTickCount (); static DWORD nbytes = 0; Description of static local variable: 1: Static local variable executes the definition statement only at the time of the first call when the function is called multiple times. 2: StaticThe lifetime of a local variable does not end with the function being executed, it is stored in the global memory. Therefore, the above reaction transmission speed code should be so understood, when the first call to the Onclientreadling function, the static DWORD Nlasttick = GetTickCount (); static DWORD nbytes = 0; These two sentences will be executed, the next by judging whether the sampling time is more than a second, the first call will certainly not more than a second, but when the second call to the function, the two sentences defining the static variable will not be executed, at this time the value of nbytes will be the last transfer size + the size of the transmission, And the value of Nlasttick is the time of the last sampling, because the time of this sampling may exceed one second, therefore, the parameter that reflects the receiving speed m_nrecvkbps will be rewritten the value, and this time, the value of Nbytes and Nlasttick will be rewritten again. If the size of the received data is 0, indicating that in the process of data transmission encountered an unpredictable error, this time the client will be removed from its connection, let it reconnect, in the see here when I suddenly thought, gh0st is how to judge the control end has been offline problem, Here we look back, because the socket that the host interacts with the controlled side is set