WinBugs ----------------------------------------------------------------------------------------------- This text tries to describe not only bugs but also various interesting things in MS Windows operating systems. Explore, discover, find, describe and contribute, please! Last update: Aug-21-2001 Can be updated without notice! ----------------------------------------------------------------------------------------------- TRUE vs. FALSE -------------- Author: EliCZ Date: Sep-24-2000 OS: All BOOL is sometimes BYTE, sometimes DWORD. It means sometimes can be FALSE == n * 0x100. For example if you return 0xFFFFFF00 from DllMain(,DLL_PROCESS_ATTACH,), the DLL is unmapped because you've returned FALSE. Solution: Work with BOOL as with BYTE. ----------------------------------------------------------------------------------------------- WriteProcessMemory can return NTSTATUS instead of BOOL ------------------------------------------------------ Author: EliCZ Date: Sep-24-2000 OS: NT 4.0, Windows 2000 When writing to PAGE_EXECUTE or PAGE_EXECUTE_READ region fails, WriteProcessMemory returns STATUS_ACCESS_VIOLATION instead of FALSE (maybe VC++ compiler bug?). Solution: Result = WriteProcessMemory(...); if((Result == STATUS_ACCESS_VIOLATION) || (Result == FALSE)) OutputDebugString("WriteProcessMemory failed!"); ----------------------------------------------------------------------------------------------- Remote thread into not-yet-initialized process causes various failures in that process -------------------------------------------------------------------------------------- Author: EliCZ Date: Sep-24-2000 OS: Windows 2000 Proof Not-yet-initialized process is process which was created with suspended primary thread that was not resumed yet (such process contains main module and ntdll.dll only). Process is initialized (~DllMains are called with DLL_PROCESS_ATTACH, etc..) by the first nonsuspended thread. Such a thread can be remote only. What it can cause depends on "thread LPC registration" (via CsrClientConnectToServer) in LPC server (typically csrss.exe process): A) Remote thread was not "LPC registered" Examples: pure Nt/ZwCreateThread; RtlCreateUserThread; RtlQueryProcessDebugInformation; CreateToolhelp23Snapshot(TH32CS_SNAPMODULE,) Here is it clear: Initialization of KERNEL32.dll (or USER32.dll) fails because thread can't connect to LPC server {Nt/ZwSecureConnectPort(,"\\Windows\\ApiPort",...) returns STATUS_PORT_CONNECTION_REFUSED because thread was not "LPC registered"} in its DllMain during DLL_PROCESS_ATTACH. Then DllMain returns FALSE and EXCEPTION_DLL_INIT_FAILED (or EXCEPTION_APP_INIT_FAILURE) is raised. What happens later (crash) is not important. B) Remote thread was "LPC registered" Examples: CreateRemoteThread DLL initialization is OK (but DLLs are initialized by remote thread), some DLLs created new window classes (COMCTL32.dll created SysHeader*, SysList*, SysTab*,.. classes). Then thread executes the routine which was specified as lpStartAddress in call to CreateRemoteThread. Then thread terminates. Alas! It took all newly created window classes (USER32.dll and WIN2K.sys classes are preserved) out! Later when application wants to create window or dialog containing erased classes (e.g. SysListView32), window creation fails. Symptoms: Application can't invoke common dialog boxes; TaskMgr can crash;.... (both common dialogs and dialogs in TaskMgr use/include window classes created by COMCTL32.dll). After remote thread termination, you will resume suspended primary thread. But this primary thread brings DLL_THREAD_ATTACH notification to DLLs and TLS callbacks. As you can see there was total role exchange: primary thread <-> remote thread. Hence, remote thread into not-yet-initialized process should not be used at all. Solution: If you really need remote thread into not-yet-initialized process, you should use CreateRemoteThread function and you should ensure the thread never terminates (at the end of thread routine put while(TRUE);). ----------------------------------------------------------------------------------------------- DPMI service "Set Debug Watchpoint" (0B00h) doesn't return handle ----------------------------------------------------------------- Author: EliCZ Date: Sep-24-2000 OS: Windows 2000 Proof This DPMI service should return handle to debug watchpoit in BX register if it was succesful (CF is clear). Unfortunately it doesn't change BX register at all. Solution: Valid handles are 0..3. Work with hardcoded values: CDW(0); CDW(1); CDW(2); CDW(3); if(SDW(...)) HandleA = 0; if(SDW(...)) HandleB = 1; if(SDW(...)) HandleC = 2; CDW(HandleB); if(SDW(...)) HandleD = 1; if(SDW(...)) HandleE = 3; CDW(HandleA); if(SDW(...)) HandleF = 0; ----------------------------------------------------------------------------------------------- LDT descriptor can be initialized via INT 0x2A ---------------------------------------------- Author: EliCZ Date: Sep-24-2000 OS: NT 4.0, Windows 2000 Interrupt 0x2A is normally used as KiGetTickCount but it can be also used in DPMI (DOS or Win16) applications for fast setting of LDT selectors (NTVDM uses it). Allowed are DPL3 code or data descriptors (forget call/int gates) with limit <= HighestUserAddress. ;Make new (LDT) selector MOV AX, 0 INT 31H JC DPMIFailed ;Now set the descriptor to writeable DATA 0..3FFH MOV EBP, 0F0F0F0F1H ;magic MOV BX, AX ;new selector MOV ECX, 0000003FFH ;low part of descriptor MOV EDX, 00000F200H ;high part of descriptor MOV EAX, EBP ;magic INT 2AH JC DPMIFailed ----------------------------------------------------------------------------------------------- API forwarding is API hooking (DLL redirection method) provided by NTDLL/KERNEL32 --------------------------------------------------------------------------------- Author: EliCZ Date: Sep-24-2000 OS: All Proof => primitive API hooking (DLL redirection) detections can give false positive results. Examples of bad detections: VirtualQuery method, comparing highest bytes of API address with module base and other module walking based detections. Note for NT: Modules containing "backwarded" APIs are loaded dynamically on demand (when thread needs address of forwarded API). Limits of API forwarding: Module name must have ".dll" extension (it can't be .exe, .drv, ...). Limits of API forwarding in 9X: First, it was nice surprise I've found that 9X supports API forwarding partially. But module containing "backwarded" API must be preloaded and ordinals forwarding (e.g. MyDll.#12) is not supported. ----------------------------------------------------------------------------------------------- User thread's environment block (TEB) is freed when thread terminates even if there exist ----------------------------------------------------------------------------------------- references to this thread ------------------------- Author: EliCZ Date: Dec-10-2000 OS: Windows 2000 (NT 4.0 ?) Proof That's because RtlQueryProcessDebugInformation (CreateToolhelp23Snapshot(TH32CS_SNAPMODULE,)) sometimes mayn't free new thread's stack. That's because RtlFreeUserStack can't free stack of terminated thread (stack section is in TEB.E0C) or may crash running thread by freeing its stack. Solution to free user thread's stack: Use ThreadFunc which terminates via RET 4 or via ExitThread (stack is then freed implicitly). In case thread is terminated via NtTerminateThread: a) create thread suspended b) get thread TEB and from it thread's stack section c) resume thread. ----------------------------------------------------------------------------------------------- Situation: Windows NT, 4.00.1381, Workstation, Service Pack 6a connted via Terminal client, 5.0.2221.1, 128 Bit to Windows 2000, 5.00.2195, Advanced Server. Used API function: NtQueryObject in ntdll.dll called from user mode with OBJECT_INFORMATION_CLASS of ObjectAllTypesInformation. Result: The function returns the right object types but only the count of object types wich are available on Windows NT 4.0 Result Windows NT 4.0 ------------------- ----------------- 1, Type 1, Type 2, Directory 2, Directory 3, SymbolicLink 3, SymbolicLink 4, Token 4, Token 5, Process 5, Process 6, Thread 6, Thread 7, Job 7, Event 8, Event 8, EventPair 9, EventPair 9, Mutant 10, Mutant 10, Semaphore 11, Callback 11, Timer 12, Semaphore 12, Profile 13, Timer 13, WindowStation 14, Profile 14, Desktop 15, WindowsStation 15, Section 16, Desktop 16, Key 17, Section 17, Port 18, Key 18, Adapter 19, Port 19, Controller 20, WaitablePort 20, Device 21, Adapter 21, Driver 22, Controller 22, IoCompletion 23, Device 23, File (24, Driver - not returned) (25, IoCompletion - not returned) (26, File - not returned) Bug info: 29 Jan 2001, NicoDE (nico@bendlins.de) ---------------------------------------- And EliCZ adds (see also LocPInfo.zip\readme.txt) : When querying \Device\NamedPipe\net\NtControlPipeX, the querying thread may be blocked. Try for example SysInternals HandleEx and try to view Properties/Security of NtControlPipeX. BTW: The new HandleEx uses INT 1, when things go wrong in NT. ----------------------------------------------------------------------------------------------- You can't open Desktop when you don't have DESKTOP_READOBJECTS and DESKTOP_WRITEOBJECTS ----------------------------------------------------------------------------------------- access allowed ------------------------- Author: EliCZ Date: Aug-21-2001 OS: Windows NT That's because Win32K.sys!xxxOpenDesktop adds to access mask, you've passed in a call to OpenDesktop, 0x81 (DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS). For example, even if you're trying to open a deskktop for READ_CONTROL only and you don't have D_RO and D_WO granted, call doesn't succeed. ----------------------------------------------------------------------------------------------- APC oddities ------------ Author: EliCZ Date: Aug-21-2001 OS: All In Windows 9x aren't APCs queued before thread begins to execute spawned before thread begins to execute (like in NT). They are spawned when thread enters an alertable state only. In Windows NT are APCs queued before thread begins to execute spawned before thread begins to execute, but in RANDOM order (not in FIFO order). ----------------------------------------------------------------------------------------------- Bug/trick/interesting thing --------------------------- Author: <You> Date: <soon> OS: ? ??? -----------------------------------------------------------------------------------------------