blob: 37c885bae7eb57b8fcfcfb063318a408daee23bc [file] [log] [blame]
/* **********************************************************
* 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