Skip to content

Instantly share code, notes, and snippets.

@justaguywhocodes
Created January 28, 2026 14:45
Show Gist options
  • Select an option

  • Save justaguywhocodes/c0b12ed5d16dd59446c90a9832e59aa1 to your computer and use it in GitHub Desktop.

Select an option

Save justaguywhocodes/c0b12ed5d16dd59446c90a9832e59aa1 to your computer and use it in GitHub Desktop.
// testdll.c
// Simple Windows DLL that exports a function compatible with rundll32.exe
// When called via rundll32.exe testdll.dll,ExecuteTest
// it writes "test executed" to C:\Users\Public\Downloads\test.txt
#include <windows.h>
#include <stdio.h>
// Exported function (rundll32-compatible signature)
extern "C" __declspec(dllexport) void CALLBACK ExecuteTest(
HWND hwnd, // unused
HINSTANCE hinst, // unused
LPSTR lpszCmdLine, // unused
int nCmdShow // unused
)
{
FILE* file = NULL;
errno_t err = fopen_s(&file, "C:\\Users\\Public\\Downloads\\test.txt", "w");
if (err == 0 && file != NULL)
{
fprintf(file, "test executed");
fclose(file);
}
// If fopen_s fails, file remains NULL and nothing is written (silent failure, same as original)
}
// Required DllMain (minimal implementation)
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#include "pch.h"
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
// DLL entry point
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// Exported function for regsvr32 compliance
EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllRegisterServer(void) {
// For testing purposes, this installs a sample service that loads a DLL (e.g., core.dll)
// Note: This requires administrative privileges to run successfully.
// In a real scenario, adjust paths and ensure the target DLL exists.
// This is a simulation of the TTP; use in isolated environments only.
SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL;
HRESULT hr = S_OK;
// Open the service control manager
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// Define the service parameters
// Assuming core.dll is in C:\Test\ and has an export named "Run" (adjust as needed)
// The binPath uses rundll32.exe to load and execute the DLL's export
TCHAR szBinPath[MAX_PATH];
StringCchPrintf(szBinPath, MAX_PATH, _T("C:\\Windows\\System32\\rundll32.exe C:\\temp\\core.dll,ExecuteTest"));
// Create the service
schService = CreateService(
schSCManager, // SCM database
_T("TestStagerService"), // Service name (change for uniqueness)
_T("Test Stager Service"), // Display name
SERVICE_ALL_ACCESS, // Desired access
SERVICE_WIN32_OWN_PROCESS, // Service typec
SERVICE_AUTO_START, // Start type
SERVICE_ERROR_NORMAL, // Error control
szBinPath, // Path to service binary
NULL, // No load ordering group
NULL, // No tag identification
NULL, // No dependencies
NULL, // LocalSystem account
NULL // No password
);
if (schService == NULL) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_EXISTS) { // Ignore if service already exists
hr = HRESULT_FROM_WIN32(err);
goto Cleanup;
}
}
// Optionally start the service (comment out if not needed)
// StartService(schService, 0, NULL);
Cleanup:
if (schService != NULL) {
CloseServiceHandle(schService);
}
if (schSCManager != NULL) {
CloseServiceHandle(schSCManager);
}
return hr;
}
// Optional: DllUnregisterServer to remove the service (for completeness)
EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllUnregisterServer(void) {
SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL;
HRESULT hr = S_OK;
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
schService = OpenService(schSCManager, _T("TestStagerService"), DELETE | SERVICE_STOP);
if (schService == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// Stop the service if running
SERVICE_STATUS_PROCESS ssp;
DWORD dwBytesNeeded;
QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded);
if (ssp.dwCurrentState != SERVICE_STOPPED) {
ControlService(schService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ssp);
}
// Delete the service
if (!DeleteService(schService)) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
Cleanup:
if (schService != NULL) {
CloseServiceHandle(schService);
}
if (schSCManager != NULL) {
CloseServiceHandle(schSCManager);
}
return hr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment