October 16, 2009

Sudo for Windows 7/Vista

Posted in For Developers, Intermediate at 6:20 pm by gloriouscomputing

It’s no secret that I like using my keyboard to get things done. It’s also no secret that Windows 7/Vista’s UAC comes up when a program asks for Admin rights. But what about if you want to run a program as Admin that doesn’t always need to be run as Admin? By default it’s just run as user, and you won’t be able to do what you need to.

For example, if I just run Notepad, I can’t save files in C:\

So what you have to do is Right-Click Notepad, and click “Run as Admin”… but what if I don’t want to? What if I want to script the same action? No luck. Windows 7 has a tool called “RunAs.exe”, but it only lets you switch to users with their Username+Password. I just want to run as myself with admin rights!

Linux people have sudo, so I just coded up a sudo.exe (in NSIS). It works just like you’d hope: “sudo.exe Notepad.exe”… or “sudo Notepad”. Of course, you’ll have to set it up so you can use it from anywhere yourself. The code for this tool is super-easy:

Name “sudo”
OutFile “sudo.exe”
SilentInstall silent
RequestExecutionLevel admin

Section
Call GetParameters
pop $0
exec $0
SectionEnd

My only problem with it is that my sudo.exe is 33kb. That’s huge for such a simple tool. If someone could code the same functionality into a smaller exe (C++ maybe?), I’d appreciate it. (I’ve tried writing it in AutoHotKey/AutoIt too, but both were even bigger!) Please let me know if you can help in the comments. Thanks!

Download Sudo

Update: Thanks everyone for the provided solutions below in the comments! Smallest solution thus far is Elevate.exe by Christof Germishuizen.

Advertisements

13 Comments »

  1. Peter DeGregorio said,

    Thanks very much for this nice solution.

    I’m going to leave a couple of pointers in case they might be useful to others. One has to do with creating the .exe and the other is about use.

    1. I downloaded NSIS 2.46 (never used before) and the exact code above would not compile. I had to add !include “FileFunc.nsh” and change Call GetParameters to ${GetParameters}

    2. I was able to use notepad directly … for example
    sudo notepad C:\Windows\system32\drivers\etc\hosts
    but mklink required adding cmd /c … for example
    sudo cmd /c mklink /d Java C:\Apps\Java\jdk1.5.0_17

  2. Christof Germishuizen said,

    hey,

    i just whacked this together quickly. forgive if it’s buggy. 😛

    compile it with lccwin32 (available @ http://www.q-software-solutions.de/downloaders )

    regards,
    christof

    elevate.c
    —–o/—–
    #include
    #include

    void parseCmdLine(LPSTR lpCmdLine, int *argc, TCHAR **argv[]) {
    if (lpCmdLine && *lpCmdLine) {
    size_t len = 0;
    int c = *argc;
    TCHAR *delimiter = 0;
    // ignore extra space chars
    if(*lpCmdLine == ‘ ‘) {
    lpCmdLine++;
    len = strspn(lpCmdLine, ” “);
    } else {
    // if first character is a double-quote, look for another, else look for a space.
    len = *lpCmdLine == ‘”‘
    ? strcspn(++lpCmdLine, delimiter=”\””)
    : strcspn(lpCmdLine, delimiter=” “);
    if ( len > 0 ) {
    *argv = realloc(*argv, (c + 1) * sizeof(TCHAR*));
    (*argv)[c] = malloc(len + 1);
    (*argv)[c][len] = 0;
    strncpy((*argv)[c], lpCmdLine, len);
    c++;
    }
    if (delimiter[0] == ‘”‘ && lpCmdLine[len] != 0) lpCmdLine++;
    }
    *argc = c;
    lpCmdLine += len;
    parseCmdLine(lpCmdLine, argc, argv);
    }
    }

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
    int result;
    TCHAR *message = “”;
    int argc = 0;
    TCHAR **argv = NULL;

    parseCmdLine(lpCmdLine, &argc, &argv);

    if (argc > 0) {
    //rebuild the command line and arguments neatly
    TCHAR *cmdLine = “”;
    TCHAR *argS = “”;
    if (strchr(argv[0], ‘ ‘)) wsprintf(cmdLine, “\”%s\””, argv[0]);
    else wsprintf(cmdLine, “%s”, argv[0]);
    for (int i = 1; i < argc; i++ )
    {
    if (strchr(argv[i], ' ')) wsprintf(argS, "%s \"%s\"", argS, argv[i]);
    else wsprintf(argS, "%s %s", argS, argv[i]);
    }
    //execute it 🙂
    ShellExecute(NULL, "runas", cmdLine, argS, NULL, SW_SHOWNORMAL);
    result = 0;
    } else {
    wsprintf(message, "%s [parameters]”, GetCommandLine());
    MessageBox(NULL, TEXT(message), TEXT(“Usage”), MB_OK);
    result = 1;
    }

    while(argc) free(argv[–argc]);
    free(argv);

    return result;
    }
    —–o\—–

    build.cmd
    —–o/—–
    @echo off
    if exist elevate.exe del elevate.exe
    lcc -O elevate.c
    lcclnk -s -subsystem windows elevate.obj shell32.lib
    if exist elevate.res del elevate.res
    if exist elevate.obj del elevate.obj
    —–o\—–

    • Christof Germishuizen said,

      meh.
      wordpress (what a piece of crap?!) mangled just about everything on that post. it won’t compile as is…
      so fix it.

      first 2 lines:
      #include <windows.h>
      #include <shellapi.h>

      unicode:
      1. replace all U+2018 and U+2019 characters with regular apostrophes (U+0027)
      2. replace all U+201C and U+201D characters with regular quotation marks (U+0022)

      • Xavier said,

        Hey Christof,

        Really want that c code 🙂 however im not that flash at c at the moment and I am unable to repair the wordpress editing… 🙂

        I replaced the unicode characters and includes as directed but it still doesnt run for me, could you perhaps just email me the code if possible ^^ (I hope you can cause im opening myself up for some serious crawler spam here lol)

        xavier.hutchinson@epicentre.com.au

        Cheers!

      • gloriouscomputing said,

        Or, why not just put it on http://pastebin.com/ or something for everyone to enjoy?

  3. Eish. Sorry guys, didn’t see anyone replied.

    Here’s the c code: http://pastebin.com/cQcixqBu
    Compile it as I described above.

    Or if you’re way too lazy an ass to compile it yourself… here’s a UUencoded elevate.exe 😛 http://pastebin.com/KuVBWgHP

    If you don’t know how to decode it, just ask google.

    Hope this helps.

  4. Akuma said,

    thanks alot. your sudo saved my day!

  5. Craig Nykamp said,

    I just found this page after searching for a way to set the “Run” box in Windows 7 to always run as admin (with UAC kept on of course).

    After someone pointing me here, and after the OP saying his was 33KB, I have come up with a 5KB solution.

    I’ve named is su.exe as that’s my preference. Simply stick it in C:\Windows\ – you can then run your application using the same method as in the original post (su notepad).

    Download: http://www.nykamp.co.uk/su.exe
    For the paranoid: http://www.virustotal.com/file-scan/report.html?id=48521c06976d833192c378f27e33c143461316d6bcd6da04b818187297f452c3-1284052926

    • Christof Germishuizen said,

      Eh? Did you notice that the above elevate.exe is only 4128bytes compared to your 5120bytes? Wuhrd.

      • Craig Nykamp said,

        Nope. Didn’t look tbh :p

      • Christof Germishuizen said,

        lol. redundancy fail.

      • Christof Germishuizen said,

        uhm, also…

        please could you explain the point of not being able to do the following with your program?

        su notepad.exe /p c:\windows\win.ini

        even trying this does not work:

        su.exe ping localhost

        haha… what the…?

  6. Anonymous said,

    The above solutions work well however because all of these are 32-bit binaries, the file system redirection is at work on 64-bit Windows and redirects it to %windir%\syswow64 and one can’t launch 64-bit binaries from %windir%\system32. Can there be a single sudo which can launch both 32-bit and 64-bit processes or a separate 64-bit EXE?


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: