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
Related
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());
}
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
I am trying to hook StartDocW to intercept printing via mhook. I use AppInit_DLLs to load my library.
DLL code is simple:
#include <windows.h>
#include "mhook/mhook-lib/mhook.h"
using StartDocPtr = int(*)(HDC, const DOCINFO*);
StartDocPtr orig;
int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
return orig(hdc, lpdi);
}
BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
orig = (StartDocPtr)GetProcAddress(GetModuleHandle("gdi32"), "StartDocW");
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook((PVOID*)&orig);
break;
}
}
Hook is working and printing is done OK. But If I change HookStartDocW to following:
int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
char buf[40];
GetModuleFileName(NULL, buf, 40);
return orig(hdc, lpdi);
}
Programs on printing will crash immediately. Even if I just leave char buf[40] and comment GetModuleHandle - program will hang. Why is this happening?
Moreover, if program crashes\hangs on printing (if I add anything besides return orig(hdc, lpdi)) - PC starts to behave very weirdly, refusing to run programs, etc. If I reboot it - Windows just endlessly spins on boot screen, the only way to bring it back to live - is to boot via liveCD and rename\delete my hook DLL.
Printing programs: Excel 2016, notepad.
Compiler - MSVC 2015, x64 release DLL compilation, using MBCS instead of unicode.
Your hook is declared wrong.
Look at the actual declaration of StartDocW() in Wingdi.h:
__gdi_entry WINGDIAPI int WINAPI StartDocW(__in HDC hdc, __in CONST DOCINFOW *lpdi);
You can ignore __gdi_entry. WINGDIAPI simply resolves to __declspec(dllimport). What is important in this declaration is the WINAPI.
Like almost all Win32 API functions, StartDocW() uses the __stdcall calling convention. The WINAPI macro resolves to __stdcall.
Your code does not specify any calling convention at all, so it uses your compiler's default, which is usually __cdecl instead. So you are mismanaging the call stack. That is why your code crashes.
You are also using DOCINFO when you should be using DOCINFOW instead. It is clear in your code that you are compiling for MBCS and not for UNICODE, so DOCINFO maps to DOCINFOA. You can't pass a DOCINFOA to StartDocW(), it expects a DOCINFOW instead.
You need to fix your declarations, eg:
#include <windows.h>
#include "mhook/mhook-lib/mhook.h"
using StartDocPtr = int (WINAPI *)(HDC, const DOCINFOW*);
StartDocPtr orig = nullptr;
int WINAPI HookedStartDocW(HDC hdc, const DOCINFOW* lpdi) {
//...
return orig(hdc, lpdi);
}
BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
orig = (StartDocPtr) GetProcAddress(GetModuleHandle(TEXT("gdi32")), "StartDocW");
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook((PVOID*)&orig);
break;
}
}
I made a very simple program that create a windows and display "Random number is: [random number from 0 to 9]" in the top left corner. The function that display the number looks like this:
void DisplayThings(HDC hdc, HWND hWnd, int randomNum)
{
std::stringstream text;
text << "Random number is: " << randomNum;
TextOut(hdc, 0, 0, text.str().c_str(), text.str().length());
}
In OllyDBG, I found it at the address 0x11211A0:
Next, I made a dll that tries to detour the DisplayThings function with the help of Microsoft Detour, here is what the dll looks like:
#pragma comment(lib, "detours.lib")
#include <Windows.h>
#include <detours.h>
#include <tchar.h>
#include <sstream>
typedef void (*pDisplayThingsFunc)(HDC hdc, HWND hWnd, int randomNum);
void DisplayThingsFunc(HDC hdc, HWND hWnd, int randomNum)
{
printf("function is being detoured\n");
TextOut(hdc, 0, 20, L"detoured", 8);
}
pDisplayThingsFunc DisplayThingsFuncToDetour = (pDisplayThingsFunc)(0x11211A0);
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
//DWORD *hiddenValueAdress = (DWORD*)(*(DWORD*)0x020FAB8);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);
DetourTransactionCommit();
break;
}
return TRUE;
}
Once I inject the dll, the address get correctly replaced with a JMP to my new functions, but then something weird happens... The console keep printing "function is being detoured" but the TextOut function fails to display anything...
Any help would be appreciated!
The compiler is optimizing the code, because it deduced that it could safely do so for this function.
It is not exported.
It is not used with function pointers.
It is not used outside the scope that is analyzed. (Depends on compiler settings)
There is most likely only one caller (if there are more different callers with different settings it's less likely that arguments get optimized away).
You could change one of those things (for example by exporting the symbol, by assigning it to a function pointer etc..).
Or you could try to hook it as-is now.
First you need to deduce where the argument you are interested in is getting passed trough, which is most likely a register.
The easiest way to do this is to analyze the call to TextOut and trace the hdc argument back.
If you are lucky and it got optimized simply by making it fastcall, change the type of both your function and your function pointer to fastcall, and be done.
If you are not that lucky, you might have to grab it from an extra register with inline assembly.
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.