In Windows 3.1 WinAPI How To Lock A File? - winapi

I was trying to run Visual Basic 4 (16-bit) in Windows 3.1 running within DosBox. However it failed to launch with error:
SHARE.exe must be installed in order to run Visual Basic
Some old MS-DOS applications just check for existence of the EXE and it's presence in autoexec.bat, but in this case the EXE exists, but the error still occurs.
Running on Windows 7 32-bit and using a debugger attached to NTVDM.exe I found the following process is used:
A Temp file is created with GetTempFilename
Call to LockFile API
Call to UnlockFile API
When I set a breakpoint at return of LockFile API and faked a faliure (returned false) On Windows 7 I got the same error message "SHARE.exe must be installed in order to run Visual Basic"
However within the VB.exe I can't find any reference to LOCKFILE API, so I suspect NTVDM.exe is translating it somehow.
The APIs that seem potentially related in the import table of VB.exe are:
Kernel!OPENFILE
Kernel!_LWRITE
Kernel!_LREAD
Kernel!_LOPEN
Kernel!_LLSEEK
Kernel!_LCREAT
Kernel!_LCLOSE
OLE2!OLELOCKRUNNING
Kernel!LOCKRESOURCE
Kernel!LOCKSEGMENT
I am trying to work out how the lock / unlock file test is done so I can try to remediate within DosBox and create my own test program to replicate in C or VB.

SHARE.exe must be installed in order to run Visual Basic
SHARE.EXE works as Terminate and Stay Resident kind of program. So it existence is not enough. It must be run, to hook into system and intercept some requests.
SHARE.EXE intercepts DOS Interupt (0x21) and DOS Multiplex Interrupt (0x2F).
In 0x21 interrupt code 0x5c handles locking and unlocking files
http://www.techhelpmanual.com/530-dos_fn_5c00h__lock_file_access.html
LockFile 5c00h
Expects:
AX 5c00H
BX file handle
CX:DX file offset from start of file (CX * 65536)+DX
SI:DI length in bytes of region to lock (SI * 65536)+DI
Returns: AX error code if CF is set to CY
This function locks access to a region of the file identified by the file handle in BX. The region of the file that begins at file logical offset CX:DX extending for a length of SI:DI is locked ...
http://www.techhelpmanual.com/531-dos_fn_5c01h__unlock_file_access.html
UnlockFile 5c01h
Expects:
AX 5c01H
BX file handle
CX:DX file offset from start of file (CX * 65536)+DX
SI:DI length in bytes of region to lock (SI * 65536)+DI
Returns: AX error code if CF is set to CY
This function unlocks access to a region of the file which was previously locked...
You could also check 5dh functions marked mostly as internal.
Implementation in Free DOS:
https://sourceforge.net/p/freedos/svn/HEAD/tree/kernel/trunk/kernel/dosfns.c
see DosLockUnlock function
https://sourceforge.net/p/freedos/svn/HEAD/tree/kernel/trunk/share/share.c
Looking at vDos source code could help if you plan to bring this funcionality to Dos Box
https://sourceforge.net/projects/vdos/files/Version%202015.04.10/
However within the VB.exe I can't find any reference to LOCKFILE API
I'm not sure if LockFile existed in Win16 (probably not), but there is possibility that sharing API is called directly through DOS interrupts.
I suspect NTVDM.exe is translating it somehow
I don't know it for sure, but I would assume that it intercepts DOS interrupts and uses Win32 API calls to simulate needed behavior.
I am trying to work out how the lock / unlock file test is done so I can try to remediate within DosBox and create my own test program to replicate in C or VB
I would try to log INT 21h and INT 2Fh calls in DOS Box.

Related

Diagnosing Win32 RegisterClass leak

