为什么没有捕获来自模拟代码的异常

本文关键字:模拟 代码 异常 为什么 | 更新日期: 2023-09-27 18:03:57

我的c#代码使用模拟,通过p/Invoke调用Win32函数

internal class Win32Native
{
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern int ImpersonateLoggedOnUser(IntPtr token);
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern int RevertToSelf();
}
try {
    var token = obtainTokenFromLogonUser();
    Win32Native.ImpersonateLoggedOnUser( token );
    throw new Exception(); // this is for simulation
    Win32Native.RevertToSelf()
} catch( Exception e ) {
    LogException( e );
    throw;
}

我还安装了AppDomain.CurrentDomain.UnhandledException处理程序,也记录所有未处理的异常。

我确信记录异常的代码在有或没有模拟的情况下都能很好地工作。

现在的问题是,在上面的代码中,看起来catch没有输入,UnhandledException也没有调用。异常的唯一跟踪是事件查看器中的一个条目。

如果我像这样添加finally:

try {
    var token = obtainTokenFromLogonUser();
    Win32Native.ImpersonateLoggedOnUser( token );
    try {
       throw new Exception(); // this is for simulation
    } finally {
        Win32Native.RevertToSelf()
    }
} catch( Exception e ) {
    LogException( e );
    throw;
}

catchUnhandledException处理程序都记录了异常。

发生了什么?被模拟的线程是否阻止了通常的异常处理?

为什么没有捕获来自模拟代码的异常

没有看到LogException的代码,我不能确定,但它可能是,无论你在那里做的是在冒充/loggedon用户的上下文中这样做,并且该用户没有用户权限做任何事情,这是你正在做的,例如写一个文件等,然后代码崩溃在那一点。事实上,你的代码只有在你"回复到自我"之后才能工作,这似乎证明了这一点。

所以我想说的是,你的异常实际上是被catch捕获的机会,但是LogException失败是因为它试图在一个不正确的用户的上下文中工作。

为了测试这一点,在您的LogException中,在尝试任何日志记录之前,尝试将当前上下文强制为"Self",并查看第一个代码片段现在是否开始工作。

问题出在日志代码上。在某些时候,我们添加了获取当前进程启动时间(Process.StartTime)的代码,当从模拟线程调用时,该代码会产生Access denied

Access is denied
System.ComponentModel.Win32Exception
at System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited)
at System.Diagnostics.Process.GetProcessTimes()
at System.Diagnostics.Process.get_StartTime()
//our logging code here

日志代码也称为System.Diagnostics.Trace.WriteLine() 调用Process.StartTime代码并通过"跟踪监听器"写入成功,仅通过后一种代码写入失败。

所以在有或没有模拟的情况下捕捉异常是没有区别的。甚至可以安装异常过滤器,以便在模拟代码的安全上下文中调用它,这可能导致特权提升。