开发者

How do the variable length fields in the windows EVENTLOGRECORD structure work?

I've tried, with little success, to identify how the variable length portion of the EVENTLOGRECORD data works.

Winnt.h defines the structure, and the following data, as follows:

typedef struct _EVENTLOGRECORD {
DWORD  Length;        // Length of full record
DWORD  Reserved;      // Used by the service
DWORD  RecordNumber;  // Absolute record number
DWORD  TimeGenerated; // Seconds since 1-1-1970
DWORD  TimeWritten;   // Seconds since 1-1-1970
DWORD  EventID;
WORD   EventType;
WORD   NumStrings;
WORD   EventCategory;
WOR开发者_如何学JAVAD   ReservedFlags; // For use with paired events (auditing)
DWORD  ClosingRecordNumber; // For use with paired events (auditing)
DWORD  StringOffset;  // Offset from beginning of record
DWORD  UserSidLength;
DWORD  UserSidOffset;
DWORD  DataLength;
DWORD  DataOffset;    // Offset from beginning of record
//
// Then follow:
//
// WCHAR SourceName[]
// WCHAR Computername[]
// SID   UserSid
// WCHAR Strings[]
// BYTE  Data[]
// CHAR  Pad[]
// DWORD Length;

    //
} EVENTLOGRECORD, *PEVENTLOGRECORD;

I can pull out the first chunk which appears to be the source with the following code, but its certainly not the intended method:

memcpy(&strings, pRecord+sizeof(EVENTLOGRECORD), tmpLog->UserSidOffset);

But from the comments in Winnt.h, I'm also getting the computer name.

So can someone explain how to determine the "SourceName" length from the EVENTLOGRECORD structure, and explain what StringOffset, DataLength and DataOffset are?

Thanks.


Note: throughout the answer I'll assume that you have a pointer to that structure like this:

EVENTLOGRECORD * elr;

to shorten the code snippets.

So can someone explain how to determine the "SourceName" length from the EVENTLOGRECORD structure

There's no field that specifies how long it is, but you can determine it quite easily: it is the first field of the record after the well-defined fields, so you can simply do:

WCHAR * SourceName=(WCHAR *)((unsigned char *)elr + sizeof(*elr));

Now, in SourceName you have a pointer to that string; you can easily determine its length with the usual string functions.

By the way, after the terminator of SourceName there should be the the ComputerName string.

and explain what StringLength

There's no StringLength member, what are you talking about?

DataLength and DataOffset are?

An event log is composed also of arbitrary binary data, that is embedded in the record.

The DataOffset member specifies the offset of such data from the beginning of the record, and DataLength specifies how long is that data. If you were to copy that data to a buffer (assuming that it's big enough), you'd do:

memcpy(targetBuffer,(unsigned char *)elr + elr->DataOffset,elr->DataLength);

By the way, instead of reading directly the include files you should read the documentation, it's far easier to understand.


Addendum about StringOffset

The StringOffset field specifies the offset of the strings associated to the event from the beginning of the record.

The StringOffset field works very much like the DataOffset field described above, but there's no corrispondent StringLength field, since the length of each string can be easily determined using the normal string functions (in fact the string section is just made of several NUL-terminated strings put one after the other).

Moreover, the location where the strings section ends can be easily determined examining the DataOffset member, in facts the strings section ends where the data chunk begins. The EVENTLOGRECORD structure also provides the NumStrings field to determine the number of strings contained in the strings section (thanks Remy Lebeau).

If you were to put these strings in a vector<wstring> you'd do something like this (careful, untested code):

vector<wstring> strings;
for(
        wchar_t * ptr=(wchar_t *)((unsigned char *)elr + elr->StringOffset);
        strings.size()<elr->NumStrings;
        ptr+=strings.back().length() + 1
    )
    strings.push_back(wstring(ptr));


So can someone explain how to determine the "SourceName" length from the EVENTLOGRECORD structure,

From what I can see, SourceName[] and Computername[] are one behind each other, separated by a '\0', with the first starting right behind DataOffset, and the second starting right behind the '\0' of the first, and going up to two bytes before UserSidOffset, with a '\0' trailing.

and explain what StringLength, DataLength and DataOffset are?

StringLength I cannot find (and StringOffset is where Strings[] starts), DataLength is the number of bytes in Data[], and DataOffset is where Data[] starts.

To read the strings, you could do something like this:

// Beware, brain-compiled code ahead!
void f(EVENTLOGRECORD* rec)
{
  std::wstring source_name(
    reinterpret_cast<const wchar_t*>( 
      reinterpret_cast<const unsigned char*>( rec 
                                            + sizeof(EVENTLOGRECORD ) ) ) );
  std::wstring computer_name( 
    reinterpret_cast<const wchar_t*>( 
      reinterpret_cast<const unsigned char*>( rec 
                                            + sizeof(EVENTLOGRECORD )
                                            + source_name.length()+1 ) ) );
  // ...
}


Please read the documentation. It tells you what the StringLength, DataLength and DataOffset members are.

As for the SourceName and ComputerName members, they are both null-terminated strings (with potentially extra padding after ComputerName to align the UserSid member). You saw the ComputerName appear in your buffer because you told memcpy() to copy the raw bytes of both members together. Try using lstrlenW() and lstrcpyW() (or equivilent functions).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