MFC extension dll resources loading problems - c++

I have built the folowing configuration:
A) MFC Extension DLL having 2 MFC dialogs.
B) MFC regular dll that uses DLL A functions.
C) win32 application (NON MFC) calling for function from DLL B
When calling functions from DLL B that inside call functions from DLL A to display a dialog an error occurs due to the fact that resource can not be found.
I have digged to find the exact root cause and themain reson seems to be the fact that the module context is set to the calling dll B rather than to the DLL A, which contains the dialog resource.
Inside DllMain the initialization is done as described in the MSDN:
static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
Hinstance = hInstance; //save instance for later reuse
// Extension DLL one-time initialization
if (AfxInitExtensionModule(extensionDLL,hInstance) == 0)
{
AfxMessageBox("Error on init AfxInitExtensionModule!");
return 0;
}
// Insert this DLL into the resource chain
new CDynLinkLibrary(extensionDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
Release();
}
return 1;
}
One workarround that i've found was to store the hInstance parameter received from DLLMain: extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
and inside DLL A when functions are called, I save current handle and set new handle the handle received from DllMain:
DLL A function1(............)
{
HINSTANCE HinstanceOld = AfxGetResourceHandle();
AfxSetResourceHandle(CErrohInstance);
.......
//display dialog
.....
AfxSetResourceHandle(HinstanceOld);
}
By using this workarround It still causses assertion but the dialogs are shown.
What should be the normal way of solving this problem?

You have to insert the resources of the extension DLL into the resource chain of the regular DLL, not the EXE. Just create a function in the extension DLL and call it in the InitInstance method of the regular DLL, like this:
void initDLL()
{
new CDynLinkLibrary(extensionDLL);
}

You say "module context" but in fact the terminus technicus is "module state".
AFAICS this is the relatively standard (i.e., most frequently occurring) MFC module state related use case here, namely: entering via callbacks / public exported APIs into internal implementation area.
AFX_MANAGE_STATE directly mentions this use case: "If you have an exported function in a DLL"
At this point, the module state that is currently active is the one of the calling party, which is not the one which is needed within implementation scope.
Since implementation scope knows that it needs a different module state (and it is the one to know which is the correct one!), it needs to temporarily switch to the correct one, to achieve having any module state related lookup (precisely: resource instance lookup) done within the correct instance scope.
And this needs to be done not manually via AfxSetModuleState(), but rather via the properly lifetime-scoped (guarantees proper destruction, at whichever cancellation points may exist, be it return or exception or whatever) mechanism of AFX_MANAGE_STATE macro.
IOW, implementation likely needs to strongly resemble something like:
BOOL MyPublicAPIOrCallback()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // ensure locally expected module state within this externally-invoked handling scope
some_handling_which_does_resource_lookup_or_whatever;
}

Dont know if you have already found the solution, if not You can try using
AfxFindResourceHandle
before accessing the problematic resource in Dll A.

I have add this lines in my DLLMain and now I don't have problems to use resources that are in other DLL's called by my DLL, like dialogs.
This is the Code:
static AFX_EXTENSION_MODULE CODIAbantailDLLDLL = { NULL, NULL };
AplicacionBase theApp;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Quitar lo siguiente si se utiliza lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// ******** VERY IMPORTANT ***********************
// IF you doesn't put this, when you call other DLL that has
// its owns resources (dialogs for instance), it crash
CoInitialize(NULL);
AfxWinInit(hInstance, NULL, ::GetCommandLine(), 0);
AfxEnableControlContainer();
//**************************************************
TRACE0("Inicializando CODIAbantailDLL.DLL\n");
// Inicialización única del archivo DLL de extensión
if (!AfxInitExtensionModule(CODIAbantailDLLDLL, hInstance))
return 0;
new CDynLinkLibrary(CODIAbantailDLLDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("Finalizando CODIAbantailDLL.DLL\n");
// Finalizar la biblioteca antes de llamar a los destructores
AfxTermExtensionModule(CODIAbantailDLLDLL);
}
return 1; // aceptar
}

