Overriding Dll | ||||||||||
1) Overriding Hook - Explanation - MessageBox example - Exe intenal example - Asm exe internal example 2) Pre Hook - Explanation - MessageBox example 3) Post Hook - Explanation - MessageBox example 4) Initializing data - Initializing data at dll loading 5) Debugging - Debugging an overriding Dll 1) Overriding Hook Explanation 1) First an overriding dll must contain a redirection array. This array defines a redirection table and the size of arguments. By the way if we want to redirect MessageBoxA calls to your own mMessageBoxA function, you need to had the following line to array {_T("User32.dll"),_T("MessageBoxA"),(FARPROC)mMessageBoxA,StackSizeOf(HWND)+StackSizeOf(LPCSTR)+StackSizeOf(LPCSTR)+StackSizeOf(UINT),0} The _T macro is just for an ansi/unicode compatibility. Library name "User32.dll" and function name "MessageBoxW" allow to get the address of original function to redirect. mMessageBoxW gives the address of your own function. At this point there's enough information to redirect. You next need to specify the size of parameters. This is done thanks to the "StackSizeOf" macro. So only do the sum of all StackSizeOf(ParameterType). Optionaly you can use the last array element to specify a different hook way (see the following for more information) 2) From now you only have to fill the content of your mMessageBoxA function.
Array syntax : { LibraryName ,FunctionName, FunctionHandler, StackSize, Additional Options} LibraryName is library name or one of WinAPIOverride keyword (DLL_ORDINAL@0xAddress@LibraryName, EXE_INTERNAL@0xAddress, EXE_INTERNAL_RVA@0xRelativeAddress, DLL_INTERNAL@0xAddress@LibraryName, EXE_INTERNAL_POINTER@0xAddress, EXE_INTERNAL_RVA_POINTER@0xRelativeAddress, DLL_INTERNAL_POINTER@0xAddress@LibraryName) FunctionName : function name Notice : For DLL_ORDINAL, EXE_INTERNAL, EXE_INTERNAL_RVA, DLL_INTERNAL, EXE_INTERNAL_POINTER, EXE_INTERNAL_RVA_POINTER and DLL_INTERNAL_POINTER you can put whatever you want for "FunctionName" parameter : as full address is specified by first parameter, FunctionName becomes useless. FunctionHandler : function called instead of original one : Must have same calling convention and parameters ! StackSize : stack size required by the function ( = sum(StackSizeOf(ParameterType)) Additional Options : Before Winapioverride 5.5.1 (overriding framework sdk version < 6) FirstBytesCanExecuteAnywhereSize : It allows you to specify if first bytes of function can be executed in another location. It's the same feature as the monitoring file "|FirstBytesCanExecuteAnywhere=" keyword. (see monitoring file advanced options) Put 0 if you want your dll to be the more portable. (Winapioverride will try to get the more efficient size by disassembling first opcodes) Else enter the number of first bytes to be executed at another location (between 5 and 64) If you want your function don't execute at another place (same as "|FirstBytesCantExecuteAnywhere" monitoring file keyword), put 0xFFFFFFFF. Since Winapioverride 5.5.1 (overriding framework sdk version >= 6) Combinaison (binary or) between the following : a) FirstBytesCanExecuteAnywhereSize : It allows you to specify if first bytes of function can be executed in another location. It's the same feature as the monitoring file "|FirstBytesCanExecuteAnywhere=" keyword. (see monitoring file advanced options) Put 0 if you want your dll to be the more portable. (Winapioverride will try to get the more efficient size by disassembling first opcodes) Else enter the number of first bytes to be executed at another location (between 5 and 64) If you want your function don't execute at another place (same as "|FirstBytesCantExecuteAnywhere" monitoring file keyword), use the OVERRIDING_DLL_API_OVERRIDE_EXTENDED_OPTION_FIRST_BYTES_CANT_EXECUTE_ANYWHERE flag. b) OVERRIDING_DLL_API_OVERRIDE_EXTENDED_OPTION_DONT_CHECK_MODULES_FILTERS flag : allow overriding to bypass overriding module filtering. That means your function will always be called instead of original API whatever the calling module. Array Items Examples {_T("User32.dll"),_T("MessageBoxA"),(FARPROC)mMessageBoxA,StackSizeOf(HWND)+StackSizeOf(LPCSTR)+StackSizeOf(LPCSTR)+StackSizeOf(UINT),0} {_T("EXE_INTERNAL@0x4010A0"),_T("RotateRegisters"),(FARPROC)mRotateRegisters,0,0} {_T("EXE_INTERNAL@0x401000"),_T("add"),(FARPROC)mInternalAddSample,StackSizeOf(int)+StackSizeOf(int),0} {_T("DLL_INTERNAL@0x1000@MyDll"),_T("TheNameIWant"),(FARPROC)myFunc,StackSizeOf(BYTE),0} {_T("DLL_ORDINAL@0x1e4@user32.dll"),_T("MessageBoxW"),(FARPROC)mMessageBoxW,StackSizeOf(HWND)+StackSizeOf(LPCWSTR)+StackSizeOf(LPCWSTR)+StackSizeOf(UINT),0} MessageBox example
Exe intenal example
Asm exe internal example Source code of asm file :
2) Pre Hook Explanation You have to fill the redirection array called "pArrayBeforeAPICall". Array syntax : { LibraryName ,FunctionName, FunctionHandler, StackSize, FirstBytesCanExecuteAnywhereSize,UserParam} LibraryName is library name or one of WinAPIOverride keyword (DLL_ORDINAL@0xAddress@LibraryName, EXE_INTERNAL@0xAddress, DLL_INTERNAL@0xAddress@LibraryName, EXE_INTERNAL_POINTER@0xAddress, DLL_INTERNAL_POINTER@0xAddress@LibraryName) FunctionName : function name Notice : For DLL_ORDINAL, EXE_INTERNAL, DLL_INTERNAL, EXE_INTERNAL_POINTER and DLL_INTERNAL_POINTER you can put whatever you want for "FunctionName" parameter : as full address is specified by first parameter, FunctionName becomes useless. FunctionHandler : function called before the original one. See below for it's declaration StackSize : stack size rquired by the function ( = sum(StackSizeOf(ParameterType)) FirstBytesCanExecuteAnywhereSize : same keyword as monitoring file one. Put 0 for better compatibility (for more information see monitoring files advanced syntax) and put 0xFFFFFFFF, if you want your function don't execute at another place (same as "|FirstBytesCantExecuteAnywhere" monitoring file keyword) UserParam : a value that will be provided to you as UserParam arg when your hook function will be called FunctionHandler decalration : Here the call back function must have following declaration BOOL __stdcall YourFunction(PBYTE pEspArgs,REGISTERS* pBeforeCallRegisters,PRE_POST_API_CALL_HOOK_INFOS* pHookInfos,PVOID UserParam). where provided parameters are the following : pEspArgs : pointer to current stack. So parameter 0 = *((PBYTE*)pEspArgs); parameter 1= *((PBYTE*)(pEspArgs+StackSizeOf(Param0Type))) parameter 2 = *((PBYTE*)(pEspArgs+StackSizeOf(Param0Type)+StackSizeOf(Param1Type))) pBeforeCallRegisters register (eax, ebx, ...) pHookInfos : gives you some information like: - the return address of API having created object, - the handle of module having done call - if current call match current overriding modules filters UserParam : UserParam value provided in pArrayBeforeAPICall. Returned Value : As you can use multiple Pre Hook functions for the same API, the returned value specify if other Pre Hook functions defined for this API must be called or not. Returning TRUE, other functions will be called. Returning FALSE, other functions won't be called. MessageBox example Example can be found in directory "Overriding Dll SDK\API\PrePostHooksMsgBox" First we fill the pArrayBeforeAPICall array. Here we use the same callback for MessageBoxA and MessageBoxW, using the user param to make difference in callback (0 for MessageBoxA and 1 for MessageBoxW) Next we write our functions handler
3) Post Hook Explanation You have to fill the redirection array called "pArrayAfterAPICall". Array syntax : { LibraryName ,FunctionName, FunctionHandler, StackSize, FirstBytesCanExecuteAnywhereSize,UserParam} LibraryName is library name or one of WinAPIOverride keyword (DLL_ORDINAL@0xAddress@LibraryName, EXE_INTERNAL@0xAddress, DLL_INTERNAL@0xAddress@LibraryName, EXE_INTERNAL_POINTER@0xAddress, DLL_INTERNAL_POINTER@0xAddress@LibraryName) FunctionName : function name Notice : For DLL_ORDINAL, EXE_INTERNAL, DLL_INTERNAL, EXE_INTERNAL_POINTER and DLL_INTERNAL_POINTER you can put whatever you want for "FunctionName" parameter : as full address is specified by first parameter, FunctionName becomes useless. FunctionHandler : function called after the original one. See below for it's declaration StackSize : stack size rquired by the function ( = sum(StackSizeOf(ParameterType)) FirstBytesCanExecuteAnywhereSize : same keyword as monitoring file one. Put 0 for better compatibility (for more information see monitoring files advanced syntax) and put 0xFFFFFFFF, if you want your function don't execute at another place (same as "|FirstBytesCantExecuteAnywhere" monitoring file keyword) UserParam : a value that will be provided to you as UserParam arg when your hook function will be called FunctionHandler decalration : Here the call back function must have following declaration BOOL __stdcall YourFunction(PBYTE pEspArgs,REGISTERS* pAfterCallRegisters,PRE_POST_API_CALL_HOOK_INFOS* pHookInfos,PVOID UserParam). where provided parameters are the following : pEspArgs : pointer to current stack. So parameter 0 = *((PBYTE*)pEspArgs); parameter 1= *((PBYTE*)(pEspArgs+StackSizeOf(Param0Type))) parameter 2 = *((PBYTE*)(pEspArgs+StackSizeOf(Param0Type)+StackSizeOf(Param1Type))) pBeforeCallRegisters register (eax, ebx, ...) pHookInfos : gives you some information like: - the return address of API having created object, - the handle of module having done call - if current call match current overriding modules filters UserParam : UserParam value provided in pArrayBeforeAPICall. Returned Value : As you can use multiple Pre Hook functions for the same API, the returned value specify if other Pre Hook functions defined for this API must be called or not. Returning TRUE, other functions will be called. Returning FALSE, other functions won't be called. MessageBox example Example can be found in directory "Overriding Dll SDK\API\PrePostHooksMsgBox" First we fill the pArrayAfterAPICall array. Here we use the same 1 callback for MessageBoxA and 2 for MessageBoxW Next we write our functions handler
4) Initializing data Initializing data at dll loading By default, overriding dlls do not use DllMain. So fill free to use it to get function addresses, set some array UserParams, or do your own variables initialization. By the way, if you need the NtDeviceIoControlFile function in your overrinding functions, as it must be dynamically loaded, you can do the following
5) Debugging Debugging an overriding Dll If your overriding dll is crashing, the following steps must be followed Notice : A classical error is due to lack of parameter checking. 1) Assume that function can be hooked To do it, just make a monitoring file containing only the function name you want to override. Load it into your target application. If monitoring works, that means function can be hooked and overrideed, else don't loose your time: it's not possible 2) Make test of your code in a small exe. Copy the code of your overriding dll, and make a call of it in the main function This can solve basics troubles. 3) a) If code crash quicky : Open your dll project, set it in debug configuration, put a breakpoint on your overrided functions, specify the targeted application path (or another application that call the overrided function) in the project properties under "Debbugging" / "Command". Start debugging your dll project by pressing F5. Targetted application will start. Now you have to load your overriding dll built in debug mode inside process. So use WinAPIOverride and load it inside the application being debugged. The breakpoint will be reached the next time the API will be called, allowing you to quickly debug b) If code doesn't crash quicky : you have to found parameters that are crashing your function, use the monitoring file created at step 1) and add the |InNoRet option. Load your monitoring file, and next your dll. When the target application crashs, just look at WinAPIOverride last log : it's the one responsable of crash. So go back to 2) using the same parameters. Notice: if parameters are unsopported, use the :DataSize and :PointedDataSize options, or one of the break parameter option coupled with |breakBeforeCall option (see monitoring file advanced syntax) |