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

发布于 2024-08-09 05:59:49 字数 1392 浏览 7 评论 0原文

我正在执行一些旧的 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 的实际路径?

谢谢。

I am trapping for the execution of some old 16-bit applications that our internal folks should no longer be using. They are 1985 DOS apps, so trapping for them was easy... capture any process that launches under NTVDM.exe

Now, the problem is finding out which program NTVDM is actually running under the hood. Apparently there are a coupleof the 1985 programs that they SHOULD be allowed to run, so I need to see the actual EXE name that is hiding under NTVDM.

        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();
    }

When I capture the instance information, I can get the command line, but the arguments are "-f -i10" ... There is no EXE name on the command line. Is there any other method/property I should be looking at to determine the EXE name of the 16-bit application that's actually running?

UPDATE: Let me refine the question: If I can find the NTVDM process, how can I -- programatically -- know the actual path to the EXE that is being executed underneath?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泪痕残 2024-08-16 05:59:50

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

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

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

如果使用这些功能的事情没有按计划进行,您可能使用的是 Vista,并且可能需要此 StackOverflow 问题,指向 下载修补程序此处介绍

“使用
VDMEnumProcessWOW 函数
枚举 DOS 虚拟机返回
无输出或输出不正确
运行 32 位的计算机
Windows Vista 版本”

更新:虽然这看起来很有希望,但我应用了补丁,运行了多个版本的代码,包括 Microsoft 的代码,虽然它们都可以工作在 XP 上,它们在 Vista 上默默地失败(没有错误或错误的返回值)。


“有点”工作代码

更新:我尝试了以下内容(除其他外)。代码,它在 C# 中编译得很好(并且可以编写得更简单,但我不想冒编组错误的风险)。当您添加这些函数时,您可以调用 Enum16BitProcesses,它将编写 我无法在 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 的程序运行在
与基于 16 位 Windows 的会话相同
程序。我也没能得到两个
独立启动基于MS-DOS
在同一个 NTVDM 中运行的程序
会议。事实上,NTVDM 会话
正在运行的 MS-DOS 程序不显示
在 VDMEnumProcessWOW 枚举中。”

看来,要找出加载了哪些进程,您需要在 NTVDM 中编写一个钩子或编写一个监听器来监视对文件的访问。当应用程序尝试读取某个进程时DOS 文件是 NTVDM.exe,它是宾果游戏。您可能想编写一个仅附加到 NTVDM.exe 的 DLL,但现在我们有点超前了:NTVDM 的这一小旅程已经显示了“可能性”。 ”最后出现了真正的恶作剧。

还有另一种方法,但时间太短,无法创建示例。您可以在 DOS 内存段中摸索,EXE 通常会在同一段加载。但我不确定是否最终会导致相同的结果以及是否值得付出努力。

The trick is not to use VDMEnumProcessWOW (which gives the VDMs), but to use VDMEnumTasksWOW. The enumerator function that you pass to this function will be called for each 16 bit task in the specified VDM.

I haven't checked it myself, but according to the documentation, this library of CodeProject does exactly that, if you pass in the PROC16 enum value. It's C++, if you need help compiling that code and calling it from C#, let me know and I'll give you an example.

A program that uses this technique is Process Master, it comes with full source. I suggest you run it to find out whether it gives the info you need, and if so, you can apply this method to your own application (it doesn't run on Windows Vista or 7, it uses old VB5 code, apparently it's not compatible. It should run on XP).

If things with these functions do not go as planned, you may be on Vista and may need the hotfix described in this StackOverflow question, which points to downloading a hotfix, which is in turn 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"

Update: while this seems promising, I applied the patch, ran several versions of the code, including Microsoft's, and while they all work on XP, they fail silently (no error, or wrong return value) on Vista.


The "kinda" working code

Update: I experimented with (amongst others) with the following code, which compiles fine in C# (and can be written simpler, but I didn't want to run a marshal-mistake risk). When you add these functions, you can call Enum16BitProcesses, which will write the filenames of the EXE files of the 16 bit processes to the Console.

I can't run it on Vista 32 bit. But perhaps others can try and compile it, or find the error in the code. It would be nice to know whether it works on other systems:

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
    }

}

Update: Intriguing read by the renown Matt Pietrek. Mind the sentence, somewhere near the end:

"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."

Seems that, to find out what processes are loaded, you'll need to write a hook into NTVDM or write a listener that monitors access to the file. When the application that tries to read a certain DOS file is NTVDM.exe, it's bingo. You may want to write a DLL that's only attached to NTVDM.exe, but now we're getting a bit ahead of ourselves. Long story short: this little ride into NTVDM has shown "possibilities" that appeared real hoaxes in the end.

There's one other way, but time is too short to create an example. You can poke around in the DOS memory segments and the EXE is usually loaded at the same segment. But I'm unsure if that eventually will lead to the same result and whether it's worth the effort.

我ぃ本無心為│何有愛 2024-08-16 05:59:50

这对我有用:

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

  • 根据软件限制策略 ->附加规则,右键单击并选择新建哈希规则。

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

现在,

C:\>编辑
系统无法执行指定的程序。

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

This works for me:

  • Follow the instructions at Description of the Software Restriction Policies in Windows XP to open the local or domain policy editor.

  • Under Software Restriction Policies -> Additional Rules, right click and select New Hash Rule.

  • Browse to (for example) edit.com. Make sure Security Level is set to Disallowed. Click OK.

Now,

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

(I get the same results from command.com and cmd.exe -- under Win XP)

尹雨沫 2024-08-16 05:59:50

有关 VDMDBG 函数的链接,您可以 P/Invoke“VDMEnumProcessWOW()” ,然后使用 PSAPI 枚举进程内的模块

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

VDMDBG 功能均无法与
16 位 DOS 应用程序。列举一下
DOS VDM,您需要使用另一个
方法。首先,你可以使用
VDMEnumProcessWOW() 列出
所有 Win16 VDM,然后枚举所有
NTVDM.exe 的实例使用一些
其他方案(例如PSAPI)。任何
完整枚举中的 NTVDM.exe
不在 Win16 列表中的是
DOS VDM。您可以创建和终止
16 位 DOS 应用程序
创建进程()和
终止进程()。

希望有帮助...

From this link about VDMDBG functions, you may be able to P/Invoke "VDMEnumProcessWOW()", then enumerate modules within the process using PSAPI.

Note Regarding 16-bit DOS Applications:

None of the VDMDBG functions work with
16-bit DOS applications. To enumerate
DOS VDMs, you need to use another
method. First, you could use
VDMEnumProcessWOW() to make a list of
all Win16 VDMs, and then enumerate all
instances of NTVDM.exe using some
other scheme (such as PSAPI). Any
NTVDM.exe from the full enumeration
that was not in the Win16 list is a
DOS VDM. You can create and terminate
16-bit DOS applications with
CreateProcess() and
TerminateProcess().

Hope that helps...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文