Monitoring Files | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
What are monitoring files ? Monitoring files are text files containing functions descriptions. Each function specified in monitoring file will be monitored when you load the monitoring file with WinAPIOverride. (see Loading Monitoring files and Overriding dll)
- Monitoring Files Automatic Generation (for dll, exe, COM, ActiveX,.NET or from debug or .map files) - Monitor all api call done by an exe - Basic Syntax (dll exports, exe internal functions, dll internal functions) - Calling Convention - Monitoring Direction - Structure management / User Types - Defines management - Advanced Syntax - Parameter Options Parameter Size Parameter Size : 32 / 64 bit compatibility Pointers passed by reference / Pointers to array / Pointers to string Parameters User Define Parameter Conditional Logging - Return Options Return Pointer Large Return Return User Define Return Conditional Logging Call Success Conditional Logging - Conditional Logging Parameter Conditional Logging Return Conditional Logging Call Success Conditional Logging - Breaking Options Breaking Time (Before or/and After Call) Parameter Conditional Breaking Return Conditional Breaking Success/Failure Conditional Breaking Logging after breaking (logs take into account changes done on registers or parameters from the break dialog) - Failure Options - Other Options Install a hook on a function pointer Install a hook on a label or inside function body Bypass module filtering for a function (usefull for callbacks) Changing the display name of a function Specify if function is not using stack shadow space (x64 only for pure asm functions not respecting ABI) - Auto Removed keywords - Particular cases : function pointer and "..." - Fully Supported Parameters - COM/ActiveX Monitoring Files - .NET Monitoring Files Basic Syntax This syntax with Monitoring Direction allows you to do basic monitoring. If you want to put filters on parameter values, break process before or after the function call, or specify failure value, refer to the advanced syntax All in [ ] is optional - Commented lines : all lines begining with ";" will be considered as comments - API or dll function : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LibraryName| [ReturnType] FuncName( ParamType [paramName] ) [;] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Examples
- Monitoring ordinal only dll exported function : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DLL_ORDINAL@0xOrdinal@DllName| [ReturnType] FuncName(ParamType [paramName]) [;] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example
- Monitoring function inside an exe : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example
Notice : to find the address of a function inside an exe refer too Faq: How to find function address - Monitoring function relative from dll base address : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DLL_INTERNAL@0xHexAddress@DllName| [ReturnType] FuncName(ParamType [paramName]) [;] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
HexAddress is the relative address from dll base address of process memory : you don't need to care if dll is rebased or not Example On some systems MessageBoxA is at the address 0x2e824 in user32.dll so in this case
- Monitoring function pointer inside an exe : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This new keyword has been introduced to securely hook function pointers. It can be use by the way to monitor some Virtual Function Table (VTBL) items (refer to your favorite C++ documentation for VTBL description) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example
- Monitoring function pointer relative from dll base address : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This new keyword has been introduced to securely hook function pointers. It can be use by the way to monitor some Virtual Function Table (VTBL) items (refer to your favorite C++ documentation for VTBL description) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DLL_INTERNAL_POINTER@0xHexAddress@DllName| [ReturnType] FuncName(ParamType [paramName]) [;] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
HexAddress is the relative address (RVA) from dll base address of process memory : you don't need to care if dll is rebased or not Example
Calling Convention To specify the calling convention, just let standard function definition like int __cdecl Function(int i,unsigned int ui)
Supported calling convention keywords are the following : - __cdecl, STDMETHODVCALLTYPE, STDAPIVCALLTYPE, STDAPIV, STDMETHODIMPV - __stdcall, WINAPI, STDAPI, WINOLEAPI,STDMETHODCALLTYPE, STDAPICALLTYPE, STDMETHODIMP - __fastcall : Microsoft fastcall : Parameters passed through ECX, EDX then by stack with Right To Left (RTL) order - __thiscall - __fastcall_borland : Borland / Embarcadero fastcall : Parameters passed through EAX, EDX, ECX then by stack with Left To Right (LTR) order (Pascal). Added in version 6.0 Monitoring direction Monitoring direction is an extra keyword to specify when parameters should be logged.
Explanation You want to monitor the following function call: strcat("To ","you"); According to the direction, results will be
Advanced Syntax Notice : All options are not case sensitive, so you can put ":logvalue" instead of ":LogValue" without any trouble. Logging options
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Breaking options : Breaking options defines when the break dialog must appears. This dialog allows you to change parameters content and returned value, show callstack and make dump. When the breaking dialog is displayed all threads of the process are suspended Notice: You can mix Logging options and breaking options like
Failure options : Failure options allow you to define when function fails. It provides 2 things : - More precise logging or breaking conditions - A visual return : failling call are hightlighted in the log list by a red background.
Other options : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|FunctionPointer: allows to install a hook on a function pointer (since v6.4.1) This behaviour as the same effect as EXE_INTERNAL_RVA_POINTER, EXE_INTERNAL_POINTER, DLL_INTERNAL_POINTER, but provides an easier writing way for exported functions lib.dll|func(int a)|FunctionPointer |DontHookReturnAddress: allows to install a hook on a label or inside a function body (since v6.0) Not hooking return address, means that stack is exactly the same between original call and the hooked one, even return address is let unchanged. The callee won't see any difference by stack crawling (by the way, this option used to bypass framework .Net stack checking for the fast .Net hooking) As stack is not affected at all, that mean you are not forced to install hook at the begining of a function. You can install this kind of hook anywhere in the code, inside the function code itself. As return address is not hooked, InNoRet monitoring is required and "Out" monitoring and "Post" hooks are not available (See Hooking Sequence). "InNoRet" monitoring, "Pre" hooks and overrinding are still availables. Notice: If you need to catch the return value, you still can do it by using two hooks with |DontHookReturnAddress option : one at the begining of function and one at the end Keep in mind that a hook needs 5 bytes, so the best is to find a 5 bytes opcode at the end of the function (Notice : Ms compiler gives you a nice gift with the __security_check_cookie call, as a call instruction is 5 bytes length) You don't need to take care of stack alignment : the hooking algorithm can handle aligned and unaligned stack Let see a standard function asm code If you require "Post" hook, use the previous technic with two "Pre" hooks. The second "Pre" hook will be in fact an equivalent of "Post" hook. |DontCheckModulesFilters : modules filters are not taken into account and function is always logged (since v6.0) That means all other logs respect provided filters, but those with the "|DontCheckModulesFilters" options don't. This can be usefull in case of callback: in this case the caller could be in kernel32 or user32 which is filtered. lib.dll|func(int a)|DontCheckModulesFilters |DisplayName=PrettyFuncName where PrettyFuncName is a function prefered name. This option allows you to change the name displayed in WinAPIOverride log list. The exported name of dll function is sometime not understandable like for C++ functions. So it makes analysis easier. By the way using msvcrt.dll|??2@YAPAXI@Z(unsigned int)|DisplayName=operator new will display operator new(45) instead of ??2@YAPAXI@Z(45) |NoStackShadowSpace x64 only, used for function with stack parameter which don't use shadow space. Should be reserved for specific asm function for which first stack parameter is at function entry Rsp (for standard functions, first stack parameter is at function entry Rsp + 0x20) ! at the begin of the line : specific for monitoring library : if line begins with !, that means it's currently disable but can be enable from monitoring library interface. Commented definitions are unvisible from library and so can't be enabled. Use '!' for function definition that generate lot's of call and are generaly not necessary (like the GetLastError() function), and use ';' before definition that can't be hooked. It is usefull to let them commented, because when the Monitoring File Builder application generates a monitoring file, it will find function definition in monitoring folder and will translate it's desactivated state for the new created monitoring files. |FirstBytesCanExecuteAnywhere |FirstBytesCanExecuteAnywhere= Change the standard hooking way to a more powerfull hooking way. This can be done if the first asm instructions of your function can be executed at an another location By the way this can be done if first asm instruction are like mov edi,edi // 8B FF push ebp // 55 mov ebp,esp // 8B EC As you can see this portion of code can be executed anywhere in memory. So instead of removing hook and call original function, hook is not removed, but the begin of function is executed in another location. The great advantage of these options is that YOU CAN'T LOOSE FUNCTION CALL. If you don't specify a value ("|FirstBytesCanExecuteAnywhere") the size of code executed at another location is 5 bytes. The "|FirstBytesCanExecuteAnywhere=" option allows you to specify the number of byte executed at another place. This number must be greater than an absolute jmp instruction (5 bytes in 32 bits) . This allows you to adjust the number of movable bytes. By the way if the movables asm code is push ebp // 55 mov ebp,esp // 8B EC sub esp,3D4h // 81 EC D4 03 00 00 we can't cut it at byte 5, else the "sub esp, 3D4h " instruction is cut, and a beautifull crash will append. But as this code can be executed anywhere and is 9 bytes, put |FirstBytesCanExecuteAnywhere=9 after the monitoring definition. Only the 9 first bytes of the function will be executed at another address. |FirstBytesCanExecuteAnywhereWithRelativeAddressChange |FirstBytesCanExecuteAnywhereWithRelativeAddressChange= Same as |FirstBytesCanExecuteAnywhere option,but specifying that a 32 bit relative address needs to be changed. The relative address to modify must be at the last 4 bytes. By the way jmp (relative) 0x3D4 // E9 4D 03 00 00 Ok, the instruction is 5 bytes length, so a hook can be installed, but if we execute this instruction at another place, the relative jump will fail. To get a working code, WinAPIOverride has to compute the new relative address from the execution location to the original destination. So specifying a such option tells WinAPIOverride to compute new relative address. |FirstBytesCanExecuteAnywhereWithRelativeAddressChange moves 5 bytes, and |FirstBytesCanExecuteAnywhereWithRelativeAddressChange= allows you to specify the number of movable bytes between 5 and 64 (warning modified address is still at the 4 last bytes) |FirstBytesCantExecuteAnywhere Force first bytes to be executed at there original place. It can be usefull if the "Do first bytes analysis (applies only on new loaded files or dll)" option is set in the options dialog. In some case the "Insecure first bytes analysis" fails only for 1 or 2 functions for 200 or more hooked functions. So once crashing functions analysed, put this flag on them and have powerful hooks. Examples of use :
|BlockingCall Allow to hook calls made by other threads even if previous calls have not ended. Use it only for slow blocking call like MessageBox or DialogBox function. Don't use it with high speed blocking functions like SendMessage or WaitForSingleObject, else your application may will crash and as using this option slow down the hook algorithm, you may will loose more messages than without this option. Notice : Use it only if you can't use the "FirstBytesCanExecuteAnywhere" options, or if Powerless hooks option is activated. This option has no effect on PowerFull hooks
Auto Removed Keywords The following list of parameter keywords is automatically removed (case insensitive) : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const, struct, in, out, inout, far, class, __in, __inout, __out, __reserved, __in_opt, __in_default, __out_opt__inout_opt, _In_, _In_opt_, _Inout_, _Inout_opt_, _Out_, _Out_opt_, _In_z_, _In_opt_z_, _Inout_z_, _Inout_opt_z_, _Out_z_, _Out_opt_z_ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Example
Particular cases : function pointer and "..." Function pointer : Since version 5.0, function parameters like lib.dll|func(int (__cdecl*)(unsigned int)) are fully supported. On previous versions, Instead of describing the whole function description, you have to use FARPROC keyword Example:
"..." : 1) If you want to make a generic monitoring, you have to remove them to avoid trying reading invalid memory. By the way the printf function will by defined by :
2) If you want to make a particular monitoring on one call, adjust the amount of parameters to the specific function call you want to watch. By the way if you want to monitor the call printf("hello my name is %s, I am %d years old", strName, nYears), just use the following monitoring description
Fully Supported Parameters Types
|