пятница, 28 мая 2010 г.

Разрешить юзеру запускать какую-либо прогу из под админа (windows)

Розникла необходимость одному юзеру использовать программу, которая требует административных прав. Давать ему права админа в системе из-за этого? Каждый раз, когда ему понадобится запустить прогу, подходить и вводить пароль? Нет! Это не наш метод!
Для этого за несколько минут была написана программка run_as_admin.exe, которой сегодня и хочу поделиться.


Дело было в Windows XP Home Edition. В нем, в отличии от Professional, нет встроенных средств для решения поставленной задачи. Поэтому пришлось написать свою программку. Писать решил на AutoIT. Ниже приводится полный исходный код:
#AutoIt3Wrapper_Run_Obfuscator=y
;
; Скрипт для запуска какого-либо приложения от учетной записи с правами администратора
; для Windows 2000 и более поздних
;
; Author:  (c) Angel2S2 aka Roman Shagrov, 2010
; E-mail & Jabber: angel2s2ru@gmail.com
; www:   http://angel2s2.blogspot.com/
;
; Date:   28.05.2010
; License:  GNU GPLv3
;

dim $user="admin"      ; Учетка с админскими правами
dim $passwd="passwd"      ; Пароль к учетке
dim $domain=@ComputerName     ; Имя домена, если есть, иначе имя компа
dim $cmd=@ScriptDir&"\file.exe"     ; Путь к исполняемому файлу программы, которую надо запускать
dim $md5=StringUpper("f5ece194f011e42d365f6bed327e99cc") ; MD5-хеш исполняемого файла

If Not FileExists($cmd) Then
 ;MsgBox features: Title=Yes, Text=Yes, Buttons=OK, Icon=Critical, Modality=System Modal
 MsgBox(4112,"Ошибка","Не найден файл в текущем каталоге.")
 Exit 1
EndIf


; source -> http://www.autoitscript.com/forum/index.php?showtopic=112711&st=0&p=789463&hl=md5&fromsearch=1&#entry789463
; #FUNCTION# ;===============================================================================
;
; Name...........: _MD5ForFile
; Description ...: Calculates MD5 value for the specific file.
; Syntax.........: _MD5ForFile ($sFile)
; Parameters ....: $sFile - Full path to the file to process.
; Return values .: Success - Returns MD5 value in form of hex string
;                          - Sets @error to 0
;                  Failure - Returns empty string and sets @error:
;                  |1 - CreateFile function or call to it failed.
;                  |2 - CreateFileMapping function or call to it failed.
;                  |3 - MapViewOfFile function or call to it failed.
;                  |4 - MD5Init function or call to it failed.
;                  |5 - MD5Update function or call to it failed.
;                  |6 - MD5Final function or call to it failed.
; Author ........: trancexx
;
;==========================================================================================
Func _MD5ForFile($sFile)
    Local $a_hCall = DllCall("kernel32.dll", "hwnd", "CreateFileW", _
            "wstr", $sFile, _
            "dword", 0x80000000, _
            "dword", 3, _
            "ptr", 0, _
            "dword", 3, _
            "dword", 0, _
            "ptr", 0)
    If @error Or $a_hCall[0] = -1 Then
        Return SetError(1, 0, "")
    EndIf
    Local $hFile = $a_hCall[0]
    $a_hCall = DllCall("kernel32.dll", "ptr", "CreateFileMappingW", _
            "hwnd", $hFile, _
            "dword", 0, _
            "dword", 2, _
            "dword", 0, _
            "dword", 0, _
            "ptr", 0)
    If @error Or Not $a_hCall[0] Then
        DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFile)
        Return SetError(2, 0, "")
    EndIf
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFile)
    Local $hFileMappingObject = $a_hCall[0]
    $a_hCall = DllCall("kernel32.dll", "ptr", "MapViewOfFile", _
            "hwnd", $hFileMappingObject, _
            "dword", 4, _
            "dword", 0, _
            "dword", 0, _
            "dword", 0)
    If @error Or Not $a_hCall[0] Then
        DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
        Return SetError(3, 0, "")
    EndIf
    Local $pFile = $a_hCall[0]
    Local $iBufferSize = FileGetSize($sFile)
    Local $tMD5_CTX = DllStructCreate("dword i[2];" & _
            "dword buf[4];" & _
            "ubyte in[64];" & _
            "ubyte digest[16]")
    DllCall("advapi32.dll", "none", "MD5Init", "ptr", DllStructGetPtr($tMD5_CTX))
    If @error Then
        DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
        DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
        Return SetError(4, 0, "")
    EndIf
    DllCall("advapi32.dll", "none", "MD5Update", _
            "ptr", DllStructGetPtr($tMD5_CTX), _
            "ptr", $pFile, _
            "dword", $iBufferSize)
    If @error Then
        DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
        DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
        Return SetError(5, 0, "")
    EndIf
    DllCall("advapi32.dll", "none", "MD5Final", "ptr", DllStructGetPtr($tMD5_CTX))
    If @error Then
        DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
        DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
        Return SetError(6, 0, "")
    EndIf
    DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
    Local $sMD5 = Hex(DllStructGetData($tMD5_CTX, "digest"))
    Return SetError(0, 0, StringUpper($sMD5))