We are trying to troubleshoot a nasty problem on a production server where the server will start misbehaving after running for awhile.
Diagnostics have led us to believe there may be a bug in a DLL that is used by one of the processes running on this server that is resulting in a global atom leak. The assumed vector is a process that is calling RegisterClass without a corresponding UnregisterClass (and the class name is using a random number as part of the name, so it's a different class name each time the process starts).
This article provided some information: https://blogs.msdn.microsoft.com/ntdebugging/2012/01/31/identifying-global-atom-table-leaks/
But we are reluctant to attempt kernel mode debugging on a production server, so we have tried installing windbg and using the !gatom command to list atoms for a given session.
I use windbg to attach to a process in one of the sessions (these processes are running as Windows Services if that matters), then invoke the !gatom command. The returned atom list doesn't have any window classes in it.
Then I read this: https://blogs.msdn.microsoft.com/oldnewthing/20150429-00/?p=44984
and it sounds like there is a separate atom table for windows classes. And no way to query it. I was hoping that we'd be able to actually see how many windows class atoms have been registered, and see if that list gets bigger over time, indicating a leak.
The documentation on !gatom is sparse, and I'm hoping I can get some expert confirmation or recommendations on how to proceed.
Does anyone have any ideas on how we can get at the list of registered Windows classes on a production server?
More detail about what happens when the server starts to misbehave:
We run many instances (>50) of the same application as separately registered services running from isolated executables and DLLs - so each of those 50 instances has their own private executables and DLLs.
During their normal run, the processes unload and reload a DLL (about every hour). There is a windows class used that's part of a "session handle" used by the DLL (the session handle is part of the registered windows class name), and that session handle is unique each time the DLL is loaded. So every hour, there is an additional Window class registration, made by a DLL (our service stays running).
After some period of time, the system will get into a state where further attempts to load the DLL in question fail. This may happen for one of the services, then gradually over time, other services will start to have the same problem.
When this happens, restarting the service does not fix the problem. The only way that we've found to get things running properly again is to reboot the server.
We are monitoring memory commit load, and we are well within the virtual memory of the server. We are even within the physical memory size.
I just did a code review the vendor of the DLL, and it looks like they are not actually calling RegisterClass from the DLL itself (they only make one RegisterClass call from the DLL, and it's a static string - not a different class name for each session). The DLL launches an EXE, and that EXE is the one that registers the session specific class name. Their EXE does call UnregisterClass (and even if it didn't, the EXE is terminated when we unload their DLL, so it seems that this may not be what is going on).
I am now out of bullets on this one. The behavior seems like some sort of resource leak or pool exhaustion. The next time this happens, I will try connecting to the failing process with windbg and see what the application atom pool looks like - but I'm not hopeful that is going to shed any light.
Update: The excellent AtomTableMonitor tool has narrowed the problem to rogue RegisterWindowMessage. I'm going to ask a more specific question focused on this exact issue: Diagnosing RegisterWindowsMessage leak
You may try using this standalone global atom monitor
The application appears to have capabilities to monitor atoms in services
that run in a different session
btw if you have narrowed it to RegisterWindowMessage
then spy++ can log the Registered messages system wide along with thread and process
spy++ (i am using it from vs2015 community)
ctrl+m select all windows in system
in the messages tab clear all and select registered
and start logging
you can also save the log (it is plain text in-spite of strange extension )
powershell -c "gc spy++.sxl -Tail 3"
<000152> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.584 point:(408, 221)
<000153> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)
<000154> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)

Increasing no of file handles in Windows 7 64 bit

