I already knew that the HttpSessionState instance was being stored in the current HttpContext's Items collection (thanks to Mr. Lutz Roeder, of course), and my initial plan was to inherit from HttpSessionState and intercept the calls made to methods like Add, Remove, etc. Alas, HttpSessionState is marked as sealed, and none of its methods is virtual.
And then I found it! Every HttpSessionState object takes a storage parameter on its creation -- an IHttpSessionState implementor. All I had to to was create an object that implements this interface, and pass it to a new HttpSessionState instance. My interface implementation simply delegates everything to the real HttpSessionState instance. Here is how to replace the built-in session object. Note that we need some reflection to call the internal constructor: