// ==WindhawkMod== // @id new-mod // @name Your Awesome Mod // @description The best mod ever that does great things // @version 0.1 // @author You // @github https://github.com/nat // @twitter https://twitter.com/jack // @homepage https://your-personal-homepage.example.com/ // @include mspaint.exe // @compilerOptions -lcomdlg32 // ==/WindhawkMod== // ==WindhawkModReadme== /* # Your Awesome Mod This is a place for useful information about your mod. Use it to describe the mod, explain why it's useful, and add any other relevant details. You can use [Markdown](https://en.wikipedia.org/wiki/Markdown) to add links and **formatting** to the readme. This short sample customizes Microsoft Paint by forcing it to use just a single color, and by blocking file opening. To see the mod in action: - Compile the mod with the button on the left or with Ctrl+B. - Run Microsoft Paint from the start menu (type "Paint") or by running mspaint.exe. - Draw something and notice that the orange color is always used, regardless of the color you pick. - Try opening a file and notice that it's blocked. # Getting started Check out the documentation [here](https://github.com/ramensoftware/windhawk/wiki/Creating-a-new-mod). */ // ==/WindhawkModReadme== // ==WindhawkModSettings== /* # Here you can define settings, in YAML format, that the mod users will be able # to configure. Metadata values such as $name and $description are optional. # Check out the documentation for more information: # https://github.com/ramensoftware/windhawk/wiki/Creating-a-new-mod#settings - color: - red: 255 - green: 127 - blue: 39 $name: Custom color $description: This color will be used regardless of the selected color. - blockOpen: true $name: Block opening files $description: When enabled, opening files in Paint is not allowed. */ // ==/WindhawkModSettings== // The source code of the mod starts here. This sample was inspired by the great // article of Kyle Halladay, X64 Function Hooking by Example: // http://kylehalladay.com/blog/2020/11/13/Hooking-By-Example.html // If you're new to terms such as code injection and function hooking, the // article is great to get started. #include using namespace Gdiplus; struct { BYTE red; BYTE green; BYTE blue; bool blockOpen; } settings; using GdipSetSolidFillColor_t = decltype(&DllExports::GdipSetSolidFillColor); GdipSetSolidFillColor_t GdipSetSolidFillColor_Original; GpStatus WINAPI GdipSetSolidFillColor_Hook(GpSolidFill* brush, ARGB color) { Wh_Log(L"GdipSetSolidFillColor_Hook: color=%08X", color); // If the color is not transparent, replace it. if (Color(color).GetAlpha() == 255) { color = Color::MakeARGB(255, settings.red, settings.green, settings.blue); } // Call the original function. return GdipSetSolidFillColor_Original(brush, color); } using GetOpenFileNameW_t = decltype(&GetOpenFileNameW); GetOpenFileNameW_t GetOpenFileNameW_Original; BOOL WINAPI GetOpenFileNameW_Hook(LPOPENFILENAMEW params) { Wh_Log(L"GetOpenFileNameW_Hook"); if (settings.blockOpen) { // Forbid the operation and return without calling the original // function. MessageBoxW(GetActiveWindow(), L"Opening files is forbidden", L"Surprise!", MB_OK); return FALSE; } return GetOpenFileNameW_Original(params); } void LoadSettings() { settings.red = Wh_GetIntSetting(L"color.red"); settings.green = Wh_GetIntSetting(L"color.green"); settings.blue = Wh_GetIntSetting(L"color.blue"); settings.blockOpen = Wh_GetIntSetting(L"blockOpen"); } // The mod is being initialized, load settings, hook functions, and do other // initialization stuff if required. BOOL Wh_ModInit() { Wh_Log(L"Init"); LoadSettings(); HMODULE gdiPlusModule = LoadLibrary(L"gdiplus.dll"); GdipSetSolidFillColor_t GdipSetSolidFillColor = (GdipSetSolidFillColor_t)GetProcAddress(gdiPlusModule, "GdipSetSolidFillColor"); Wh_SetFunctionHook((void*)GdipSetSolidFillColor, (void*)GdipSetSolidFillColor_Hook, (void**)&GdipSetSolidFillColor_Original); Wh_SetFunctionHook((void*)GetOpenFileNameW, (void*)GetOpenFileNameW_Hook, (void**)&GetOpenFileNameW_Original); return TRUE; } // The mod is being unloaded, free all allocated resources. void Wh_ModUninit() { Wh_Log(L"Uninit"); } // The mod setting were changed, reload them. void Wh_ModSettingsChanged() { Wh_Log(L"SettingsChanged"); LoadSettings(); }