Jump to content

Welcome to MSFN Forum
Register now to gain access to all of our features. Once registered and logged in, you will be able to create topics, post replies to existing threads, give reputation to your fellow members, get your own private messenger, post status updates, manage your profile and so much more. This message will be removed once you have signed in.
Login to Account Create an Account


Photo

Apparent bug in 2k netman.dll

- - - - -

  • Please log in to reply
5 replies to this topic

#1
WildBill

WildBill

    Senior Member

  • Developer
  • 697 posts
  • Joined 09-August 05
  • OS:none specified
  • Country: Country Flag
I'm *still* at it trying to get my Win2k kernel32 rewrite finished, and chasing the last few bugs is driving me batty. For anyone not up-to-date on my progress, my VM boots, but I'm getting a few errors in Event Viewer and this causes some application problems. I've been trying to hunt down the bugs via remote debugging and LOTS of debugging output in my rewritten DLL.

This would be a lot easier if I wasn't chasing red herrings. Case in point:

Error: exception 0xC0000005 (access violation). When a thread awakens from a call to Sleep(), it finds that EIP is invalid and throws an exception.

What's really happening: netman is making an API call that causes a thread to get spawned, but unloads the DLL before it can complete.

Here's an assembly code snippet from netman.dll:

.text:7627C5BB                 push    offset aWzcsvc  ; "wzcsvc"
.text:7627C5C0                 call    ds:LoadLibraryW
.text:7627C5C6                 mov     esi, eax
.text:7627C5C8                 test    esi, esi
.text:7627C5CA                 jz      short loc_7627C5F0
.text:7627C5CC                 push    offset aWzctrayiconrea ; "WZCTrayIconReady"
.text:7627C5D1                 push    esi             ; hModule
.text:7627C5D2                 call    ds:GetProcAddress
.text:7627C5D8                 test    eax, eax
.text:7627C5DA                 jz      short loc_7627C5E5
.text:7627C5DC                 lea     ecx, [ebp+NameBuffer]
.text:7627C5E2                 push    ecx
.text:7627C5E3                 call    eax
.text:7627C5E5
.text:7627C5E5 loc_7627C5E5:                           ; CODE XREF: CConnectionManager::Advise(IUnknown *,ulong *)+18Fj
.text:7627C5E5                 test    esi, esi
.text:7627C5E7                 jz      short loc_7627C5F0
.text:7627C5E9                 push    esi             ; hLibModule
.text:7627C5EA                 call    ds:FreeLibrary
.text:7627C5F0
.text:7627C5F0 loc_7627C5F0:

And this is what it means in C:

hModule = LoadLibraryW(L"wzcsvc");
hModuleA = hModule;
if ( hModule )
{
  WZCTrayIconReady = GetProcAddress(hModule, "WZCTrayIconReady");
  if ( WZCTrayIconReady )
  {
    ((void (__stdcall *)(WCHAR *))WZCTrayIconReady)(&NameBuffer);
  }
  if ( hModuleA )
  {
    FreeLibrary(hModuleA);
  }
}

So basically it loads wzcsvc.dll, calls WZCTrayIconReady, and then unloads it. The problem is that WZCTrayIconReady spawns a worker thread via QueueUserWorkItem, and the worker routine does a Sleep() for 1 second. So when the call immediately returns to netman, it immediately unloads wzcsvc--and when the worker thread wakes up, BOOM! Even the MSDN documentation for QueueUserWorkItem() points out to make sure to not unload a DLL before the work item has completed.

XP fixes this by statically linking wzcsvc.dll into netman.dll. Now, it's possible that my slowing things down with all the debugging output is causing the error to manifest itself. I might have to fix netman before I can continue on my kernel32 rewrite mission.

(sigh)


How to remove advertisement from MSFN

#2
WildBill

WildBill

    Senior Member

  • Developer
  • 697 posts
  • Joined 09-August 05
  • OS:none specified
  • Country: Country Flag
At least it was easy to fix...

Today's red herring: secur32.dll

.text:7C342FF0 ; void __stdcall SecpUnloadVMList(void)
.text:7C342FF0 ?SecpUnloadVMList@@YGXXZ proc near      ; CODE XREF: ProcDetach(void *,void *)+30p
.text:7C342FF0                 push    esi
.text:7C342FF1                 push    edi
.text:7C342FF2                 mov     edi, offset ?SecVMListLock@@3U_RTL_CRITICAL_SECTION@@A ; _RTL_CRITICAL_SECTION SecVMListLock
.text:7C342FF7                 push    edi
.text:7C342FF8                 call    ds:RtlEnterCriticalSection
.text:7C342FFE                 mov     esi, ?SecVMList@@3PAU_VMLIST@@A ; _VMLIST * SecVMList
.text:7C343004
.text:7C343004 loc_7C343004:                           ; CODE XREF: SecpUnloadVMList(void)+44j
.text:7C343004                 test    esi, esi
.text:7C343006                 jz      short loc_7C343036
.text:7C343008                 push    8000h
.text:7C34300D                 lea     eax, [esi+4]
.text:7C343010                 push    0           <---------------- BUG
.text:7C343012                 push    eax
.text:7C343013                 push    0FFFFFFFFh
.text:7C343015                 call    ds:NtFreeVirtualMemory
.text:7C34301B                 mov     ecx, esi
.text:7C34301D                 mov     esi, [esi]
.text:7C34301F                 mov     eax, large fs:18h
.text:7C343025                 mov     eax, [eax+30h]
.text:7C343028                 push    ecx
.text:7C343029                 push    0
.text:7C34302B                 push    dword ptr [eax+18h]
.text:7C34302E                 call    ds:RtlFreeHeap
.text:7C343034                 jmp     short loc_7C343004
.text:7C343036 ; ---------------------------------------------------------------------------
.text:7C343036
.text:7C343036 loc_7C343036:                           ; CODE XREF: SecpUnloadVMList(void)+16j
.text:7C343036                 push    edi
.text:7C343037                 call    ds:RtlLeaveCriticalSection
.text:7C34303D                 push    edi
.text:7C34303E                 call    ds:RtlDeleteCriticalSection
.text:7C343044                 pop     edi
.text:7C343045                 pop     esi
.text:7C343046                 retn
.text:7C343046 ?SecpUnloadVMList@@YGXXZ endp

This routine is called by scur32!ProcDetach, which is called when secur32.dll is unloaded. The problem is highlighted above: the call to NtFreeVirtualMemory gets passed along to ntoskrnl ZwVirtualMemory:

NTSTATUS ZwFreeVirtualMemory(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID *BaseAddress,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG FreeType
);

The third parameter is a pointer to a SIZE_T, and it isn't optional. Consequently, ntoskrnl throws an access violation exception when it tries to dereference the null pointer.

This was also easy to fix, though neither of these two bugs fixed my existing kernel32 bugs (though they at least aren't getting in the way now). Sometime soon I'll issue another update to KB2393802 with updated netman.dll and secur32.dll files. At this rate the patch is turning into its own mini service pack -- I'm beginning to wonder if we need some sort of naming or numbering convention for issuing our own patches separate from ones that MS issues.

Edited by WildBill, 23 March 2013 - 03:54 PM.


#3
tomasz86

tomasz86

    www.windows2000.tk

  • Member
  • PipPipPipPipPipPipPipPip
  • 2,520 posts
  • Joined 27-November 10
  • OS:XP Pro x86
  • Country: Country Flag

I'm beginning to wonder if we need some sort of naming or numbering convention for issuing our own patches separate from ones that MS issues.

That's why I started to add the "UU" prefix like when I was still preparing single unofficial updates, ex. Windows2000-UU-KB927489-v3-x86-Global.exe. This way you know that it's an unofficial package as soon as you look at its name. It's also very easy to filter when searching.
Posted Image
Unofficial Service Pack 5.2 for MS Windows 2000 <- use this topic if you need help with UURollup, Update Rollup 2 and other unofficial packages

#4
Phenomic

Phenomic

    Member

  • Member
  • PipPip
  • 277 posts
  • Joined 31-July 09
  • OS:none specified
  • Country: Country Flag

I'm *still* at it trying to get my Win2k kernel32 rewrite finished, and chasing the last few bugs is driving me batty. For anyone not up-to-date on my progress, my VM boots, but I'm getting a few errors in Event Viewer and this causes some application problems. I've been trying to hunt down the bugs via remote debugging and LOTS of debugging output in my rewritten DLL.
...


I don't get it, how can you rewrite DLLs without the source code?

#5
WildBill

WildBill

    Senior Member

  • Developer
  • 697 posts
  • Joined 09-August 05
  • OS:none specified
  • Country: Country Flag
Spend $2000 on Ida Pro + the decompiler, and invest *lots* of time analyzing the DLL...

#6
blackwingcat

blackwingcat

    Friend of MSFN

  • Member
  • PipPipPipPipPip
  • 772 posts
  • Joined 31-May 08
  • OS:Windows 2000 Professional
  • Country: Country Flag
Really ?

If the MEM_RELEASE flag is set in the FreeType parameter, the variable pointed to by RegionSize must be zero. ZwFreeVirtualMemory frees the entire region that was reserved in the initial allocation call to ZwAllocateVirtualMemory.

I think that it is correct.

And Windows XP also same code.

L77FA7122:
push 00008000h
push 00000000h < -
lea eax,[esi+04h]
push eax
push FFFFFFFFh
call [ntdll.dll!NtFreeVirtualMemory]
mov ecx,esi
mov esi,[esi]
mov eax,fs:[00000018h]
mov eax,[eax+30h]
push ecx
push 00000000h
push [eax+18h]
call [ntdll.dll!RtlFreeHeap]
jmp L77FA2350




At least it was easy to fix...

Today's red herring: secur32.dll

.text:7C342FF0 ; void __stdcall SecpUnloadVMList(void)
.text:7C342FF0 ?SecpUnloadVMList@@YGXXZ proc near      ; CODE XREF: ProcDetach(void *,void *)+30p
.text:7C342FF0                 push    esi
.text:7C342FF1                 push    edi
.text:7C342FF2                 mov     edi, offset ?SecVMListLock@@3U_RTL_CRITICAL_SECTION@@A ; _RTL_CRITICAL_SECTION SecVMListLock
.text:7C342FF7                 push    edi
.text:7C342FF8                 call    ds:RtlEnterCriticalSection
.text:7C342FFE                 mov     esi, ?SecVMList@@3PAU_VMLIST@@A ; _VMLIST * SecVMList
.text:7C343004
.text:7C343004 loc_7C343004:                           ; CODE XREF: SecpUnloadVMList(void)+44j
.text:7C343004                 test    esi, esi
.text:7C343006                 jz      short loc_7C343036
.text:7C343008                 push    8000h
.text:7C34300D                 lea     eax, [esi+4]
.text:7C343010                 push    0           <---------------- BUG
.text:7C343012                 push    eax
.text:7C343013                 push    0FFFFFFFFh
.text:7C343015                 call    ds:NtFreeVirtualMemory
.text:7C34301B                 mov     ecx, esi
.text:7C34301D                 mov     esi, [esi]
.text:7C34301F                 mov     eax, large fs:18h
.text:7C343025                 mov     eax, [eax+30h]
.text:7C343028                 push    ecx
.text:7C343029                 push    0
.text:7C34302B                 push    dword ptr [eax+18h]
.text:7C34302E                 call    ds:RtlFreeHeap
.text:7C343034                 jmp     short loc_7C343004
.text:7C343036 ; ---------------------------------------------------------------------------
.text:7C343036
.text:7C343036 loc_7C343036:                           ; CODE XREF: SecpUnloadVMList(void)+16j
.text:7C343036                 push    edi
.text:7C343037                 call    ds:RtlLeaveCriticalSection
.text:7C34303D                 push    edi
.text:7C34303E                 call    ds:RtlDeleteCriticalSection
.text:7C343044                 pop     edi
.text:7C343045                 pop     esi
.text:7C343046                 retn
.text:7C343046 ?SecpUnloadVMList@@YGXXZ endp

This routine is called by scur32!ProcDetach, which is called when secur32.dll is unloaded. The problem is highlighted above: the call to NtFreeVirtualMemory gets passed along to ntoskrnl ZwVirtualMemory:

NTSTATUS ZwFreeVirtualMemory(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID *BaseAddress,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG FreeType
);

The third parameter is a pointer to a SIZE_T, and it isn't optional. Consequently, ntoskrnl throws an access violation exception when it tries to dereference the null pointer.

This was also easy to fix, though neither of these two bugs fixed my existing kernel32 bugs (though they at least aren't getting in the way now). Sometime soon I'll issue another update to KB2393802 with updated netman.dll and secur32.dll files. At this rate the patch is turning into its own mini service pack -- I'm beginning to wonder if we need some sort of naming or numbering convention for issuing our own patches separate from ones that MS issues.


Edited by blackwingcat, 25 March 2013 - 09:10 PM.

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
BlackWingCat =^^=
http://blog.livedoor.jp/blackwingcat/
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users



How to remove advertisement from MSFN