1. Compiler was MSVC4.
2. If DLL is COM server (it has exports DllCanUnloadNow, DllGetClassObject, and optionaly DllRegisterServer, DllUnregisterServer) than definitely it is build with help of ATL (usualy via ATL2.0).
How looks like things covered from programmer?:
in assembler:
(NOTE:this is not a binary identic realization to output of MSVC4+ATL)
(NOTE:I moved tryRawDllMain in separate function, this done only for readability, no one MSVC don`t do it this way, they check rawDLLmain inline in DllEntryPoint)
(NOTE:In original preserved much more registers and logical blocks are a bit messed with each other - I show only fully workable optimized for size and readability functional identic code - for understanding what is happened)
(NOTE:Used real assembler dialect FASM with altered macro procedure with esp stack realization, for readable trickering added macros prepare & invoks)
Code: Select all
tryRawDllMain: procedure (hinstDLL, fdwReason, lpvReserved)
mov eax, 1 ; TRUE
cmp [rawDLLmain],eax
jb .locret
stdcall [rawDLLmain],hinstDLL,fdwReason,lpvReserved
.locret:
ret
endp
CRT_INIT: procedure (hinstDLL, fdwReason, lpvReserved)
mov eax, DLL_PROCESS_ATTACH
;mov eax, TRUE - same as above
cmp [fdwReason], eax
ja .locret
je .DLL_PROCESS_ATTACH_case
.DLL_PROCESS_DETACH_case:
xor eax, eax
cmp [need_DLL_PROCESS_DETACH_counter], eax
jle .locret
dec [need_DLL_PROCESS_DETACH_counter]
inc eax
cmp [Memory], eax
jb .locret
mov eax, [Memory.End]
.loop_slots:
sub eax, 4
cmp eax, [Memory]
jb .done_slots
push eax
mov eax, [eax]
test eax, eax
jz .skip_call
call eax
.skip_call:
pop eax
jmp .loop_slots
.done_slots:
cinvoke free,[Memory]
xor eax, eax
mov [Memory],eax
inc eax
jmp .locret
.DLL_PROCESS_ATTACH_case:
cinvoke malloc, $80
mov [Memory], eax
test eax, eax
jz .locret
mov [Memory.End], eax
mov dword [eax], 0
cinvoke initterm,InitTerm.Start,InitTerm.End
inc [need_DLL_PROCESS_DETACH_counter]
mov eax, 1
.locret:
ret
endp
DllEntryPoint : procedure (hinstDLL, fdwReason, lpvReserved)
; if we`ll look on it from side of DisableThreadLibraryCalls launched in DllMain
; there are left only DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH & wine specific dwReasons
; b.t.w. wine specific dwReasons historicaly successfully handled until the opposite is determined
mov eax, DLL_PROCESS_ATTACH
;mov eax, TRUE - same as above
cmp [fdwReason], eax
ja .locret ; before locret should be calls of DllMain & CRT_INIT that
jb .DLL_PROCESS_DETACH_case
.DLL_PROCESS_ATTACH_case:
stdcall tryRawDllMain(hinstDLL, fdwReason, lpvReserved)
test eax, eax
jz .locret
stdcall CRT_INIT(hinstDLL, fdwReason, lpvReserved)
test eax, eax
jz .locret
stdcall DllMain(hinstDLL, fdwReason, lpvReserved)
test eax, eax
jnz .locret
stdcall CRT_INIT(hinstDLL, DLL_PROCESS_DETACH, lpvReserved)
xor eax, eax
jmp .locret
.DLL_PROCESS_DETACH_case:
cmp [need_DLL_PROCESS_DETACH_counter], eax
jz .locret
stdcall DllMain(hinstDLL, fdwReason, lpvReserved)
stdcall CRT_INIT(hinstDLL, fdwReason, lpvReserved)
test eax, eax
jz .locret
stdcall tryRawDllMain(hinstDLL, fdwReason, lpvReserved)
; jmp .skip_not_PROCESS_reasons
;.not_PROCESS_reasons:
; stdcall DllMain(hinstDLL, fdwReason, lpvReserved) ; return value ignored - it allways true for not_PROCESS_reasons
;.skip_not_PROCESS_reasons:
.locret:
ret
endp
DllMain: procedure (hinstDLL, fdwReason, lpvReserved)
cmp [fdwReason], DLL_PROCESS_ATTACH
ja .retTrue
jb .DLL_PROCESS_DETACH_case
.DLL_PROCESS_ATTACH_case:
mov eax, [hinstDLL]
mov [hInstance], eax
prepare DisableThreadLibraryCalls,hinst
stdcall ComModule.Init,ComModule,ObjectMap,eax
invoks DisableThreadLibraryCalls,stack
jmp .retTrue
.DLL_PROCESS_DETACH_case:
stdcall ComModule.Term,ComModule
.retTrue:
mov eax,1
ret
endp
Code: Select all
extern “C” BOOL WINAPI tryRawDllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{ if (rawDLLmain == NULL) return TRUE
else return rawDLLmain(hinstDLL, fdwReason, lpvReserved);
}
extern “C” BOOL WINAPI CRT_INIT(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{ if (dwReason == DLL_PROCESS_ATTACH)
{ Memory = malloc($80);
if (Memory == NULL) return FALSE;
Memory.End = Memory;
Memory = NULL;
initterm(InitTerm.Start,InitTerm.End);
need_DLL_PROCESS_DETACH_counter++;
}
else if (dwReason == DLL_PROCESS_DETACH)
if (need_DLL_PROCESS_DETACH_counter > 0)
{ need_DLL_PROCESS_DETACH_counter--;
if (Memory == NULL) return TRUE;
temp = Memory.End
while (&temp-&Memory >0)
{
pointer(&temp)--;
if (temp != NULL) temp();
};
free(Memory);
Memory = NULL;
}
else return FALSE;
}
return TRUE;
}
extern “C” BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{ if (dwReason == DLL_PROCESS_ATTACH)
{ if (tryRawDllMain(hinstDLL, fdwReason, lpvReserved) && CRT_INIT(hinstDLL, fdwReason, lpvReserved))
{ if (DllMain(hinstDLL, fdwReason, lpvReserved)) return TRUE
else return tryRawDllMain(hinstDLL, fdwReason, lpvReserved);
}
return FALSE;
}
else if (dwReason == DLL_PROCESS_DETACH)
if (!(need_DLL_PROCESS_DETACH_counter == 0))
{ DllMain(hinstDLL, fdwReason, lpvReserved);
if (CRT_INIT(hinstDLL, fdwReason, lpvReserved)) return tryRawDllMain(hinstDLL, fdwReason, lpvReserved)
else return FALSE;
}
else return TRUE;
}
extern “C” BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{ if (dwReason == DLL_PROCESS_ATTACH)
{ hInstance = hinstDLL
ComModule.Init(ObjectMap,hinstDLL);
DisableThreadLibraryCalls(hinstDLL);
}
else if (dwReason == DLL_PROCESS_DETACH) ComModule.Term();
return TRUE;
}
I never met any OS file were rawDLLmain was defined. Profit of usage rawDLLmain is zero - because it don`t replace CRT_INIT but only precede it.
Internal content of CRT_INIT evaluated from version to version (of MSVC).
If that topic will not be banned and someone will interest in it I can continue describe internals hidden even in HLL opensource.
I can repeat (here I going to describe only things relative to obsolete technology ATL2.0 & MSVC4 - from times when components of win9x were written on it).