The MASM Forum

Miscellaneous => The Orphanage => Topic started by: pcMike on September 10, 2015, 03:03:20 PM

Title: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 10, 2015, 03:03:20 PM
Hi Hutch,

Back in 2007 I let you know about an issue with the NTVDM.INC and MTVDM.LIB in MASM 10 here:
http://www.masmforum.com/board/index.php?topic=10004.0

[Edit]At the time I thought the problem was due to an incorrect MGetVdmPointer PROTO and Library.

Mine:   MGetVdmPointer PROTO :DWORD,:DWORD,:CHAR
Yours:     MGetVdmPointer PROTO :DWORD,:DWORD,:DWORD

Today I finally got around to upgrading to MASM32 11, and I see this problem was never fixed.

I confirmed that both the NTVDM.INC and NTVDM.LIB included with v11 have the same issue. I am attaching the working NTVDM.LIB which I have been using for the past 15 years. When I replaced your v11 .LIB file with mine, and edited your v11 NTVDM.INC to correct the MgetVdmPointer PROTO, my program works fine again.

Also, I noticed that when I attempted to install version 11 on Windows 10 32-bit, I got several error messages during the install, such as:
The ordinal 201 could not be located in the dynamic link library: C:\Windows\AppPatch\AcGenral.DLL
The ordinal 201 could not be located in the dynamic link library: C:\Windows\AppPatch\AcLayers.DLL
There were a few more of these, but I did not write them down.

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: TouEnMasm on September 10, 2015, 04:23:15 PM
Hello,
a char is a BYTE.
in 32 bits PROTO :BYTE must be interpreted as "push Byte".
Push byte don't exist and masm re-interpret this to push a dword.
The error is elsewhere,made a listing of your source code and you will see what happen.
in your lib
     3FE2 _MGetVdmPointer@12                ;12 =3 * sizeof dword
     3FE2 __imp__MGetVdmPointer@12
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: zedd151 on September 10, 2015, 05:55:05 PM
hutch:
Quote
...MASM does not have bugs....
(talking about another subject)

from here:
http://masm32.com/board/index.php?topic=3958.msg41686#msg41686

 :P
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: jj2007 on September 10, 2015, 07:23:00 PM
Hi Mike,

Welcome back :icon14:

This is so exotic that it probably just got forgotten. I would have needed that function ages ago when I still worked with 16-bit GfaBasic...

