[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);即将窗口的扩展样式改回来。

发布了1 篇原创文章 · 获赞 1 · 访问量 1万+

  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);即将窗口的扩展样式改回来。

猜你喜欢

转载自blog.csdn.net/likeping/article/details/47045131