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

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

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

  WqlEventQuery query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 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枚举值,这个CodeProject库就是这样做的。 它是C ++,如果你需要帮助编译代码并从C#调用它,请告诉我,我会给你一个例子。

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

如果具有这些function的东西没有按计划进行,你可能在Vista上并且可能需要此StackOverflow问题中描述的修补程序,该问题指向下载修补程序 ,该修补程序依次在此处描述 :

“使用VDMEnumProcessWOW函数枚举虚拟DOS机器的应用程序在运行32位版本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 hMod16, IntPtr hTask16, IntPtr ptrModName, IntPtr ptrFileName, 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 } } 

更新:着名的Matt Pietrek阅读。 记住句子,在接近结尾的地方:

“对于初学者来说,基于MS-DOS的程序似乎总是在单独的NTVDM会话中运行。我永远无法让基于MS-DOS的程序在与基于Windows的16位程序相同的会话中运行。我能够在同一个NTVDM会话中运行两个独立启动的基于MS-DOS的程序。事实上,运行MS-DOS程序的NTVDM会话不会出现在VDMEnumProcessWOW枚举中。“

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

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

这对我有用:

  • 按照Windows XP中软件限制策略说明中的说明打开本地或域策略编辑器。

  • 在“软件限制策略 – >其他规则”下,右键单击并选择“新建哈希规则”。

  • 浏览(例如) edit.com 。 确保“安全级别”设置为“不允许”。 单击确定。

现在,

C:\>edit
The system cannot execute the specified program.

(我从command.comcmd.exe得到了相同的结果 – 在Win XP下)

从这个关于VDMDBG函数的链接 ,您可以P / Invoke“VDMEnumProcessWOW()”,然后使用PSAPI枚举进程中的模块 。

关于16位DOS应用程序的注意事项:

VDMDBG函数都不适用于16位DOS应用程序。 要枚举DOS VDM,您需要使用另一种方法。 首先,您可以使用VDMEnumProcessWOW()来创建所有Win16 VDM的列表,然后使用其他一些方案(例如PSAPI)枚举NTVDM.exe的所有实例。 完整枚举中不在Win16列表中的任何NTVDM.exe都是DOS VDM。 您可以使用CreateProcess()和TerminateProcess()创建和终止16位DOS应用程序。

希望有帮助……