`

OSSEC an open source HIDS --- LogCollector

阅读更多

这些天仔细分析了OSSEC日志收集(LogCollector)部分的细节。

       OSSEC-LogCollector是创建一个无限循环,类似一个监听日志的守护进程,只要监听到日志有变动,就用SOCEKT发送消息给日志分析(analysisd)的守护进程,然后进行解码、匹配等操作。

      

下面先讲OSSEC是如何读取日志的。以读取WINDOWS XP下的事件日志为例。

读取事件日志主要是用到了Windows.h中的几个API:

OpenEventLog,CloseEventLog,ReadEventLog,GetLastError,等。

代码在最下面,我先说明一下每个函数的作用。

int StartEL(char *app, HIDSEL *el) 

打开日志,返回该日志的数目。

char *GetELCategory(int categoryID)

根据类型ID获取日志类型。

char *GetEventDLL(char *evt_name, char *source, char *evt) 

从注册表获取日志的名称。

char *GetELMsg(EVENTLOGRECORD *er,  char *name,  char * source, LPTSTR *elSStr) 

获取该条日志的描述信息。

void ReadEL(HIDSEL *el, int printit)

读取事件日志。注,若只需要读取一次日志,printit设为1即可。OSSEC设置此参数的做法,我想是要忽略已有的日志,只对新产生的日志做处理。

#include "stdio.h"
#include "windows.h"

#define BUFFER_SIZE 2048*256
#define HIDS_MAXSTR 6144
#define HIDS_FLSIZE 256
#define HIDS_LOG_HEADER 256

/*Event logging local structure*/
typedef struct _HIDSEL
{
	int timeOfLast;
	char *name;
	
	EVENTLOGRECORD *er;
	HANDLE h;
	DWORD record;
}HIDSEL;

/*
 *Starts the event logging for each el
 */
int StartEL(char *app, HIDSEL *el)
{
	DWORD recordNum = 0;

	/*Opening the event log*/
	el->h = OpenEventLog(NULL,app);
	if(!el->h)
	{
		printf("HIDS-LogCollecotor ERROR: Uable to open the event log : %s.", app); 
		return (-1);
	}
	
	el->name = app;
	
	if(GetOldestEventLogRecord(el->h, &el->record) == 0)
	{
		/*Unable to read oldest event log record*/
		printf("HIDS-LogCollecotor ERROR: Uable to query last event log from: %s.", app); 
		CloseEventLog(el->h);
		el->h = NULL;
		return(-1);
	}
	
	if(GetNumberOfEventLogRecords(el->h, &recordNum) == 0)
	{		 
		printf("HIDS-LogCollecotor ERROR: Uable to get the number of event logs from: %s.", app); 
		CloseEventLog(el->h);
		el->h = NULL;
		return(-1);
	}
	
	if(recordNum <= 0)
	{
		return 0;
	}
	
	return (int)recordNum;
}

/* 
 * Returns a string related to the category id of the log.
 */
char *GetELCategory(int categoryID)
{
    char *cat;
    switch(categoryID)
    {
        case EVENTLOG_ERROR_TYPE:
            cat = "ERROR";
            break;
        case EVENTLOG_WARNING_TYPE:
            cat = "WARNING";
            break;
        case EVENTLOG_INFORMATION_TYPE:
            cat = "INFORMATION";
            break;
        case EVENTLOG_AUDIT_SUCCESS:
            cat = "AUDIT_SUCCESS";
            break;
        case EVENTLOG_AUDIT_FAILURE:
            cat = "AUDIT_FAILURE";
            break;
        default:
            cat = "Unknown";
            break;
    }
    return	cat;
}


/**
 * Returns the event.
 */
char *GetEventDLL(char *evt_name, char *source, char *evt) 
{
    //char *retStr;
    HKEY key;
    DWORD ret;
    char keyName[512];


    keyName[511] = '\0';

    _snprintf(keyName, 510, 
            "System\\CurrentControlSet\\Services\\EventLog\\%s\\%s", 
            evt_name, 
            source);


    /* Checking if we have it in memory. */
    
    //retStr = OSHash_Get(dll_hash, keyName + 42);
    //if(retStr)
    //{
    //    return(retStr);
    //}
    
    /* Opening registry */	    
    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 
                    KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
    {
        return(NULL);    
    }


    ret = MAX_PATH -1;	
    if (RegQueryValueEx(key, "EventMessageFile", NULL, 
                NULL, (LPBYTE)evt, &ret) != ERROR_SUCCESS)
    {
        evt[0] = '\0';	
        RegCloseKey(key);
        return(NULL);
    }
    else
    {
        /* Adding to memory. */
        char *skey;
        char *sval;

        skey = strdup(keyName + 42);
        sval = strdup(evt);
        
        if(skey && sval)
        {
            //OSHash_Add(dll_hash, skey, sval); 
        }
        else
        {
            printf("Log Collector: ERROR: Not enough Memory. Exiting.");
        }
    }
    
    RegCloseKey(key);
    return(evt);
}


/**
 * Returns a descriptive message of the event.
 */
char *GetELMsg(EVENTLOGRECORD *er,  char *name, 
		    char * source, LPTSTR *elSStr) 
{
    DWORD fmFlags = 0;
    char strTmp[257];
    char event[MAX_PATH +1];
    char *curr_str;
    char *next_str;
    LPSTR message = NULL;

    HMODULE hevt;

    /* Initializing variables */
    event[MAX_PATH] = '\0';
    strTmp[256] = '\0';


    /* Flags for format event */
    fmFlags |= FORMAT_MESSAGE_FROM_HMODULE;
    fmFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
    fmFlags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;



    /* Get the file name from the registry (stored on event) */
    if(!(curr_str = GetEventDLL(name, source, event)))
    {
        return(NULL);	    
    }	    



    /* If our event has multiple libraries, try each one of them */ 
    while((next_str = strchr(curr_str, ';')))
    {
        *next_str = '\0';

        ExpandEnvironmentStrings(curr_str, strTmp, 255);

        /* Reverting back old value. */
        *next_str = ';';
        

        /* Loading library. */
        hevt = LoadLibraryEx(strTmp, NULL, 
                             DONT_RESOLVE_DLL_REFERENCES |
                             LOAD_LIBRARY_AS_DATAFILE);
        if(hevt)
        {
            if(!FormatMessage(fmFlags, hevt, er->EventID, 0,
                              (LPTSTR) &message, 0, elSStr))
            {
                message = NULL;		  
            }
            FreeLibrary(hevt);

            /* If we have a message, we can return it */
            if(message)
                return(message);
        }


        curr_str = next_str +1;
    }

    
    /* Getting last value. */
    ExpandEnvironmentStrings(curr_str, strTmp, 255);
    hevt = LoadLibraryEx(strTmp, NULL, 
                         DONT_RESOLVE_DLL_REFERENCES |
                         LOAD_LIBRARY_AS_DATAFILE);
    if(hevt)
    {
        int hr;    
        if(!(hr = FormatMessage(fmFlags, hevt, er->EventID, 
                        0,
                        (LPTSTR) &message, 0, elSStr)))
        {
            message = NULL;		  
        }
        FreeLibrary(hevt);

        /* If we have a message, we can return it */
        if(message)
            return(message);
    }

    return(NULL);
}


/*
 *Reads the event log.
 */
void ReadEL(HIDSEL *el, int printit)
{
	DWORD _evtid = 65535;
    DWORD nstr;
    DWORD usrSize;
    DWORD domainSize;
    DWORD read, needed;
    int sizeLeft;
    int strSize;
    int id;

    char mbuffer[BUFFER_SIZE +1];
    LPSTR sstr = NULL;

    char *strTmp = NULL;
    char *category;
    char *source;
    char *computerName;
    char *descriptiveMsg;

    char elUsr[HIDS_FLSIZE +1];
    char elDomain[HIDS_FLSIZE +1];
    char elStr[HIDS_MAXSTR +1];
    char finalMsg[HIDS_MAXSTR +1];
    LPSTR elSStr[HIDS_FLSIZE +1];

    /* Er must point to the mbuffer */
    el->er = (EVENTLOGRECORD *) &mbuffer; 

    /* Zeroing the values */
    elStr[HIDS_MAXSTR] = '\0';
    elUsr[HIDS_FLSIZE] = '\0';
    elDomain[HIDS_FLSIZE] = '\0';
    finalMsg[HIDS_MAXSTR] = '\0';
    elSStr[0] = NULL;
    elSStr[HIDS_FLSIZE] = NULL;
    
    /* Event log is not open */
    if(!el->h)
    {
        return;
    }
    
    /* Reading the event log */
    while(ReadEventLog(el->h,
				EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
				0,
				el->er, BUFFER_SIZE - 1, &read, &needed))
	{
        if(!printit)
        {
            /* Setting er to the beginning of the buffer */
            el->er = (EVENTLOGRECORD *)&mbuffer;
            continue;
        }

        
        while(read > 0)
        {
            /* We need to initialize every variable before the loop */
            category = GetELCategory(el->er->EventType);
            source = (LPSTR) ((LPBYTE) el->er + sizeof(EVENTLOGRECORD));
            computerName = source + strlen(source) + 1;
            descriptiveMsg = NULL;

            /* Getting event id. */
            id = (int)el->er->EventID & _evtid;
                            
            /* Initialing domain/user size */
            usrSize = 255; domainSize = 255;
            elDomain[0] = '\0';
            elUsr[0] = '\0';

            /* We must have some description */
            if(el->er->NumStrings)
            {	
                sizeLeft = HIDS_MAXSTR - 1024;	

                sstr = (LPSTR)((LPBYTE)el->er + el->er->StringOffset);
                elStr[0] = '\0';

                for (nstr = 0;nstr < el->er->NumStrings;nstr++)
                {
                    strSize = strlen(sstr);
                    if(sizeLeft > 1)
					{
                        strncat(elStr, sstr, sizeLeft);
                    }

                    strTmp = strchr(elStr, '\0');
                    if(strTmp)
                    {
                        *strTmp = ' ';		
                        strTmp++; *strTmp = '\0';
                    }
                    else
                    {
                        printf("Log Collector: Invalid application string (size+)");
                    }
                    sizeLeft-=strSize + 2;

                    if(nstr <= 92)
                    {
                        elSStr[nstr] = (LPSTR)sstr;
                        elSStr[nstr +1] = NULL;
                    }

                    sstr = strchr((LPSTR)sstr, '\0');
                    
                    if(sstr)
                        sstr++;
                    else
                        break;     
				}

                /* Get a more descriptive message (if available) */                
                descriptiveMsg = GetELMsg(el->er, 
                                          el->name,
                                          source, 
                                          elSStr);                
                                                        
                if(descriptiveMsg != NULL)
                {
                    /* Remove any \n or \r */
                    /* Replace tabs from the argument field to spaces.
                     * So whenever we have option:\tvalue\t, it will
                     * become option: value\t
                     */
                    strTmp = descriptiveMsg;    
                    while(*strTmp != '\0')
                    {
                        if(*strTmp == '\n')
                            *strTmp = ' ';
                        else if(*strTmp == '\r')
                            *strTmp = ' ';
                        else if((*strTmp == ':') && (strTmp[1] == '\t'))
                        {
                            strTmp[1] = ' ';
                            strTmp++;
                        }
                                    
                        strTmp++;
                    }
                }
            }
            else
            {
                strncpy(elStr, "(no message)", 128);	
            }


            /* Getting username */
            if(el->er->UserSidLength)
            {
                SID_NAME_USE account_type;
                if(!LookupAccountSid(NULL, 
                                    (SID *)((LPSTR)el->er + 
                                    el->er->UserSidOffset),
                                    elUsr, 
                                    &usrSize, 
                                    elDomain, 
                                    &domainSize, 
                                    &account_type))		
                {
                    strncpy(elUsr, "(no user)", 255);
                    strncpy(elDomain, "no domain", 255);
                }

            }
            else
            {
                strncpy(elUsr, "(no user)", 255);	
                strncpy(elDomain, "no domain", 255);	
            }


            if(printit)
            {
                DWORD _evtid = 65535;
                int id = (int)el->er->EventID & _evtid; 
               
                finalMsg[HIDS_MAXSTR - HIDS_LOG_HEADER] = '\0'; 
                finalMsg[HIDS_MAXSTR - HIDS_LOG_HEADER -1] = '\0'; 
                
                printf("WinEvtLog: %s: %s(%d): %s: %s: %s: %s: %s\n", 
                        el->name,
                        category, 
                        id,
                        source,
                        elUsr,
                        elDomain,
                        computerName,
                        descriptiveMsg != NULL?descriptiveMsg:elStr);	
                
				/*send msg to server
				 ...................
				 ...................
				 */
            }

            if(descriptiveMsg != NULL)
            {
                LocalFree(descriptiveMsg);
            }

            /* Changing the point to the er */
            read -= el->er->Length;
            el->er = (EVENTLOGRECORD *)((LPBYTE) el->er + el->er->Length);
        }		

        /* Setting er to the beginning of the buffer */	
        el->er = (EVENTLOGRECORD *)&mbuffer;
    }

	
    id = GetLastError();
    if(id == ERROR_HANDLE_EOF)
    {
        return;
    }
    /* Event log was cleared. */
    else if(id == ERROR_EVENTLOG_FILE_CHANGED)
    {
        printf("Log Collector: WARN: Event log cleared: '%s'", el->name);
        
        /* Closing the event log and reopenning. */
        CloseEventLog(el->h);
        el->h = NULL;

        /* Reopening. */
        if(StartEL(el->name, el) < 0)
        {
            printf("Log Collector: ERROR: Unable to reopen event log '%s'", el->name);
        }
    }

    else
    {
        printf("Log Collector: WARN: Error reading event log: %d", id);
    }
}
					  

int main()
{
	HIDSEL hidsEL[3];
	int a,b,c;
	a = StartEL("System",&hidsEL[0]);
	//b = StartEL("Security",&hidsEL[1]);
	//c = StartEL("Application",&hidsEL[2]);
	ReadEL(&hidsEL[0],1);
	//ReadEL(&hidsEL[1],1);
	//ReadEL(&hidsEL[2],1);
	system("pause");
	return 0;
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics