c# – 在NTVDM下运行的16位应用程序

我正在捕获执行一些我们内部人员不再使用的旧16位应用程序.它们是1985年的DOS应用程序,因此捕获它们很容易…捕获在NTVDM.exe下启动的任何进程

现在,问题是找出NTVDM实际上在哪个程序下运行.显然,1985年的程序中有几个应该被允许运行,所以我需要看到隐藏在NTVDM下的实际EXE名称.

WqlEventQuery query =
            new WqlEventQuery("__InstanceCreationEvent",new TimeSpan(0,1),"TargetInstance isa \"Win32_Process\"");

        ManagementEventWatcher watcher = new ManagementEventWatcher(query);

        watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);

        watcher.Start();


...


    static void watcher_EventArrived(object sender,EventArrivedEventArgs e)
    {
        ManagementBaSEObject instance = (ManagementBaSEObject)e.NewEvent["TargetInstance"];

        ProcessInfo PI = new ProcessInfo();
        PI.ProcessID = int.Parse(instance["ProcessID"].ToString());
        PI.ProcessName = instance["Name"].ToString();
        PI.Processpath = instance["ExecutablePath"].ToString();

        // Here's the part I need...
        PI.ActualEXE = ???;

        // ... do the magic on the PI class ...

        instance.dispose();
    }

当我捕获实例信息时,我可以获取命令行,但参数是“-f -i10”…命令行上没有EXE名称.是否有任何其他方法/属性我应该查看以确定实际运行的16位应用程序的EXE名称

更新:让我改进一下这个问题:如果我能找到NTVDM进程,我怎样才能 – 以编程方式 – 知道正在执行的EXE的实际路径?

谢谢.

解决方法

诀窍不是使用 VDMEnumProcessWOW(它提供VDM),而是使用 VDMEnumTasksWOW.将为指定VDM中的每个16位任务调用传递给此函数的枚举器函数.

我自己没有检查过,但是根据文档,如果传入PROC16枚举值,这个library of CodeProject就是这样做的.它是C,如果你需要帮助编译代码并从C#调用它,请告诉我,我会给你一个例子.

使用这种技术的程序是Process Master,它带有完整的源代码.我建议你运行它以确定它是否提供了你需要的信息,如果是这样,你可以将这个方法应用到你自己的应用程序(它不能在Windows Vista或7上运行,它使用旧的VB5代码,显然它不是兼容.它应该在XP上运行).

如果具有这些功能的东西没有按计划运行,您可能在Vista上并且可能需要此StackOverflow question中描述的修补程序,该修补程序指向downloading a hotfix,而described here依次为described here

“An application that uses the
VDMEnumProcessWOW function to
enumerate virtual DOS machines returns
no output or incorrect output on a
computer that is running a 32-bit
version of Windows Vista”

更新:虽然这似乎很有希望,我应用了补丁,运行了几个版本的代码,包括微软的代码,虽然它们都在XP上工作,但它们在Vista上无声地失败(没有错误错误的返回值).

“有点”的工作代码

更新:我使用以下代码进行了实验(其中包括),这些代码在C#中编译得很好(并且可以编写得更简单,但我不想运行编组错误风险).添加这些函数时,可以调用Enum16BitProcesses,它将16位进程的EXE文件文件名写入控制台.

我无法在Vista 32位上运行它.但也许其他人可以尝试编译它,或者在代码中找到错误.很高兴知道它是否适用于其他系统:

public class YourEnumerateClass
{
    public static void Enum16BitProcesses()
    {
        // create a delegate for the callback function
        ProcesstasksExDelegate procTasksDlgt = 
             new ProcesstasksExDelegate(YourEnumerateClass.ProcesstasksEx);

        // this part is the easy way of getting NTVDM procs
        foreach (var ntvdm in Process.GetProcessesByName("ntvdm"))
        {
            Console.WriteLine("ntvdm id = {0}",ntvdm.Id);
            int apiRet = VDMEnumTaskWOWEx(ntvdm.Id,procTasksDlgt,IntPtr.Zero);
            Console.WriteLine("EnumTaskWOW returns {0}",apiRet);
        }

    }

    // declaration of API function callback
    public delegate bool ProcesstasksExDelegate(
        int ThreadId,IntPtr hMod16,IntPtr hTask16,IntPtr ptrModName,IntPtr ptrFileName,IntPtr UserDefined
        );

    // the actual function that fails on Vista so far
    [DllImport("VdmDbg.dll",SetLastError = false,CharSet = CharSet.Auto)]
    public static extern int VDMEnumTaskWOWEx(
        int processId,ProcesstasksExDelegate TaskEnumProc,IntPtr lparam);

    // the actual callback function,on Vista never gets called
    public static bool ProcesstasksEx(
        int ThreadId,IntPtr UserDefined
        )
    {
        // using PtrToStringAnsi,based on Matt's comment,if it fails,try PtrToStringAuto
        string filename = Marshal.PtrToStringAnsi(ptrFileName);
        Console.WriteLine("Filename of WOW16 process: {0}",filename);
        return false;       // false continues enumeration
    }

}

更新:Intriguing read由着名的Matt Pietrek.记住句子,在接近结尾的地方:

“For starters,MS-DOS-based programs
seem to always run in separate NTVDM
sessions. I was never able to get an
MS-DOS-based program to run in the
same session as a 16-bit Windows-based
program. nor was I able to get two
independently started MS-DOS-based
programs to run in the same NTVDM
session. In fact,NTVDM sessions
running MS-DOS programs don’t show up
in VDMEnumProcessWOW enumerations.”

看来,为了找出加载了哪些进程,您需要在NTVDM中编写一个钩子,或者编写一个监视器来监视对该文件的访问.当试图读取某个DOS文件的应用程序是NTVDM.exe时,它就是宾果游戏.您可能想编写一个仅附加到NTVDM.exe的DLL,但现在我们已经领先于自己了.长话短说:这次进入NTVDM的小车已经显示出“可能性”,最终出现了真正的恶作剧.

还有另外一种方法,但时间太短,无法创造一个例子.您可以在DOS内存段中查找,并且EXE通常在同一段中加载.但我不确定这最终会导致相同的结果,是否值得努力.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...