1 #ifndef NCBI_WIN_HOOK__HPP
2 #define NCBI_WIN_HOOK__HPP
3 
4 /* $Id: ncbi_win_hook.hpp 403742 2013-06-18 15:26:09Z grichenk $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Sergey Sikorskiy
30  *
31  * File Description:  Windows DLL function hooking
32  *
33  */
34 
35 
36 /** @addtogroup WinHook
37  *
38  * @{
39  */
40 
41 #if defined(NCBI_OS_MSWIN)
42 
43 #include <corelib/ncbi_safe_static.hpp>
44 #include <process.h>
45 #include <Tlhelp32.h>
46 #include <vector>
47 
48 BEGIN_NCBI_SCOPE
49 
50 namespace NWinHook
51 {
52 
53     ///////////////////////////////////////////////////////////////////////////////
54     class NCBI_DBAPIDRIVER_EXPORT CWinHookException : public CCoreException
55     {
56     public:
57         enum EErrCode {
58             eDbghelp,
59             eDisabled
60         };
61 
62         /// Translate from the error code value to its string representation.
63         virtual const char* GetErrCodeString(void) const;
64 
65         // Standard exception boilerplate code.
66         NCBI_EXCEPTION_DEFAULT(CWinHookException, CCoreException);
67     };
68 
69 
70     ///////////////////////////////////////////////////////////////////////////////
71     /// class CHookedFunctions
72     ///
73     class CHookedFunction;
74 
75     int my_stricmp(const char* left, const char* right);
76 
77     // !!! Not thred-safe class !!!
78     class CHookedFunctions
79     {
80     public:
81         CHookedFunctions(void);
82         ~CHookedFunctions(void);
83 
84     public:
85         /// Return the address of an CHookedFunction object
86         CRef<CHookedFunction> GetHookedFunction(
87             PCSTR pszCalleeModName,
88             PCSTR pszFuncName
89             ) const;
90 
91         /// Return the address of an CHookedFunction object
92         CRef<CHookedFunction> GetHookedFunction(
93             HMODULE hmod,
94             PCSTR   pszFuncName
95             ) const;
96 
97         /// Add a new object to the container
98         BOOL AddHook(const CRef<CHookedFunction> pHook);
99         /// Remove exising object pointer from the container
100         BOOL RemoveHook(const CRef<CHookedFunction> pHook);
101 
102         void UnHookAllFuncs(void);
103 
HaveHookedFunctions(void) const104         bool HaveHookedFunctions(void) const
105         {
106 //             return(m_FunctionList.size() > 0);
107             size_t num = 0;
108 
109             ITERATE(TModuleList, it, m_ModuleList) {
110                 num += it->second.size();
111             }
112 
113             return (num > 0);
114         }
115 
116     private:
117         /// Return the name of the function from EAT by its ordinal value
118         BOOL x_GetFunctionNameFromExportSection(
119             HMODULE hmodOriginal,
120             DWORD   dwFuncOrdinalNum,
121             PSTR    pszFuncName
122             ) const;
123         /// Return the name of the function by its ordinal value
124         void x_GetFunctionNameByOrdinal(
125             PCSTR   pszCalleeModName,
126             DWORD   dwFuncOrdinalNum,
127             PSTR    pszFuncName
128             ) const;
129         void x_GetFunctionNameByOrdinal(
130             HMODULE hmodOriginal,
131             DWORD   dwFuncOrdinalNum,
132             PSTR    pszFuncName
133             ) const;
134 
135     private:
136         struct SNocaseCmp {
operator ()NWinHook::CHookedFunctions::SNocaseCmp137             bool operator()(const string& x, const string& y) const {
138                 return my_stricmp(x.c_str(), y.c_str()) < 0;
139             }
140         };
141         typedef map<string, CRef<CHookedFunction>, SNocaseCmp> TFunctionList;
142         typedef map<void*, TFunctionList> TModuleList;
143         typedef map<string, TFunctionList, SNocaseCmp> TModuleNameList;
144 
145         // TFunctionList m_FunctionList;
146         TModuleList     m_ModuleList;
147         TModuleNameList m_ModuleNameList;
148 
149         // Because of CApiHookMgr::HackModuleOnLoad
150         friend class CApiHookMgr;
151     };
152 
153 
154     ///////////////////////////////////////////////////////////////////////////////
155     /// class CApiHookMgr
156     ///
157     class CApiHookMgr {
158     private:
159         CApiHookMgr(void);
160         ~CApiHookMgr(void);
161         void operator =(const CApiHookMgr&);
162 
163     public:
164         static CApiHookMgr& GetInstance(void);
165 
166         /// Hook up an API
167         BOOL HookImport(PCSTR pszCalleeModName,
168                         PCSTR pszFuncName,
169                         PROC  pfnHook
170                         );
171 
172         /// Restore hooked up API function
173         BOOL UnHookImport(PCSTR pszCalleeModName,
174                           PCSTR pszFuncName
175                           );
176 
177         /// Used when a DLL is newly loaded after hooking a function
178         void WINAPI HackModuleOnLoad(HMODULE hmod,
179                                      DWORD   dwFlags
180                                      );
181 
182         /// Return the address of an CHookedFunction object
183         /// Protected version.
184         CRef<CHookedFunction> GetHookedFunction(HMODULE hmod,
185                                                 PCSTR   pszFuncName
186                                                 ) const;
187 
188         /// Indicates whether there is hooked function
189         bool HaveHookedFunctions(void) const;
190 
191     private:
192         /// Hook all needed system functions in order to trap loading libraries
193         BOOL x_HookSystemFuncs(void);
194 
195         /// Unhook all functions and restore original ones
196         void x_UnHookAllFuncs(void);
197 
198         /// Used to trap events when DLLs are loaded
199         static HMODULE WINAPI MyLoadLibraryA(PCSTR  pszModuleName);
200         /// Used to trap events when DLLs are loaded
201         static HMODULE WINAPI MyLoadLibraryW(PCWSTR pszModuleName);
202         /// Used to trap events when DLLs are loaded
203         static HMODULE WINAPI MyLoadLibraryExA(PCSTR  pszModuleName,
204                                                HANDLE hFile,
205                                                DWORD  dwFlags
206                                                );
207         /// Used to trap events when DLLs are loaded
208         static HMODULE WINAPI MyLoadLibraryExW(PCWSTR pszModuleName,
209                                                HANDLE hFile,
210                                                DWORD  dwFlags
211                                                );
212         /// Returns address of replacement function if hooked function is
213         /// requested
214         static FARPROC WINAPI MyGetProcAddress(HMODULE hmod,
215                                                PCSTR   pszProcName
216                                                );
217 
218         /// Returns original address of the API function
219         static FARPROC WINAPI xs_GetProcAddressWindows(
220             HMODULE hmod,
221             PCSTR   pszProcName
222             );
223 
224         /// Add a newly intercepted function to the container
225         BOOL x_AddHook(PCSTR  pszCalleeModName,
226                        PCSTR  pszFuncName,
227                        PROC   pfnOrig,
228                        PROC   pfnHook
229                        );
230 
231         /// Remove intercepted function from the container
232         BOOL x_RemoveHook(PCSTR pszCalleeModName,
233                           PCSTR pszFuncName
234                           );
235 
236         mutable CFastMutex m_Mutex;
237         /// Container keeps track of all hacked functions
238         CHookedFunctions m_pHookedFunctions;
239         /// Determines whether all system functions has been successfuly hacked
240         BOOL m_bSystemFuncsHooked;
241 
242         friend class CSafeStatic_Allocator<CApiHookMgr>;
243     };
244 
245 
246     class NCBI_DBAPIDRIVER_EXPORT COnExitProcess
247     {
248     public:
249         typedef void (*TFunct) (void);
250 
251         static COnExitProcess& Instance(void);
252 
253         // Return true in case of success.
254         bool Add(TFunct funct);
255         void Remove(TFunct funct);
256         void ClearAll(void);
257 
258     private:
259         COnExitProcess(void);
260         ~COnExitProcess(void);
261 
262         // Hook function prototype
263         static void WINAPI xs_ExitProcess(UINT uExitCode);
264 
265     private:
266         typedef vector<TFunct> TRegistry;
267 
268         CFastMutex  m_Mutex;
269         TRegistry   m_Registry;
270         bool        m_Hooked;
271 
272         friend class CSafeStatic_Allocator<COnExitProcess>;
273     };
274 }
275 
276 END_NCBI_SCOPE
277 
278 #endif // NCBI_OS_MSWIN
279 
280 /* @} */
281 
282 #endif  // NCBI_WIN_HOOK__HPP
283