This program will bring up a UAC prompt to run the specified program elevated in Windows Vista. It will bring up a 'Run As' dialog in Windows XP SP3. I'm not sure what it does in any other version of Windows.
; Link with /SUBSYSTEM:WINDOWS
.686
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
INCLUDE windows.inc
INCLUDE kernel32.inc
INCLUDE user32.inc
INCLUDE msvcrt.inc
INCLUDE shell32.inc
INCLUDE masm32.inc
INCLUDE c:\masm32\macros\macros.asm
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
INCLUDELIB msvcrt.lib
INCLUDELIB shell32.lib
INCLUDELIB masm32.lib
RunElevated PROTO :DWORD,:PTR BYTE,:PTR BYTE
GetErrorMessage PROTO :DWORD,:PTR BYTE,:DWORD
.CODE
start:
call main
INVOKE ExitProcess, 0
main PROC
LOCAL err:DWORD
LOCAL szBuffer[256]:BYTE
INVOKE RunElevated, NULL, SADD("regedit.exe"), NULL
.IF eax == FALSE
mov err, edx
INVOKE GetErrorMessage, err, ADDR szBuffer, SIZEOF szBuffer
INVOKE MessageBox, NULL, ADDR szBuffer, SADD("RunElevated"), MB_ICONERROR
.ENDIF
ret
main ENDP
;---------------------------------------
RunElevated PROC hWnd:DWORD, pFilename:PTR BYTE, pParameters:PTR BYTE
; Requests the OS to run the executable elevated.
; Returns TRUE if successful, or FALSE otherwise.
; If FALSE then return error information in edx
LOCAL sei:SHELLEXECUTEINFO
INVOKE RtlZeroMemory, ADDR sei, SIZEOF sei
mov sei.cbSize, SIZEOF SHELLEXECUTEINFO
mov eax, hWnd
mov sei.hwnd, eax
mov sei.fMask, SEE_MASK_FLAG_DDEWAIT OR SEE_MASK_FLAG_NO_UI
mov eax, CTXT("runas")
mov sei.lpVerb, eax
mov eax, pFilename
mov sei.lpFile, eax
mov eax, pParameters
mov sei.lpParameters, eax
mov sei.nShow, SW_SHOWNORMAL
INVOKE ShellExecuteEx, ADDR sei
.IF eax == FALSE
INVOKE GetLastError
mov edx, eax
xor eax, eax
.ELSE
mov eax, 1
.ENDIF
ret
RunElevated ENDP
;---------------------------------------
GetErrorMessage PROC dwErrorNum:DWORD, pBuffer:PTR BYTE, dwBufferLen:DWORD
LOCAL hModule :DWORD
LOCAL dwDefLangID:DWORD
LOCAL dwFlags :DWORD
LOCAL retv :SDWORD
LOCAL pTmpBuffer :PTR BYTE
mov hModule, NULL
mov pTmpBuffer, NULL
INVOKE GetUserDefaultLangID
mov dwDefLangID, eax
mov eax, FORMAT_MESSAGE_ALLOCATE_BUFFER OR FORMAT_MESSAGE_FROM_SYSTEM OR FORMAT_MESSAGE_IGNORE_INSERTS
mov dwFlags, eax
.IF dwErrorNum >= NERR_BASE && dwErrorNum <= MAX_NERR
INVOKE LoadLibraryEx, SADD("netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE
mov hModule, eax
.IF hModule != NULL
mov eax, dwFlags
or eax, FORMAT_MESSAGE_FROM_HMODULE
mov dwFlags, eax
.ENDIF
.ENDIF
INVOKE FormatMessage, dwFlags, hModule, dwErrorNum, dwDefLangID, ADDR pTmpBuffer, 0, NULL
.IF eax
dec dwBufferLen
INVOKE lstrcpyn, pBuffer, pTmpBuffer, dwBufferLen
INVOKE LocalFree, pTmpBuffer
mov retv, 0
.ELSE
INVOKE GetLastError
mov retv, eax
.ENDIF
.IF hModule != NULL
INVOKE FreeLibrary, hModule
.ENDIF
mov eax, retv
ret
GetErrorMessage ENDP
;---------------------------------------
END start
[edit] Updated GetErrorMessage (uses lstrcpyn instead of lstrcpy)
This one is a little more useful, accepts command line arguments. For Windows Vista.
; Link with /SUBSYSTEM:WINDOWS
.686
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
INCLUDE windows.inc
INCLUDE kernel32.inc
INCLUDE user32.inc
INCLUDE msvcrt.inc
INCLUDE shell32.inc
INCLUDE masm32.inc
INCLUDE c:\masm32\macros\macros.asm
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
INCLUDELIB msvcrt.lib
INCLUDELIB shell32.lib
INCLUDELIB masm32.lib
GetCommandLineItemsCount PROTO
GetCommandLineItem PROTO :DWORD
RunElevated PROTO :DWORD,:PTR BYTE,:PTR BYTE
GetErrorMessage PROTO :DWORD,:PTR BYTE,:DWORD
.CODE
start:
call main
INVOKE ExitProcess, 0
;---------------------------------------
main PROC
LOCAL pszCommand1:PTR BYTE
LOCAL pszCommand2:PTR BYTE
LOCAL err:DWORD
LOCAL szBuffer[256]:BYTE
INVOKE GetCommandLineItemsCount
.IF eax == 2
INVOKE GetCommandLineItem, 1 ; get the first argument
mov pszCommand1, eax
INVOKE lstrlen, pszCommand1
.IF eax > 0
INVOKE RunElevated, NULL, pszCommand1, NULL
.IF eax == FALSE
mov err, edx
INVOKE GetErrorMessage, err, ADDR szBuffer, SIZEOF szBuffer
INVOKE MessageBox, NULL, ADDR szBuffer, SADD("RunElevated"), MB_ICONERROR
.ENDIF
.ENDIF
.ELSEIF eax == 3
INVOKE GetCommandLineItem, 1 ; get the first argument
mov pszCommand1, eax
INVOKE GetCommandLineItem, 2 ; get the second argument
mov pszCommand2, eax
INVOKE lstrlen, pszCommand1
.IF eax > 0
INVOKE RunElevated, NULL, pszCommand1, pszCommand2
.IF eax == FALSE
mov err, edx
INVOKE GetErrorMessage, err, ADDR szBuffer, SIZEOF szBuffer
INVOKE MessageBox, NULL, ADDR szBuffer, SADD("RunElevated"), MB_ICONERROR
.ENDIF
.ENDIF
.ELSE
INVOKE MessageBox, NULL, SADD("Usage: RunElevated exepath [arg]"), SADD("RunElevated"), MB_ICONINFORMATION
.ENDIF
ret
main ENDP
;---------------------------------------
GetCommandLineItemsCount PROC
; Returns the number of individual command-line arguments in EAX
; Will always return at least 1
; eax = 1 = 1 item = name of current exe (item 0)
; eax = 2 = 2 items = name of current exe (item 0) + first argument (item 1)
; eax = 3 = 3 items = name of current exe (item 0) + first argument (item 1) + second argument (item 2)
; ...
LOCAL dwArgC:DWORD
LOCAL pArgV:PTR DWORD
LOCAL pEnv:PTR DWORD
LOCAL bWildCard:DWORD
LOCAL StartInfo:STARTUPINFO
mov bWildCard, FALSE
INVOKE crt___getmainargs, ADDR dwArgC, ADDR pArgV, ADDR pEnv, bWildCard, ADDR StartInfo
; __getmainargs
; pArgV is a pointer to an array of pointers.
; Each pointer points to an individual command-line argument.
; dwArgC is the number of individual command-line arguments.
; pEnv is a pointer to an array of pointers.
; Each pointer points to an individual environment variable.
; A NULL pointer signals the end of the array of pointers.
; bWildCard is a boolean value controlling whether the command line
; will be globbed (e.g. *.* expanded to be all files in the startup
; directory).
; StartInfo is a pointer to a STARTUPINFO structure.
mov eax, dwArgC
ret
GetCommandLineItemsCount ENDP
;---------------------------------------
GetCommandLineItem PROC dwItem:DWORD
; dwItem = 0 = name of current exe
; dwItem = 1 = first argument
; dwItem = 2 = second argument
; ...
; Returns a pointer to the command-line item.
; NULL otherwise.
LOCAL dwArgC:DWORD
LOCAL pArgV:PTR DWORD
LOCAL pEnv:PTR DWORD
LOCAL bWildCard:DWORD
LOCAL StartInfo:STARTUPINFO
mov bWildCard, FALSE
INVOKE crt___getmainargs, ADDR dwArgC, ADDR pArgV, ADDR pEnv, bWildCard, ADDR StartInfo
; __getmainargs
; pArgV is a pointer to an array of pointers.
; Each pointer points to an individual command-line argument.
; dwArgC is the number of individual command-line arguments.
; pEnv is a pointer to an array of pointers.
; Each pointer points to an individual environment variable.
; A NULL pointer signals the end of the array of pointers.
; bWildCard is a boolean value controlling whether the command line
; will be globbed (e.g. *.* expanded to be all files in the startup
; directory).
; StartInfo is a pointer to a STARTUPINFO structure.
mov eax, dwItem
.IF eax >= dwArgC
xor eax, eax
.ELSE
mov edx, pArgV
mov ecx, dwItem
mov eax, [edx+ecx*4]
.ENDIF
ret
GetCommandLineItem ENDP
;---------------------------------------
RunElevated PROC hWnd:DWORD, pFilename:PTR BYTE, pParameters:PTR BYTE
; Requests the OS to run the executable elevated.
; Returns TRUE if successful, or FALSE otherwise.
; If FALSE then return error information in edx
LOCAL sei:SHELLEXECUTEINFO
INVOKE RtlZeroMemory, ADDR sei, SIZEOF sei
mov sei.cbSize, SIZEOF SHELLEXECUTEINFO
mov eax, hWnd
mov sei.hwnd, eax
mov sei.fMask, SEE_MASK_FLAG_DDEWAIT OR SEE_MASK_FLAG_NO_UI
mov eax, CTXT("runas")
mov sei.lpVerb, eax
mov eax, pFilename
mov sei.lpFile, eax
mov eax, pParameters
mov sei.lpParameters, eax
mov sei.nShow, SW_SHOWNORMAL
INVOKE ShellExecuteEx, ADDR sei
.IF eax == FALSE
INVOKE GetLastError
mov edx, eax
xor eax, eax
.ELSE
mov eax, 1
.ENDIF
ret
RunElevated ENDP
;---------------------------------------
GetErrorMessage PROC dwErrorNum:DWORD, pBuffer:PTR BYTE, dwBufferLen:DWORD
LOCAL hModule :DWORD
LOCAL dwDefLangID:DWORD
LOCAL dwFlags :DWORD
LOCAL retv :SDWORD
LOCAL pTmpBuffer :PTR BYTE
mov hModule, NULL
mov pTmpBuffer, NULL
INVOKE GetUserDefaultLangID
mov dwDefLangID, eax
mov eax, FORMAT_MESSAGE_ALLOCATE_BUFFER OR FORMAT_MESSAGE_FROM_SYSTEM OR FORMAT_MESSAGE_IGNORE_INSERTS
mov dwFlags, eax
.IF dwErrorNum >= NERR_BASE && dwErrorNum <= MAX_NERR
INVOKE LoadLibraryEx, SADD("netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE
mov hModule, eax
.IF hModule != NULL
mov eax, dwFlags
or eax, FORMAT_MESSAGE_FROM_HMODULE
mov dwFlags, eax
.ENDIF
.ENDIF
INVOKE FormatMessage, dwFlags, hModule, dwErrorNum, dwDefLangID, ADDR pTmpBuffer, 0, NULL
.IF eax
dec dwBufferLen
INVOKE lstrcpyn, pBuffer, pTmpBuffer, dwBufferLen
INVOKE LocalFree, pTmpBuffer
mov retv, 0
.ELSE
INVOKE GetLastError
mov retv, eax
.ENDIF
.IF hModule != NULL
INVOKE FreeLibrary, hModule
.ENDIF
mov eax, retv
ret
GetErrorMessage ENDP
;---------------------------------------
END start
Any reason for using crt___getmainargs instead of CommandLineToArgvW ?
I found __getmainargs to be pretty easy to use. Why not?
Greg,
Make me a little wiser here, what is the sense of "elevated" in Vista ? Is it something like running a process with its priority set higher ?
Quote from: Greg on June 25, 2008, 04:21:06 AM
I found __getmainargs to be pretty easy to use. Why not?
Just curious. It seems to need a bit more (in the way of vars), but I guess does a bit more too.
Are you a C programmer? Since I'm not, my first choice would be CommandLineToArgvW (or a roll-your-own version for win9x).
hutch, elevated means (usually) "run as administrator" or at least brings up the UAC dialog asking permission to run at a higher user access (I think).
greg, does your code bring up the dialog, or bypass it? (not having vista, it's hard to check).[edit]Sorry, read your 1st post properly - is there any way of bypassing the dialog?[/edit]
sinsi,
Yes, I have a background in C programming. Just trying out something different. Yes, it does bring up the UAC dialog, and no, there is not a way to bypass the UAC dialog.
hutch,
In Windows Vista your user account does not automatically have administrator privileges. Running a program 'elevated' means running with administrator privileges.
This is a very good article about it Inside Windows Vista User Account Control (http://technet.microsoft.com/en-us/magazine/cc138019.aspx)
I am currently finishing up a program that demonstrates how a program can request elevation at startup. It's done with a manifest element. I'll post it when it's ready.
The attached program is an example intended for Windows Vista. It demonstrates how a program can request elevation at start up. Notice the manifest element about "requireAdministrator". It also shows how to add an 'elevation required' shield to a button.
[attachment deleted by admin]
Greg,
Thanks for that link! I also found the following link:
http://social.msdn.microsoft.com/forums/en-US/windowsgeneraldevelopmentissues/thread/8f19b0ba-cb14-4081-8622-c3b3a6481e48/
helpful with a problem I had with a program which required mouse control of a separate program. It describes how to add the uiAccess parameter to the manifest. Which also required adding "a valid, trusted digital signature to execute" see post by Jimmy Brush. It worked for me in fasm.
Thanks again,
farrier
I read somewhere I think that running as administrator also opens up security holes ie if your app opens browser then browser is also running as administrator (may be bad example but I think you will get the drift)
Hi Greg,
Just curious, why the SEE_MASK_FLAG_DDEWAIT flag ? It is deprecated and since it instructs Windows to complete any outstanding DDE conversations before allowing the program to terminate it was normally only used with programs that exited very quickly.
Edgar
I don't know Donkey, it was close to two years ago when I did this. I see it is deprecated, when was it deprecated? It says to use use SEE_MASK_NOASYNC instead, notice the numbers (0x00000100) are the same. I'm sure I got it from an example (probably Microsoft) that I was looking at at that time.
Quote from: MSDN SHELLEXECUTEINFO
SEE_MASK_FLAG_DDEWAIT (0x00000100)
0x00000100. Do not use; use SEE_MASK_NOASYNC instead.
SEE_MASK_NOASYNC (0x00000100)
0x00000100. Wait for the execute operation to complete before returning. This flag should be used by callers that are using ShellExecute forms that might result in an async activation, for example DDE, and create a process that might be run on a background thread. (Note: ShellExecuteEx runs on a background thread by default if the caller's threading model is not Apartment.) Calls to ShellExecuteEx from processes already running on background threads should always pass this flag. Also, applications that exit immediately after calling ShellExecuteEx should specify this flag.
If the execute operation is performed on a background thread and the caller did not specify the SEE_MASK_ASYNCOK flag, then the calling thread waits until the new process has started before returning. This typically means that either CreateProcess has been called, the DDE communication has completed, or that the custom execution delegate has notified ShellExecuteEx that it is done. If the SEE_MASK_WAITFORINPUTIDLE flag is specified, then ShellExecuteEx calls WaitForInputIdle and waits for the new process to idle before returning, with a maximum timeout of 1 minute.
For further discussion on when this flag is necessary, see the Remarks section.
Remarks
The SEE_MASK_NOASYNC flag must be specified if the thread calling ShellExecuteEx does not have a message loop or if the thread or process will terminate soon after ShellExecuteEx returns. Under such conditions, the calling thread will not be available to complete the DDE conversation, so it is important that ShellExecuteEx complete the conversation before returning control to the calling application. Failure to complete the conversation can result in an unsuccessful launch of the document.
If the calling thread has a message loop and will exist for some time after the call to ShellExecuteEx returns, the SEE_MASK_NOASYNC flag is optional. If the flag is omitted, the calling thread's message pump will be used to complete the DDE conversation. The calling application regains control sooner, since the DDE conversation can be completed in the background.
MSDN online says that, but the 2003 SDK I have doesn't even mention SEE_MASK_NOASYNC.
Online also says the minimum required client for ShellExecuteEx is XP, whereas the SDK says Windows 95/NT 3.51 ::)
QuoteOnline also says the minimum required client for ShellExecuteEx is XP, whereas the SDK says Windows 95/NT 3.51
there are a lot of these what seem to be discrepencies
i think they specify only the OS level that behaves as the document specifies
older OS's may well support the function, but enough of the behaviour has changed that they are not included
at least, that is how it appears to me
of course - they quit supporting win9x long ago - that may have something to do with it :P
As I have understood it it lists the earliest *supported* compatible version online