Related

C++ Windows: Access same variable from main process and CallWndProc process

I have a single-file DLL that receives and stores a _bstr_t as a global variable, then sets a Windows hook for the WH_CALLWNDPROC procedure.
In the CallWndProc function, I attempt to read the _bstr_t, but it has no value.
I printed out the variable's address from both functions and they are different.
This is not surprising as I think that the CallWndProc function is called in a different process' thread.
My question is, what is the easiest and best way to share the variable between them?
I am trying to avoid having to use ATL COM to store it for inter-process access.
Example code:
// foo.cpp
#include <comutil.h>
static HHOOK g_hook = NULL;
static _bstr_t shared = "";
static LRESULT WINAPI CallWndProc(int nHookCode, WPARAM wParam, LPARAM lParam) {
if (nHookCode == 12345) {
// Do something with '_bstr_t shared'
shared += " bar";
return 0;
}
return CallNextHookEx(g_hook, nHookCode, wParam, lParam);
}
extern "C" __declspec(dllexport) void _stdcall Do(char* someStr, long handle) {
shared = someStr;
DWORD threadId = GetWindowThreadProcessId((HWND) handle, &process);
HINSTANCE hInst = GetModuleHandle("foo.dll");
g_hook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, hInst, thread);
// Check value of '_bstr_t shared', or call a COM function to store it somewhere.
// However, the value of 'shared' does not include the string appended in CallWndProc.
}
Extra info:
DLL is called by Java using JNI.
DLL is built as a multi-threaded DLL.
I went with the ATL COM approach to act as a global store of values.
Not my ideal solution, but a workable one.
However, I think Hans Passant's comment on the question is a better way of doing it since it does not require a separate process to be running.

global variable in dll inconsistent?

I am creating a (temporary) log file from a dll. But the global variable I defined seem to be inconsistent.
Here is how I define variables in dll's main cpp file.
char * g_bfr;
__declspec(dllexport) CMemFile memFile;
Then in DllMain function:
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("UTLADO.DLL Initializing!\n");
g_bfr = new char[1000]();
memFile.Attach((BYTE*)g_bfr, 1000 );
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(AcnDll, hInstance))
return 0;
new CDynLinkLibrary(AcnDll);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("UTLADO.DLL Terminating!\n");
delete[] g_bfr;
// Terminate the library before destructors are called
AfxTermExtensionModule(AcnDll);
}
return 1; // ok
}
The problem is when I use the memFile in the dll to write log to memory, somewhere down the road, it becomes bad as if newly declared (uninitialized). See the where file positions/size are all reset.
What makes thing weirder is when I set breakpoint in DllMain, inside case DLL_PROCESS_ATTACH, it never breaks there (like never called) but the initialization does work! Breakpoint in case DLL_PROCESS_DETACH does work and is called only when I close application.
So, in a nutshell, it appears that memFile gets created another time during course of the application but should it? How can I make sure I only have one instance of the global variable in the dll?
After you have finished using the DLL, try using the FreeLibrary function.
However, this method has not been considered for concurrent use.
enter link description here

CreateThread inside another thread

