VC++ project, how to define DLL missing error messages? - c++

So the idea is when the user haven't installed DirectX End-User Runtime the program to show message like "DirectX Runtime missing! Download it from here", instead of the windows loader error (eg.: "d3dx9_43.dll is missing!"). So I find a very funky solution of the problem as I used a delay loaded DLL's and an DLL check before any function defined in the module is invoked using LoadLibrary. If the dll is missing the program shows a user-defined dialog box and exits, otherwise it calls FreeLibrary with the HMODULE returned by LoadLibrary and continues executing. This is implemented as a function like follows:
bool CheckResourcesAvailability() //Mainly check for the existence of delay loaded DLL's
{
HMODULE hMod; //Resourse handle
if((hMod = LoadLibraryEx(_T("d3d9.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) == NULL)
{
DialogBox(hProgramInstance, MAKEINTRESOURCE(IDD_DX_RE), 0, (DLGPROC)&DxRedistMissingDlg);
return false;
}
FreeLibrary(hMod);
if((hMod = LoadLibraryEx(_T("D3DX9_43.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) == NULL)
{
DialogBox(hProgramInstance, MAKEINTRESOURCE(IDD_DX_RE), 0, (DLGPROC)&DxRedistMissingDlg);
return false;
}
FreeLibrary(hMod);
return true;
}
*As DxRedistMissingDlg and MAKEINTRESOURCE(IDD_DX_RE) creates the user-defined error message dialog.
And In WinMain it's called as follows:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hProgramInstance = hInstance;
#ifndef _DEBUG
SetErrorMode(SEM_FAILCRITICALERRORS); //Don't display windows error messages
#endif
//Check for missing delay - loaded dependencies and inform the user
if(!CheckResourcesAvailability())
return -1;
//Some other code.........
}
But I don't think this is the cleanest way to do it. First we aren't sure that d3dx9.lib really inherits from D3DX9_43.dll (I know that because I used IDA PRO) and also the LoadLibrary function is called twice - one time at the CheckResourcesAvailability() function and second when the DLL is delay-loaded. Any ideas for a better implementation?

Use delay load hooks to let the delay loader notify you whenever a given DLL or a specific exported function is missing. Not only does that tell you which DLL/function is missing, but also lets you specify a substitute DLL/function if desired.

Related

What is invoke_main and mainCRTStartup?

I have a CUI based and GUI based application that is written with CPP language. GUI based application has the following code:
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const TCHAR* title = TEXT("پیام");
const TCHAR* text = TEXT("سلام، من یک پنجره هستم.");
MessageBox(NULL, text, title, MB_OKCANCEL | MB_ICONINFORMATION);
return 0;
}
and CUI based program has the following code:
#include <Windows.h>
#include <iostream>
int main(int argc, const char* argv)
{
const char* cMessage = "Native Windows Development.\n";
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), cMessage, strlen(cMessage), NULL, NULL);
return 0;
}
However, when I debug these programs in WinDBG, I have seen before main and WinMain function, a lot of other functions like mainCRTStartup and invoke_main for CUI based app and WinMainCRTStartup and invoke_main for GUI based app have called.
What are these functions and what they did before executing the main? and also how can I get more information about these two function?
With VS tool, we could see the call stack below:
And if you double-click on each call of the stack, you could see what it did in the code(as comments, the source code was located at ..\VC\Tools\MSVC\14.24.28314\crt\src\vcruntime).
First wWinMainCRTStartup is just to call function __scrt_common_main:
extern "C" int wWinMainCRTStartup()
{
return __scrt_common_main();
}
In __scrt_common_main, the comments contains the detals:
// This is the common main implementation to which all of the CRT main functions
// delegate (for executables; DLLs are handled separately).
static __forceinline int __cdecl __scrt_common_main()
{
// The /GS security cookie must be initialized before any exception handling
// targeting the current image is registered. No function using exception
// handling can be called in the current image until after this call:
__security_init_cookie();
return __scrt_common_main_seh();
}
The function is the common main implementation to which all of the CRT
main functions delegate (for executables; DLLs are handled
separately) and __security_init_cookie is to initialize /GS security cookie
before any exception handling for current image.
Then, it was the __scrt_common_main_seh:
initialize crt, acquire startup lock, check the current native startup state, release startup lock, invoke the dynamically initialized __declspec(thread) variables, register the callback function for thread-local destructors.
After complete the Initialization, call invoke_main, as the name, it invoke main/wWinMain.
static int __cdecl invoke_main()
{
return wWinMain(
reinterpret_cast<HINSTANCE>(&__ImageBase),
nullptr,
_get_wide_winmain_command_line(),
__scrt_get_show_window_mode());
}

Hooking with MS Detours crash when hook function is called C++

I wrote a simple program that does 3 things:
It calls MessageBoxA (MBA) with the text "NOT HOOKED"
Then it loads a dll file that I've created that hooks the MBA function and recalls MBA with the text "HOOKED".
After that, it calls MBA again with the same text ("NOT HOOKED").
Of course, the second MBA call should be hooked and display a message with "HOOKED" text it.
Eventually it calls FreeLibrary and exits.
Here is the .cpp file:
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
//Place the path of the dll file here, "DLLs\\HookDLL.dll" is the default path.
char dllPath[] = "HookDLL.dll";
//Display a pop-up message with the "NOT HOOKED" message and title.
MessageBoxA(NULL, "NOT HOOKED", "NOT HOOKED", MB_OK);
//Load the dll file
HMODULE hModule = LoadLibraryA((LPCSTR)dllPath);
//If hModule is null, then the dll wasn't loaded.
//An error message will be printed out to the console.
if (!hModule) {
cout << "Couldn't load the DLL file!" << endl;
return 1;
}
//This is the tricky part.
//This should display a pop-up message like before with the "NOT HOOKED" message and title,
//but the dll that was loaded should hook MessageBoxA function,
//and call a new one with a "HOOKED" message and title instead.
MessageBoxA(NULL, "NOT HOOKED", "NOT HOOKED", MB_OK);
FreeLibrary(hModule);
return 0;
}
here is the .dll file:
#include "pch.h"
#include "detours.h"
#include <iostream>
#include <Windows.h>
using namespace std;
typedef int(WINAPI* MBA)(HWND, LPCSTR, LPCSTR, UINT);
MBA originalMBA = NULL;
int HookedMessageBoxA(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
) {
return originalMBA(NULL, "HOOKED", "HOOKED", MB_OK);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD reason,
LPVOID lpReserved
)
{
if (reason == DLL_PROCESS_ATTACH) {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
originalMBA = (MBA)DetourFindFunction("user32.dll", "MessageBoxA");//Pointer the the original MBA (MessageBoxA) function.
DetourAttach(&(PVOID&)originalMBA, (PVOID)HookedMessageBoxA);
DetourTransactionCommit();
}
return TRUE;
}
When I build and run on Debug mode, it crashes on the second MBA call (in the .cpp file of course):
It displays the hooked MBA with "HOOKED" in it like it should, then the it crashes, printing the error below and the program exits with code 3:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one calling convention with a function
pointer declared with a different calling convention.
I've checked this error and the exit code and found lots of informative posts and solutions, but I couldn't make any of them work for me (maybe I've done something wrong).
NOTE1:
If I'm on Release mode, I can call as many MBA calls as I want as long as they precedes the FreeLibrary call, and all of them will be hooked fine by the .dll file, and the program will exit correctly.
But if I try to call the MBA function after the FreeLibrary call - the program crashes with this error:
Exception thrown at 0x50011000 in ProgrammingTask.exe: 0xC0000005: Access violation executing location 0x50011000.
NOTE2:
I tried detaching the dll using DetourDetouch, but it didn't solve it, maybe I did it wrong.
Also, I tried reading about CreateRemoteThread, but was too messy for me.
Thanks in advance.
FOUND IT!
Forgot to add __stdcall to the HookedMessageBox function.
So, instead of int HookedMessageBoxA
I rewrote it to this:
int __stdcall HookedMessageBoxA
Thanks all for your help! <3

Windows 7 taskbar state with minimal code

What would be the shortest code to set the state of a Windows 7 taskbar button for a known window handle?
The goal is to write a console utility that changes the progress and state (colour) of the console window taskbar item from a batch script. While the script performs different tasks, the taskbar item of its console window should represent the current state.
I get the window handle with the GetConsoleWindow() function, but then it seems to require loads of COM and Shell API stuff that I don't understand. One example I've found uses a whole GUI application with MFC to demonstrate the API, but most of it is way too complicated for my little tool and I don't understand it well enough to remove the stuff I don't need.
The tool should compile on Windows 7 with VS2010 (C++) but also run on earlier Windows versions (doing nothing if a feature is not available).
I created a class to set the progress in the Win7 taskbar for a project at one time. It's a wrapper for the ITaskBarList3 interface available from the Windows Shell. It's specifically done with ITaskBarList3.SetProgressState and ITaskBarList3.SetProgressValue functions.
This is the code I dug up:
#include <shobjidl.h>
#include <windows.h>
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Ole32.lib")
class Win7TaskbarProgress
{
public:
Win7TaskbarProgress();
virtual ~Win7TaskbarProgress();
void SetProgressState(HWND hwnd, TBPFLAG flag);
void SetProgressValue(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal);
private:
bool Init();
ITaskbarList3* m_pITaskBarList3;
bool m_bFailed;
};
Win7TaskbarProgress::Win7TaskbarProgress()
{
m_pITaskBarList3 = NULL;
m_bFailed = false;
}
Win7TaskbarProgress::~Win7TaskbarProgress()
{
if (m_pITaskBarList3)
{
m_pITaskBarList3->Release();
CoUninitialize();
}
}
void Win7TaskbarProgress::SetProgressState( HWND hwnd, TBPFLAG flag )
{
if (Init())
m_pITaskBarList3->SetProgressState(hwnd, flag);
}
void Win7TaskbarProgress::SetProgressValue( HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal )
{
if (Init())
m_pITaskBarList3->SetProgressValue(hwnd, ullCompleted, ullTotal);
}
bool Win7TaskbarProgress::Init()
{
if (m_pITaskBarList3)
return true;
if (m_bFailed)
return false;
// Initialize COM for this thread...
CoInitialize(NULL);
CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_pITaskBarList3);
if (m_pITaskBarList3)
return true;
m_bFailed = true;
CoUninitialize();
return false;
}
Note you still need to call RegisterWindowMessage("TaskbarButtonCreated") and ChangeWindowMessageFilterEx() to setup an message filter before SetProgressValue() can work.
According to the MSDN docs you are supposed to recreate your object each time you get the created message but I found I just had to do the ChangeWindowMessageFilterEx() and it works fine for normal circumstances.

Create a DLL that can be run

Windows has an utility called rundll32.exe that can execute native dynamic link libraries as applications.
Say I have a piece of code that prints "Hello World!" to the console. Is it possible to write a library in C++ (preferably Visual C++) that can be executed using rundll32.exe and will run this code? If so, how?
Googling "rundll32", the 3rd hit was a link to documentation,
http://support.microsoft.com/kb/164787
According to that documentation, rundll32 calls a user-specified function with signature like wWinMain (except the first argument here is a window handle instead of an instance handle),
void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
So, trying this out:
// File [foo.def]
EXPORTS
sayHello
// File [foo.cpp]
#include <iostream>
namespace myCode {
void sayHello()
{
using namespace std;
cout << "Hello, world!" << endl;
}
} // namespace myCode
#undef UNICODE
#define UNICODE
#include <windows.h>
extern "C"
__declspec( dllexport )
void CALLBACK sayHello( HWND, HINSTANCE, wchar_t const*, int )
{
AllocConsole();
freopen( "CONIN$", "r", stdin );
freopen( "CONOUT$", "w", stdout );
freopen( "CONOUT$", "w", stderr );
DWORD const infoBoxOptions = MB_ICONINFORMATION | MB_SETFOREGROUND;
MessageBox( 0, L"Before call...", L"DLL message:", infoBoxOptions );
myCode::sayHello();
MessageBox( 0, L"After call...", L"DLL message:", infoBoxOptions );
}
Building & running:
[d:\dev\test]
> cl foo.cpp foo.def user32.lib /MD /LD /D _CRT_SECURE_NO_WARNINGS
foo.cpp
Creating library foo.lib and object foo.exp
[d:\dev\test]
> rundll32 foo.dll,sayHello
[d:\dev\test]
> _
The output is presented in its own console window, created via AllocConsole, which is generally necessary since rundll32 is a GUI subsystem program (this is also the reason for the freopen calls).
To present the output in an existing console window one can just omit the calls to AllocConsole and freopen, and redirect standard output of rundll32 to a pipe. E.g. standard output can be piped through Windows’ more when the output is just a few lines, or through some *nix-utility cat for more lines. However, in the standard command interpreter [cmd.exe] it doesn’t work to just redirect the output to con.
http://support.microsoft.com/kb/164787
This MSDN article I believe is still accurate; you define an entrypoint as
void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
While it is possible to use rundll32 to run a properly-designed function in a DLL, it is not recommended. Doing so means that your DLL is at the mercy of rundll32's process settings (large address awareness, terminal service awareness, DPI awareness, elevation manifest, etc.) Even worse: If some other rundll32 process triggers an application compatibility behavior (such as low fragmentation heap), then that will affect all rundll32 processes including yours.
Just write a separate EXE.
Like said by Joe and yourself, use something like this:
void CALLBACK func(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
std::cout << "Hello world!" << std::endl;
}
However, CALLBACK = __stdcall, which, when your "func" is exported will changed to _func#16
You could change this name, http://support.microsoft.com/kb/140485
so, you might want to try something similar to this:
rundll32.exe DLLTest.dll,_func#16

Global Keyboard hook not working

I have created a global Keyboard hook.
Hook is created in a DLL.
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hkb=NULL;
static CMyFile *pLF;
#pragma data_seg()
HINSTANCE hins = NULL;
extern "C"
LRESULT __declspec(dllexport) __stdcall CALLBACK KeyBoardHookProc(
int nCode,
WPARAM wParam,
LPARAM lParam)
{
if (nCode < 0) {
return CallNextHookEx(0, nCode, wParam, lParam);
}
return CallNextHookEx(hkb, nCode, wParam, lParam);
}
extern "C"
LRESULT __declspec(dllexport) __stdcall CALLBACK Install()
{
pLF = new CMyFile(L"c:\\1.txt");
hkb = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardHookProc,hins,0);
return 0;
}
extern "C"
BOOL __declspec(dllexport) __stdcall CALLBACK UnInstall()
{
return UnhookWindowsHookEx(hkb);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH :
hins = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH :
break;
case DLL_THREAD_DETACH :
break;
case DLL_PROCESS_DETACH :
break;
}
return TRUE;
}
I have craeted one EXe that loads this dll and calls install function of the hook dll.
HMODULE hMod = LoadLibrary(L"hk.dll");
if(hMod!=NULL)
{
typedef LRESULT (__stdcall CALLBACK *_installhk)() ;
_installhk installProc;
installProc = (_installhk) GetProcAddress(hMod,"Install");
if(installProc!=NULL)
{
installProc();
}
}
While debugging breakpoint on KeyBoardHookProc is being hit only once when I launch the exe.
The exe keeps on running unless I close it but if I enter anything else from keyboard the hook procedure not getting called.
What could be the reason for this?
Is this not the right way to setup global keyboard hook?
How did you test that the hook procedure is not called ? If you tried to check it with a breakpoint, you have to take care that your hook dll is loaded in every process but your breakpoint is only put in your current process.
If you have any window in your application, focus on it before hitting keys or debug it using logs.
Another solution is to hook with WH_KEYBOARD_LL which does not require an extra DLL. You can hook directly from your process.
Have a look at the late Paul DiLascia's code which installs a global keyboard hook to trap the Ctrl+Alt+Del, Task Manager. MSDN September 2002 'Disabling keys in XP with TrapKeys'
Hope this helps,
Best regards,
Tom.
This may not be directly related to your main problem, but your use of the CMyFile object has several issues:
The CMyFile object is allocated dynamically using new CMyFile(...). This will create it only in the memory space of one process.
The pLF pointer is uninitialized. This means it will be placed in the BSS segment instead of the shared data segment. To fix this, declare it with CMyFile *pLF = NULL;.
CMyFile itself probably has members containing file handles and/or pointers which won't work properly in other processes.
Regarding your main question:
You seem to be creating the hook correctly as far as I can see.
There is no need to cast to HOOKPROC in the call to SetWindowsHookEx. If you get a warning without it, there is a problem with your function type.
There's no need for the if statement in the hook proc - the first parameter to CallNextHookEx is ignored anyway on modern Windows, so both branches effectively do the same thing.
I don't know if I'd trust debugger breakpoints on a hook procedure called from different processes - it's possible that the procedure is called but the debugger isn't catching it.
extern "C" is good it will get rid of the name mangling mentioned above but __stdcall will conflict with this.
You should use the RegisterHoyKey API call instead - it's much less hassle (as I found out myself recently when I replaced a similar keyboard hook DLL!).
Check your export section for DLL and see what name linker exported your "Install" function. C++ mangles with export function names. I bet you anything it is not "Install" but rather _Install#12 or something like that.