Consider the following piece of .NET code:
byte[] hash = { 0x60, 0x2B, 0x45, 0x9D, 0xA0, 0x6D, 0xD5, 0x02, 0x43, 0x86, 0xC1, 0xBA, 0x6B, 0x14, 0x37, 0x88, 0x63, 0x08, 0x39, 0xA0 };
using (var adminBase = TemporaryComObject.Wrap(new MSAdminBase_W()))
using (var ptrHash = new AllocHGlobal(hash))
{
using (var siteKey = new AdminBaseKey(adminBase.Com, adminBase.Com.OpenKey(METADATA_MASTER_ROOT_HANDLE, "/LM/W3SVC/1", METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10000)))
{
var record = new METADATA_RECORD
{
dwMDIdentifier = 5506,
dwMDAttributes = METADATA_INHERIT,
dwMDUserType = IIS_MD_UT_SERVER,
dwMDDataType = BINARY_METADATA,
pbMDData = ptrHash.Buffer,
dwMDDataLen = hash.Length
};
adminBase.Com.SetData(siteKey.Handle, string.Empty, ref record);
}
adminBase.Com.SaveData();
}
This code attempts to set the SSLCertHash IIS6 metabase property from .NET.
It runs absolutely fine if the .NET application is compiled for x86, meaning the following line is found in the respective .csproj file:
<PlatformTarget>x86</PlatformTarget>
However, dragons come when I omit this line and compile for AnyCPU. Namely, what happens is that inetinfo.exe crashes with Access Violation. Here is the relevant snapshot of the windbg output window:
(24f0.cbc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
msvcrt!memmove+0x1e5:
000007fe`fe371111 8b040a mov eax,dword ptr [rdx+rcx] ds:00000000`00000010=????????
0:001> k
Child-SP RetAddr Call Site
00000000`008ee1f8 000007fe`f5a64e71 msvcrt!memmove+0x1e5
00000000`008ee200 000007fe`f5a64da0 abocomp!PROPERTY_ENTRY::Create+0x79
00000000`008ee230 000007fe`f5a5c21b abocomp!PROPERTY_BAG::SetData+0xbc
00000000`008ee270 000007fe`f5a6088a abocomp!ABO_NODE::SetData+0xa3
00000000`008ee2a0 000007fe`f5a9456f abocomp!ABO_WRAPPER::SetData+0x1ca
00000000`008ee580 000007fe`f5ad3e54 COADMIN!CADMCOMW::SetData+0x127
00000000`008ee630 000007fe`fdfd51d0 ADMWPROX!IMSAdminBaseW_R_SetData_Thunk+0xb4
00000000`008ee6b0 000007fe`fdedf16e RPCRT4!NdrStubCall2+0xa36
00000000`008eecd0 000007fe`fdee0ccd ole32!CStdStubBuffer_Invoke+0x8b
00000000`008eed00 000007fe`fdee0c43 ole32!SyncStubInvoke+0x5d
00000000`008eed70 000007fe`fdd9a4f0 ole32!StubInvoke+0xdb
00000000`008eee20 000007fe`fdee14d6 ole32!CCtxComChnl::ContextInvoke+0x190
00000000`008eefb0 000007fe`fdee122b ole32!AppInvoke+0xc2
00000000`008ef020 000007fe`fdedfd6d ole32!ComInvokeWithLockAndIPID+0x52b
00000000`008ef1b0 000007fe`fdfa50f4 ole32!ThreadInvoke+0x30d
00000000`008ef250 000007fe`fdfa4f56 RPCRT4!DispatchToStubInCNoAvrf+0x14
00000000`008ef280 000007fe`fdfa775b RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x146
00000000`008ef3a0 000007fe`fdfa769b RPCRT4!RPC_INTERFACE::DispatchToStub+0x9b
00000000`008ef3e0 000007fe`fdfa7632 RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x5b
00000000`008ef460 000007fe`fdfa532d RPCRT4!LRPC_SCALL::DispatchRequest+0x422
00000000`008ef540 000007fe`fdfc2e7f RPCRT4!LRPC_SCALL::HandleRequest+0x20d
00000000`008ef670 000007fe`fdfc2a35 RPCRT4!LRPC_ADDRESS::ProcessIO+0x3bf
00000000`008ef7b0 00000000`7753b68b RPCRT4!LrpcIoComplete+0xa5
00000000`008ef840 00000000`7753feff ntdll!TppAlpcpExecuteCallback+0x26b
00000000`008ef8d0 00000000`76e5652d ntdll!TppWorkerThread+0x3f8
00000000`008efbd0 00000000`7754c521 kernel32!BaseThreadInitThunk+0xd
00000000`008efc00 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
0:001> g
(24f0.cbc): Access violation - code c0000005 (!!! second chance !!!)
msvcrt!memmove+0x1e5:
000007fe`fe371111 8b040a mov eax,dword ptr [rdx+rcx] ds:00000000`00000010=????????
I have absolute no idea what is going on. Do you?
Additional information
- I am running Windows 7 64 bits, IIS 7.5 with IIS6 metabase enabled
- I do not use the
System.DirectoryServices
to modify the SSLCertHash metabase property, because it is impossible - http://support.microsoft.com/kb/313624 explains it. This article contains more useful information on the subject. - The types
TemporaryComObject
,AllocHGlobal
,AdminBaseKey
ensure that the COM object, unmanaged memory and admin base key are property released/closed. - The interop assembly for the MSAdminBase COM object was obtained using a variation of the technique described here - http://www.moserware.com/2009/04/using-obscure-windows-com-apis-in-net.html. Only I did not recreate the interop code, rather the respective IDL file. Then I compiled it with MIDL to produce the respective TLB file, which I passed to TlbImp to produce the interop assembly.
The C definition of the METADATA_RECORD type is found in file mddefw.h from the SDK:
typedef struct _METADATA_RECORD
{
DWORD dwMDIdentifier;
DWORD dwMDAttributes;
DWORD dwMDUserType;
DWORD dwMDDataType;
DWORD dwMDDataLen;
unsigned char *pbMDData;
DWORD dwMDDataTag;
} METADATA_RECORD;
In the interop assembly, that I have produced, the type is declared like so:
[StructLayout(LayoutKind.Sequential, Pack=4), ComConversionLoss]
public struct METADATA_RECORD
{
public int dwMDIdentifier;
public int dwMDAttributes;
public int dwMDUserType;
public int dwMDDataType;
public int dwMDDataLen;
[ComConversionLoss]
public IntPtr pbMDData;
public int dwMDDataTag;
}
Notice the presence of the ComConversionLoss
attribute. I do not know if it matters or not, but when I created the interop assembly I got the following warning:
TlbImp : warning TI3016: The type library importer could not convert the signature for the member 'MSAdminBaseLib.METADATA_RECORD.pbMDData'. [C:\Work\IISCertObj\SimpleNCServerSecurity.csproj]
There is another post of mine (yet unanswered) which deals with this problem exactly.
Thank you very much.
EDIT
I have a feeling it has to do with the StructLayout.Pack = 4
. I am still to learn how to make TlbImp do not insert it...
EDIT2
And indeed, it is the problem. As it turns out, the output produced by TlbImp requires further tweaking. I had to disassemble it with Reflector.NET and remove the explicit Pack statements. Now everything works fine.
I have found the problem - indeed Pack = 4 did the trouble.