I am having an issue creating a thread inside of another thread. Normally I would be able to do this, but the reason for this issue is because I've Incremented Reference Count of the DLL which starts these threads. I need to start multiple threads inside this DLL. How can I get around this and be able to issue multiple CreateThread()'s when needed in my project without experiencing problems because of the Incremented Reference Count in my DLL?
Here is the function I've written to Increment Reference Count in my DLL file:
BOOL IncrementReference( HMODULE hModule )
{
if ( hModule == NULL )
return FALSE;
TCHAR ModulePath[ MAX_PATH + 1 ];
if ( GetModuleFileName( hModule , ModulePath , MAX_PATH ) == 0 )
return FALSE;
if ( LoadLibrary( ModulePath ) == NULL )
return FALSE;
return TRUE;
}
As requested, here is a PoC program to recreate the issue I am facing. I am really hoping this will help you guys point me to a solution. Also, take note, the DLL is being unloading due to conditions in the application which I am targeting (hooks that are already set in that application), so Incrementing the Reference Count is required for my thread to run in the first place.
Also, I can't run more than one operation in the main thread as it has its own functionality to take care of and another thread is required on the side to take care of something else. They must also run simultaneously, hence I need to fix this issue of making more than one thread in an Incremented DLL.
// dllmain.cpp : Defines the entry point for the DLL application.
#pragma comment( linker , "/Entry:DllMain" )
#include <Windows.h>
#include <process.h>
UINT CALLBACK SecondThread( PVOID pParam )
{
MessageBox( NULL , __FUNCTION__ , "Which Thread?" , 0 );
return 0;
}
UINT CALLBACK FirstThread( PVOID pParam )
{
MessageBox( NULL , __FUNCTION__ , "Which Thread?" , 0 );
_beginthreadex(0, 0, &SecondThread, 0, 0, 0);
return 0;
}
BOOL IncrementReference( HMODULE hModule )
{
if ( hModule == NULL )
return FALSE;
TCHAR ModulePath[ MAX_PATH + 1 ];
if ( GetModuleFileName( hModule , ModulePath , MAX_PATH ) == 0 )
return FALSE;
if ( LoadLibrary( ModulePath ) == NULL )
return FALSE;
return TRUE;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
if (IncrementReference(0))
_beginthreadex(0, 0, &FirstThread, 0, 0, 0);
}
break;
}
return TRUE;
}
As you can see, the code never executes the SecondThread function. The question is, why? And what can be done to fix it?
#pragma comment( linker , "/Entry:DllMain" )
That was a very bad idea, the proper entrypoint for a DLL is not in fact DllMain(). You have to keep in mind that WinMain and DllMain are just place-holder names. A way for Microsoft to document the relevance of executable file entrypoints. By convention you use those same names in your program, everybody will understand what they do.
But there's a very important additional detail in a C or C++ program, the CRT (C runtime library) needs to be initialized first. Before you can run any code that might make CRT function calls. Like _beginthreadex().
In other words, the default /ENTRY linker option is not DllMain(). The real entrypoint of a DLL is _DllMainCRTStartup(). A function inside the CRT that takes care of the required initialization, then calls DllMain(). If you wrote one in your program then that's the one that runs. If you didn't then a dummy one in the CRT gets linked.
All bets are off when you make CRT function calls and the CRT wasn't initialized. You must remove that #pragma so the linker will use the correct entrypoint.
According to MSDN you schould neither call LoadLibrary nor CreateThread inside DllMain - your code does both!
The MCVE as posted has three problems:
The first is a simple mistake, you're calling IncrementReference(0) instead of IncrementReference(hModule).
The second is that there is no entry point for rundll32 to use; the entry point argument is mandatory, or rundll32 won't work (I don't think it even loads the DLL).
The third is the #pragma as pointed out by Hans.
After fixing the IncrementReference() call, removing the #pragma and adding an entry point:
extern "C" __declspec(dllexport) void __stdcall EntryPoint(HWND, HINSTANCE, LPSTR, INT)
{
MessageBoxA( NULL , __FUNCTION__ , "Which Thread?" , 0 );
}
You can then run the DLL like this:
rundll32 testdll.dll,_EntryPoint#16
This works on my machine; EntryPoint, FirstThread and SecondThread all generate message boxes. Make sure you do not dismiss the message box from EntryPoint prematurely, as that will cause the application to exit, taking the other threads with it.
The call to LoadLibrary is still improper, however it does not appear to have any side-effects in this scenario (probably because the library in question is guaranteed to already be loaded).
(Previous) Answer:
The MCVE can be fixed by simply moving the call to IncrementReference from DllMain to FirstThread. That is the only safe and correct way to resolve the problem.
Addendum: as Hans pointed out, you'll also need to remove the /Entry pragma.
(Redundant?) Commentary:
If the application that is loading the DLL is misbehaving to the extent where the DLL is being unloaded before FirstThread can run, and assuming for the sake of argument that you can't fix it, the only realistic option is to work around the problem - for example, DllMain could suspend all the other threads in the process so that they cannot unload the DLL, and resume them from FirstThread after the call to IncrementReference.
Or you could try hooking FreeLibrary, or reverse engineering the loader and messing with the reference count directly, or removing the hooks the application has placed, or loading a separate copy of the DLL by hand inside DllMain (with your own DLL loader rather than the one Windows provides) or starting a separate process and working from there or, oh, no doubt there's any number of other possibilities, but at that point I'm afraid the question really is too broad for Stack Overflow, particularly since you can't give us the real details of what the application is doing.

Easyhook: unmanaged hooking, how to call original function / change return status?

So I have a hook function at winspool.drv!WritePrinter, which is successfully hooked with unmanaged C++ remotely injected to spoolsv.exe.
Currently, the hook seems to either replace original function, or corrupt the stack in an undetectable way: after hooking, WritePrinter calls result in no printer activity outside the hook.
I've figured out there's at least one way to call original function, so-called LhGetOldProc. However, using it leads to crashes, don't sure if this is easyhook-related error or it's just bad casting.
So, how do I properly call original function in Easyhook unmanaged version?
Hook callback with LhGetOldProc:
UCHAR *uc = NULL;
LhGetOldProc(hhW, &uc);
typedef BOOL (*wp)(_In_ HANDLE, _In_ LPVOID, _In_ DWORD cbBuf, _Out_ LPDWORD);
wp my_wp = reinterpret_cast<wp>(reinterpret_cast<long>(uc)); // http://stackoverflow.com/questions/1096341/function-pointers-casting-in-c
BOOL res ;
if (my_wp == 0x0) {
return -1;
} else {
res = my_wp(hPrinter, pBuf, cbBuf, pcWritten); // crash
}
Hook code:
HMODULE hSpoolsv = LoadLibraryA("winspool.drv");
TRACED_HOOK_HANDLE hHook = new HOOK_TRACE_INFO();
NTSTATUS NtStatus;
UNICODE_STRING* NameBuffer = NULL;
HANDLE hRemoteThread;
FORCE(LhInstallHook(GetProcAddress(hSpoolsv, "WritePrinter"), WritePrinterHookA, 0x0, hHook));
ULONG ACLEntries[1] = { (ULONG) - 1 };
FORCE(LhSetExclusiveACL(ACLEntries, 1, hHook));
hhW = hHook;
TIL: in 2013, CodePlex (where EasyHook discussion list is) doesn't accept third level domains for e-mail when registering with Microsoft account. Not going to use Firebug to bypass the form.
The stack gets corrupted because your function pointer has the wrong calling convention.
The default calling convention is __cdecl which expects the caller to clean the stack.
typedef BOOL (* wp)(_In_ HANDLE ....);
equals:
typedef BOOL (__cdecl* wp)(_In_ HANDLE ...);
but the winapi functions use __stdcall calling convention which expects the callee to clean the stack.
you will have to typedef a __stdcall function:
typedef BOOL (__stdcall* wp)(_In_ HANDLE ....);

API Hooking which takes effect across entire process - both EXE and DLLs