EndFunc ;_MD5ForFile


If $md5 == _MD5ForFile($cmd) Then
 if Not IsAdmin() Then
  RunAs($user, $domain, $passwd, 0, $cmd)
 Else
  Run($cmd)
 EndIf
Else
 ;MsgBox features: Title=Yes, Text=Yes, Buttons=OK, Icon=Critical, Modality=System Modal
 MsgBox(4112,"Ошибка","Файл повержден либо подменен.")
 Exit 1
EndIf
[СКАЧАТЬ]
Перед компиляцией надо подправить 5 переменных в начале кода. Они хорошо прокомментированы, поэтому останавливаться на них не будем. Я компилировал с обфускацией с настройками по дефолту, чтобы нельзя было выдрать из exe'шника админский пароль.
После компиляции кладем полученный exe'шник в папку с программой и запускаем :)



Для Windows XP Professional это сделать проще. Открываем консоль под учеткой юзера, который будет работать с прогой, требующей админских прав, и выполняем команду:
runas /user:admin /savecred "X:\path\to\file.exe"
Будет запрошен пароль админа, вводим. Теперь откроем ярлык, запускающий программу, и в нем в поле "Объект" впишем эту команду. Все, юзер может пользоваться прогой (пароль у него больше спрашиваться не будет).





PS: Про существование программ, на подобии написанной мной, я знаю, но мне хотелось написать подобную утилитку самому.





Информация с сайта http://angel2s2.blogspot.com/. Если Вы читаете информацию на другом сайте, пожалуйста свяжитесь с автором сайта http://angel2s2.blogspot.com/.

8 комментариев:

  1. Спасибо :))

    Давай уже тоже на AutoIT перебирайся с бейсика ;)) :-Р

    ОтветитьУдалить
  2. а я давал просто полные права на папку с установленной софтиной, пока помогало... но все равно на вооружение возьму, спасибо

    ОтветитьУдалить
  3. В домашней ХРшке не прокатит, там нет такой возможности.
    К тому же эта прога, из-за которой и писал прогу, подгружает драйвер свой при запуске. Именно из-за этого и нужны были админские права.

    ОтветитьУдалить
  4. Давай уже тоже на AutoIT перебирайся с бейсика ;)) :-Р

    Кто-то еще на байсике сидит O_o. Ну вы и динозавры :-D

    P.S. сам с него начинал еще в школе)

    ОтветитьУдалить
  5. Не совсем бейсик... VBScript, если быть точнее. Для WSH он его юзает.

    ОтветитьУдалить
  6. Потом из той, запускаемой под админом программки, можно будет наделать кучу гадостей, из её меню "File" и т. п...

    ОтветитьУдалить
  7. В моем случае этого сделать было нельзя, т.к. там нету этого меню, да и вообщем лазеек :) Там была, на сколько я помню, прога для сканера штрих-кода. Сканер был старый и работал от com-порта, а прога не хотела работать с юзерскими правами. Заменить сканер на более новый тоже не было возможности. Поэтому и пришлось так извращаться :)


    А так, да, из проги, запущенной с правами админа, потенциально, можно натворить многое :)

    ОтветитьУдалить