I am working on a C# project to search the contents of windows event log files. It needs to be compatible with .evt and .evtx files.
I copied the code from http://www.codeproject.com/Articles/15288/Parsing-event-log-evt-file that reads .evt files and in the case of some files (not all) when I run it, I get the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". This happens on the line:
*((int*)pd) = *((int*)ps);
The entire listing is:
namespace EventLogParser
{
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
// Show the progress
public delegate void ProgressHandler(int val, int max);
// Send any message to UI
public delegate void MessageHandler(string msg);
// Parsed a new event.
public delegate void NewEventFoundHandler(object[] items);
internal class EventLogParser
{
//Constants for api call
private const int NoError = 0;
private const int ErrorInsufficientBuffer = 122;
private readonly uint _offset;
public EventLogParser()
{
TimeZoneInformation tzi;
GetTimeZoneInformation(out tzi);
_offset = (uint)(tzi.bias * 60) - (uint)(tzi.daylightBias * 60);
}
public event ProgressHandler OnProgress;
public event MessageHandler OnAction;
public event NewEventFoundHandler OnFoundRecord;
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool LookupAccountSid(
string lpSystemName,
[MarshalAs(UnmanagedType.LPArray)] byte[] sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder referencedDomainName,
ref uint cchReferencedDomainName,
out SidNameUse peUse);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern int GetTimeZoneInformation(out TimeZoneInformation lpTimeZoneInformation);
// Ctor
// Parse the file
public unsafe void Parse(string filename)
{
//try
//{
// Open the file
using (var fs = new FileStream(filename, FileMode.Open))
{
// Use BinaryReader to read the file
using (var br = new BinaryReader(fs))
{
//Read the header of the file
var header = new byte[sizeof(EventLogHeader)];
br.Read(header, 0, header.Length);
var eventLogHeader = new EventLogHeader(header);
// Validate the file
if (!eventLogHeader.IsValid())
{
OnAction("Invalid file format.");
return;
}
//
var totalEvents = (int)(eventLogHeader.NextIndex - 1);
OnAction(String.Format("Found {0} events", totalEvents));
// Read the items
var cnt = 0;
var offset = eventLogHeader.FooterOffset;
while (true)
{
var buff = ReadEntry(br, ref offset);
var e = ReadEntry(buff);
if (e == null)
continue;
cnt++;
var dt = GetTime(e.Rec.TimeGenerated);
OnFoundRecord(
new object[]
{
Enum.GetName(typeof (EventLogEntryType), e.Rec.EventType),
dt.ToShortDateString(),
dt.ToShortTimeString(),
e.SourceName,
e.Strings,
e.Rec.EventCategory,
e.Rec.EventID,
e.UserSid,
e.Computername
});
if (cnt % 200 == 0) OnProgress(cnt, totalEvents);
if (offset == 48)
break;
}
}
}
//}
//catch (Exception ex)
//{
// OnAction(String.Format("Error Occurred! {0}", ex.Message));
//}
}
// Read an event log record as byte[] from the file.
private byte[] ReadEntry(BinaryReader br, ref uint endPoint)
{
br.BaseStream.Seek(endPoint - 4, SeekOrigin.Begin);
if (br.BaseStream.Position >= br.BaseStream.Length)
{
return new byte[0];
}
var length = br.ReadUInt32();
endPoint -= length;
br.BaseStream.Seek(endPoint, SeekOrigin.Begin);
var buff = new byte[length];
br.Read(buff, 0, buff.Length);
return buff;
}
// Parse the byte[] as an event log record
private unsafe EventLogEntry ReadEntry(byte[] buff)
{
EventLogEntry entry;
try
{
fixed (byte* ptr = buff)
{
entry = new EventLogEntry { Rec = new EventLogRecord(buff) };
// Read SourceName
var start = (uint)sizeof(EventLogRecord);
// Get the Source Name
entry.SourceName = ReadString(ptr, ref start);
// Get the Computer Name
entry.Computername = ReadString(ptr, ref start);
// Get the User Name
var uname = new byte[entry.Rec.UserSidLength];
Copy(ptr, ref start, uname, uname.Length);
entry.UserSid = GetUserInfo(uname);
// read the strings
entry.Strings = ReadString(ptr, ref start, (int)(entry.Rec.DataOffset - entry.Rec.StringOffset) / 2);
// read the data
entry.Data = new byte[(int)entry.Rec.DataLength];
Copy(ptr, ref start, entry.Data, entry.Data.Length);
//
}
}
catch (Exception)
{
entry = null;
}
return entry;
}
// Read string from the byte[]
private unsafe string ReadString(byte* ptr, ref uint start)
{
var result = new StringBuilder();
ptr += start;
while (true)
{
var temp = (char)*((ushort*)ptr);
ptr += 2;
start += 2;
if (temp == '\0')
break;
result.Append(temp);
}
return result.ToString();
}
// Read the Description according to the length specified.
private unsafe string ReadString(byte* ptr, ref uint start, int count)
{
var result = new StringBuilder(count);
ptr += start;
for (; count > 0; count--)
{
var temp = (char)*((ushort*)ptr);
ptr += 2;
start += 2;
result.Append(temp);
}
return result.ToString();
}
// Get the user name from SID
private string GetUserInfo(byte[] buff)
{
var name = new StringBuilder();
var cchName = (uint)name.Capacity;
var referencedDomainName = new StringBuilder();
var cchReferencedDomainName = (uint)referencedDomainName.Capacity;
SidNameUse sidUse;
int err = NoError;
if (
!LookupAccountSid(null, buff, name, ref cchName, referencedDomainName, ref cchReferencedDomainName,
out sidUse))
{
err = Marshal.GetLastWin32Error();
if (err == ErrorInsufficientBuffer)
{
name.EnsureCapacity((int)cchName);
referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
err = NoError;
if (
!LookupAccountSid(null, buff, name, ref cchName, referencedDomainName,
ref cchReferencedDomainName, out sidUse))
err = Marshal.GetLastWin32Error();
}
}
if (err == 0)
return String.Format(@"{0}\{1}", referencedDomainName, name);
return @"N\A";
}
// copy the byte[]
private unsafe void Copy(byte* pSrc, ref uint srcIndex, byte[] dst, int count)
{
if (count == 0)
return;
fixed (byte* pDst = dst)
{
var ps = pSrc;
ps += srcIndex;
byte* pd = pDst;
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n = 0; n < count / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n = 0; n < count % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
srcIndex += (uint)count;
}
}
// Convert to seconds to date time format
private DateTime GetTime(uint time)
{
var output = new DateTime(1970, 1, 1, 0, 0, 0);
time = time - _offset;
output = output.AddSeconds(time);
return output;
}
public class EventLogEntry
{
public string Computername;
public byte[] Data;
public string SourceName;
public string Strings;
public string UserSid;
public EventLogRecord Rec;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct EventLogFooter
{
public uint FooterLength; // length
public uint Unknown0; // 0x11111111
public uint Unknown1; // 0x22222222
public uint Unknown2; // 0x33333333
public uint Unknown3; // 0x44444444
public uint Unknown4;
public uint FooterOffset;
public uint NextIndex;
public uint Unknown7;
public uint EndFooterLength;
public EventLogFooter(byte[] data)
{
fixed (byte* pData = data)
{
this = *(EventLogFooter*)pData;
}
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct EventLogHeader
{
public uint HeaderLength; // length
public uint Signature; // signature
public uint Unknown1;
public uint Unknown2;
public uint Unknown3;
public uint FooterOffset;
public uint NextIndex;
public uint FileLength; // always wont give correct value
public uint Unknown6;
public uint Unknown7;
public uint Unknown8;
public uint EndHeaderLength;
public EventLogHeader(byte[] data)
{
fixed (byte* pData = data)
{
this = *(EventLogHeader*)pData;
}
}
/// <summary>
/// Checks whether the evt file is a valid one.
/// </summary>
public bool IsValid()
{
return HeaderLength == 0x00000030 &&
Signature == 0x654C664c &&
Unknown1 == 0x00000001 &&
Unknown2 == 0x00000001;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct EventLogRecord
{
public uint Length;
public uint Reserved;
public uint RecordNumber;
public uint TimeGenerated;
public uint TimeWritten;
public uint EventID;
public ushort EventType;
public ushort NumStrings;
public ushort EventCategory;
public ushort ReservedFlags;
public uint ClosingRecordNumber;
public uint StringOffset;
public uint UserSidLength;
public uint UserSidOffset;
public uint DataLength;
public uint DataOffset;
public EventLogRecord(byte[] data)
{
fixed (byte* pData = data)
{
this = *(EventLogRecord*)pData;
}
}
}
private enum SidNameUse
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}
[StructLayout(LayoutKind.Sequential)]
private struct SystemTime
{
public readonly short year;
public readonly short month;
public readonly short dayOfWeek;
public readonly short day;
public readonly short hour;
public readonly short minute;
public readonly short second;
public readonly short milliseconds;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct TimeZoneInformation
{
public readonly int bias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public readonly string standardName;
public readonly SystemTime standardDate;
public readonly int standardBias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public readonly string daylightName;
public readonly SystemTime daylightDate;
public readonly int daylightBias;
}
}
}
Does anyone know what could be done to fix this?
Any help would be greatly appreciated.