现在,问题是找出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的实际路径?
谢谢.
解决方法
我自己没有检查过,但是根据文档,如果传入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通常在同一段中加载.但我不确定这最终会导致相同的结果,是否值得努力.