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).
精彩评论