Googling reveals few hits for MGetVdmPointer. One is apparently a very old Microsoft source (here (http://yabause-rr.googlecode.com/svn/trunk/src/windows/ddk/vddsvc.h)), with this definition:

PBYTE
MGetVdmPointer(
 ULONG    Address,
 ULONG    Size,
 UCHAR   ProtectedMode
);

As ToutEnMasm wrote above, this may be interpreted as push byte - a no-no in Win32. Infact, the assemblers I have tested do NOT push a byte - they push a dword. This is not a problem when you use, in the snippet below,
Code: [Select]
invoke pb, 1, 2, 3
The 3 gets pushed as the DWORD 00000003h

But look at the second invoke:
  mov eax, 12345678h
  invoke pb, 1, 2, al

According to the proc definition, 00000078h should be pushed, e.g. using
Code: [Select]
movzx eax, al
push eax

But all assemblers tested (ML 6.14, 6.15 and 10.0, JWasm) simply push eax - so you have 12345678h on the stack... now find out what exactly implies for your code ;-)


Code: [Select]
include \masm32\include\masm32rt.inc
.code
pb proc arg1, arg2, arg3:UCHAR
  ret
pb endp

start:
  invoke pb, 1, 2, 3
  mov eax, 12345678h
  invoke pb, 1, 2, al
  exit
end start
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 10, 2015, 08:47:46 PM
Hi ToutEnMasm and JJ,

You are correct, the problem was not the difference in NTVDM.INC. I changed the CHAR back to a DWORD, and the result was the same either way, so it has to be something different in NTVDM.LIB which is causing the issue. Now that I took a closer look, it don't think it's even related to the mGetVdmPointer routine at all, as the failure occurs before hand.

I don't remember how I acquired my original working NTVDM.LIB, but just now I tried using inc2l.exe to recreate the NTVDM.LIB (under Windows 10), and it fails the same in the same way as the one included with MASM32 v11, and it is also the same file size.

I'll explain a little about the issue itself.
I have a DOS application that uses the NTVDM "BOP" functions to interface with a Win32 Virtual Device Driver .DLL file. Details on how this is done can be found here:
http://www.ragestorm.net/tutorial?id=27

When I use the version of NTVDM.LIB that comes with MASM32 10 or 11 to build my .DLL file, the BOP function that registers the .DLL file fails with the result AX=1, which means "Could not find .DLL file", even though it is in the \windows\system32\ directory as it should be. But when I build the same .DLL using my older NTVDM.LIB, it works fine.

Here is a snippit of the DOS stub which loads the DLL:

Code: [Select]
;  The following BOP Macros were taken from ISVBOP.H
;  They allow a DOS app to interface with a Win32 DLL.
;  See ISVBOP.H and isvbop.inc for more information.

BOP_3RDPARTY    EQU     58h
BOP_UNSIMULATE  EQU     FEh
.RegisterModule macro   
db      0C4h, 0C4h, BOP_3RDPARTY, 0
endm
.UnRegisterModule macro
db      0C4h, 0C4h, BOP_3RDPARTY, 1
endm
.DispatchCall   macro   
db      0C4h, 0C4h, BOP_3RDPARTY, 2
endm

; ** RegisterModule - This Bop call is made from the 16 bit module
; *                   to register a third party DLL with the bop
; *                   manager. This call returns a handle to the
; *                   16bit caller which is to be used later to
; *                   dispatch a call to the DLL.
; *
; *  INPUT:
; *      Client DS:SI - asciiz string of DLL name.
; *      Client ES:DI - asciiz string of Init Routine in the DLL. (Optional)
; *      Client DS:BX - asciiz string to Dispatch routine in the DLL.
; *
; *  OUTPUT:
; *      SUCCESS:
; *          Client Carry Clear
; *          Client AX = Handle (non Zero)
; *      FAILURE:
; *          Client Carry Set
; *          Client AX = Error Code
; *                 AX = 1 - DLL not found
; *                 AX = 2 - Dispatch routine not found.
; *                 AX = 3 - Init Routine Not Found
; *                 AX = 4 - Insufficient Memory
; *
; *  NOTES:
; *      RegisterModule results in loading the DLL (specified in DS:bp).
; *      Its Init routine (specified in ES:DI) is called. Its Dispatch
; *      routine (specified in DS:BX) is stored away and all the calls
; *      made from DispatchCall are dispacthed to this routine.
; *      If ES and DI both are null than the caller did'nt supply the init
; *      routine.
;
mov     si,offset dllname_text
mov     bx,offset dispatchname_text
xor     ax,ax
xor     di,di
mov     es,di
.RegisterModule                 ; BOP Register Modual
jnc     VDD_loaded              ; CF=0 indicates success
cmp     ax,1
jne     VDD_chk1
mov    dx,offset msg_file_not_found     ; 'Can't find .dll'
jmp     short show_error

In case it helps, here is a exports dump of my original NTVDM.LIB
Code: [Select]
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>dumpbin /exports \users\mike\ntvdm.lib
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file \users\mike\ntvdm.lib

File Type: LIBRARY

     Exports

       ordinal    name

                  _BlockWOWIdle@4
                  _CurrentMonitorTeb
                  _DBGNotifyDebugged@4
                  _DBGNotifyNewTask@8
                  _DBGNotifyRemoteThreadAddress@8
                  _DispatchInterrupts@0
                  _ExpLdt
                  _ExpVdmTib
                  _FlatAddress
                  _GetDOSAppName@4
                  _GetWOWShortCutInfo@8
                  _IsCdRomFile@4
                  _MGetVdmPointer@12
                  _RegisterWOWIdle@0
                  _ResumeTimerThread@0
                  _SelectorLimit
                  _Sim32pGetVDMPointer@8
                  _SoftPcEoi@8
                  _SuspendTimerThread@0
                  _VDDAllocMem@12
                  _VDDAllocateDosHandle@12
                  _VDDAssociateNtHandle@12
                  _VDDDeInstallIOHook@12
                  _VDDDeInstallMemoryHook@12
                  _VDDDeInstallUserHook@4
                  _VDDExcludeMem@12
                  _VDDFreeMem@12
                  _VDDIncludeMem@12
                  _VDDInstallIOHook@16
                  _VDDInstallMemoryHook@16
                  _VDDInstallUserHook@20
                  _VDDQueryDMA@12
                  _VDDReleaseDosHandle@8
                  _VDDReleaseIrqLine@8
                  _VDDRequestDMA@16
                  _VDDReserveIrqLine@8
                  _VDDRetrieveNtHandle@16
                  _VDDSetDMA@16
                  _VDDSimulate16@0
                  _VDDTerminateVDM@0
                  _VdmDbgAttach@0
                  _VdmGetParametersInfoError@0
                  _VdmMapFlat@12
                  _VdmParametersInfo@12
                  _VdmTraceEvent@12
                  _WOWSysErrorBox@20
                  _WaitIfIdle@0
                  _call_ica_hw_interrupt@12
                  _cmdCheckTemp@4
                  _cmdCheckTempInit@0
                  _cpu_createthread@4
                  _demClientErrorEx@12
                  _demFileDelete@4
                  _demFileFindFirst@12
                  _demFileFindNext@4
                  _demGetCurrentDirectoryLCDS@8
                  _demGetFileTimeByHandle_WOW@4
                  _demIsShortPathName@8
                  _demLFNCleanup@0
                  _demLFNGetCurrentDirectory@8
                  _demSetCurrentDirectoryGetDrive@8
                  _demSetCurrentDirectoryLCDS@8
                  _demWOWLFNAllocateSearchHandle@4
                  _demWOWLFNCloseSearchHandle@4
                  _demWOWLFNEntry@4
                  _demWOWLFNGetSearchHandle@4
                  _demWOWLFNInit@4
                  _fSeparateWow
                  _getAF@0
                  _getAH@0
                  _getAL@0
                  _getAX@0
                  _getBH@0
                  _getBL@0
                  _getBP@0
                  _getBX@0
                  _getCF@0
                  _getCH@0
                  _getCL@0
                  _getCS@0
                  _getCX@0
                  _getDF@0
                  _getDH@0
                  _getDI@0
                  _getDL@0
                  _getDS@0
                  _getDX@0
                  _getEAX@0
                  _getEBP@0
                  _getEBX@0
                  _getECX@0
                  _getEDI@0
                  _getEDX@0
                  _getEFLAGS@0
                  _getEIP@0
                  _getES@0
                  _getESI@0
                  _getESP@0
                  _getFS@0
                  _getGS@0
                  _getIF@0
                  _getIP@0
                  _getIntelRegistersPointer@0
                  _getMSW@0
                  _getOF@0
                  _getPF@0
                  _getSF@0
                  _getSI@0
                  _getSP@0
                  _getSS@0
                  _getZF@0
                  _host_CreateThread@24
                  _host_ExitThread@4
                  _host_com_close@4
                  _host_direct_access_error@4
                  _host_simulate@0
                  _pDeviceChain
                  _setAF@4
                  _setAH@4
                  _setAL@4
                  _setAX@4
                  _setBH@4
                  _setBL@4
                  _setBP@4
                  _setBX@4
                  _setCF@4
                  _setCH@4
                  _setCL@4
                  _setCS@4
                  _setCX@4
                  _setDF@4
                  _setDH@4
                  _setDI@4
                  _setDL@4
                  _setDS@4
                  _setDX@4
                  _setEAX@4
                  _setEBP@4
                  _setEBX@4
                  _setECX@4
                  _setEDI@4
                  _setEDX@4
                  _setEFLAGS@4
                  _setEIP@4
                  _setES@4
                  _setESI@4
                  _setESP@4
                  _setFS@4
                  _setGS@4
                  _setIF@4
                  _setIP@4
                  _setMSW@4
                  _setOF@4
                  _setPF@4
                  _setSF@4
                  _setSI@4
                  _setSP@4
                  _setSS@4
                  _setZF@4

  Summary

          A8 .debug$S
          14 .idata$2
          14 .idata$3
           4 .idata$4
           4 .idata$5
           A .idata$6

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: jj2007 on September 11, 2015, 04:30:46 AM
BOP is voodoo, nobody here is old enough for that 8)

