From: win32 on

Hi.
I am facing strange problem with object Event while global hook WH_CBT
is installed and when an USB flash drive is inserted.

The bug reveals itself only when compiling in VS6+SP6 and does not
appear in VS 2008. Alas, I need this project compiled only in VS6.
Here is the code:

#pragma data_seg(".shared")
HHOOK g_hook=NULL;
#pragma data_seg()

#pragma comment(linker, "/SECTION:.shared,RWS")

HINSTANCE g_hInstance;

LRESULT CALLBACK HookFunc(int nCode, WPARAM wParam,LPARAM lParam){
return CallNextHookEx(g_hook, nCode, wParam, lParam);
}

extern "C" __declspec(dllexport) void InitHook(){
g_hook=SetWindowsHookEx(WH_CBT,HookFunc,g_hInstance,0);
MSG msg;
int ret;
// setting message loop
while((ret=GetMessage(&msg,0,0,0))!=0){
if(ret==-1){

} else {
DispatchMessage(&msg);
}
}
}

unsigned WINAPI MyThread(void *p){
HANDLE hEvent=CreateEvent(NULL,false,false,"myevent");
DWORD dwErr=GetLastError();
if(dwErr==ERROR_ALREADY_EXISTS){ // if this code deleted
SetEvent(hEvent); // the bug
Sleep(3000); // does not appear
}

WaitForSingleObject(hEvent,INFINITE); // waiting infinite
CloseHandle(hEvent);
ExitProcess(0); // exiting process
return 0;
}



BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if(ul_reason_for_call==DLL_PROCESS_ATTACH){
g_hInstance=(HINSTANCE)hModule;
char szFileName[MAX_PATH];
GetModuleFileName(NULL,szFileName,MAX_PATH);
strlwr(szFileName);
BOOL bOk=false;
if(strstr(szFileName,"notepad")!=NULL ||
strstr(szFileName,"rundll32")!=NULL) bOk=true;

if(bOk){
UINT uid;
HANDLE hTh=(HANDLE)_beginthreadex(NULL,0,MyThread,NULL,0,&uid);
CloseHandle(hTh);
}

return bOk;
}
else
if(ul_reason_for_call==DLL_PROCESS_DETACH){
UnhookWindowsHookEx(g_hook);
}

return TRUE;
}

In short my app is:
- a dll that is spawned by rundll32.exe and installs WH_CBT hook
- in order that rundll32 process will not finish we set message
loop(GetMessage\DispathMessage)
- for DllMain we create thread in which some event is created and then
we put infinite wait on it
- when notepad is executed our dll is injected into it



Take a look on this part of our thread's code:

DWORD dwErr=GetLastError();
if(dwErr==ERROR_ALREADY_EXISTS){
SetEvent(hEvent);
Sleep(3000);
}

It is not important what sense does this code make. It is more
important that when the only one instance of rundll32 process is
launched (the event named 'myevent' is not opened or created anywhere)
the function GetLastError cannot return ERROR_ALREADY_EXISTS (a priori
no event with such name!), that is why two calls - SetEvent and Sleep
are never executed. And it is true, these two calls do not take place
and execution goes to WaitForSingleObject. Here we have infinite wait.
And now! As soon as we insert our flash drive into USB port by some
fantastic way the event hEvent is signalled and the call
WaitForSingleObject is finished with WAIT_OBJECT_0 code.


In essence, the code mentioned above makes the following sense: if
another one instance of rundll32 is launched and our dll is injected
in it then we have to terminate the preceding instance. And in
preceding instance there is a wait on hEvent. This event gets
signalled if GetLastError returns ERROR_ALREADY_EXISTS in new process.
Then we will have an infinite wait in new process until another one
instance of rundll32 with our dll injected is launched. And so on.

The most interesting thing is that there is no bug with flash drive
when the code is compiled in VS2008. Try to compile in VC6 (I have SP6
installed) and run the dll from the command prompt: rundll32.exe c:
\project\some\debug\prg.dll,InitHook.
And then insert an USB flash drive. And you will see that our
rundll32.exe process will terminate.


If I change the message loop

while((ret=GetMessage(&msg,0,0,0))!=0){
if(ret==-1){

} else {
DispatchMessage(&msg);
}
}

to


Sleep(INFINITE);

the situatuon will not change - after the flash drive insertion the
event is signalled and that's it.

And now focus.
Delete the code:

DWORD dwErr=GetLastError();
if(dwErr==ERROR_ALREADY_EXISTS){
SetEvent(hEvent);
Sleep(3000);
}


And the bug disappears!
What we have? Some fantom code executes the part of code post factum
(or spawns the thread once again) and since the event named 'myevent'
already exists GetLastError returns ERROR_ALREADY_EXISTS and the call
to SetEvent(hEvent) is executed. By the way if we delete
SetEvent(hEvent) then bug disappears too. Also there is no bug
detected if I remove the hook logic (if I do not call
SetWindowsHookEx).
But why VS2008 is not exposed to the bug?
My OS is Windows XP SP3.
Thanks in advanced for the answers.
From: David Schwartz on

I would bet you $100 to your $5 that the reason the event is being
signaled is because your code to signal it is running. That's why it
doesn't get signaled if you remove that code.

DS
From: win32 on
On 30 июн, 01:58, David Schwartz <dav...(a)webmaster.com> wrote:
> I would bet you $100 to your $5 that the reason the event is being
> signaled is because your code to signal it is running. That's why it
> doesn't get signaled if you remove that code.
>
> DS
I have been investigating and you're true - simply after the flash
drive is inserted a new process rundll32 is initiated to show the
dialog box(so that a user may choose what to do with flash!). But I
could not guess the reason just because I have disabled the dialog
box. Anyway the rundll32 process is launched and quickly terminated,
and of course DllMain is executed (dll is loaded into another
rundll32...) and the thread is spawned so that the event is signalled!
Thanx to all for attention!
From: Ulrich Eckhardt on
win32 wrote:
> Anyway the rundll32 process is launched and quickly terminated, and of
> course DllMain is executed (dll is loaded into another rundll32...)
> and the thread is spawned so that the event is signalled!

Just wondering, but isn't it Evil Foobar(tm) to spawn a thread in DllMain()?
Or am I missing an exception to that rule here?

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932