可惜一个漂亮mm已经问了,大家都嫌她分少。本着助人为乐的精神,帮她问问。请大家帮忙啊。监视WM_ENDSESSION和WM_QUERYENDSESSION消息用了全局钩子,可是我用了还是没有反应,
不知哪位有过相关经验,如能告知,不胜感激!我在dll里建立了一个全局的钩子,如下:
SetWindowsHookEx(WH_GETMESSAGE, MyProc,   hInst, 0);回掉函数中来监视消息
LRESULT CALLBACK MyProc(int code, WPARAM wParam, LPARAM lParam)
{
switch (((MSG*)lParam)->message) 
{
    case WM_QUERYENDSESSION:
   {
switch( ((MSG*)lParam)->lParam )
{
case ENDSESSION_LOGOFF:
{
AfxMessageBox(TEXT("log off"));
                  //some other functions here
                  ((MSG*)lParam)->message=NULL;
}
break;
}
}
return ::CallNextHookEx(g_hHookscreensaver, code, wParam, lParam);
}可是点击注销后,没有弹出对话框,而且消息没有变空,还是直接注销了!
不知道为什么?

解决方案 »

  1.   

    1 系统的注销,采用的假如是强制方式,那么将不发送WM_ENDSESSION和WM_QUERYENDSESSION消息;
    2 确认一下switch语句是否走到了;
      

  2.   

    监视WM_ENDSESSION和WM_QUERYENDSESSION消息用了全局钩子???随便一个窗口响应这两个消息就行了。
    另外,我认为监视注销最好的方法是API HookHook API:ExitWindows/ExitWindowsEx
      

  3.   

    To:danyueer(淡月儿:清水上的足音)
    不是使用强制的方法,是正常的注销,就是因为在switch处设了断点也没用,才想问问各位经验丰富的人啦!
      

  4.   

    应该用WH_CALLWNDPROC钩子,我刚测试过,但是设置message=0;并不能阻止系统注销。(起码我没做出来)但是能响应消息。
    要注意的是:因为系统存在的窗口可能比较多,所以用钩子拦截这个消息的时候会出现很多次!
      

  5.   

    To:DentistryDoctor(雅克医生<改行做程序员了>)
    我去试试看。谢谢啦,有问题可能还要麻烦您呢!
      

  6.   

    To:hyamw(林锋) 
    其实我不是要阻止,那是试验,是想判断到用户注销,在注销前先处理自己的一些函数!
    我刚用WH_CALLWNDPROC钩子试了一下,不能响应注销消息呀,一点注销系统就说是否结束调试,应该怎么设参数,怎么响应消息呀?
      

  7.   

    当然不能在IDE的环境下调试了,一注销IDE会收到注销消息,当然会结束调试了。你可以直接运行,用AfxMessageBox(TEXT("log off"));来判断是否收到注销的消息。
      

  8.   

    就是把WH_GETMESSAGE换成WH_CALLWNDPROC后,回调函数还是这样对吧?
      

  9.   

    LRESULT CALLBACK MyProc(int code, WPARAM wParam, LPARAM lParam)
    {
    switch (((CWPSTRUCT*)lParam)->message) 
    {
    case WM_QUERYENDSESSION:
    {
    switch( ((CWPSTRUCT*)lParam)->lParam )
    {
    case ENDSESSION_LOGOFF:
    {
    FILE *pFile = NULL;
    ((CWPSTRUCT*)lParam)->message = 0;
    AfxMessageBox(TEXT("log off"));
    return 0;
    }
    break;
    }
    }
    }
    return ::CallNextHookEx(g_hMessage, code, wParam, lParam);
    }
      

  10.   

    消息有时不能拦截到
    拦截api
      

  11.   

    谢谢楼上,真的可以收到消息啦!成功~~~~
    遇到这个问题,顺便再去研究研究拦截api的hook。以前没用过,今天一搜看见好多帖子,学习ing~~~
      

  12.   

    如果要禁止注销,个人认为还是应该用hook API的方法
      

  13.   

    能否说得具体点,我看了一个钟头还是不太知道怎么用api hook?
      

  14.   

    (1) 打开前面创建的ActiveKey项目。  (2) 在ActiveKey.h文件中加入HOOKAPI结构,此结构用来存储被挡截API函数名称、原API函数地址和替代函数地址。   typedef struct tag_HOOKAPI 
       { 
       LPCSTR szFunc;//被HOOK的API函数名称。
       PROC pNewProc;//替代函数地址。
       PROC pOldProc;//原API函数地址。
       }HOOKAPI, *LPHOOKAPI;    (3) 打开ActiveKey.cpp文件,首先加入一个函数,用于定位输入库在输入数据段中的IAT地址。代码如下:   extern "C" __declspec(dllexport)PIMAGE_IMPORT_DESCRIPTOR 
       LocationIAT(HMODULE hModule, LPCSTR szImportMod) 
       //其中,hModule为进程模块句柄;szImportMod为输入库名称。
       { 
       //检查是否为DOS程序,如是返回NULL,因DOS程序没有IAT。
       PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule; 
       if(pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL; 
        //检查是否为NT标志,否则返回NULL。
        PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader+ (DWORD)(pDOSHeader->e_lfanew)); 
        if(pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL; 
        //没有IAT表则返回NULL。
        if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0) return NULL; 
        //定位第一个IAT位置。 
        PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDOSHeader + (DWORD)(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)); 
        //根据输入库名称循环检查所有的IAT,如匹配则返回该IAT地址,否则检测下一个IAT。
        while (pImportDesc->Name) 
        { 
         //获取该IAT描述的输入库名称。
       PSTR szCurrMod = (PSTR)((DWORD)pDOSHeader + (DWORD)(pImportDesc->Name)); 
       if (stricmp(szCurrMod, szImportMod) == 0) break; 
       pImportDesc++; 
        } 
        if(pImportDesc->Name == NULL) return NULL; 
       return pImportDesc; 
       }   再加入一个函数,用来定位被挡截API函数的IAT项并修改其内容为替代函数地址。代码如下:   extern "C" __declspec(dllexport) 
       HookAPIByName( HMODULE hModule, LPCSTR szImportMod, LPHOOKAPI pHookApi) 
       //其中,hModule为进程模块句柄;szImportMod为输入库名称;pHookAPI为HOOKAPI结构指针。
       { 
        //定位szImportMod输入库在输入数据段中的IAT地址。
        PIMAGE_IMPORT_DESCRIPTOR pImportDesc = LocationIAT(hModule, szImportMod); 
      if (pImportDesc == NULL) return FALSE; 
        //第一个Thunk地址。
        PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->OriginalFirstThunk)); 
       //第一个IAT项的Thunk地址。
        PIMAGE_THUNK_DATA pRealThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->FirstThunk)); 
        //循环查找被截API函数的IAT项,并使用替代函数地址修改其值。
       while(pOrigThunk->u1.Function) 

     //检测此Thunk是否为IAT项。
    if((pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG) 
    {
      //获取此IAT项所描述的函数名称。
     PIMAGE_IMPORT_BY_NAME pByName =(PIMAGE_IMPORT_BY_NAME)((DWORD)hModule+(DWORD)(pOrigThunk->u1.AddressOfData)); 
     if(pByName->Name[0] == '\0') return FALSE; 
      //检测是否为挡截函数。
    if(strcmpi(pHookApi->szFunc, (char*)pByName->Name) == 0) 
      { 
           MEMORY_BASIC_INFORMATION mbi_thunk;
           //查询修改页的信息。
           VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); 
    //改变修改页保护属性为PAGE_READWRITE。
           VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect); 
    //保存原来的API函数地址。
          if(pHookApi->pOldProc == NULL) 
    pHookApi->pOldProc = (PROC)pRealThunk->u1.Function; 
      //修改API函数IAT项内容为替代函数地址。
    pRealThunk->u1.Function = (PDWORD)pHookApi->pNewProc; 
    //恢复修改页保护属性。
    DWORD dwOldProtect; 
           VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect); 
          } 

      pOrigThunk++; 
      pRealThunk++; 

      SetLastError(ERROR_SUCCESS); //设置错误为ERROR_SUCCESS,表示成功。
      return TRUE; 
       }    (4) 定义替代函数,此实例中只给MessageBoxA和recv两个API进行挡截。代码如下:   static int WINAPI MessageBoxA1 (HWND hWnd , LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
       {
        //过滤掉原MessageBoxA的正文和标题内容,只显示如下内容。
    return MessageBox(hWnd, "Hook API OK!", "Hook API", uType); 
       } 
       static int WINAPI recv1(SOCKET s, char FAR *buf, int len, int flags )
       {
       //此处可以挡截游戏服务器发送来的网络数据包,可以加入分析和处理数据代码。
       return recv(s,buf,len,flags);
       }    (5) 在KeyboardProc函数中加入激活挡截API代码,在if( wParam == 0X79 )语句中后面加入如下else if语句:   ......
       //当激活F11键时,启动挡截API函数功能。
       else if( wParam == 0x7A )
       { 
        HOOKAPI api[2];
    api[0].szFunc ="MessageBoxA";//设置被挡截函数的名称。
    api[0].pNewProc = (PROC)MessageBoxA1;//设置替代函数的地址。
    api[1].szFunc ="recv";//设置被挡截函数的名称。
    api[1].pNewProc = (PROC)recv1; //设置替代函数的地址。
    //设置挡截User32.dll库中的MessageBoxA函数。
    HookAPIByName(GetModuleHandle(NULL),"User32.dll",&api[0]);
    //设置挡截Wsock32.dll库中的recv函数。
    HookAPIByName(GetModuleHandle(NULL),"Wsock32.dll",&api[1]);
       }
       ......    (6) 在ActiveKey.cpp中加入头文件声明 "#include "wsock32.h"。 从“工程”菜单中选择“设置”,弹出Project Setting对话框,选择Link标签,在“对象/库模块”中输入Ws2_32..lib。  (7) 重新编译ActiveKey项目,产生ActiveKey.dll文件,将其拷贝到Simulate.exe目录下。运行Simulate.exe并启动全局钩子。激活任意应用程序,按F11键后,运行此程序中可能调用MessageBoxA函数的操作,看看信息框是不是有所变化。同样,如此程序正在接收网络数据包,就可以实现封包功能了。抄来的文章,没测试过   :)
    如果要拦截所有应用程序的API,应该使用WH_GETMESSAGE等钩子
      

  15.   

    用Winlogon通知包(Winlogon Notification Package)
    就是一个DLL,HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify下创建一个项项里的说明:
    Asynchronous[REG_DWORD]:表明是否异步处理winlogon事件,如设为 1,winlogon将启动一个新线程来处理。
    DllName[REG_EXPAND_SZ]:指定要加载的DLL名。
    Impersonate[REG_DWORD]:表明是否以登陆用户的权限来处理事件。
    Lock[REG_SZ]:锁定桌面事件。
    Logoff[REG_SZ]:注销事件。
    Logon[REG_SZ]:登陆事件。
    Shutdown[REG_SZ]:关机事件。
    StartScreenSaver[REG_SZ]:启动屏保事件。
    StartShell[REG_SZ]:启动shell(一般指explorer.exe)事件。
    Startup[REG_SZ]:系统开机事件。
    StopScreenSaver[REG_SZ]:停止屏保事件。
    Unlock[REG_SZ]:解除桌面锁定事件。
      

  16.   

    在listeningsocket.cpp文件里添加:
    void CListeningSocket::OnAccept(int nErrorCode)
    {
    .........//要写什么就看你自己的了
    }
    定义了一个OnAccept()函数却没有实现,当然会出错了