(but the reactos guys have something here (http://code.reactos.org/browse/reactos/branches/ntvdm/subsystems/ntvdm/bop.c)...)
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: hutch-- on September 11, 2015, 08:11:21 AM
I would be inclined to use LoadLibrary() and GetProcAddress() to test the function calls you are after.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 11, 2015, 09:32:13 AM
I would be inclined to use LoadLibrary() and GetProcAddress() to test the function calls you are after.

But the issue is occurring before any (known) Win32 function calls are made. It's something at the BOP level which is failing to accept the DLL as being valid. I can't call LoadLibrary() from the DOS stub.

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: nidud on September 11, 2015, 09:56:05 AM
deleted
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: hutch-- on September 11, 2015, 12:16:54 PM
Normally in Win32 a DOS stub serves the purpose of advising a DOS user that the executable is for a later OS version and as 16 bit real mode code, it would not have access to a 32 bit PE DLL. I would have a look at the guts of the library you have that works to see what format it is in but I seriously doubt its a Microsoft /COFF format library, it sounds like a DOS style driver.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 11, 2015, 02:46:31 PM
Hutch,

In this case the DOS "stub" uses the BOP instructions to register a Win32 DLL and then call it's functions and later on unregister the DLL.
In my case the stub is a DOS TSR that uses interrupts to communicate with the Win32 DLL. I attached the old working version of the NTVDM.LIB library in my initial post.

This article describes the DOS BOP instruction set:
http://www.ragestorm.net/tutorial?id=27

Regards.  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: hutch-- on September 11, 2015, 03:17:12 PM
Just having a quick read of the link you provided, you would be restricted to XP or earlier and relying on an undocumented capacity to interface 16 bit DOS with Win32. Now again if you need to do stuff like this and you have a working library, I would try and disassemble the library to find out what format it is written in. You may them be able to reproduce a library that performs tasks of that type with whatever functionality you have in mind. This is not a bug in the include and lib file, it is an undocumented hack to interface 16 bit code with Win32 code.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: TouEnMasm on September 11, 2015, 04:28:04 PM
The MGetVdmPointer function had a limited usage,i386.
Here an extract of VDDSVC.sdk.
Have you an i386 computer ????????
seems you have no other choice than use another function.
Quote
IFDEF i386
Sim32FlushVDMPointer   equ   < r( addess, size, buffer, mode)>
MGetVdmPointer PROTO :DWORD ,:DWORD ,:DWORD
ELSE
Sim32GetVDMPointer PROTO :DWORD ,:DWORD ,:DWORD
Sim32FlushVDMPointer PROTO :DWORD ,:DWORD ,:XMASM ,:DWORD
ENDIF
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 11, 2015, 10:45:15 PM
Hutch,  This is a program which I originally wrote in 2001, and it works perfectly under 32-bit Windows 10, 8.1, 8, 7, XP, 2000 as well as every 32-bit version of Windows Server (even Core).

It only fails if I substitute my old NTVDM.LIB with the one you included in MASM32 v10 or v11. In previous versions of MASM32, you did not include the NTVDM.LIB.

ToutEnMasm: It works on my Intel Xeon, I7, I5, I3, Core 2 duo, P4, as well as AMD CPU's. It works on both physical machines, and virtual environments including VMware and HyperV. The DLL uses the following settings and includes:
    .686
    .model flat, stdcall
    option casemap :none
    include \masm32\include\windows.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\ntvdm.inc
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\ntvdm.lib

The DLL uses pipes to redirect data to an EXE Winsock Communication engine, effectively allowing DOS applications such as BBS software to be accessed via telnet.  (For some reason, I could not use Winsock directly from the DLL itself).

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 11, 2015, 10:56:07 PM
I should mention that BOP functions are not undocumented Voodoo. They are documented in older versions of the Microsoft DDK.
https://archive.org/stream/WinNT3.1DDKDoc/Win32SubSysGuide#page/n245/

There is also more information here:
http://sta.c64.org/blog/dosvddaccess.html

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: hutch-- on September 12, 2015, 09:16:05 AM
Mike,

I still give you the same advice, if you have a working library then disassemble it and find out what its format is. ALL of the libraries in MASM32 are import libraries that are purely Win32, not hybrid left overs from much earlier operating system versions. Now if you can accurately determine what the format is, you may need to get some of the tools from the era when this stuff was in use, probably from an antique DDK as Microsoft did some unusual stuff long ago. Internal code in the old VXD device drivers for Win9x had 16 bit code in them.

What you are after is not conventional Win32 PE format code, its hybrid 16/32 bit code from the era when Win9x was still being developed.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 12, 2015, 01:24:15 PM
Thanks Hutch,

Assuming that I were to find out what format the old NTVDM.LIB is in, what would be our next step? The old .LIB file works fine for me, and if you don't feel it's worthwhile adding BOP support in your NTVDM.LIB I understand. On the other hand if you want to support it, I would be glad to try to help as I feel it would be a worthwhile feature for the MASM32 project.

I googled for "decompile static library" and l found that IDA will disassemble a .LIB file, but this is a commercial product which I don't own.

I tried using DUMPBIN /disasm ntvdm.lib, but it only produced the following summery:

Code: [Select]
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file ntvdm.lib

File Type: LIBRARY

  Summary

          A8 .debug$S
          14 .idata$2
          14 .idata$3
           4 .idata$4
           4 .idata$5
           A .idata$6

Next I tried "DUMPBIN /all NTVDM.LIB" which produced over 4300 lines of output which I attached to a text file here.
I don't  know what to look for to determine the file format however. Can anyone suggest something?

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: MichaelW on September 12, 2015, 02:09:42 PM
Mike,

The MASM32 ntdll.lib is apparently for ntdll.dll, and judging from the dump of your library, it's for ntdll.exe, which as far as I know is correct. This has come up before, see  here (http://masm32.com/board/index.php?topic=1086.0) and  here (http://masm32.com/board/index.php?topic=1086.msg10198#msg10198), and further down where Vortex posted an import library.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 12, 2015, 04:45:41 PM
Hi Michael,

That is very interesting. The dump shows that my working NTVDM.LIB is for NTVDM.EXE as you said, but I don't think there is such a thing as an NTVDM.DLL file... at least there is not in Windows 10 or Windows 7.  I saw in one of those threads you mentioned that NTVDM.DLL does not exist in XP either.  There is an NTVDMD.DLL, but I would think that would use a different set of functions.

I am surprised that the NTVDM.INC included with MASM32 would reference the function names found in the EXE version of NTVDM.LIB. Assuming that there was an NTVDM.DLL in some version of Windows, would it use the same function names as the .EXE?

If in fact there is an NTVDM.DLL in some versions of Windows, could it be possible to combine both the DLL and EXE libraries into a single .LIB file?

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: MichaelW on September 12, 2015, 04:56:45 PM
There was no NTVDM.DLL included in Windows 2000, so I suspect that there never was such a DLL. And there is no NTVDM.* included in my Windows 8.1-64, and I suspect not in any 64-bit version of Windows because there is no built-in support for 16-bit code.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 13, 2015, 12:37:05 AM
I could not find NTVDM.DLL in any versions of Windows (2000 and later) either. As I recall, the NTVDM.LIB and .INC were not added to MASM32 until version 10, so its very odd as the full dump confirms that it is from NTVDM.DLL. There are dozens of "Archive member name at 38D6: ntvdm.dll/", as well as this:

RAW DATA #2
  00000000: 6E 74 76 64 6D 2E 64 6C 6C 00                    ntvdm.dll.

So I compared the output of "dumpbin /exports ntvdm.lib" and the two versions are nearly identical, except for the following:

The 1999 NTVDM.LIB has this export which does not exist in the MASM32v11 version:
_ExpVdmTib


The MASM32 version has the following exports which do not exist in the 1999 version:
_Dos_Flag_Addr
_DpmiSetIncrementalAlloc@4
_demGetPhysicalDriveType@4

They both have a different count for the following export:

1999 version:                 MASM32 v11 version:
_cpu_createthread@4      _cpu_createthread@8

I suspect the 1999 version was created from a Windows 2000 NTVDM, so it's logical that a later version of Windows may have added the 3 additional functions. I suspect that the "_ExpVdmTib" which is missing from the MASM32 version is a likely cause of the issue.

I have attached both versions of the exports dump here.

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10 SOLVED!
Post by: pcMike on September 13, 2015, 03:33:56 AM
Michael and Hutch,

It turns out that Nidud solved the bug in the link that Michael provided:
http://masm32.com/board/index.php?topic=1086.0

Nidud wrote a program that patches the MASM32 NTVDM.LIB and changes every instance of "NTVDM.EXE" to "NTVDM.DLL" as it should be, and this allows a DOS BOP command to successfully register a Win32 Virtual Device Driver DLL that was compiled using this Library.

Hutch, please confirm that you read this, and it would be great if you could apply the fix in MASM32 version 12. :-)

Michael, thanks for pointing me to the solution. I originally tried the versions that Vortex posted in the same thread, but neither one of those were BOP compatible.

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: Vortex on September 13, 2015, 05:53:09 AM
Hi pcMike,

There is no such a thing like BOP compatible import libraries. You can check the Microsoft Portable Executable and Common Object File Format Specification.
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: pcMike on September 13, 2015, 08:29:50 AM
Hi Vortex,

Yes, the only reason that the MASM32 version of NTVDM.LIB would fail to build a DLL which is compatible with a DOS BOP "register VDD" command, was because the MASM32 version incorrectly references a non-existent NTVDM.DLL instead of NTVDM.EXE as it should.  If you manually hex edit it to reference the .EXE instead, then it works perfectly
(or use the patch program mtvdmp.asm that Nidud wrote).

Regards,  Mike
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: MichaelW on September 13, 2015, 11:57:45 PM
Interesting, my Windows 7-64 system has in system32 the file ntvdm64.dll, with the description "16-bit Emulation on NT64".
Title: Re: Bug in NTVDM.INC/LIB in MASM 11 and 10
Post by: dedndave on September 14, 2015, 12:46:33 AM
i don't think it's impossible
i think they just didn't want that many layers of virtualization in the registry