From 5be1a70cf087c27e400f937804a970420e7ca853 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Tue, 6 Mar 2018 14:56:48 +0100 Subject: [PATCH 1/8] Update minhook to 1.3.3 --- include/minhook | 2 +- nvdaHelper/minHook/sconscript | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/minhook b/include/minhook index ed5b5119afb..8fda4f5481f 160000 --- a/include/minhook +++ b/include/minhook @@ -1 +1 @@ -Subproject commit ed5b5119afb4127dd66905e2899c3265d8040aea +Subproject commit 8fda4f5481fed5797dc2651cd91e238e9b3928c6 diff --git a/nvdaHelper/minHook/sconscript b/nvdaHelper/minHook/sconscript index 71d06f69b36..fa8b56481e8 100644 --- a/nvdaHelper/minHook/sconscript +++ b/nvdaHelper/minHook/sconscript @@ -10,15 +10,13 @@ env=env.Clone(CPPPATH=minhookPath.Dir('include')) if 'analyze' in env['nvdaHelperDebugFlags']: env.Append(CCFLAGS='/analyze-') -HDESourceFile='HDE64/src/HDE64.c' if env['TARGET_ARCH']=='x86_64' else 'HDE32/HDE32.c' +HDESourceFile='HDE/HDE64.c' if env['TARGET_ARCH']=='x86_64' else 'HDE/HDE32.c' sourceFiles=[ HDESourceFile, - 'buffer.cpp', - 'export.cpp', - 'hook.cpp', - 'thread.cpp', - 'trampoline.cpp', + 'buffer.c', + 'hook.c', + 'trampoline.c', ] objFiles=[env.Object('_minHook_%s.obj'%x.replace('/','_'),minhookPath.File('src/%s'%x)) for x in sourceFiles] From b1dddf94b18c1ec0707e81420f33d6c627666085 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Tue, 6 Mar 2018 15:05:53 +0100 Subject: [PATCH 2/8] Fix log for MH_Initialize --- nvdaHelper/remote/apiHook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index 4c9848e5a51..cd52deb77b0 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -78,7 +78,7 @@ defMHFP(MH_DisableHook); return false; } if ((res=MH_Initialize_fp())!=MH_OK) { - LOG_ERROR("MH_CreateHook failed with " << res); + LOG_ERROR("MH_Initialize failed with " << res); FreeLibrary(minhookLibHandle); minhookLibHandle=NULL; return false; From 1c77ab1f06ba28763d237730b888496c5386c6dd Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Tue, 6 Mar 2018 16:11:08 +0100 Subject: [PATCH 3/8] Updated license for minhook --- copying.txt | 150 ++++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/copying.txt b/copying.txt index a6660123844..017a1c16ddd 100644 --- a/copying.txt +++ b/copying.txt @@ -9,7 +9,7 @@ All applicable licenses are included below. = GNU General Public License version 2 = Most of the source code for NVDA itself is available under this license. -``` +`` Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. @@ -1199,85 +1199,87 @@ e) modify or distribute the source code of any Distributable Code so that any pa This applies to MinHook, available from http://github.com/RaMMicHaeL/minhook ``` -/* - * MinHook - The Minimalistic API Hooking Library for x64/x86 - * Copyright (c) 2009 Tsuda Kageyu. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ +MinHook - The Minimalistic API Hooking Library for x64/x86 +Copyright (C) 2009-2017 Tsuda Kageyu. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. ================================================================================ -/* - * Hacker Disassembler Engine 32 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ +Hacker Disassembler Engine 32 C +Copyright (c) 2008-2009, Vyacheslav Patkov. +All rights reserved. -/* - * Hacker Disassembler Engine 64 C - * Copyright (c) 2008-2009, Vyacheslav Patkov. - * All rights reserved. - * - */ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: -================================================================================ -Portions of this software are Copyright (c) 2005-2007 Paul Hsieh. -================================================================================ -/* A portable stdint.h - **************************************************************************** - * BSD License: - **************************************************************************** - * - * Copyright (c) 2005-2007 Paul Hsieh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +Hacker Disassembler Engine 64 C +Copyright (c) 2008-2009, Vyacheslav Patkov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` = The MIT License = From 56811bdd37f82a173eb33ed336342aee2e44e1d8 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Thu, 5 Apr 2018 14:53:40 +0200 Subject: [PATCH 4/8] Update Minhook function pointers and added new one for StatusToString. Provide more user friendly logging with StatusToString --- nvdaHelper/remote/apiHook.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index cd52deb77b0..4105cf82ba5 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -36,9 +36,10 @@ bool error_setNHFP=false; //function pointer typedefs for all minHook functions for use with getProcAddress typedef MH_STATUS(WINAPI *MH_Initialize_funcType)(); typedef MH_STATUS(WINAPI *MH_Uninitialize_funcType)(); -typedef MH_STATUS(WINAPI *MH_CreateHook_funcType)(void*,void*,void**); -typedef MH_STATUS(WINAPI *MH_EnableHook_funcType)(void*); -typedef MH_STATUS(WINAPI *MH_DisableHook_funcType)(void*); +typedef MH_STATUS(WINAPI *MH_CreateHook_funcType)(LPVOID,LPVOID,LPVOID*); +typedef MH_STATUS(WINAPI *MH_EnableHook_funcType)(LPVOID); +typedef MH_STATUS(WINAPI *MH_DisableHook_funcType)(LPVOID); +typedef const char*(WINAPI *MH_StatusToString_funcType)(MH_STATUS); #define defMHFP(funcName) funcName##_funcType funcName##_fp=NULL @@ -55,10 +56,11 @@ defMHFP(MH_Uninitialize); defMHFP(MH_CreateHook); defMHFP(MH_EnableHook); defMHFP(MH_DisableHook); +defMHFP(MH_StatusToString); bool apiHook_initialize() { LOG_DEBUG("calling MH_Initialize"); - int res; + MH_STATUS res; wstring dllPath=dllDirectory; dllPath+=L"\\minhook.dll"; if((minhookLibHandle=LoadLibrary(dllPath.c_str()))==NULL) { @@ -78,7 +80,7 @@ defMHFP(MH_DisableHook); return false; } if ((res=MH_Initialize_fp())!=MH_OK) { - LOG_ERROR("MH_Initialize failed with " << res); + LOG_ERROR("MH_Initialize failed with " << res << " (" << MH_StatusToString_fp(res) <<")"); FreeLibrary(minhookLibHandle); minhookLibHandle=NULL; return false; @@ -104,9 +106,9 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi } LOG_DEBUG("requesting to hook function " << functionName << " at address 0X" << std::hex << realFunc << " in module " << moduleName << " at address 0X" << moduleHandle << " with new function at address 0X" << newHookProc); void* origFunc; - int res; + MH_STATUS res; if((res=MH_CreateHook_fp(realFunc,newHookProc,&origFunc))!=MH_OK) { - LOG_ERROR("MH_CreateHook failed with " << res); + LOG_ERROR("MH_CreateHook failed with " << res << " (" << MH_StatusToString_fp(res) <<")"); FreeLibrary(moduleHandle); return NULL; } @@ -117,7 +119,7 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi } bool apiHook_enableHooks() { - int res; + MH_STATUS res; if(!minhookLibHandle) { LOG_ERROR(L"apiHooks not initialized"); return false; @@ -128,7 +130,7 @@ bool apiHook_enableHooks() { } bool apiHook_terminate() { - int res; + MH_STATUS res; //If the process is exiting then minHook will have already removed all hooks and unloaded if(isProcessExiting) return true; if(!minhookLibHandle) { From 32b4aacf895e0fc9d6c762a8ef6d894435eb1d42 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Mon, 9 Apr 2018 12:45:09 +0200 Subject: [PATCH 5/8] Revert logging with StatusToString, as it seem to cause crashes --- nvdaHelper/remote/apiHook.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index 4105cf82ba5..fde420e5444 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -39,7 +39,6 @@ typedef MH_STATUS(WINAPI *MH_Uninitialize_funcType)(); typedef MH_STATUS(WINAPI *MH_CreateHook_funcType)(LPVOID,LPVOID,LPVOID*); typedef MH_STATUS(WINAPI *MH_EnableHook_funcType)(LPVOID); typedef MH_STATUS(WINAPI *MH_DisableHook_funcType)(LPVOID); -typedef const char*(WINAPI *MH_StatusToString_funcType)(MH_STATUS); #define defMHFP(funcName) funcName##_funcType funcName##_fp=NULL @@ -56,7 +55,6 @@ defMHFP(MH_Uninitialize); defMHFP(MH_CreateHook); defMHFP(MH_EnableHook); defMHFP(MH_DisableHook); -defMHFP(MH_StatusToString); bool apiHook_initialize() { LOG_DEBUG("calling MH_Initialize"); @@ -80,7 +78,7 @@ defMHFP(MH_StatusToString); return false; } if ((res=MH_Initialize_fp())!=MH_OK) { - LOG_ERROR("MH_Initialize failed with " << res << " (" << MH_StatusToString_fp(res) <<")"); + LOG_ERROR("MH_Initialize failed with " << res); FreeLibrary(minhookLibHandle); minhookLibHandle=NULL; return false; @@ -108,7 +106,7 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi void* origFunc; MH_STATUS res; if((res=MH_CreateHook_fp(realFunc,newHookProc,&origFunc))!=MH_OK) { - LOG_ERROR("MH_CreateHook failed with " << res << " (" << MH_StatusToString_fp(res) <<")"); + LOG_ERROR("MH_CreateHook failed with " << res); FreeLibrary(moduleHandle); return NULL; } From e75dedd417cca3f4ec59a87ac2f88827fe1c4aa4 Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Mon, 9 Apr 2018 13:28:36 +0200 Subject: [PATCH 6/8] Make debugging minhook hooking errors more user friendly by also logging the module and function names in the error --- nvdaHelper/remote/apiHook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index fde420e5444..e7598d0ca8e 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -106,7 +106,7 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi void* origFunc; MH_STATUS res; if((res=MH_CreateHook_fp(realFunc,newHookProc,&origFunc))!=MH_OK) { - LOG_ERROR("MH_CreateHook failed with " << res); + LOG_ERROR("MH_CreateHook for function " << functionName << " in module " << moduleName << " failed with " << res); FreeLibrary(moduleHandle); return NULL; } From 0cb6dbd6d259f31f57d919bef4bef4919325a69d Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Mon, 9 Apr 2018 13:33:39 +0200 Subject: [PATCH 7/8] Review action --- copying.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/copying.txt b/copying.txt index 017a1c16ddd..b1bb62a8089 100644 --- a/copying.txt +++ b/copying.txt @@ -9,7 +9,7 @@ All applicable licenses are included below. = GNU General Public License version 2 = Most of the source code for NVDA itself is available under this license. -`` +``` Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. From 6e8c557d587cd62db0381c6554a810f66e4cc96b Mon Sep 17 00:00:00 2001 From: Leonard de Ruijter Date: Mon, 7 May 2018 06:08:29 +0200 Subject: [PATCH 8/8] Review actions --- nvdaHelper/remote/apiHook.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index e7598d0ca8e..3e855cc63e1 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -58,7 +58,6 @@ defMHFP(MH_DisableHook); bool apiHook_initialize() { LOG_DEBUG("calling MH_Initialize"); - MH_STATUS res; wstring dllPath=dllDirectory; dllPath+=L"\\minhook.dll"; if((minhookLibHandle=LoadLibrary(dllPath.c_str()))==NULL) { @@ -77,7 +76,8 @@ defMHFP(MH_DisableHook); minhookLibHandle=NULL; return false; } - if ((res=MH_Initialize_fp())!=MH_OK) { + MH_STATUS res = MH_Initialize_fp(); + if (res!=MH_OK) { LOG_ERROR("MH_Initialize failed with " << res); FreeLibrary(minhookLibHandle); minhookLibHandle=NULL; @@ -104,8 +104,8 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi } LOG_DEBUG("requesting to hook function " << functionName << " at address 0X" << std::hex << realFunc << " in module " << moduleName << " at address 0X" << moduleHandle << " with new function at address 0X" << newHookProc); void* origFunc; - MH_STATUS res; - if((res=MH_CreateHook_fp(realFunc,newHookProc,&origFunc))!=MH_OK) { + MH_STATUS res = MH_CreateHook_fp(realFunc,newHookProc,&origFunc); + if(res!=MH_OK) { LOG_ERROR("MH_CreateHook for function " << functionName << " in module " << moduleName << " failed with " << res); FreeLibrary(moduleHandle); return NULL; @@ -117,25 +117,23 @@ void* apiHook_hookFunction(const char* moduleName, const char* functionName, voi } bool apiHook_enableHooks() { - MH_STATUS res; if(!minhookLibHandle) { LOG_ERROR(L"apiHooks not initialized"); return false; } - res=MH_EnableHook_fp(MH_ALL_HOOKS); + MH_STATUS res=MH_EnableHook_fp(MH_ALL_HOOKS); nhAssert(res==MH_OK); return TRUE; } bool apiHook_terminate() { - MH_STATUS res; //If the process is exiting then minHook will have already removed all hooks and unloaded if(isProcessExiting) return true; if(!minhookLibHandle) { LOG_ERROR(L"apiHooks not initialized"); return false; } - res=MH_DisableHook_fp(MH_ALL_HOOKS); + MH_STATUS res=MH_DisableHook_fp(MH_ALL_HOOKS); nhAssert(res==MH_OK); g_hookedFunctions.clear(); //Give enough time for all hook functions to complete.