| /* ********************************************************** |
| * Copyright (c) 2014-2022 Google, Inc. All rights reserved. |
| * Copyright (c) 2005-2010 VMware, Inc. All rights reserved. |
| * **********************************************************/ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * * 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. |
| * |
| * * Neither the name of VMware, Inc. nor the names of its contributors may be |
| * used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * 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 VMWARE, INC. 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. |
| */ |
| |
| /* |
| * mfapi.h |
| * |
| * Interface for controlling Determina protection on a local machine |
| * |
| * (assumes a proper installation exists) |
| * |
| */ |
| |
| #ifndef _DETERMINA_MFAPI_H_ |
| #define _DETERMINA_MFAPI_H_ |
| |
| #ifndef _WIN32_WINNT |
| # define _WIN32_WINNT 0x0500 |
| #endif |
| |
| #include <windows.h> |
| #include <wchar.h> |
| |
| /* we don't want to include core headers here */ |
| typedef UINT_PTR process_id_t; |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* custom Win32-style error codes; using "high" constants so that |
| * it's obvious it's not win32. */ |
| #define ERROR_OPTION_NOT_FOUND 0xffffffff |
| #define ERROR_NOT_INITIALIZED 0xfffffffe |
| #define ERROR_UNKNOWN_ENTRY 0xfffffffd |
| #define ERROR_DETACH_NOT_ALLOWED 0xfffffffc |
| #define ERROR_UNSUPPORTED_OS 0xfffffffb |
| #define ERROR_LIST_VIOLATION 0xfffffffa |
| #define ERROR_LENGTH_VIOLATION 0xfffffff9 |
| #define ERROR_DETACH_ERROR 0xfffffff8 |
| #define ERROR_PARSE_ERROR 0xfffffff7 |
| #define ERROR_DRMARKER_ERROR 0xfffffff6 |
| |
| /************************ |
| * policy import/export * |
| ************************/ |
| |
| /* |
| * |
| * policy definition format specification |
| * -------------------------------------- |
| * |
| * |
| * the syntax of the policy definition message is as follows: |
| |
| * <policy_message> ::== |
| * POLICY_VERSION=30000 |
| * APPINITFLAGS=<string> |
| * APPINITALLOWLIST=<string> |
| * APPINITBLOCKLIST=<string> |
| * GLOBAL_PROTECT=<boolean> |
| * <application_block>* |
| * |
| * <application_block> ::== |
| * BEGIN_BLOCK |
| * <app_specifier> |
| * [ <hot_patch_block> ] |
| * <dynamorio_option_line>* |
| * END_BLOCK |
| * |
| * <app_specifier> ::== [ GLOBAL | APP_NAME=<string> ] |
| * |
| * <dynamorio_option_line> ::== <dynamorio_option>=<string> |
| * |
| * <dynamorio_option> ::== |
| * [ DYNAMORIO_OPTIONS | |
| * DYNAMORIO_AUTOINJECT | |
| * DYNAMORIO_RUNUNDER | |
| * DYNAMORIO_HOT_PATCH_MODES | |
| * DYNAMORIO_HOT_PATCH_POLICIES ] |
| * |
| * <hot_patch_block> ::== |
| * BEGIN_MP_MODES |
| * <num_hot_patch_lines> |
| * <hot_patch_line>* |
| * END_MP_MODES |
| * |
| * <num_hot_patch_lines> ::== (int) |
| * |
| * <hot_patch_line> ::== |
| * <patch_id>:<patch_mode> |
| * |
| * <patch_mode> ::== [ 0 | 1 | 2 ] |
| * |
| * <patch_id>: provided by Determina |
| * |
| * <boolean> ::== [ 0 | 1 ] |
| * |
| * |
| * |
| * details: |
| * |
| * (1) the APPINITFLAGS, together with the APPINITBLOCKLIST and |
| * APPINITALLOWLIST, controls how our bootstrap dll is added to the |
| * AppInit_DLLs registry key. the value of the flags should be a sum |
| * of the APPINIT_* flags as defined in share/config.h |
| * |
| * The APPINITBLOCKLIST and APPINITALLOWLIST values are only used if |
| * specified by the flags. we'll provide the allowlist/blocklist. |
| * |
| * |
| * (2) GLOBAL_PROTECT: OPTIONAL: if this is 0, then protection is |
| * disabled (and all application blocks are optional). in normal |
| * situations this will be 1. if this is not specified, then the |
| * current setting is kept (see also enable_protection) |
| * |
| * |
| * (3) there must be a GLOBAL block, which should come first, and it |
| * must have DYNAMORIO_RUNUNDER=1 set as an option. for consistency it |
| * should set DYNAMORIO_OPTIONS to blank (DYNAMORIO_OPTIONS=). |
| * |
| * |
| * (4) the APP_NAME must be a valid "application id". this is usually |
| * the .exe filename, but can also be "qualified". we will provide a |
| * complete list of supported applications. |
| * |
| * |
| * (5) some applications will also require special values for |
| * DYNAMORIO_RUNUNDER; we will provide this information as well. |
| * |
| * |
| * (6) DYNAMORIO_AUTOINJECT must be specified for every non-global |
| * application block, and it should be of the format |
| * "\lib\NNNNN\dynamorio.dll", where NNNNN is the version number of |
| * the core dll being used. in general, any value that starts with a |
| * "\" will have the local installation path prepended when using the |
| * actual value (eg, it indicates a relative installation path). |
| * |
| * |
| * (7) DYNAMORIO_OPTIONS is a string consisting of protection options |
| * to our core. the variability in this will depend on the level of |
| * configurability desired in your UI; but the majority of the options |
| * will not need to change. probably the only configuration necessary |
| * will be whether an app should be on or off; and this should be |
| * controlled by including or excluding the corresponding app block. |
| * |
| * |
| * (8) to enable hot patching, there are three additional |
| * requirements: |
| * (a) the global DYNAMORIO_HOT_PATCH_DEFS option should be |
| * declared, and point to the relative subpath of the hot patch |
| * definitions file (provided with the update package). Typically |
| * this should just be "\config" -- the engine version and |
| * file name is standard. Of course this file must exist in the |
| * proper place: "\config\30000\hotp-defs.cfg". |
| * (b) similary, each app must provide the DYNAMORIO_HOT_PATCH_MODES |
| * subpath for the hotp modes file. Typically this will be the |
| * config directory followed by the app name, e.g., |
| * "\config\detertest.exe". The modes files are created by the |
| * import process and should NOT be created manually. |
| * (c) Each app that requires patches must specify a list of patch |
| * id's and their "modes". The mode codes are 0 = Off, 1 = |
| * Detect Only, 2 = Protect. Typically only modes 0 and 2 will |
| * be used. As indicated above, the first line must be the number |
| * of patches specified. The list of patch id's and their |
| * descriptions is provided by Determina in the patch update |
| * packages. |
| * |
| * See sample.mfp for an example policy string. |
| * |
| */ |
| |
| /* import the specified configuration, thus enabling Determina |
| * protection for all newly launched processes. note that, according |
| * to the policy definition (GLOBAL_PROTECT), this will either call |
| * enable_protection or disable_protection. |
| * |
| * if synchronize_system, then any processes were under Determina |
| * but are now configured to be off will be detached. otherwise, |
| * no changes will be made to any running processes. |
| * |
| * if inject_flag is not NULL, it will return whether or not injection |
| * should be turned on, e.g., with the enable_protection() |
| * method. this is mainly to allow clients to call |
| * enable_protection_ex() with various custom flags. if inject_flag |
| * is NULL, the import method will take care of enabling or disabling |
| * protection based on the policy. |
| * |
| * if warning is not NULL, it will be set to an error |
| * code indicating if a non-critical error (such as detach) was |
| * encountered. |
| * |
| * note that unlike other methods, the policy definition is a char |
| * (not WCHAR) -- this is because (presumably) the policy |
| * definition is being read from an ASCII file or a network |
| * connection. */ |
| DWORD |
| policy_import(char *policy_definition, BOOL synchronize_system, BOOL *inject_flag, |
| DWORD *warning); |
| |
| /* returns a policy definition string based on the current registry |
| * configuration. |
| * may return ERROR_MORE_DATA, in which case the call should |
| * be re-tried with a larger buffer. |
| * again note char buffer. */ |
| DWORD |
| policy_export(char *policy_buffer, SIZE_T maxchars, SIZE_T *needed); |
| |
| /* convenience method for loading from a file */ |
| DWORD |
| load_policy(WCHAR *filename, BOOL synchronize_system, DWORD *warning); |
| |
| /* convenience method for storing to a file */ |
| DWORD |
| save_policy(WCHAR *filename); |
| |
| /* returns ERROR_SUCCESS unless the policy_buffer is invalid. */ |
| DWORD |
| validate_policy(char *policy_buffer); |
| |
| /* writes an empty policy to the registry (so that no apps will be |
| * protected). distinct from disable_protection, which just clears |
| * the AppInit_DLLs key. */ |
| DWORD |
| clear_policy(); |
| |
| /************************ |
| * AppInit_DLLs setting * |
| ************************/ |
| |
| /* enable Determina protection on the system. note that this is not |
| * required if implicitly invoked in policy_import. */ |
| DWORD |
| enable_protection(); |
| |
| /* checks the current protection status. */ |
| BOOL |
| is_protection_enabled(); |
| |
| /* disable Determina protection on the system. */ |
| DWORD |
| disable_protection(); |
| |
| /* |
| * For more detailed control over the AppInit_DLLs key, use |
| * the following function. |
| * |
| * AppInit_DLLs flags: |
| * (for enable_protection_ex()) |
| * |
| * APPINIT_FORCE_TO_FRONT |
| * Forces preinject dll to the front of the AppInit_DLLs list. |
| * |
| * APPINIT_FORCE_TO_BACK |
| * Forces preinject dll to the back of the AppInit_DLLs list. |
| * |
| * APPINIT_USE_BLOCKLIST |
| * Will read blocklist from blocklist config parameter and |
| * validate against it. |
| * |
| * APPINIT_USE_ALLOWLIST |
| * Will read allowlist from allowlist config parameter and |
| * validate against it. |
| * |
| * APPINIT_CHECK_LISTS_ONLY |
| * If set, the lists are only checked, not enforced; intended |
| * for use with at least one of the two flags below. |
| * |
| * APPINIT_WARN_ON_LIST_VIOLATION |
| * Whether to generate a warning if a allowlist/blocklist |
| * violation was detected. |
| * |
| * APPINIT_BAIL_ON_LIST_VIOLATION |
| * If set, the preinjector will not be added to the |
| * list, thus effectively disabling Determina. |
| * |
| * |
| * The following flags apply only for platforms which |
| * require preinject to be in SYSTEM32 (ie, NT4 for now). |
| * |
| * APPINIT_SYS32_USE_LENGTH_WORKAROUND |
| * Not yet supported -- must be zero. Placeholder |
| * for using some alternate technique to handle |
| * other dlls which may be in the list. |
| * |
| * APPINIT_SYS32_FAIL_ON_LENGTH_ERROR |
| * If existing entries + preinject name |
| * exceeds the 31-character limit, leave key |
| * untouched and report an error. |
| * |
| * APPINIT_SYS32_CLEAR_OTHERS |
| * If set, any other appinit entries are |
| * cleared, regardless of length. otherwise, |
| * all entries are left intact, and an |
| * operation that results in too long of |
| * a string will be truncated but succeed |
| * unless APPINIT_SYS32_FAIL_ON_LENGTH_ERROR |
| * is set. |
| * |
| * APPINIT_SYS32_TRUNCATE |
| * If set, appinit is truncated to 31 chars |
| * before writing; otherwise, the entire |
| * string is written, even if over the limit. |
| * |
| */ |
| |
| #define APPINIT_FORCE_TO_FRONT 0x1 |
| #define APPINIT_FORCE_TO_BACK 0x2 |
| #define APPINIT_USE_BLOCKLIST 0x4 |
| #define APPINIT_USE_ALLOWLIST 0x8 |
| #define APPINIT_CHECK_LISTS_ONLY 0x10 |
| #define APPINIT_WARN_ON_LIST_VIOLATION 0x20 |
| #define APPINIT_BAIL_ON_LIST_VIOLATION 0x40 |
| #define APPINIT_SYS32_USE_LENGTH_WORKAROUND 0x100 |
| #define APPINIT_SYS32_FAIL_ON_LENGTH_ERROR 0x200 |
| #define APPINIT_SYS32_CLEAR_OTHERS 0x400 |
| #define APPINIT_SYS32_TRUNCATE 0x800 |
| #define APPINIT_OVERWRITE 0x1000 |
| |
| /* The flags, blocklist, allowlist, list_error parameters are as |
| * described above. |
| * The inject parameter controls whether protection is enabled or |
| * disabled. If disabled all other parameters are ignored. |
| * The custom_preinject_name allows a non-standard DLL to be used; |
| * generally this should be NULL. |
| * The current_list buffer (of size maxchars) is optional; if provided |
| * it will contain the contents of the AppInit_DLLs key before any |
| * changes are made; this is useful in the case that list_error |
| * violation is reported. |
| */ |
| DWORD |
| enable_protection_ex(BOOL inject, DWORD flags, const WCHAR *blocklist, |
| const WCHAR *allowlist, DWORD *list_error, |
| const WCHAR *custom_preinject_name, WCHAR *current_list, |
| SIZE_T maxchars); |
| |
| /************************* |
| * process status * |
| *************************/ |
| |
| /* generic process walk callback routine; the callback should |
| * return FALSE to abort the walk. optionally takes a parameter |
| * which can be passed to the enumerate_processes method. */ |
| typedef BOOL (*process_callback)(ULONG pid, WCHAR *process_name, void **param); |
| |
| /* helper method: for each running processes on the system, |
| * executes the callback with the specified info. (everything is |
| * synchronous here.) |
| * note that this is much cleaner than the Win32 api's tlhelp32 |
| * interface, which should NEVER be used! */ |
| DWORD |
| enumerate_processes(process_callback pcb, void **param); |
| |
| /* process status codes */ |
| #define INJECT_STATUS_PROTECTED 1 |
| #define INJECT_STATUS_NATIVE 2 |
| #define INJECT_STATUS_UNKNOWN 3 |
| |
| /* returns one of above status definitions in the status pointer. |
| * if the build pointer is non-NULL, returns the build number of the |
| * core (if the process is protected).*/ |
| DWORD |
| inject_status(process_id_t pid, DWORD *status, DWORD *build); |
| |
| /* returns TRUE if the indicated process is configured for |
| * protection, yet is not running under Determina (this means it |
| * must be restarted before protection will take effect). |
| * returns FALSE if the process is under Determina or not configured |
| * for protection. (or in the case of any error.) |
| * note this is fairly expensive because it needs to load the current |
| * policy from the registry and check against it. a more efficient |
| * API may be exposed in the future. |
| */ |
| BOOL |
| is_process_pending_restart(process_id_t pid); |
| |
| /* returns TRUE if any process is_pending_restart */ |
| BOOL |
| is_any_process_pending_restart(); |
| |
| /******************** |
| * detach / nudge * |
| ********************/ |
| |
| /* in ms */ |
| #define DETACH_RECOMMENDED_TIMEOUT 60000 |
| #define NUDGE_NO_DELAY 0 |
| |
| /* this is recommended for all hotp notification methods. */ |
| #define NUDGE_RECOMMENDED_PAUSE 100 |
| |
| /* detach from indicated process -- if allow_upgraded_perms, then |
| * attempt to acquire necessary privileges (usually necessary) */ |
| DWORD |
| detach(process_id_t pid, BOOL allow_upgraded_perms, DWORD timeout_ms); |
| |
| /* detach from all running processes (with timeout). |
| * timeout is per process */ |
| DWORD |
| detach_all(DWORD timeout); |
| |
| /* detach from all processes with the matching exe name */ |
| DWORD |
| detach_exe(WCHAR *exename, DWORD timeout_ms); |
| |
| /* make sure that only configured processes are running under |
| * Determina */ |
| DWORD |
| consistency_detach(DWORD timeout); |
| |
| /* use this to notify a process to use new configuration information |
| * in the memory patch "modes" file. */ |
| DWORD |
| hotp_notify_modes_update(process_id_t pid, BOOL allow_upgraded_perms, DWORD timeout_ms); |
| |
| /* use this to notify a process to use new configuration information |
| * in the memory patch "definitions" file -- note that since new |
| * policy definitions will be re-loaded, this will also cause the |
| * modes information to be re-read as well. */ |
| DWORD |
| hotp_notify_defs_update(process_id_t pid, BOOL allow_upgraded_perms, DWORD timeout_ms); |
| |
| /* get modes update for all running processes. timeout is per process */ |
| DWORD |
| hotp_notify_all_modes_update(DWORD timeout_ms); |
| |
| /* get defs update for all running processes. timeout is per process */ |
| DWORD |
| hotp_notify_all_defs_update(DWORD timeout_ms); |
| |
| /* get modes update for all running processes matching exe name. |
| * timeout is per process */ |
| DWORD |
| hotp_notify_exe_modes_update(WCHAR *exename, DWORD timeout_ms); |
| |
| /************************ |
| * event log * |
| ************************/ |
| |
| /* |
| * start_eventlog_monitor: |
| * spawns a new thread which monitors the Araksha event log for |
| * new messages. the eventlog_callback is called for each new |
| * event with parameters as described above. any warnings, errors, |
| * failurse, etc. trigger the cb_err callback. |
| * returns a handle to the listener thread. |
| * |
| * use stop_eventlog_monitor to cleanly destroy the listener thread |
| */ |
| |
| /* monitor error codes */ |
| #define ELM_ERR_FATAL 1 |
| #define ELM_ERR_WARN 2 |
| #define ELM_ERR_CLEARED 3 |
| |
| typedef void (*eventlog_formatted_callback)(unsigned int mID, unsigned int type, |
| WCHAR *message, DWORD timestamp); |
| |
| typedef void (*eventlog_raw_callback)(EVENTLOGRECORD *record); |
| |
| typedef void (*eventlog_error_callback)(unsigned int errcode, WCHAR *message); |
| |
| /* last_record must be a valid eventlog record number!! |
| * this can be obtained from the "raw" callback by the RecordNumber |
| * value of the EVENTLOGRECORD struct. |
| * pass -1 to retrieve all event records. */ |
| DWORD |
| start_eventlog_monitor(BOOL use_formatted_callback, eventlog_formatted_callback cb_format, |
| eventlog_raw_callback cb_raw, eventlog_error_callback cb_err, |
| DWORD next_record); |
| |
| void |
| stop_eventlog_monitor(); |
| |
| /* removes all events from the Determina event log */ |
| DWORD |
| clear_eventlog(); |
| |
| HANDLE |
| get_eventlog_monitor_thread_handle(); |
| |
| BOOL |
| is_violation_event(DWORD eventType); |
| |
| /* helper method for parsing message strings in an EVENTLOGRECORD */ |
| const WCHAR * |
| next_message_string(const WCHAR *prev_string); |
| |
| /* helper method for getting the (pathless) executable name out |
| * of an EVENTLOGRECORD */ |
| const WCHAR * |
| get_event_exename(EVENTLOGRECORD *pevlr); |
| |
| /* helper method for getting the PID out of an EVENTLOGRECORD */ |
| UINT |
| get_event_pid(EVENTLOGRECORD *pevlr); |
| |
| /* helper method for getting the Threat ID out of an EVENTLOGRECORD. |
| * If the event type does not have a Threat ID parameter (e.g., for |
| * information events), then this will return NULL. */ |
| const WCHAR * |
| get_event_threatid(EVENTLOGRECORD *pevlr); |
| |
| /* helper method for getting the formatted text from an EVENTLOGRECORD |
| * structure. */ |
| DWORD |
| get_formatted_message(EVENTLOGRECORD *pevlr, WCHAR *buf, DWORD maxchars); |
| |
| /*************************************** |
| * system information / installation * |
| ***************************************/ |
| |
| /* supported platform identifiers */ |
| #define PLATFORM_UNKNOWN 0 |
| #define PLATFORM_WIN_2000 100 |
| #define PLATFORM_WIN_XP 110 |
| #define PLATFORM_WIN_2003 120 |
| #define PLATFORM_WIN_NT_4 130 |
| #define PLATFORM_VISTA 140 |
| #define PLATFORM_WIN_7 150 |
| #define PLATFORM_WIN_8 160 |
| #define PLATFORM_WIN_8_1 170 |
| #define PLATFORM_WIN_10 180 |
| #define PLATFORM_WIN_10_1511 190 |
| #define PLATFORM_WIN_10_1607 200 |
| #define PLATFORM_WIN_10_1703 210 |
| #define PLATFORM_WIN_10_1709 220 |
| #define PLATFORM_WIN_10_1803 230 |
| |
| DWORD |
| get_platform(DWORD *platform); |
| |
| const WCHAR * |
| get_installation_path(); |
| |
| const WCHAR * |
| get_product_name(); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif |