Category Archives: Programming

Statically Compiled LINQ Queries Are Broken In .NET 4.0

Written by William Roush on January 19, 2014 at 5:31 pm

Diving into how a minor change in error handling in .NET 4.0 has broken using compiled LINQ queries as per the MSDN documentation.

Query was compiled for a different mapping source than the one associated with the specified DataContext.

When working on high performing LINQ code this error can cause a massive amount of headaches. This StackOverflow post blames the problem on using multiple LINQ mappings (which the same mappings from different DataContexts will count as "different mappings"). In the example below, we’re going to use the same mapping, but different instances which is extremely common for short-lived DataContexts (and reusing DataContexts come with a long list of problematic side-effects).

namespace ConsoleApplication1
{
    using System;
    using System.Data.Linq;
    using System.Linq;

    class Program
    {
        protected static Func<MyContext, Guid, IQueryable<Post>> Query =
            CompiledQuery.Compile<MyContext, Guid, IQueryable<Post>>(
                (dc, id) =>
                    dc.Posts
                        .Where(p => p.AuthorID == id)
            );

        static void Main(string[] args)
        {
            Guid id = new Guid("340d5914-9d5c-485b-bb8b-9fb97d42be95");
            Guid id2 = new Guid("2453b616-739f-458f-b2e5-54ec7d028785");

            using (var dc = new MyContext("Database.sdf"))
            {
                Console.WriteLine("{0} = {1}", id, Query(dc, id).Count());
            }

            using (var dc = new MyContext("Database.sdf"))
            {
                Console.WriteLine("{0} = {1}", id2, Query(dc, id2).Count());
            }

            Console.WriteLine("Done");
            Console.ReadKey();
        }
    }
}

This example follows MSDN’s examples, yet I’ve seen people recommending you do this to resolve the changes in .NET 4.0:

protected static Func<MyContext, string, IQueryable<Post>> Query
{
    get
    {
        return
            CompiledQuery.Compile<MyContext, string, IQueryable<Post>>(
                 (dc, id) =>
                    dc.Posts
                        .Where(p => p.AuthorID == id)
            );
    }
}

Wait a second! I’m recompiling on every get, right? I’ve seen claims it doesn’t. However peeking at the IL code doesn’t hint at that, the process is as follows:

  • Check if the query is assignable from ITable, if so let the Lambda function compile it.
  • Create a new CompiledQuery object (just stores the Lambda function as a local variable called “query”).
  • Compile the query using the provider specified by the DataContext (always arg0).

At no point is there a cache check, the only place a cache could be placed is in the provider (which SqlProvider doesn’t have one), and that would be a complete maintenance mess if it was done that way.

Using a test application (code is available at https://bitbucket.org/StrangeWill/blog-csharp-static-compiled-linq-errors/, use the db.sql file to generate the database, please use a local installation of MSSQL server to give the best speed possible so that we can evaluate query compilation times), we’re going to force invoking the CompiledQuery.Compile method on every iteration (10,000 by default) by passing in delegates as opposed to passing in the resulting compiled query.

QueryCompiled Average: 0.5639ms
QueryCompiledGet Average: 1.709ms
Individual Queries Average: 2.1312ms
QueryCompiled Different Context (.NET 3.5 only) Average: 0.6051ms
QueryCompiledGet Different Context Average: 1.7518ms
Individual Queries Different Context Average: 2.0723ms

We’re no longer seeing the 1/4 the runtime you get with the compiled query. The primary problem lies in this block of code found in CompiledQuery:

if (context.Mapping.MappingSource != this.mappingSource)
{
	throw Error.QueryWasCompiledForDifferentMappingSource();
}

This is where the CompiledQuery will check and enforce that you’re using the same mapper, the problem is that System.Data.Linq.Mapping.AttributeMappingSource doesn’t provide an Equals override! So it’s just comparing whether or not they’re the same instance of an object, as opposed to them being equal.

There are a few fixes for this:

  • Use the getter method, and understand that performance benefits will mainly be seen where the result from the property is cached and reused in the same context.
  • Implement your own version of the CompiledQuery class.
  • Reuse DataContexts (typically not recommended! You really shouldn’t…).
  • Stick with .NET 3.5 (ick).
  • Update: RyanF below details sharing a MappingSource below in the comments. This is by far the best solution.

Using Windows Vault To Store TortoiseHg (Mercurial) Passwords

Written by William Roush on December 17, 2013 at 7:34 pm

Mercurial has a built-in method for storing passwords, but it stores them plaintext in your settings file. For those of us bound by various compliance regulations, or just those of us that care about security, this is a huge no-no.

First you’ll want to clear your password from TortoiseHg’s authentication section for your repository if you haven’t already (this will remove your credentials from your “.hg\hgrc” settings file in the repo, you may want to manually confirm this).

Mercurial-Auth

Next you need to enable the Mercurial Keyring extension by pasting the text below into your mercurial.ini file (can be accessed via File > Settings > Edit File), which is bundled with TortoiseHg, so a path is not required:

[extensions]
mercurial_keyring=

On the next push it’ll ask for your password, put it in and it should never ask again.

To confirm/update your password was saved in the Windows Vault, go to your Control Panel > User Accounts > Manage your credentials

Mercurial-Windows-Vault>

Tamper-proof Licensing Using Cryptographic Signatures

Written by William Roush on November 4, 2013 at 9:15 pm

I’m going to dive right into writing a basic licensing system using strong established cryptographical signing processes to prevent tampering or the creation of a key generator. I’m going to digitally sign the plain-text license using OpenPGP’s private key, this will generate a human readable license file, but modifying the payload will cause an exception to be thrown and tampering detected.

Solutions

I’m going to go over the basic options available. There are many others and there are a lot of hybrids of these various types, but for a quick introduction to licensing options, this should get you up to speed.

No Licensing

Of course the option for no licensing is always available. This provides no protection against a user copying your application and giving it to another user. Sometimes the overhead of writing and maintaining licensing code may not be worth the effort.

Plaintext Keys

Plaintext keys store user information, dates, times and keys in various locations, such as files on the hard disk, registry keys or resource files. These are fairly trivial to change and circumvention information can be passed around by word of mouth. You can attempt to store keys in hidden places like some other software, but these can and likely will be tracked down, and depending on if your method is ethically unsound, can land you unfavorable opinion with your would-be customers.

These are very easy, and can be a preferred choice if you’re not concerned with someone attempting to crack your licensing code, but may want some features granted by having licensing support in your software.

Symmetrical Cryptography / Hash Verification

Both of these methods fall under the same pros/cons for the most part. Symmetrical keys will encrypt the entire license file and should use some sort of secure algorithm (ex: AES256) with a secret key. Hash verification may store the data encrypted or unencrypted, but will hash the key information either with a secret method or a secret salt and store that with the license file, where you can validate that it hasn’t been tampered with, tampered keys fail validation.

Both of these suffer from the same issue: the code to decrypt/hash and verify your license files provide all the information needed to encrypt/hash new license files, allowing someone to create a license generator. In other languages these is a higher barrier of entry to be able to reverse engineer a native library, but in .NET your code can be fairly easily decompiled and methods like this reverse engineered (generally even when obfuscated).

Asymmetrical Cryptography

Asymmetrical cryptography, also known as Public-key cryptography is a method of encrypting data using the public key, and only being able to decrypt it with the private key (this can also be used for verification purposes by reversing the usage of the keys). In our example, we’ll use the example of digital signatures: where we use the private key for signing the license, and the public key to verify it hasn’t been tampered with.

Without the private key, a user cannot issue new licenses, a key generator will be impossible to make without one. The best bet resides in the malicious person to take one of two paths: to modify the software to remove the license requirement entirely, or modify the software to use a different public key, so they can use their own private key to generate licenses.

We’re on a better path now: a malicious user that has to patch our binaries to circumvent licensing will incur the overhead of having to patch every binary we release, while we can’t ever stop circumvention, we can make it annoying!

Online Verification

Online verification is one of the hardest methods, if not the hardest to circumvent. However a lot has to be assumed about your customers. You need to assume your users will be online at regular intervals, additional the use of software they’ve purchased will be entirely dependent on you keeping your licensing servers up and running.

Circumvention requires you to rewrite binaries to no longer check online, or spoof authentication servers.

PGP and You

I’m going to useĀ OpenPGP, an open encryption standard that includes public-key cryptography. This library is used a lot for signing/encrypting e-mails and code among various programming groups, and I’ll continue to use this later for various examples such as signing code in a later blog.

Generating Your Key Pair

I recommend using GPG4Win, an easy to use application for creating and managing GPG and X509 certificates.

Select "File" > "New Certificate"

Select “File” > “New Certificate”

We want to create an OpenPGP key pair.

We want to create an OpenPGP key pair.

Enter the certificate information.

Enter the certificate information.

Your private key is the key to your kingdom, use a strong passphrase.

You want to save the private key (*.gpg) somewhere where your application can access it.

You want to save the private key (*.gpg) somewhere where your application can access it.

You'll want to export the public key too.

You’ll want to export the public key too.

Dealing with PGP On .NET

I’m going to use a very commonly used cryptography library for .NET BouncyCastle, mainly because it’s extremely powerful and licensed under MIT a very open license friendly to both open source projects and closed source.

An Example License File

We’re going to go ahead with the most basic setup: we’re not going to encrypt the payload so we can understand what is going on, for further obscurity you can encrypt the payload or even the entire license, but it wont add much additional security (just make it harder to understand what is going on till they decompile your .NET code).

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

William Roush
1/1/2018 12:00:00 AM
1/1/2014 12:00:00 AM
-----BEGIN PGP SIGNATURE-----
Version: BCPG C# v1.7.4114.6375

iQFYBAABAgBCBQJSdv5OOxxSb3VzaFRlY2ggRXhhbXBsZSBDb2RlIFNpZ25pbmcg
S2V5IDxleGFtcGxlQHJvdXNodGVjaC5uZXQ+AAoJEGyAwS0mpw1Ki5MH/jQAKiur
FF06Q7D0BeaUE6eBk40I2LocZwSE2Osx94Tdux08L8vpaOUG4xBx6UsNKusvrbaV
hSxeU1e1LkO3QMu8+//FAFsJizTYjYZRoRe167WFRlQbteZdgeB1S+HMdDhsBs+Z
3+FGAulhs7EBmRkgSoYEX0NdJc1uEfW5kRr4KfL4v+m9UU6Z796KWFzOi8xqTcRG
eO9cNV7QtAzBOpI2CVuq6KuGj5VjNtQsxUrUNl6U/giV61Y5TYOfRnL47kX4U6sf
Uzp/iRZqemi+n7iBjMsO37+baANySaBRSKUG0EXtQM9sVxHZ7aGoXpjsU+oeWtBY
iWPAPX1ePwQ6LcM=
=57ao
-----END PGP SIGNATURE-----

Writing Your License File Management Code

First I’m going to outline some basics, we’re going to store a name and two dates, a software expiration date and a support expiration date. Additionally I’ll override ToString() for testing purposes, and write a method that returns the license data as a byte array that’ll go into our signed license file.

using System;
using System.IO;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Security;

public class License
{
    public string Name { get; set; }
    public DateTime SoftwareExpires { get; set; }
    public DateTime SupportExpires { get; set; }

    protected PgpPrivateKey PrivateKey { get; set; }
    public PgpPublicKey PublicKey { get; set; }

    public override string ToString()
    {
        return string.Format("Name: {1}{0}Software Expires: {2}{0}Support Expires: {3}",
            Environment.NewLine,
            this.Name,
            this.SoftwareExpires,
            this.SupportExpires
        );
    }

    private byte[] PrepareLicenseForStorage()
    {
        var licenseData = string.Format(
            "{0}\n{1}\n{2}",
            this.Name,
            this.SoftwareExpires.ToString(),
            this.SupportExpires.ToString()
        );

        return Encoding.UTF8.GetBytes(licenseData);
    }

Next we’re going to define how to read a public key out of a file.

public void ReadPublicKey(string path)
{
    using (var keyFileStream = File.OpenRead(path))
    using (var pgpDecoderStream = PgpUtilities.GetDecoderStream(keyFileStream))
    {
        var keyRingBundle = new PgpPublicKeyRingBundle(pgpDecoderStream);
        var keyRings = keyRingBundle.GetKeyRings();
        foreach (PgpPublicKeyRing keyRing in keyRings)
        {
            this.PublicKey = keyRing.GetPublicKey();
            break;
        }
    }
}

Then we’re going to define how to read a private key out of a file.

public void ReadPrivateKey(string path)
{
    using (var keyFileStream = File.OpenRead(path))
    using (var pgpDecoderStream = PgpUtilities.GetDecoderStream(keyFileStream))
    {
        // Get the key ring from the private key file.
        var keyRingBundle = new PgpSecretKeyRingBundle(pgpDecoderStream);
        var keyRings = keyRingBundle.GetKeyRings();

        // Get the first key from the key ring (it's an enumerable, so it's annoying).
        PgpSecretKey secretKey = null;
        foreach(PgpSecretKeyRing keyRing in keyRings)
        {
            secretKey = (PgpSecretKey)keyRing.GetSecretKey();
            break;
        }

        // Get the private key, we don't have a pass phrase on this (you should though!). 
        // Do NOT hard code this into the library, take it as a parameter from your key generation
        // software.
        this.PrivateKey = secretKey.ExtractPrivateKey("".ToCharArray());
    }
}

Next we’re going to define the code for creating a license file.

public void CreateLicenseFile(string fileName)
{
    var hashAlgorithm = HashAlgorithmTag.Sha1;
    using (var fileWriter = new FileStream(fileName, FileMode.Create))
    using (var outputStream = new ArmoredOutputStream(fileWriter))
    {
        // Continue our signature.
        var signatureGenerator = new PgpSignatureGenerator(this.PublicKey.Algorithm, hashAlgorithm);
        signatureGenerator.InitSign(PgpSignature.BinaryDocument, this.PrivateKey);
        foreach (string userId in this.PublicKey.GetUserIds())
        {
            var pgpSigatureSubpacketGenerator = new PgpSignatureSubpacketGenerator();
            pgpSigatureSubpacketGenerator.SetSignerUserId(false, userId);
            signatureGenerator.SetHashedSubpackets(pgpSigatureSubpacketGenerator.Generate());
            break;
        }

        var licenseDataBuffer = this.PrepareLicenseForStorage();

        // We're going to write out the cleartext portion.
        outputStream.BeginClearText(hashAlgorithm);
        outputStream.Write(licenseDataBuffer, 0, licenseDataBuffer.Length);

        // This updates our signature with the data in our license.
        signatureGenerator.Update(licenseDataBuffer, 0, licenseDataBuffer.Length);
        outputStream.EndClearText();

        // Add newline after text so we start the PGP signature header on the next line.
        byte[] newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
        fileWriter.Write(newLineBytes, 0, newLineBytes.Length);

        // Outputs the signature into the file.
        using (var bcpgStream = new BcpgOutputStream(outputStream))
        {
            signatureGenerator.Generate().Encode(bcpgStream);
        }
    }
}

Finally, we need to be able to create a license object from a signed license file.

public static License LoadLicenseFromFile(string fileName, PgpPublicKey publicKey)
{
    using (var inputStream = new FileStream(fileName, FileMode.Open))
    using (var armoredStream = new ArmoredInputStream(inputStream))
    using (var memoryStream = new MemoryStream())
    {
        // We're going to read the payload of the signed text in.
        while (armoredStream.IsClearText())
        {
            memoryStream.WriteByte((byte)armoredStream.ReadByte());
        }
        
        // Load the signature data from the armored file and initalize it with the public key.
        PgpObjectFactory pgpFact = new PgpObjectFactory(armoredStream);
        PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
        PgpSignature sig = p3[0];
        sig.InitVerify(publicKey);

        // We're going to seek to the beginning, and strip off the final "/r/n-" from the message.
        memoryStream.Seek(0, SeekOrigin.Begin);
        for (int i = 0; i < memoryStream.Length - 3; i++)
        {
            sig.Update((byte)memoryStream.ReadByte());
        }
        
        if (!sig.Verify())
        {
            throw new Exception("Verification Failed")
        }

        // Parse our stored license data.
        string[] licenseData = Encoding.UTF8.GetString(memoryStream.ToArray()).Split('\n');
        return new License
        {
            Name = licenseData[0],
            SoftwareExpires = DateTime.Parse(licenseData[1]),
            SupportExpires = DateTime.Parse(licenseData[2])
        };   
    }
}

From here we have the underlying infrastructure needed to write a license file that cannot be tampered with and that our application can verify is correct.

Changes To Production Code

First in production you’ll never want to ship your licensing software with your private key or with your secret phrase, that stays with you for generating new keys. Secondly we’ll want to read the private key from some internal resource so a malicious hacker can’t just replace your public key file without modifying binaries.

High Performance Event Log Reader

Written by William Roush on October 30, 2013 at 11:07 pm

Why Do You Need A High Performance Event Log Reader?

I ran into this issue when trying to figure out how to keep up with Windows’ ability to generate logs out the nose when full auditing is turned on. WMI would bury a CPU and refuse to keep up. The next solution was to write an event log reader in C#, it was barely able to keep up (and fell behind at times), and put a significant strain on the server, there must be an easier way if Windows is able to write logs this quickly, surely I can read them.

The problem is that the format that you consume these logs in through the various methods listed above is not the format Windows writes them to disk in.

Can’t This Be Done In .NET’s Libraries?

The short answer is no. The long answer is “well, yes, but you’re going to be calling C level libraries via PInvoke, and have to redeclare a lot of things defined in Windows.h + WinBase.h”, I will provide all the tools needed to write one in C, at which point you can wrap it in a C++/CLR or PInvoke your way to victory.

Typical Event Log Data Access Via C# And Performance Issues

namespace TestApplication
{
    using System;
    using System.Diagnostics;

    class Program
    {
        static void Main(string[] args)
        {
            EventLog eventLog = new EventLog("System");
            EventLogEntry entry = eventLog.Entries[0];
            Console.WriteLine("EventID: {0}", entry.EventID);
            Console.WriteLine("TimeGenerated: {0}", entry.TimeGenerated);
            Console.WriteLine("Message: {0}", entry.Message);
            Console.ReadKey();
        }
    }
}

Wow that was easy! Well sort of… this requires us to read all of the system event log into from eventLog.Entries, this can take awhile to load if you’re on a system with a large number of event logs. On top of having to read all of the data in at once with no ability to seek (corrected by Dmitry below), we have to process the entry’s message… we’ll get into that when we dive into the C code to get that done. There are additional methods (EventLogQuery/EventLogReader), but these don’t help enough.

How Can We Overcome The Inefficiencies?




Like with most other things: go down to C! There are many benefits to the raw WINAPI methods, those include:
  • Only format the event body when we want it, otherwise we can just inspect the string payload.
  • We could cache the event log format strings as we need them improving processing performance for repetitive messages.
  • Read from the front or the back (struct has length at the beginning and end of it for easy skipping of records).
  • C WINAPI calls is about as light weight as you’re going to get it and not go insane (you’ll go a little insane from WINAPI alone).



These of course can be consumed using PInvoke and juggling types into .NET/using marshals/unsafe blocks. I'm not going to get into it as we're exploring these data structures in C, I'll probably be releasing a full managed library later so keep an eye out for it.


#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <WinBase.h>
#include <strsafe.h>

using namespace std;

#define MAX_TIMESTAMP_LEN 23 + 1

void GetTimestamp(const DWORD Time, WCHAR DisplayString[]);

int main(array<System::String ^> ^args)
{
  // Simple enough, we're just opening the System event log from our
  // local system.
  // Detailed here:
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363672(v=vs.85).aspx
  HANDLE hEventLog = OpenEventLog(NULL, L"System");
  if(hEventLog == INVALID_HANDLE_VALUE)
  {
    cout << "Invalid handle value returned." << endl;
  }

  LPVOID lpBuffer = 0;
  DWORD dwReadFlags = EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ;
  DWORD dwRecordOffset = 0;
  DWORD nNumerOfBytesToRead = 1024;
  DWORD pnBytesRead = NULL;
  DWORD pnMinNumberOfBytesNeeded = NULL;
  DWORD recordCount = 0;
  PBYTE lastRecord = 0;
  PBYTE currentRecord = 0;

  lpBuffer = (PBYTE)malloc(nNumerOfBytesToRead);
  if(lpBuffer == NULL)
  {
    cout << "Not enough memory." << endl;
  }

  // ReadEventLog is detailed here:
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363674(v=vs.85).aspx
  if(!ReadEventLog(
    hEventLog,
    dwReadFlags,
    dwRecordOffset,
    lpBuffer,
    nNumerOfBytesToRead,
    &pnBytesRead,
    &pnMinNumberOfBytesNeeded
  ))
  {
    cout << "Error: " << GetLastError() << endl;
    cout << "Failure to read event log" << endl;
  }

  GetNumberOfEventLogRecords(hEventLog, &recordCount);
  cout << "Records found: " << recordCount << endl;

  // PEVENTLOGRECORD is detailed here:
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646(v=vs.85).aspx
  PEVENTLOGRECORD pRecord = (PEVENTLOGRECORD)lpBuffer;

  // Breaking EventID down.
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363651(v=vs.85).aspx
  int code = (pRecord->EventID & 0x0000FFFF);
  int facility = (pRecord->EventID & 0x0FFF0000) >> 16;
  int reserved = (pRecord->EventID & 0x10000000) >> 28;
  int customer = (pRecord->EventID & 0x20000000) >> 29;
  int sev = (pRecord->EventID & 0xC0000000) >> 30;

  // The source is the first record
  // See remarks:
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646(v=vs.85).aspx
  // WCHAR SourceName[] <--- We're getting this one.
  // WCHAR Computername[] <-- We could do a "wcslen(pSource) + 1" to read this.
  // SID   UserSid <-- "wcslen(pComputerName) + 1"
  // WCHAR Strings[] <-- We get this later using StringOffset.
  // BYTE  Data[]
  // CHAR  Pad[]
  // DWORD Length <-- This is the length at the end of the record for
  // reading from the end.
  LPWSTR pSource = (LPWSTR)(((PBYTE)pRecord) + sizeof(EVENTLOGRECORD));

  // We're going to print out some basic information.
  cout << "EventID: " << pRecord->EventID << endl;
  cout << "Code: " << code << endl;
  cout << "facility: " << facility << endl;
  cout << "reserved: " << reserved << endl;
  cout << "customer: " << customer << endl;
  cout << "sev: " << sev << endl;
  cout << "Number of strings: " << pRecord->NumStrings << endl;
  wcout << L"Source:" << pSource << endl;

  // Pull the timestamp.
  WCHAR TimeStamp[MAX_TIMESTAMP_LEN];
  GetTimestamp(pRecord->TimeGenerated, TimeStamp);
  wcout << L"Time: " << TimeStamp << endl;

  // This information is found under 
  // HKLM/SYSTEM/CurrentControlSet/services/eventog/System/
  //	Service Control Manager/EventMessageFile
  // We know this is from "Service Control Manager" by it's source listed in 
  // the event log. In reality we'd use the source to dig the registry and
  // load this...
  HANDLE hResources = LoadLibraryEx(
    L"c:\\Windows\\system32\\services.exe",
    NULL,
    LOAD_LIBRARY_AS_IMAGE_RESOURCE 
    | LOAD_LIBRARY_AS_DATAFILE
  );
  if (NULL == hResources)
  {
    cout << "LoadLibrary failed with " << GetLastError() << endl;
  }

  // Build out our argument list from the strings stored with the event.
  DWORD dwFormatFlags = FORMAT_MESSAGE_FROM_SYSTEM
    | FORMAT_MESSAGE_FROM_HMODULE
    | FORMAT_MESSAGE_ALLOCATE_BUFFER;
  DWORD_PTR* pArgs = (DWORD_PTR*)malloc(sizeof(DWORD_PTR) * pRecord->NumStrings);
  LPWSTR pString = (LPWSTR)(((PBYTE)pRecord) + pRecord->StringOffset);

  // This is only used for arrays, but for a quick PoC we'll just code it
  // because it's easier to understand, see how Microsoft does it in
  // http://msdn.microsoft.com/en-us/library/windows/desktop/bb427356(v=vs.85).aspx
  // under "GetMessageString".
  dwFormatFlags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
  for(DWORD i = 0; i < pRecord->NumStrings; i++)
  {
    pArgs[i] = (DWORD_PTR)pString;
    pString += wcslen(pString) + 1;
  }

  // Get our formatted message from our resource file + argument list we built.
  LPWSTR pMessage = NULL;
  if(!FormatMessage(
    dwFormatFlags,
    hResources, // This is the library that we loaded earlier, it contains
        // the string format information.
    pRecord->EventID,
    0,
    (LPWSTR)&pMessage,
    0,
    (va_list*)pArgs))
  {
    cout << "Format failed with: " << GetLastError() << endl;
  }
  else
  {
    wcout  << "strings: " << pMessage << endl;
  }

  free(pArgs);
  cin.ignore();

  return 0;
}

// Taken from http://msdn.microsoft.com/en-us/library/windows/desktop/bb427356(v=vs.85).aspx
void GetTimestamp(const DWORD Time, WCHAR DisplayString[])
{
  ULONGLONG ullTimeStamp = 0;
  ULONGLONG SecsTo1970 = 116444736000000000;
  SYSTEMTIME st;
  FILETIME ft, ftLocal;

  ullTimeStamp = Int32x32To64(Time, 10000000) + SecsTo1970;
  ft.dwHighDateTime = (DWORD)((ullTimeStamp >> 32) & 0xFFFFFFFF);
  ft.dwLowDateTime = (DWORD)(ullTimeStamp & 0xFFFFFFFF);
  
  FileTimeToLocalFileTime(&ft, &ftLocal);
  FileTimeToSystemTime(&ftLocal, &st);
  StringCchPrintf(DisplayString, MAX_TIMESTAMP_LEN, L"%d/%d/%d %.2d:%.2d:%.2d", 
    st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
}

Further Improvements To Be Made

A few things need to be done to this design, first we need to be able to load new resources depending on the source so that we always can pull the formatted strings we need, for that we'll need to dig around the registry. Of course this should be rewritten to spit out managed objects (either via C++/clr or PInvoke) and give a much more developer-friendly interface.