Как работают поля переменной длины в структуре окон EVENTLOGRECORD? - PullRequest
2 голосов
/ 21 июня 2010

Я пытался с небольшим успехом определить, как работает часть переменной длины данных 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;

Я могу вытащить первый блок, который выглядит как источник, с помощью следующего кода, но это определенно не тот метод, который предполагается:

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

Но из комментариев в Winnt.h я также получаю имя компьютера.

Так может кто-нибудь объяснить, как определить длину «SourceName» из структуры EVENTLOGRECORD, и объяснить, что такое StringOffset, DataLength и DataOffset?

Спасибо.

Ответы [ 3 ]

6 голосов
/ 21 июня 2010

Примечание : в ответе я буду предполагать, что у вас есть указатель на эту структуру, подобную этой:

EVENTLOGRECORD * elr;

чтобы сократить фрагменты кода.

Так может кто-нибудь объяснить, как определить длину "SourceName" из структуры EVENTLOGRECORD

Нет поля, которое бы указывало, как долго это будет, но вы можете определить его довольно легко: это первое поле записи после хорошо определенных полей, поэтому вы можете просто сделать:

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

Теперь, в SourceName у вас есть указатель на эту строку; Вы можете легко определить его длину с помощью обычных строковых функций.

Кстати, после терминатора SourceName должна быть строка ComputerName.

и объясни, что такое StringLength

Там нет StringLength участника, о чем ты говоришь?

DataLength и DataOffset - это?

Журнал событий также состоит из произвольных двоичных данных, включенных в запись.

Элемент DataOffset указывает смещение таких данных от начала записи, а DataLength указывает, как долго эти данные. Если бы вы скопировали эти данные в буфер (при условии, что он достаточно большой), вы бы сделали:

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

Кстати, вместо того, чтобы читать непосредственно включаемые файлы, вы должны прочитать документацию , это гораздо легче понять.

<ч />

Приложение о StringOffset

Поле StringOffset указывает смещение строк, связанных с событием, с начала записи.

Поле StringOffset работает очень похоже на поле DataOffset, описанное выше, но нет соответствующего поля StringLength, поскольку длину каждой строки можно легко определить с помощью обычных строковых функций (на самом деле строковый раздел просто состоит из нескольких NUL определенных строк, расположенных одна за другой).

Кроме того, место, где заканчивается секция строк, может быть легко определено с помощью элемента DataOffset, в действительности секция строк заканчивается там, где начинается блок данных. Структура EVENTLOGRECORD также предоставляет поле NumStrings для определения количества строк, содержащихся в разделе строк (спасибо Реми Лебо).

Если бы вы поместили эти строки в 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));
1 голос
/ 21 июня 2010

Так может кто-нибудь объяснить, как определить длину «SourceName» из структуры EVENTLOGRECORD,

Из того, что я вижу, SourceName[] и Computername[] расположены один за другим, разделены '\0', причем первый начинается сразу за DataOffset, а второй начинается сразу за '\0' из первый и идущий до двух байтов до UserSidOffset, с трейлингом '\0'.

и объясните, что такое StringLength, DataLength и DataOffset?

StringLength Я не могу найти (а StringOffset - это то, где начинается Strings[]), DataLength - это количество байтов в Data[], а DataOffset - это то, где начинается Data[].

Чтобы прочитать строки, вы можете сделать что-то вроде этого:

// 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 ) ) );
  // ...
}
0 голосов
/ 21 июня 2010

Пожалуйста, прочитайте документацию .Он сообщает вам, что такое элементы StringLength, DataLength и DataOffset.

Что касается элементов SourceName и ComputerName, то они оба являются строками с нулевым символом в конце (с потенциально дополнительным заполнением послеComputerName для выравнивания элемента UserSid).Вы увидели, что ComputerName появился в вашем буфере, потому что вы сказали memcpy () скопировать необработанные байты обоих членов вместе.Попробуйте использовать lstrlenW() и lstrcpyW() (или эквивалентные функции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...