[VC++]控制檯程序窗口隱藏

HWND   hWnd;  

  SetConsoleTITle("HEHE");  

  hWnd=::FindWindow(NULL,"HEHE");  

  ShowWindow(hWnd,SW_HIDE); 

當創建一個控制檯程序時,又不想看到其窗口可用如下代碼解決:

#ifdef NDEBUG
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
#endif

首先來看一下linker的 /subsystem 選項  該選項的語法形式如下:
  
/SUBSYSTEM:{CONSOLE|EFI_APPLICATION|EFI_BOOT_SERVICE_DRIVER|
  
EFI_ROM|EFI_RUNTIME_DRIVER|NATIVE|POSIX|WINDOWS|WINDOWSCE}
  [,major[.minor]] 

 這個鏈接選項告訴操作系統如何運行可執行文件  CONSOLE:
  win32 字符模式應用程序,此種類型的應用程序在運行的時候會產生一個類似DOS窗口的控制檯窗口,如果在應用程序的主函數爲main()或者wmain(),在默認情況下該應用程序就是一個控制檯應用程序

  Extensible Firmware Interface和CPU具體架構相關的一個參數選項,並不常用,在這裏暫不詳細介紹.如果對此有興趣的可以訪問intel主頁來查看相關內容
   NATIVE;
  設備驅動器選項,如果/DRIVER:WDM選項被設定的話,該鏈接選項(NATIVE)就爲默認選項  

  POSIX:
  在windows NT 種運行在POSIX子系統上的應用程序  

  WINDOWS:
  該類型的應用程序不產生console窗口,該類型的應用程序的窗口由用戶自己創建,簡而言之就是一個標準的Win32 application,其入口地址爲WinMain()函數或者wWinMain()函數的地址如果你在應用程序種定義的主函數爲WinMain或者wWinMain,在默認情況下該應用程序就是一個Win32 Application !  

  WINDOWSCE:
  運行在windows CE上的應用程序  

  major and minor (optional):
  主版本號和次版本號,該選項爲可選,該選項爲0~65535之間的十進制整數  

  從上面可以看出如果我們建立一個win32 console application的話,linker的/subsystem選項應該爲CONSOLE,可以在VC開發環境的project->setting->link->project option中看到!  
  接下來我們再看看應用程序是如何運行的!
  我們知道用VC編寫的程序,運行的時候是需要 C\C++運行庫支持的.當我們運行一個C/C++程序的時候鏈接器會首先尋找應用程序的啓動函數,例如
:
  如果你建立了一個console程序的話,編譯器得鏈接開關會是以下這種形式

  /subsystem:"console" /entry:"mainCRTStartup"  (ANSI)
  
/subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)
  

  如果你建立了一個win32 application,編譯器得鏈接開關則會是一下形式
  /subsystem:"windows" /entry:"WinMain"  (ANSI)
  /sbusystem:"windows" /entry:"wWinMain" (UINCODE)  

  上面的兩種形式可以再project->setting->link->project option中看到上面的subsystem和entry並不需要都設置,如果你只設置了/subsystem:"console"的話,那麼默認的entry開關在默認情況下應爲/entry:"mainCRTStartup"反之,如果你在應用程序中定義了main函數的話,默認情況下,你的/subsystem開關應該爲/system:"console"  
  在默認情況下/subsystem 和/entry開關是匹配的,也就是console對應mainCRTStartup或者wmainCRTStartupwindows對應WinMain或者wWinMain  
  但是我們也可以通過手動改動的方式使他們不匹配  
  例如我們可以這樣改動  
  #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 設置入口地址  
  int main(int argc, char* argv[])

  {
  
MessageBox(NULL, "hello", "Notice", MB_OK);
  
return 0;
  }  

  在默認情況下鏈接器看到/subsystem下是windows選項的時候,它會自動尋找WinMain或者wWinMain  
  但我們強制指定入口地址,這樣運行程序的時候默認的console窗口就會隱藏!但我們強制指定入口地址,這樣運行程序的時候默認的console窗口就會隱藏!
