1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
14 #include "os_crypto/md5/md5_op.h"
15 #include "os_crypto/sha1/sha1_op.h"
16 #include "os_crypto/md5_sha1/md5_sha1_op.h"
19 #define MAX_KEY_LENGTH 255
21 #define MAX_VALUE_NAME 16383
23 /* Places to story the registry values */
24 #define SYS_WIN_REG "syscheck/syscheckregistry.db"
25 #define SYS_REG_TMP "syscheck/syscheck_sum.tmp"
27 /* Global variables */
33 void os_winreg_open_key(char *subkey, char *fullkey_name);
36 int os_winreg_changed(char *key, char *md5, char *sha1)
38 char buf[MAX_LINE + 1];
42 /* Seek to the beginning of the db */
43 fseek(syscheck.reg_fp, 0, SEEK_SET);
45 while (fgets(buf, MAX_LINE, syscheck.reg_fp) != NULL) {
46 if ((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != '\n')) {
49 /* Remove the \n before reading */
50 n_buf = strchr(buf, '\n');
57 n_buf = strchr(buf, ' ');
62 if (strcmp(n_buf + 1, key) != 0) {
66 /* Entry found, check if checksum is the same */
68 if ((strncmp(buf, md5, sizeof(os_md5) - 1) == 0) &&
69 (strcmp(buf + sizeof(os_md5) - 1, sha1) == 0)) {
70 /* File didn't change */
79 fseek(syscheck.reg_fp, 0, SEEK_END);
80 fprintf(syscheck.reg_fp, "%s%s %s\n", md5, sha1, key);
84 /* Notify of registry changes */
85 int notify_registry(char *msg, __attribute__((unused)) int send_now)
87 if (SendMSG(syscheck.queue, msg,
88 SYSCHECK_REG, SYSCHECK_MQ) < 0) {
89 merror(QUEUE_SEND, ARGV0);
91 if ((syscheck.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
92 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
95 /* If we reach here, we can try to send it again */
96 SendMSG(syscheck.queue, msg, SYSCHECK_REG, SYSCHECK_MQ);
102 /* Check if the registry entry is valid */
103 char *os_winreg_sethkey(char *reg_entry)
108 /* Get only the sub tree first */
109 tmp_str = strchr(reg_entry, '\\');
116 if (strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0) {
117 sub_tree = HKEY_LOCAL_MACHINE;
118 } else if (strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0) {
119 sub_tree = HKEY_CLASSES_ROOT;
120 } else if (strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0) {
121 sub_tree = HKEY_CURRENT_CONFIG;
122 } else if (strcmp(reg_entry, "HKEY_USERS") == 0) {
123 sub_tree = HKEY_USERS;
125 /* Return tmp_str to the previous value */
126 if (tmp_str && (*tmp_str == '\0')) {
132 /* Check if ret has nothing else */
133 if (ret && (*ret == '\0')) {
137 /* Fix tmp_str and the real name of the registry */
138 if (tmp_str && (*tmp_str == '\0')) {
145 /* Query the key and get all its values */
146 void os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name)
151 /* QueryInfo and EnumKey variables */
152 TCHAR sub_key_name_b[MAX_KEY_LENGTH + 2];
153 TCHAR class_name_b[MAX_PATH + 1];
154 DWORD sub_key_name_s;
155 DWORD class_name_s = MAX_PATH;
157 /* Number of sub keys */
158 DWORD subkey_count = 0;
160 /* Number of values */
163 /* Variables for RegEnumValue */
164 TCHAR value_buffer[MAX_VALUE_NAME + 1];
165 TCHAR data_buffer[MAX_VALUE_NAME + 1];
169 /* Data type for RegEnumValue */
172 /* Initializing the memory for some variables */
173 class_name_b[0] = '\0';
174 class_name_b[MAX_PATH] = '\0';
175 sub_key_name_b[0] = '\0';
176 sub_key_name_b[MAX_KEY_LENGTH] = '\0';
177 sub_key_name_b[MAX_KEY_LENGTH + 1] = '\0';
179 /* We use the class_name, subkey_count and the value count */
180 rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL,
181 &subkey_count, NULL, NULL, &value_count,
182 NULL, NULL, NULL, NULL);
184 /* Check return code of QueryInfo */
185 if (rc != ERROR_SUCCESS) {
189 /* Check if we have sub keys */
191 /* Open each subkey and call open_key */
192 for (i = 0; i < subkey_count; i++) {
193 sub_key_name_s = MAX_KEY_LENGTH;
194 rc = RegEnumKeyEx(hKey, i, sub_key_name_b, &sub_key_name_s,
195 NULL, NULL, NULL, NULL);
197 /* Checking for the rc */
198 if (rc == ERROR_SUCCESS) {
199 char new_key[MAX_KEY + 2];
200 char new_key_full[MAX_KEY + 2];
201 new_key[MAX_KEY + 1] = '\0';
202 new_key_full[MAX_KEY + 1] = '\0';
205 snprintf(new_key, MAX_KEY,
206 "%s\\%s", p_key, sub_key_name_b);
207 snprintf(new_key_full, MAX_KEY,
208 "%s\\%s", full_key_name, sub_key_name_b);
210 snprintf(new_key, MAX_KEY, "%s", sub_key_name_b);
211 snprintf(new_key_full, MAX_KEY,
212 "%s\\%s", full_key_name, sub_key_name_b);
216 os_winreg_open_key(new_key, new_key_full);
221 /* Get values (if available) */
223 /* md5 and sha1 sum */
229 /* Clear the values for value_size and data_size */
230 value_buffer[MAX_VALUE_NAME] = '\0';
231 data_buffer[MAX_VALUE_NAME] = '\0';
232 checksum_fp = fopen(SYS_REG_TMP, "w");
234 printf(FOPEN_ERROR, ARGV0, SYS_REG_TMP, errno, strerror(errno));
239 for (i = 0; i < value_count; i++) {
240 value_size = MAX_VALUE_NAME;
241 data_size = MAX_VALUE_NAME;
243 value_buffer[0] = '\0';
244 data_buffer[0] = '\0';
246 rc = RegEnumValue(hKey, i, value_buffer, &value_size,
247 NULL, &data_type, (LPBYTE)data_buffer, &data_size);
249 /* No more values available */
250 if (rc != ERROR_SUCCESS) {
254 /* Check if no value name is specified */
255 if (value_buffer[0] == '\0') {
256 value_buffer[0] = '@';
257 value_buffer[1] = '\0';
260 /* Write value name and data in the file (for checksum later) */
261 fprintf(checksum_fp, "%s=", value_buffer);
265 fprintf(checksum_fp, "%s\n", data_buffer);
268 /* Print multiple strings */
269 mt_data = data_buffer;
272 fprintf(checksum_fp, "%s ", mt_data);
273 mt_data += strlen(mt_data) + 1;
275 fprintf(checksum_fp, "\n");
278 fprintf(checksum_fp, "%08x\n", (unsigned int)*data_buffer);
281 for (j = 0; j < data_size; j++) {
282 fprintf(checksum_fp, "%02x",
283 (unsigned int)data_buffer[j]);
285 fprintf(checksum_fp, "\n");
290 /* Generate checksum of the values */
293 if (OS_MD5_SHA1_File(SYS_REG_TMP, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_TEXT) == -1) {
294 merror(FOPEN_ERROR, ARGV0, SYS_REG_TMP, errno, strerror(errno));
298 /* Look for p_key on the reg db */
299 if (os_winreg_changed(full_key_name, mf_sum, sf_sum)) {
300 char reg_changed[MAX_LINE + 1];
301 snprintf(reg_changed, MAX_LINE, "0:0:0:0:%s:%s %s",
302 mf_sum, sf_sum, full_key_name);
305 notify_registry(reg_changed, 0);
312 /* Open the registry key */
313 void os_winreg_open_key(char *subkey, char *full_key_name)
318 /* Sleep X every Y files */
319 if (ig_count >= syscheck.sleep_after) {
320 sleep(syscheck.tsleep + 1);
325 /* Registry ignore list */
326 if (full_key_name && syscheck.registry_ignore) {
327 while (syscheck.registry_ignore[i] != NULL) {
328 if (strcasecmp(syscheck.registry_ignore[i], full_key_name) == 0) {
333 } else if (full_key_name && syscheck.registry_ignore_regex) {
335 while (syscheck.registry_ignore_regex[i] != NULL) {
336 if (OSMatch_Execute(full_key_name, strlen(full_key_name),
337 syscheck.registry_ignore_regex[i])) {
344 if (RegOpenKeyEx(sub_tree, subkey, 0, KEY_READ, &oshkey) != ERROR_SUCCESS) {
345 merror(SK_REG_OPEN, ARGV0, subkey);
349 os_winreg_querykey(oshkey, subkey, full_key_name);
354 /* Main function to read the registry */
355 void os_winreg_check()
361 debug1("%s: DEBUG: Starting os_winreg_check", ARGV0);
363 /* Zero ig_count before checking */
366 /* Check if the registry fp is open */
367 if (syscheck.reg_fp == NULL) {
368 syscheck.reg_fp = fopen(SYS_WIN_REG, "w+");
369 if (!syscheck.reg_fp) {
370 merror(FOPEN_ERROR, ARGV0, SYS_WIN_REG, errno, strerror(errno));
375 /* Get sub class and a valid registry entry */
376 while (syscheck.registry[i] != NULL) {
380 /* Ignored entries are zeroed */
381 if (*syscheck.registry[i] == '\0') {
386 /* Read syscheck registry entry */
387 debug1("%s: DEBUG: Attempt to read: %s", ARGV0, syscheck.registry[i]);
389 rk = os_winreg_sethkey(syscheck.registry[i]);
390 if (sub_tree == NULL) {
391 merror(SK_INV_REG, ARGV0, syscheck.registry[i]);
392 *syscheck.registry[i] = '\0';
397 os_winreg_open_key(rk, syscheck.registry[i]);
399 sleep(syscheck.tsleep * 5);
402 /* Notify of db completed */
404 sleep(syscheck.tsleep * 5);
405 notify_registry(HC_SK_DB_COMPLETED, 1);