Windows EVENTLOGRECORD结构中的可变长度字段如何工作?

reu*_*cam 2 c++ winapi

我试图确定EVENTLOGRECORD数据的可变长度部分是如何工作的,但收效甚微.

Winnt.h定义了结构和以下数据,如下所示:

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;
WORD   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;
Run Code Online (Sandbox Code Playgroud)

我可以使用以下代码拉出第一个看起来像源代码的块,但它肯定不是预期的方法:

memcpy(&strings, pRecord+sizeof(EVENTLOGRECORD), tmpLog->UserSidOffset);
Run Code Online (Sandbox Code Playgroud)

但是从Winnt.h中的评论中,我也得到了计算机名称.

那么有人可以解释如何从EVENTLOGRECORD结构中确定"SourceName"长度,并解释StringOffset,DataLength和DataOffset是什么?

谢谢.

Mat*_*lia 6

注意:在整个答案中,我会假设您有一个指向该结构的指针,如下所示:

EVENTLOGRECORD * elr;
Run Code Online (Sandbox Code Playgroud)

缩短代码片段.

那么有人可以解释如何从EVENTLOGRECORD结构中确定"SourceName"长度

没有字段指定它的长度,但您可以很容易地确定它:它是明确定义的字段之后的记录的第一个字段,因此您可以简单地执行:

WCHAR * SourceName=(WCHAR *)((unsigned char *)elr + sizeof(*elr));
Run Code Online (Sandbox Code Playgroud)

现在,SourceName你有一个指向该字符串的指针; 您可以使用常用的字符串函数轻松确定其长度.

顺便说一句,在终结器之后SourceName应该有ComputerName字符串.

并解释一下StringLength

没有StringLength会员,你在说什么?

DataLength和DataOffset是?

事件日志也由嵌入在记录中的任意二进制数据组成.

DataOffset成员指定从记录的开始偏移这样的数据,并DataLength指定有多长数据.如果您要将该数据复制到缓冲区(假设它足够大),您可以:

memcpy(targetBuffer,(unsigned char *)elr + elr->DataOffset,elr->DataLength);
Run Code Online (Sandbox Code Playgroud)

顺便说一下,您应该阅读文档,而不是直接阅读包含文件,它更容易理解.


关于.的附录 StringOffset

StringOffset字段指定与记录开头的事件关联的字符串的偏移量.

StringOffset字段与上述DataOffset字段非常相似,但没有相应的StringLength字段,因为每个字符串的长度可以使用普通的字符串函数轻松确定(实际上字符串部分只是由几个NUL终止的字符串组成一个后面的字符串其他).

此外,可以容易地确定检查该DataOffset成员的字符串部分结束的位置,事实上,字符串部分在数据块开始处结束.该EVENTLOGRECORD结构还提供了NumStrings字段来确定字符串部分中包含的字符串数量(感谢Remy Lebeau).

如果你把这些字符串放在一个vector<wstring>你做这样的事情(仔细的,未经测试的代码):

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));
Run Code Online (Sandbox Code Playgroud)