上面是在代碼中使用#pragma指令來設置,還有一種就是直接在開發環境的

project->setting->link->project option中手工改動!
寫了這麼多,自己都有點感覺亂,沒有辦法,以前沒寫過什麼文章,所以措辭可能不太好,希望大家見諒。

1:如果console程序已經寫好了,不能改了,也可以。寫一個API程序,不要畫窗口,然後用CreateProcess調用寫好的console程序,把屬性設成SW_HIDE即可。
2:不能用控制檯來寫(CONSLOE),要用WINMAIN做入口就可以了,不畫窗口,別人就都看不見了. 你只用想想辦法把你的進程在任務欄裏面隱藏住就可以.
3:如果是console程序,用API函數GetStdHandle()獲得控制檯程序的窗口句柄,然後在隱藏窗口

4://這一句隱藏控制檯
#pragma   comment(linker,"/subsystem:\"windows\"  /entry:\"mainCRTStartup\"" )
你要寫控制檯程序就用這個

VC下揭開特洛伊木馬的隱藏面紗

一、引言
  特洛伊木馬曾在網上造成很大恐慌,此類黑客程序通過欺騙手段在普通網絡用戶端安裝木馬的服務端,使用戶的計算機在上網時留有後門,而黑客則可以通過這個後門對被感染的計算機隨心所欲地進行監視、破壞。顯然這種黑軟對於普通網絡用戶的危害是非常嚴重的。

  就本質而言黑客軟件仍然屬於應用程序,是基於套接字的網絡通訊程序。因此黑客能成功攻擊被感染計算機的一個非常必要的先決條件就是此時被攻擊方已經有木馬程序的服務端在運行。由於木馬程序是一種惡意程序,能在被攻擊者沒有察覺的情況下悄悄啓動運行爲攻擊者打開後門,故顯然不能象其他程序一樣堂而皇之的顯示在任務欄和任務列表中,否則會立即爲用戶所察覺而將其關閉,也就失去了爲攻擊者提供後門的作用。本文下面就針對其隱藏程序的機理展開討論。

  二、程序在任務欄中的隱藏原理

  程序在任務欄的隱藏比較簡單,首先要保證程序主界面的隱藏,一般是通過修改應用程序類的初始化實例函數InitInstance()ShowWindow()語句的SW_SHOW參數爲SW_HIDE來實現的。主界面隱藏的同時任務欄雖然也會消失,但在程序啓動時會閃一下,因此需要修改程序的擴展屬性。一種方法是SDK的寫法,即直接利用GetWindowLong()獲取到當前的擴展屬性然後通過邏輯運算去掉原有的WS_EX_APPWINDOW屬性,並新添加一個WS_EX_TOOLWINDOW屬性,這樣系統會將其認爲是一個工具條窗口而不會再在任務欄中加以顯示。最後需要將修改過的擴展屬性通過SetWindowLong()函數將其寫回。這兩個函數的聲明分別如下:

  LONG GetWindowLong(HWND hWnd,int nIndex);
  
LONG SetWindowLong(HWND hWnd,int nIndex,LONG dwNewLong);
  另一種很簡便的是MFC的寫法:在程序框架類的預創建窗口函數裏通過直接對CREATESTRUCT結構對象的邏輯操作而將程序屬性進行改變:

  
cs.style=WS_POPUP;
  cs.dwExStyle 
=WS_EX_TOOLWINDOW;
  這兩種寫法雖然表現形式各不相同,其本質都是一樣的。

