/* @(#) $Id: win-registry.c,v 1.8 2007/07/20 00:19:27 dcid Exp $ */ /* Copyright (C) 2003-2007 Daniel B. Cid * All rights reserved. * * This program is a free software; you can redistribute it * and/or modify it under the terms of the GNU General Public * License (version 3) as published by the FSF - Free Software * Foundation. * * License details at the LICENSE file included with OSSEC or * online at: http://www.ossec.net/en/licensing.html */ /* Windows only */ #ifdef WIN32 #include "shared.h" #include "syscheck.h" #include "os_crypto/md5/md5_op.h" #include "os_crypto/sha1/sha1_op.h" /* Default values */ #define MAX_KEY_LENGTH 255 #define MAX_KEY 2048 #define MAX_VALUE_NAME 16383 /* Global variables */ HKEY sub_tree; int ig_count = 0; int run_count = 0; /** Notify list values **/ char *registry_list[NOTIFY_LIST_SIZE + 3]; int registry_list_size = 0; /** Function prototypes 8*/ void os_winreg_open_key(char *subkey, char *fullkey_name); int os_winreg_changed(char *key, char *md5, char *sha1) { char buf[MAX_LINE +1]; buf[MAX_LINE] = '\0'; /* Seeking to the beginning of the db */ fseek(syscheck.reg_fp, 0, SEEK_SET); while(fgets(buf, MAX_LINE, syscheck.reg_fp) != NULL) { if((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != '\n')) { char *n_buf; /* Removing the \n before reading */ n_buf = strchr(buf, '\n'); if(n_buf == NULL) continue; *n_buf = '\0'; n_buf = strchr(buf, ' '); if(n_buf == NULL) continue; if(strcmp(n_buf +1, key) != 0) continue; /* Entry found, checking if checksum is the same */ *n_buf = '\0'; if((strncmp(buf, md5, sizeof(os_md5) -1) == 0)&& (strcmp(buf + sizeof(os_md5) -1, sha1) == 0)) { /* File didn't change. */ return(0); } /* File did changed */ return(1); } } fseek(syscheck.reg_fp, 0, SEEK_END); fprintf(syscheck.reg_fp, "%s%s %s\n", md5, sha1, key); return(1); } /** int notify_registry(char *msg) * Notifies of registry changes. */ int notify_registry(char *msg, int send_now) { int i = 0; /* msg can be null to flag send_now */ if(msg) { /* Storing message in the notify list */ os_strdup(msg, registry_list[registry_list_size]); if(registry_list_size >= NOTIFY_LIST_SIZE) { send_now = 1; } registry_list_size++; } /* Delay sending */ if(!send_now) return(0); /* Sending all available messages */ while(i < registry_list_size) { if(SendMSG(syscheck.queue, registry_list[i], SYSCHECK_REG, SYSCHECK_MQ) < 0) { merror(QUEUE_SEND, ARGV0); if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0) { ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH); } /* If we reach here, we can try to send it again */ SendMSG(syscheck.queue, registry_list[i],SYSCHECK_REG,SYSCHECK_MQ); } os_free(registry_list[i]); registry_list[i] = NULL; i++; } registry_list_size = 0; return(0); } /** char *os_winreg_sethkey(char *reg_entry) * Checks if the registry entry is valid. */ char *os_winreg_sethkey(char *reg_entry) { char *ret = NULL; char *tmp_str; /* Getting only the sub tree first */ tmp_str = strchr(reg_entry, '\\'); if(tmp_str) { *tmp_str = '\0'; ret = tmp_str+1; } /* Setting sub tree */ if(strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0) { sub_tree = HKEY_LOCAL_MACHINE; } else if(strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0) { sub_tree = HKEY_CLASSES_ROOT; } else if(strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0) { sub_tree = HKEY_CURRENT_CONFIG; } else if(strcmp(reg_entry, "HKEY_USERS") == 0) { sub_tree = HKEY_USERS; } else { /* Returning tmp_str to the previous value */ if(tmp_str && (*tmp_str == '\0')) *tmp_str = '\\'; return(NULL); } /* Checking if ret has nothing else. */ if(ret && (*ret == '\0')) ret = NULL; /* fixing tmp_str and the real name of the registry */ if(tmp_str && (*tmp_str == '\0')) *tmp_str = '\\'; return(ret); } /* void os_winreg_querykey(HKEY hKey, char *p_key) * Query the key and get all its values. */ void os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name) { int i, rc; DWORD j; /* QueryInfo and EnumKey variables */ TCHAR sub_key_name_b[MAX_KEY_LENGTH +1]; TCHAR class_name_b[MAX_PATH +1]; DWORD sub_key_name_s; DWORD class_name_s = MAX_PATH; /* Number of sub keys */ DWORD subkey_count = 0; /* Number of values */ DWORD value_count; /* Variables for RegEnumValue */ TCHAR value_buffer[MAX_VALUE_NAME +1]; TCHAR data_buffer[MAX_VALUE_NAME +1]; DWORD value_size; DWORD data_size; /* Data type for RegEnumValue */ DWORD data_type = 0; /* Initializing the memory for some variables */ class_name_b[0] = '\0'; class_name_b[MAX_PATH] = '\0'; sub_key_name_b[0] = '\0'; sub_key_name_b[MAX_KEY_LENGTH] = '\0'; /* We use the class_name, subkey_count and the value count. */ rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL, &subkey_count, NULL, NULL, &value_count, NULL, NULL, NULL, NULL); /* Check return code of QueryInfo */ if(rc != ERROR_SUCCESS) { return; } /* Checking if we have sub keys */ if(subkey_count) { /* We open each subkey and call open_key */ for(i=0;i= syscheck.sleep_after) { sleep(syscheck.tsleep); ig_count = 0; } ig_count++; /* Registry ignore list */ if(full_key_name && syscheck.registry_ignore) { while(syscheck.registry_ignore[i] != NULL) { if(strcasecmp(syscheck.registry_ignore[i], full_key_name) == 0) { return; } i++; } } else if(full_key_name && syscheck.registry_ignore_regex) { i = 0; while(syscheck.registry_ignore_regex[i] != NULL) { if(OSMatch_Execute(full_key_name, strlen(full_key_name), syscheck.registry_ignore_regex[i])) { return; } i++; } } if(RegOpenKeyEx(sub_tree, subkey, 0, KEY_READ, &oshkey) != ERROR_SUCCESS) { merror(SK_REG_OPEN, ARGV0, subkey); return; } os_winreg_querykey(oshkey, subkey, full_key_name); RegCloseKey(oshkey); return; } /** void os_winreg_check() * Main function to read the registry. */ void os_winreg_check() { int i = 0; char *rk; /* Debug entries */ debug1("%s: DEBUG: Starting os_winreg_check", ARGV0); /* Zeroing ig_count before checking */ ig_count = 0; /* Checking if the registry fp is open */ if(syscheck.reg_fp == NULL) { syscheck.reg_fp = fopen(SYS_WIN_REG, "w+"); if(!syscheck.reg_fp) { merror(FOPEN_ERROR, ARGV0, SYS_WIN_REG); return; } } /* Zeroing list memory */ registry_list_size = NOTIFY_LIST_SIZE + 2; while(registry_list_size >= 0) { registry_list[registry_list_size] = NULL; registry_list_size--; } registry_list_size = 0; /* Getting sub class and a valid registry entry */ while(syscheck.registry[i] != NULL) { sub_tree = NULL; rk = NULL; /* Ignored entries are zeroed */ if(*syscheck.registry[i] == '\0') { i++; continue; } /* Reading syscheck registry entry */ debug1("%s: DEBUG: Attempt to read: %s", ARGV0, syscheck.registry[i]); rk = os_winreg_sethkey(syscheck.registry[i]); if(sub_tree == NULL) { merror(SK_INV_REG, ARGV0, syscheck.registry[i]); *syscheck.registry[i] = '\0'; i++; continue; } os_winreg_open_key(rk, syscheck.registry[i]); i++; sleep(syscheck.tsleep *5); } /* Notify of db completed. */ if(run_count > 1) { notify_registry(HC_SK_DB_COMPLETED, 1); } notify_registry(NULL, 1); run_count++; return; } #endif /* WIN32 */ /* EOF */