I have an application consists of a single EXE and multiple DLLs. After reading Windows via C/C++, I try to perform hook on Sleep function in one of the DLL, and expecting the hook will work across both EXE and all DLLs. Note that, CAPIHook code is getting from Windows via C/C++'s sample code
In DLL Project
void WINAPI MySleep( DWORD dwMilliseconds );
CAPIHook g_Sleep("Kernel32.dll", "Sleep", (PROC)MySleep);
typedef void (WINAPI *Sleep_Type)( DWORD dwMilliseconds );
// Hook function.
void WINAPI MySleep( DWORD dwMilliseconds )
{
printf ("-------> In MySleep\n");
((Sleep_Type)(PROC)g_Sleep)(dwMilliseconds);
}
// This is an example of an exported function.
DLL_API int dll_function_which_is_going_to_call_sleep(void)
{
printf ("DLL function being called\n");
printf ("Call Sleep in DLL function\n");
Sleep(100);
return 42;
}
In EXE Project
void CexeDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
printf ("Button being clicked\n");
printf ("Call Sleep in EXE function\n");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
printf ("Call Sleep in EXE function\n");
Sleep(100);
dll_function_which_is_going_to_call_sleep();
}
This is the output I am getting
Button being clicked
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
Call Sleep in EXE function
-------> In MySleep
DLL function being called
Call Sleep in DLL function
What make me feel strange is that, I am expecting CAPIHook will take effect across entire single process. Since EXE and DLLs belong to a same process, both should be able to reach MySleep. However, my observation is that, only call from EXE will reach MySleep, but not DLL.
I locate sample code right here CAPIHook-doesnt-have-effect-in-entire-process.zip, it contains dll and exe projects.
I also once drop in replace CHookAPI with code in apihijack. Same problem still happen. The hooking effect will not spread across entire process.
Is there anything I had missed out? Please do not suggest me to use EasyHook, Detours, ..., as I just want to know why the above code won't work, and how I can fix it.
This is because the original CAPIHook does not replace local IAT (in your case, the DLL project which contains binaries for CAPIHook).
The reason behind this was to protect itself from infinite recursion which lead to stackoverflow (which the users will also post question in SO :D).
To ensure that any subsequent modules loaded will be importing the "correct" function,CAPIHook search and re-direct LoadLibrary and GetProcAddress upon construction.
However, these function are used by CAPIHook itself too, so changing local IAT to proxy function (CAPIHook::LoadLibrary or CAPIHook::GetProcAddress) will cause infinite recursion as the proxies unintentionally called itself while trying to call underlying OS API !
One way to solve this is by modifying CAPIHook to check whether it is alright to replace local IAT.
1.) New attribute m_bIncludeLocalIAT added to CAPIHook and ctor/dtor modified accordingly.
class CAPIHook
{
...
CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT = TRUE);
...
BOOL m_bIncludeLocalIAT;
...
};
CAPIHook::CAPIHook( PSTR pszCalleeModName, PSTR pszFuncName,
PROC pfnHook, BOOL bIncludeLocalIAT) {
...
m_bIncludeLocalIAT = bIncludeLocalIAT;
...
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook, m_bIncludeLocalIAT);
}
CAPIHook::~CAPIHook() {
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig, m_bIncludeLocalIAT);
...
}
2.) New parameter added to the static function CAPIHook::ReplaceIATEntryInAllMods.
static void WINAPI ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnOrig, PROC pfnHook, BOOL bReplaceLocalIAT){
HMODULE hmodThisMod = ExcludeAPIHookMod
? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
// Get the list of modules in this process
CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me = { sizeof(me) };
for (BOOL bOk = th.ModuleFirst(&me); bOk; bOk = th.ModuleNext(&me)) {
if (bReplaceLocalIAT || (me.hModule != hmodThisMod)) {
// Hook this function in this module
ReplaceIATEntryInOneMod(
pszCalleeModName, pfnCurrent, pfnNew, me.hModule);
}
}
}
3.) Update the static CAPIHook instances
CAPIHook CAPIHook::sm_LoadLibraryA ("Kernel32.dll", "LoadLibraryA",
(PROC) CAPIHook::LoadLibraryA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryW ("Kernel32.dll", "LoadLibraryW",
(PROC) CAPIHook::LoadLibraryW, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC) CAPIHook::LoadLibraryExA, FALSE);
CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC) CAPIHook::LoadLibraryExW, FALSE);
CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC) CAPIHook::GetProcAddress, FALSE);