三.程序在任務列表中的隱藏原理
  任務列表(Ctrl+Alt+Del時彈出的對話框)顯示了當前系統正在運行的一些應用程序,如果實現了上一步,雖然在任務欄看不見程序,但有經驗的用戶可以通過觀察任務列表而發現一些值得懷疑的應用程序而在此將其關閉。所以大多數黑軟也都通過較複雜的手段實現了自身在任務列表中的隱藏,使被發現的機會大大降低。

  在Win9x/2000中,一般每個應用程序都要通過一個API(應用程序接口)函數RegisterServiceProcess()向系統申請註冊成爲一個服務進程,並且也是通過這個函數註銷其服務進程來結束這個服務進程的運行。如果一個進程註冊爲一個服務進程,通過Ctrl+Alt+Del就可以在任務列表裏看見該進程的標題。而如果一個進程運行了但沒有向系統申請註冊成爲服務進程那麼就不會在任務列表裏顯示。黑軟也正是利用這個原理使自身在運行時能在任務列表中實現隱藏。該函數存放於系統內核Kernel32.dll中,具體聲明如下:

  
DWORD RegisterServiceProcess(DWORD dwProcessId,DWORD dwType);
  其第一個參數指定爲一個服務進程的進程標識,如果是0則註冊當前的進程;第二個參數指出是註冊還是註銷當前的進程,其狀態分別爲:RSP_SIMPLE_SERVICERSP_UNREGISTER_SERVICE。黑軟一般是在程序啓動初始化時首先從Kernel32.dll動態連接庫中將RegisterServiceProcess()函數加載到內存,然後再通過該函數將程序從任務列表中隱藏:

  //Kernel32.dll中加載RegisterServiceProcess()

  
HMODULE m_hKernel=::GetModuleHandle("Kernel32.DLL");
  
RSP m_rsp=(RSP)::GetProcAddress(m_hKernel,"RegisterServiceProcess");
  m_rsp(::GetCurrentProcessId(),1);//此時爲隱藏,當第二個參數爲0時顯示

  另外,還有一部分黑軟是通過ShowWindowAsync()函數啓動一個新的線程來顯示一個新窗口的。該函數的原形爲:

  
BOOL ShowWindowAsync(HWND hWnd,int nCmdShow);
  而黑軟正是鑽了該函數的第二個參數可以設置窗體顯示狀態的空子,在設置成SW_HIDE時就可以使目標窗體(黑軟)從任務列表中隱藏。

  四、小結

  以上就是Win9x/2000下的黑客程序所具備的一些基本功能,在此基礎上我們可以藉助於其實現技巧來編寫出一些諸如後臺監控之類的實用程序。並且可以通過對黑客類軟件的隱藏機理的分析能使廣大用戶對此類黑軟採取一些必要的措施,通過加強防範來使自己的損失防患於未然。

VC窗口啓動時隱藏

最近經常見論壇上有人問,程序在啓動時如何隱藏。以下是我總結的一些方法,歡迎大家討論,找出更好的方法。

    對於這類問題,大家最容易想到的可能就是在PreCreateWindow中添加cs.style &=~WS_VISIBLE;這是不可行的。程序仍可使用ShowWindow()將窗體顯示出來.

1.基於對話框的程序
   我在論壇上看到有人說在OnInitDialog()中加上ShowWindow(SW_HIDE)對話框便不出現了,其實是不可行的。至於原因,我認爲是系統是在OnInitDialog()後調用ShowWindow(SW_SHOW)讓對話框顯示的.可以添加下面代碼:
CXXDlg::OnInitDialog()
{
...
Sleep(5000);
return TRUE;
}
可以發現5秒後對話框才顯示出來.至於在何時調用的我也不清楚,但是我們可以在OnPaint()中加上ShowWindow(SW_HIDE),來達到隱藏的目的.不過使用的這種方法,會有一點閃爍.另外一種方法就是在OnInitDialog()中使用SetWindowPlacement()

GetWindowPlacement(&m_wp); //恢復時用
ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//從任務欄中去掉.

WINDOWPLACEMENT wp;
wp.length=sizeof(WINDOWPLACEMENT);
wp.flags=WPF_RESTORETOMAXIMIZED;
wp.showCmd=SW_HIDE;
SetWindowPlacement(&wp);

