我正在捕获执行一些我们内部人员不再使用的旧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();
}
Run Code Online (Sandbox Code Playgroud)
当我捕获实例信息时,我可以获取命令行,但参数是"-f -i10"...命令行上没有EXE名称.是否有任何其他方法/属性我应该查看以确定实际运行的16位应用程序的EXE名称?
更新:让我改进一下这个问题:如果我能找到NTVDM进程,我怎样才能 - 以编程方式 - 知道正在执行的EXE的实际路径?
谢谢.
诀窍不是使用VDMEnumProcessWOW(它提供VDM),而是使用VDMEnumTasksWOW.将为指定VDM中的每个16位任务调用传递给此函数的枚举器函数.
我自己没有检查过,但根据文档,如果传入PROC16枚举值,这个CodeProject库就是这样做的.这是C++,如果你需要帮助编译代码并从C#调用它,请告诉我,我会给你一个例子.
使用这种技术的程序是Process Master,它带有完整的源代码.我建议你运行它以确定它是否提供了你需要的信息,如果是这样,你可以将这个方法应用到你自己的应用程序(它不能在Windows Vista或7上运行,它使用旧的VB5代码,显然它不是兼容.它应该在XP上运行).
如果具有这些功能的东西没有按计划进行,您可能在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
}
}
Run Code Online (Sandbox Code Playgroud)
更新: 有趣的阅读由著名马特·皮特里克.记住句子,在接近结尾的地方:
"对于初学者来说,基于MS-DOS的程序似乎总是在单独的NTVDM会话中运行.我永远无法让基于MS-DOS的程序在与基于Windows的16位程序相同的会话中运行.我能够在同一个NTVDM会话中运行两个独立启动的基于MS-DOS的程序.实际上,运行MS-DOS程序的NTVDM会话不会出现在VDMEnumProcessWOW枚举中."
看来,为了找出加载了哪些进程,您需要在NTVDM中编写一个钩子,或者编写一个监视器来监视对该文件的访问.当试图读取某个DOS文件的应用程序是NTVDM.exe时,它就是宾果游戏.您可能想编写一个仅附加到NTVDM.exe的DLL,但现在我们已经领先于自己了.长话短说:这次进入NTVDM的小车已经显示出"可能性",最终出现了真正的恶作剧.
还有另外一种方法,但时间太短,无法创造一个例子.您可以在DOS内存段中查找,并且EXE通常在同一段中加载.但我不确定这最终会导致相同的结果,是否值得努力.
| 归档时间: |
|
| 查看次数: |
4387 次 |
| 最近记录: |