我正在执行一些旧的 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 位任务调用您传递给此函数的枚举器函数。

我自己没有检查过,但根据文档,这个 CodeProject 库 如果您传入 PROC16 枚举值,则确实会执行此操作。它是 C++,如果您需要编译该代码并从 C# 调用它的帮助,请告诉我,我会给您一个示例。

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

如果这些功能的情况没有按计划进行,您可能使用的是 Vista,并且可能需要此中描述的修补程序 StackOverflow问题, ,这指向 下载修补程序, ,依次是 此处描述:

“使用VDMenumProcesswow函数枚举虚拟DOS机器的应用程序在运行32位版本的Windows Vista的计算机上没有输出或不正确的输出”。

更新: 虽然这看起来很有希望,但我应用了补丁,运行了多个版本的代码,包括 Microsoft 的代码,虽然它们都可以在 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位程序的同一会话中运行。我也无法获得两个独立启动的基于MS-DOS的程序来在同一NTVDM会话中运行。实际上,运行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 /调用“VDMEnumProcessWOW ()”,然后使用PSAPI过程中枚举模块

  

注意对于16位DOS应用程序:

     

的VDMDBG功能无一起工作   16位DOS应用程序。枚举   DOS的VDM,您需要使用另一个   方法。首先,你可以使用   VDMEnumProcessWOW()进行列表   所有的Win16的VDM,然后枚举所有   使用一些NTVDM.EXE的情况下,   其它方案(诸如PSAPI)。任何   NTVDM.EXE从完整枚举   这不是在Win16的列表是   DOS VDM。您可以创建和终止   16位DOS应用程序   的CreateProcess()和   了TerminateProcess()。

希望帮助...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top