還有一種更簡單的方法:在OnInitDialog()中調用下面代碼.
SetWindowPos(&wndTop,0,0,0,0,NULL);

2.基於單文檔的程序

我們一般採用的方法就是將InitInstance()中的:
CXXApp::InitInstance()
{
   //m_pMainWnd->ShowWindow(SW_SHOW);
}
但是這樣窗體還會有閃爍。

因爲MFC還要在ActiveFrame顯示框架,所以我們還需要添加下面代碼:
void CMainFrame::ActivateFrame(int nCmdShow)
{
   nCmdShow=SW_HIDE;
   CFrameWnd::ActivateFrame(nCmdShow);
}
或者
:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   AfxGetApp()->m_nCmdShow=SW_HIDE;
}
順便說一下,上面通過ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW)的方法來實現從任務欄去掉按鈕,這樣當顯示時還要切換顯示的模式,其實還可以通過調用TaskbarList組件直接刪除和添加
:
ITaskbarList的定義在shobjidl.h(vs.net)中。

也可以手動定義:
DECLARE_INTERFACE_(ITaskbarList,IUnknown)
{
   STDMETHOD(QueryInterface)(THIS_ REFIID riid,LPVOID* ppvObj) PURE;
   STDMETHOD_(ULONG,AddRef)(THIS) PURE;
   STDMETHOD_(ULONG,Release)(THIS) PURE;
   STDMETHOD(ActivateTab)(HWND) PURE;
   STDMETHOD(AddTab)(HWND) PURE;
   STDMETHOD(DeleteTab)(HWND) PURE;
   STDMETHOD(HrInit)(void) PURE;
};
BOOL CMy2App::InitInstance()
{
   CoInitialize(0);
   ITaskbarList *pObj;
   CoCreateInstance(CLSID_TaskbarList,NULL,CLSCTX_INPROC_SERVER,IID_ITaskbarList,(void**)&pObj);
   pObj->DeleteTab(m_pMainWnd->m_hWnd); //從任務欄上刪除

   //pObj->AddTab(m_pMainWnd->m_hWnd); //添加

   pObj->Release();
   CoUninitialize();
}

所以我們還可以用將窗體最小化,並從任備欄上刪除按鈕的方法來實現隱藏.

有很多應用程序要求一起動就隱藏起來,這些程序多作爲後臺程序運行,希望不影響其他窗口,往往只在托盤區顯示一個圖標。這些程序通常都是對話框程序,而對話框在初始化的過程上與SDI、MDI的初始化是不同的,對話框只需要DoModule或者是CreateDialog等等對話框函數調用一次便可,SDI、MDI則要好幾步才行。這樣看來,對話框在使用方法上面是隱藏了不少細節的,其中就沒有SDI、MDI所要求的ShowWindow(nCmdShow)這一步。因此對話框要想一運行就隱藏,並不是很直接的。有一些方法可以做到這一點,下面我們就來看看幾種方案。
1.定時器

最直觀,又是最無奈的一個方法就是使用定時器。既然我們在對話框開始顯示之前不能用ShowWindow(SW_HIDE)將其隱藏,那就給一個時間讓它顯示,完了我們在隱藏它。

方法:

1.在OnInitDialog()函數裏設置定時器:(WINDOWS API裏面響應消息WM_INITDIALOG)

SetTimer(1, 1, NULL);
2.添加處理WM_TIMER的消息處理函數OnTimer,添加代碼:

if(nIDEvent == 1)
{
DeleteTimer(1);
ShowWindow(SW_HIDE);
}
這種方法的缺點是顯而易見的,使用定時器,使得程序的穩定性似乎打一個折扣;窗口是要先顯示出來的,那麼效果就是窗口閃了一下消失。

2.改變對話框顯示狀況

在對話框初始化時改變其顯示屬性可以讓它隱藏起來。方法是調用SetWindowPlacement函數:

