从编译到 AnyCPU 的 .NET 应用程序通过 IMSAdminBase 传递字节数组时,inetinfo.exe 内部出现访问冲突
请考虑以下 .NET 代码:
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();
}
该代码尝试从 .NET 设置 SSLCertHash IIS6 元数据库属性。
如果 .NET 应用程序是针对 x86 编译的,那么它运行得绝对正常,这意味着在相应的 .csproj 文件中可以找到以下行:
<PlatformTarget>x86</PlatformTarget>
但是,当我省略此行并针对 AnyCPU 进行编译时,龙就来了。也就是说,发生的情况是 inetinfo.exe 因访问冲突而崩溃。这是windbg输出窗口的相关快照:
(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=????????
我完全不知道发生了什么。你?
其他信息
- 我运行的是 Windows 7 64 位、启用了 IIS6 元数据库的 IIS 7.5
- 我不使用 System.DirectoryServices 来修改 SSLCertHash 元数据库属性,因为这是不可能的 - http://support.microsoft.com/kb/313624 对此进行了解释。 本文包含更多有用的信息主题。
TemporaryComObject
、AllocHGlobal
、AdminBaseKey
类型确保 COM 对象、非托管内存和管理基本密钥的属性被释放/关闭。- MSAdminBase COM 对象的互操作程序集是使用此处描述的技术的变体获得的 - http://www.moserware.com/2009/04/using-obscure-windows-com-apis-in-net.html。只是我没有重新创建互操作代码,而是重新创建相应的 IDL 文件。然后我使用 MIDL 对其进行编译以生成相应的 TLB 文件,并将其传递给 TlbImp 以生成互操作程序集。
METADATA_RECORD 类型的 C 定义可在 SDK 的 mddefw.h 文件中找到:
typedef struct _METADATA_RECORD
{
DWORD dwMDIdentifier;
DWORD dwMDAttributes;
DWORD dwMDUserType;
DWORD dwMDDataType;
DWORD dwMDDataLen;
unsigned char *pbMDData;
DWORD dwMDDataTag;
} METADATA_RECORD;
在我生成的互操作程序集中,该类型的声明如下:
[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;
}
请注意 ComConversionLoss
属性的存在。我不知道这是否重要,但是当我创建互操作程序集时,我收到以下警告:
TlbImp : warning TI3016: The type library importer could not convert the signature for the member 'MSAdminBaseLib.METADATA_RECORD.pbMDData'. [C:\Work\IISCertObj\SimpleNCServerSecurity.csproj]
有 我的另一篇文章(尚未得到答复)准确地处理了这个问题。
非常感谢。
编辑
我有一种感觉,它与StructLayout.Pack = 4
有关。我仍在学习如何使 TlbImp 不插入它...
EDIT2
事实上,这就是问题所在。事实证明,TlbImp 生成的输出需要进一步调整。我必须使用 Reflector.NET 对其进行反汇编并删除显式的 Pack 语句。现在一切正常。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我发现了问题 - 确实 Pack = 4 造成了麻烦。
I have found the problem - indeed Pack = 4 did the trouble.