I have an application that has 10000 threads running at a time. Each thread opens the same file. The problem is whenever I launch the application with 10K threads, the application terminates after creating 500 threads(file handles). I have tried the same application on Linux and is running fine after I tweaked the ulimit option. Is there any limit on the file handles a process can open in Windows? I have been googling and all I get is to change the entries in config.nt file in C\Windows\System32....
But I found out that the said file does not exist for 64 bit OS. Is there any way that I can change the limit in Windows?
My OS is WINDOWS 7 64 bit.
To view the total number of handles (not just file handles) your application opened at a given time: Just to make sure it's the handle limit.
Download Process Explorer from https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx
Make sure to set appropiate refresh speed.
Open it and go to View -> Select Columns -> press on the tab "Process Performance"and click on "Handle Count".
For Windows 7 x64 bit, a process can have 16.711.680 handles opened simultaneously.
If you want to check limits for yourself then read below.
Check that by using a tool from Windows Internals Book (https://technet.microsoft.com/en-us/sysinternals/bb963901.aspx). Tool's name is TestLimit and you will find it in the lower part of the page under the Book Tools header.
There are no ways to increase this limit for Windows Operating Systems as far as I know, and I looked also.
As others stated, think of a method to minimize the large number of threads.
Maybe your application closes the file, but not the handle.
My advice, if you really need using very large handle count, start a new process every time handle count is about 16m.
running out of Microsoft C runtime library file descriptors (Harry Johnston) appears to be the right diagnosis.
https://learn.microsoft.com/en-us/cpp/c-runtime-library/file-handling. The default max is 512 open file descriptors. The solution therefore is a line of code early in main:
_setmaxstdio(newmax);
How to do that in Python is another question.

Concurrent File read write

I'm on a Win7 platform, I have a third party software that opens and writes to a given file. I would like to intercept the data going into that file and view it, before the process finishes. While the file is being filled, it is visibly getting bigger in explorer, so the data is being written IMO. Of course, any attempt (using any high- or low-level api I know of, writing in Python if it makes any difference) results in an" access is denied" error 5 or "The process cannot access the file because it is being used by another process." error 32.
What am I missing?
You cannot access the file unless the other app allows it. When it opens/creates the file, it specifies sharing rights for the file. If you try to open the file while it is already open, using flags that are not compatible with the sharing rights, your open will fail. If you want to open the file for read-only access, the other app must open/create the file with read sharing enabled. You can use a tool like SysInternals Process Monitor to see what sharing rights the other app is actually using.

Does OpenProcess always write lock the file?

I want to call the Windows API OpenProcess function on another process running on the machine. Will this always cause the file whose process I am opening to be write locked? Or does it depend on the access rights I request?
Yes, it is a fundamental property of Windows. When an executable file gets loaded (EXE or DLL), Windows creates a memory mapped view of the file. Chunks of code or data from the executable file get page-faulted into RAM, as needed to keep the program running. It works the other way around too, when Windows needs to make RAM available for another program then it throws chunks of mapped pages away, the ones that weren't used in a while. Those pages don't take up space in the paging file if they are code, they can be reloaded from the executable file.
Very efficient, code that was written when 16 megabytes of RAM was a luxury. The memory mapped section keeps a write lock on the file. Still useful in this day and age, it prevents some kind of malware with fecking with the code of a running process.
The process file is locked while the process is running; it doesn't have anything to do with OpenProcess. The file is unlocked when the process terminates.

Meaning of hex number in Windows crash dialog

Every now and then (ahem...) my code crashes on some system; quite often, my users send screenshots of Windows crash dialogs. For instance, I recently received this:
Unhandled win32 exception # 0x3a009598 in launcher2g.exe:
0xC00000005: Access violation writing location 0x00000000.
It's clear to me (due to the 0xc0000005 code as well as the written out error message) that I'm following a null pointer somewhere in my launcher2g.exe process. What's not clear to me is the significance of the '0x3a009598' number. Is this the code offset in the process' address space where the assembler instruction is stored which triggered the problem?
Under the assumption that 0x3a000000 is the position where the launcher2g.exe module was loaded into the process, I used the Visual Studio debugger to check the assembler code at 0x3a009598 but unfortunately that was just lots of 'int 3' instructions (this was a debug build, so there's lots of int 3 padding).
I always wondered how to make the most of these # 0x12345678 numbers - it would be great if somebody here could shed some light on it, or share some pointers to further explanations.
UPDATE: In case anybody finds this question in the future, here's a very interesting read I found which explains how to make sense of error messages as the one I quoted above: Finding crash information using the MAP file.
0x3a009598 would be the address of the x86 instruction that caused the crash.
The EXE typically gets loaded at its preferred load address - usually 0x04000000 iirc. So its probably bloody far away from 0x3a009598. Some DLL loaded by the process is probably located at this address.
Crash dumps are usually the most useful way to debug this kind of thing if you can get your users to generate and send them. You can load them with Visual Studio 2005 and up and get automatic symbol resolution of system dlls.
Next up, the .map files produced by your build process should help you determine the offending function - assuming you do manage to figure out which exe/dll module the crash was inside, and what its actual load address was.
On XP users can use DrWatsn32 to produce and send you crash dumps. On Vista and up, Windows Error Reporting writes the crash dumps to c:\users\\AppData\Local\Temp*.mdmp

Resources