BOOL CDialogExDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//DO something
WINDOWPLACEMENT wp;
wp.length=sizeof(WINDOWPLACEMENT);
wp.flags=WPF_RESTORETOMAXIMIZED;
wp.showCmd=SW_HIDE;
SetWindowPlacement(&wp);
return TRUE;
}
在需要顯示時(通常是響應熱鍵或者托盤圖標的鼠標消息):

WINDOWPLACEMENT wp;
wp.length=sizeof(WINDOWPLACEMENT);
wp.flags=WPF_RESTORETOMAXIMIZED;
wp.showCmd=SW_SHOW;
SetWindowPlacement(&wp);
這樣的效果很不理想:窗口顯示在屏幕的左上角,並且是隻有標題欄,要正常顯示,還需加上如下代碼:
定義一個成員變量
CRect rect;
在OnInitDialog()裏面:

GetWindowRect(&rect);
在需要顯示的地方:

SetWindowPos(&wndNoTopMost, wndRc.left, wndRc.top, wndRc.right, wndRc.bottom, SWP_SHOWWINDOW);
CenterWindow();
即使這樣,效果還是很差。

這種方法還有一個弊端是當程序開始運行並且隱藏起來後,原來激活的窗口變成了非激活狀態了,而當對話框顯示出來後,對話框自身也是非激活狀態的。


3.不繪製窗口
當對話框顯示時將要響應消息WM_PAINT繪製客戶區,相應消息WM_NCPAINT繪製窗口邊框。我們在窗口第一次自繪自身時隱藏窗口,可以收到比較良好的效果。由於窗口是先畫窗口邊框,所以我們僅需處理WM_NCPAINT即可。代碼如下:

添加WM_NCPAINT處理函數。
void CMyDialog::OnNcPaint()
{
static int i = 2;
if(i > 0)
{
i --;
ShowWindow(SW_HIDE);
}
else
CDialog::OnNcPaint();
}
這裏有個問題:爲什麼要定義靜態變量i而且設其值爲2呢?

我們只要窗口隱藏第一次,所以定義這個變量可以判斷是否時首次顯示窗口。當程序開始運行時,系統發送(SendMessage)WM_NCPAINT消息,此時程序的窗口邊框應該被顯示,但是此時我們沒有作任何顯示的操作,而是將窗口隱藏,ShowWindow(SW_HIDE)將把窗口的WS_VISIBLE屬性去掉,繼續執行,程序將檢查WS_VISIBLE屬性,如果沒有則顯示窗口,所以又發送了一個WM_NCPAINT消息。所以我們要處理兩次WM_NCPAINT消息。

在需要窗口顯示時,調用ShowWindow(SW_SHOW)即可。

程序執行的結果是,原來處於激活狀態的窗口可能會閃動兩下,然後仍然處於激活狀態。這種處理方式比上面的方式要優越得多。

4.將對話框作爲子窗口

這種方法是採用SDI框架,主窗口始終隱藏,對話框作爲主窗口的成員變量,在CMainFrame::OnCreate()裏面加入下代碼:

if(!dlg.Create(IDD_MYDIALOG, this))
{
return –1;
}
dlg.ShowWindow(SW_HIDE);
在要顯示對話框的地方用dlg.ShowWindow(SW_SHOW);即可。注意,主窗口一定要隱藏,否則對話框可能會閃現一下。

隱藏狀態欄窗口

上面介紹了幾種檢查對話框的方法,大家如果試過的話可能已經注意到系統狀態欄裏在程序啓動時會有程序的圖標閃過,在隱藏對話框的時候這個也是要隱藏的,方法很簡單:

在OnInitDialog()函數裏面加上ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);即可。在要顯示窗口的地方加上代碼ModifyStyleEx(WS_EX_TOOLWINDOW, WS_EX_APPWINDOW);即將窗口的擴展樣式改回來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章