如题,谢谢大家了,如果没有现成的代码能够指条路子也行。

解决方案 »

  1.   

    楼上的能不能说得详细一点,我对hook不了解
      

  2.   

    关于HOOKS
    使用HOOK 将会降低系统效率,因为它增加了系统处量消息的工作量。建议在必要时才使用HOOK,并在消息处理完成后立即移去该HOOK。
    HOOK链
    WINDOWS提供了几种不同类型的HOOKS;不同的HOOK可以处理不同的消息。例如,WH_MOUSE HOOK用来监视鼠标消息。
    WINDOWS为这几种HOOKS维护着各自的HOOK链。HOOK链是一个由应用程序定义的回调函数队列,当某种类型的消息发生时,WINDOWS向此种类型的HOOK链的第一个函数发送该消息,在第一函数处理完该消息后由该函数向链表中的下一个函数传递消息,依次向下。如果链中某个函数没有向下传送该消息,那么链表中后面的函数将得不到此消息。(对于某些类型的HOOK,不管HOOK链中的函数是否向下传递消息,与此类型HOOK联系的所有HOOK函数都会收到系统发送的消息)
    HOOK过程
    为了拦截特定的消息,你可以使用SetWindowsHookEx函数在该类型的HOOK链中安装你自己的HOOK函数。该函数语法如下:
    public function  MyHook(nCode,wParam,iParam) as long
    ‘加入代码
    end function
    其中MyHook可以随便命名,其它不能变。该函数必须放在模块段。nCode指定HOOK类型。wParam,iParam的取值随nCode不同而不同,它代表了某种类型的HOOK的某个特定的动作。
    SetWindowsHookEx总是将你的HOOK函数放置在HOOK链的顶端。你可以使用CallNextHookEx函数将系统消息传递给HOOK链中的下一个函数。
    [注释]对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时,HOOK函数中的CallNextHookEx语句将被忽略。
    全局HOOK函数可以拦截系统中所有线程的某个特定的消息(此时该HOOK函数必须放置在DLL中),局部HOOK函数可以拦截指定线程的某特定消息(此时该HOOK函数可以放置在DLL中,也可以放置在应用程序的模块段)。
    [注释] 建议只在调试时使用全局HOOK函数。全局HOOK函数将降低系统效率,并且会同其它使用该类HOOK的应用程序产生冲突。HOOK类型
    WH_CALLWNDPROC 和 WH_CALLWNDPROCRET  HOOK
    WH_CALLWNDPROC 和WH_CALLWNDPROCRET HOOK可以监视SendMessage发送的消息。系统在向窗体过程发送消息前,将调用WH_CALLWNDPROC;在窗体过程处理完该消息后系统将调用WH_CALLWNDPROCRET。
    WH_CALLWNDPROCRET HOOK会向HOOK过程传送一个CWPRETSTRUCT结构的地址。该结构包含了窗体过程处理系统消息后的一些信息。
    WH_CBT Hook
    系统在激活,创建,消毁,最小化,最大化,移动,改变窗体前;在完成一条系统命令前;在从系统消息队列中移去鼠标或键盘事件前;在设置输入焦点前,或同步系统消息队列前,将调用WH_CBT HOOK。你可以在你的HOOK 过程拦截该类HOOK,并返回一个值,告诉系统,是否继续执行上面的操作。
    WH_DEBUG HOOK
    系统在调用与某种HOOK类型联系的HOOK过程前,将调用WH_DEBUG ,应用程序可以使用该HOOK决定是否让系统执行某种类型的HOOK。
    WH_FOREGROUNDIDLE Hook
    系统在空闲时调用该HOOK,在后台执行优先权较低的应用程序。
    WH_GETMESSAGE Hook
    WH_GETMESSAGE Hook使应用程序可以拦截GetMessage 或 PeekMessage的消息。应用程序使用WH_GETMESSAGE HOOK监视鼠标、键盘输入和发送到队列中的其它消息。
    WH_JOURNALRECORD Hook
    WH_JOURNALRECORD Hook使应用程序可以监视输入事件。典型地,应用程序使用该HOOK记录鼠标、键盘输入事件以供以后回放。该HOOK是全局HOOK,并且不能在指定线程中使用。
    WH_JOURNALPLAYBACK Hook
    ` WH_JOURNALPLAYBACK Hook使应用程序可以向系统消息队列中插入消息。该HOOK可以回放以前由WH_JOURNALRECORD HOOK录制的鼠标、键盘输入事件。在WH_JOURNALPLAYBACK Hook安装到系统时,鼠标、键盘输入事件将被屏蔽。该HOOK同样是一个全局HOOK,不能在指定线程中使用。
    WH_JOURNALPLAYBACK Hook返回一个时间暂停值,它告诉系统,在处理当前回放的消息时,系统等待百分之几秒。这使得此HOOK可以控制在回放时的时间事件。
    WH_KEYBOARD Hook
    WH_KEYBOARD Hook使应用程序可以监视由GetMessage和PeekMessage返回的WM_KEYDOWN 及WM_KEYUP消息。应用程序使用该HOOK监视发送到消息队列中的键盘输入。
    WH_MOUSE Hook
    WH_MOUSE Hook 使应用程序可以监视由GetMessage和PeekMessage返回的消息。应用程序使用该HOOK监视发送到消息队列中的鼠标输入。
    WH_MSGFILTER and WH_SYSMSGFILTER Hooks
    WH_MSGFILTER 和WH_SYSMSGFILTER Hooks使应用程序可以监视菜单、滚动条、消息框、对话框,当用户使用ALT+TAB或ALT+ESC来切换窗体时,该HOOK也可以拦截到消息。WH_MSGFILTER仅在应用程序内部监视菜单、滚动条、消息框、对话框,而WH_SYSMSGFILTER则可以在系统内监视所有应用程序的这些事件。
    WH_SHELL Hook
    一个SHELL程序可以使用WH_SHELL Hook来接收重要的信息。当一个SHELL程序被激活前或当前窗体被创建、消毁时,系统会调用WH_SHELL Hook过程。
    使用HOOK
    安装、消毁HOOK过程
    监视系统事件安装、消毁HOOK过程
    使用SetWindowsHookEx函数,指定一个HOOK类型,自己的HOOK过程是全局还是局部HOOK,同时给出HOOK过程的进入点,就可以轻松的安装你自己的HOOK过程。
    为了安装一个全局HOOK过程,必须在应用程序外建立一个DLL,并将该HOOK函数封装到其中,应用程序在安装全局HOOK过程时必须先得到该DLL模块的句柄。将DLL名传递给LoadLibrary 函数,就会得到该DLL模块的句柄;得到该句柄 后,使用GetProcAddress函数可以得到HOOK过程的地址。最后,使用SetWindowsHookEx将HOOK过程的首址嵌入相应的HOOK链中,SetWindowsHookEx传递一个模块句柄,它为HOOK过程的进入点,线程标识符置为0,指出:该HOOK过程同系统中的所有线程关联。
    以下是C写的例程,大家可以方便的转换为VB程序。
    HOOKPROC hkprcSysMsg; 
    static HINSTANCE hinstDLL; 
    static HHOOK hhookSysMsg; 
    hinstDLL = LoadLibrary((LPCTSTR) "c:\\windows\\sysmsg.dll"); 
    hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc"); 
    hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER, 
        hkprcSysMsg, hinstDLL, 0);
      

  3.   

    首先得到所谓异常的弹出窗口的特征,然后根据特征来用hook等拦截窗口
      

  4.   

    to  oyljerry(勇敢的心) :
    异常窗口的特征是指?
    另,只能用hook就没有其他的办法了吗?
      

  5.   

    捕捉其他程序的异常比较困难,除非象softice这样去接管底层.
    关掉异常弹出的窗口是可以的.
    用消息钩子监控WM_SHOWWINDOW消息,如果符合条件,则post wm_close 消息
      

  6.   

    本人对hook不了解,如果必须得用hook的话那位兄弟能够告诉我具体怎么做?感谢!
      

  7.   

    一般程序出问题主要有两种异常:违规访问和空句柄,WIN32的API里有这两个异常的函数,直接HOOK就行了.
      

  8.   

    用DebugAPI吧,DebugAPI 可以捕获进程中的所有异常
    具体框架如下:
    1.取得进程ID,Win98/2000下用ToolHelp函数Process32First,Process32Next,
    NT4.0下用PSAPI,EnumProcess
    2.用DebugAPI调试进程,这需要写一个线程来等待调试事件CREATE_PROCESS_DEBUG_INFO dbgProcInfo;DWORD WINAPI ThreadProc(LPVOID lParam){
      if(!DebugActiveProcess(dwProcessID)){
         MessageBox(NULL,"调试进程失败!",NULL,MB_OK);
         return -1;
      }

      DEBUG_EVENT dbg;
      while(WaitForDebugEvent(&dbg,INFINITE)){
         //被调试进程触发退出事件
         if(dbg.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT){
    break;
         }
         //调试进程后将立刻触发的事件
         //可以将结构CREATE_PROCESS_DEBUG_INFO保存,留作后用,
         //结构具体定义参看msdn或Winbase.H
         if(dbg.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT){
    dbgProcInfo = dbg.u.CreateProcessInfo;
         }
         //被调试进程发生异常
         //值得注意的是在上面的CREATE_PROCESS_DEBUG_EVENT触发后,
         //紧接着就会触发一个int 3异常,中断被调试进程,只需简单的
         //::ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
         //就行了,被调试进程就会继续执行.
         else if(dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT){
             //结构DEBUG_EVENT中就存储着异常代码
             //dbg.u.Exception.ExceptionRecord.ExceptionCode [异常代码]
             //可以在这里选择做出异常处理,常见异常有:
    //EXCEPTION_ACCESS_VIOLATION = C0000005h   读写内存冲突
    //EXCEPTION_INT_DIVIDE_BY_ZERO = C0000094h 非法除0
    //EXCEPTION_STACK_OVERFLOW = C00000FDh     堆栈溢出或者越界
    //EXCEPTION_GUARD_PAGE = 80000001h 由Virtual Alloc建立起来的属性页冲突
    //EXCEPTION_NONCONTINUABLE_EXCEPTION = C0000025h
             //不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常
    //EXCEPTION_INVALID_DISPOSITION = C0000026h
             //在异常处理过程中系统使用的代码
    //EXCEPTION_BREAKPOINT = 80000003h 调试时因代码中int3中断
    //EXCEPTION_SINGLE_STEP = 80000004h 处于被单步调试状态(int 1)
             //还有一些我就不一一列出了,参看msdn
         }
         //下一句是将调试事件处理完之后的后续手段,dwContinueFlag 通常用DBG_CONTINUE
         //也就是让被调试进程继续执行
         //另外还可以用以下常数:(msdn中都有)
         //DBG_TERMINATE_THREAD
         //DBG_TERMINATE_PROCESS
         //DBG_CONTROL_C
         //DBG_CONTROL_BREAK
         //DBG_EXCEPTION_NOT_HANDLED
         ::ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,dwContinueFlag);
       }
    }至于关闭windows 的异常窗体,说实在的没用,既然你的进程发生了未处理异常,
    强制关闭windows 的提示窗口,进程也无法继续了。如果非要这么做的话,建议向进程的地址空间中插入一段异常处理代码.
    windows 弹出异常窗体是因为发生未处理异常,如果你插入处理代码就不会了在插入的代码中作如下处理
    //ExceptionFilterProc即异常处理函数
    SetUnhandledExceptionFilter(ExceptionFilterProc);
    异常处理函数定义如下
    DWORD __stdcall ExceptionFilterProc(EXCEPTION_POINTERS *){
       //如果你能处理该异常就处理,否则直接返回
       //返回值有如下选择
       //EXCEPTION_EXECUTE_HANDLER = 1    已经处理了异常,结束程序
       //EXCEPTION_CONTINUE_SEARCH = 0 不处理异常,转交系统处理(将弹出windows的消息框)
       //EXCEPTION_CONTINUE_EXECUTION = -1 修复错误,从异常发生处继续执行
    }这些东西虽然不是什么新鲜玩艺,也并不复杂,但如果你是初次接触的话,
    还是得花些功夫去研究的。建议学学Win32 ASM,看看在ASM中是怎样使用SEH的。
      

  9.   

    另外解答一下你的几个问题
    1.用户程序发生异常后,将被系统捕获
    2.Windows内部采用了结构化异常处理(SEH)来处理捕获的异常
    SEH有两种,一种是进程相关SEH,用API SetUnhandledExceptionFilter(ExpProc)
    来设置处理函数,进程中的任意一个线程发生异常都会在这处理.
    另一中是线程相关SEH,这是一个链式结构的DD,只处理指定相关线程中的异常,
    如果你没有在这个链中插入自己的异常处理函数,系统将弹出错误框,然后结束进程。
    3.在VC中,M$将SEH封装为
    __try{
    }__finally{
    }

    __try{
    }__except(DWORD ExceptionProc()){
    }两种
      

  10.   

    非常感谢 xlt123(杀了你好吗)!
    我采用你的方法基本上可以实现我的功能了,但现在有一个问题就是无论被调试程序有没有异常,只要我把调试程序关掉,被调试的程序也被关掉了,怎样才能使关掉调试程序时被调试程序(没有异常时)依然正常运行呢?
      

  11.   

    记得买第一台电脑的时候,小心翼翼的在电脑里装了一款诺顿的放死机软件(当时用Win98操作系统,稳定性不是很好。此款软件可侦测即将发生的bule screen ,并提前给出提示)。后来没用了,可发现其实并没有太大的区别,该死的总要死,不该死的总不会死。如果真的可以完全避免死机,微软早就作了。不知道你的目的是什么,个人观点,仅供参考。
      

  12.   

    原来如此,可惜我不懂,帮不上忙。帮你顶。up up up ! ! !
      

  13.   

    sorry,
    被DebuAPI挂接后的进程是无法摆脱挂接的,
    即调试进程结束后,被调试进程必然被结束。一个小经验:如果你想杀掉任务器中的一个进程,但任务
    管理器却告诉你“拒绝访问”,你可以选中进程,点鼠标
    右键,选择“调试”(当然,机器里得有调试器,如VC),
    就可以kill它了,对付某些恶心的病毒还是挺有用的.
      

  14.   

    这个,我的办法是,先远程注入一个dll到该进程,然后,dll里执行嵌入汇编,注意,要在程序进程空间内执行,搜索FS寄存器最后一个SEH节点得设置。这样,本来交给系统的异常,就交给了最后一个节点指定的地址。不过这个只能在win2000,nt,xp下使用。
    或者把exe当一个module使用loadLibrary读取进取,GetProcAddress导出main函数,try执行。
    当然,你的读取exe得exe得修改编译设置,不能把基地址指定0x400000
      

  15.   

    真的很失望,被挂接的程序在出现异常后被终止。不管怎样还是非常感谢xlt123(杀了你好吗) !to sx_enter(菜虫):你说的方法有点难,能说得详细一点吗?或者放点源码,多谢!
      

  16.   

    我觉得你可以让两个程序共享一个缓冲区,当一个程序的异常被捕获时,由该程序在这个共享缓冲区中设置标志值,和填入异常代码,另一个程序检测到共享缓冲区中的标志改变后,读取先前填入的异常代码。如果,被监测的程序在没有异常捕获前就终止了,另一个程序可以用win32 api函数每个一段时间查询先前的程荀进程是否还在。
      

  17.   

    不好意思,今天测试了一下我说的第2个办法,发现不行。除非自己重定位全部代码,所以过于麻烦。至于fs寄存器的那个,肯定可以。不过手头没有现成的代码,你查找一下有关windows seh的资料。