Как создать ярлык, позволяющий обычным пользователям запускать приложение с правами администратора. Упрощаем запуск приложений в Windows от имени администратора без отключения UAC

Что делать, если нужно запустить программу, но вы не хотите устанавливать ее? Zero Install в помощь!

Миллиарды людей по всему миру используют компьютеры или ноутбуки на операционной системе Windows. Обычно, мы устанавливаем программы, после чего они занимают свободное место на диске и используют оперативную память. Это снижает скорость работы компьютера.

Сегодня мы расскажем, как вы можете увеличить производительность компьютера и снизить нагрузку на память. Для этого вам нужно запускать необходимые программы без их установки.

Как запустить программу без установки?

1. Скачайте Zero Install.

Во-первых, скачайте программное обеспечение Zero Install , которое позволит вам запускать программы без необходимости устанавливать их на компьютер.

2. Установите Zero Install.

После того, как вы скачали Zero Install, дважды нажмите на файл, чтобы установите его. Затем запустите новую программу на своем компьютере.

3. Нажмите на в кладку «Каталог».

Как только Zero Install будет запущена на компьютере или ноутбуке Windows, вы должны перейти во вкладку «Catalog». Здесь нажмите на кнопку «Refresh list», чтобы обновить список доступных программ.

4. Выберите программу, чтобы запустить .

Внимательно посмотрите полный список доступных программ. Если вы нашли нужную вам программу, выделите ее и нажмите «Run». Некоторые программы могут выбрать браузер Firefox или Mozilla для запуска. Просто дождитесь полной загрузки программного обеспечения, после чего вы сможете запустить ее на своем компьютере, не устанавливая.


Подведение итогов

Если на вашем компьютере недостаточно свободной памяти или мощности, чтобы запустить программу, вы можете использовать Zero Install. Я думаю, что это отличный способ не засорять свой компьютер программами, которые вам нужны на один раз.

Также вашему компьютеру может не хватать мощности для запуска определенных программ, например, Eclipse IDE, JetBrains, NetBeans и т.д. Это действительно тяжелые программы для разработчиков, которые потребляют большое количество оперативной памяти.

Zero Install поможет запустить эти, и многие другие программы, без установки на компьютер.

Не было достаточно подробно описано самого главного: как же запустить этот код на реальном железе? Как создать собственный загрузочный диск? В этой статье мы подробно ответим на все эти вопросы (частично данные вопросы разбирались в предыдущей статье, но для удобства чтения позволим себе небольшое дублирование материала).

В интернете существует огромное количество описаний и туториалов о для того как написать собственную мини-ОС, даже существуют сотни готовых маленьких хобби-ОС. Один из наиболее достойных ресурсов по этой тематике, который хотелось бы особо выделить, это портал osdev.org. Для дополнения предыдущей статьи про PCI (и возможности писать последующие статьи о различных функциях, которые присутствуют в любой современной ОС), мы опишем пошаговые инструкции по созданию загрузочного диска с привычной программой на языке С. Мы старались писать максимально подробно, чтобы во всем можно было разобраться самостоятельно.

Итак, цель: затратив как можно меньше усилий, создать собственную загрузочную флешку, которая всего на всего печатает на экране компьютера классический “Hello World”.

Если быть более точным, то нам нужно “попасть” в защищенный режим с отключенной страничной адресацией и прерываниями – самый простой режим работы процессора с привычным поведением для простой консольной программы. Самый разумный способ достичь такой цели – собрать ядро поддерживающее формат multiboot и загрузить его с помощью популярного загрузчика Grub. Альтернативой такого решения является написание собственного volume boot record (VBR), который бы загружал написанный собственный загрузчик (loader). Приличный загрузчик, как минимум, должен уметь работать с диском, с файловой системой, и разбирать elf образы. Это означает необходимость написания множества ассемблерного кода, и немало кода на С. Одним словом, проще использовать Grub, который уже умеет делать все необходимое.

Начнем с того, что для дальнейших действий необходим определенный набор компиляторов и утилит. Проще всего воспользоваться каким-нибудь Linux (например, Ubuntu), поскольку он уже будет содержать все что нужно для создания загрузочной флэшки. Если вы привыкли работать в Windows, то можно настроить виртуальную машину с Linux (при помощи Virtual Box или VMware Workstation).

Если вы используете Linux Ubuntu, то прежде всего необходимо установить несколько утилит:
1. Grub. Для этого воспользуемся командой:

Sudo apt-get install grub

2. Qemu. Он нужен, чтобы все быстро протестировать и отладить (Ссылка на статью про отладчик), для этого аналогично команда:

Sudo apt-get install qemu

Теперь наш план выглядит так:
1. создать программу на C, печатающую строку на экране.
2. собрать из нее образ (kernel.bin) в формате miniboot, чтобы он был доступен для загрузки с помощью GRUB.
3. создать файл образа загрузочного диска и отформатировать его.
4. установить на этот образ Grub.
5. скопировать на диск созданную программу (kernel.bin).
6. записать образ на физический носитель или запустить его в qemu.

а процесс загрузки системы:

Чтобы все получилось, необходимо будет создать несколько файлов и каталогов:

Шаг 1. Создание кода целевой программы (ядра):

Создаем файл kernel.c, который будет содержать следующий код, печатающий сообщение на экране:

#include "printf.h" #include "screen.h" #include "types.h" void main(void) { clear_screen(); printf("n>>> Hello World!n"); }

Тут все привычно и просто. Добавление функций printf и clear_screen будет рассмотрено дальше. А пока надо дополнить этот код всем необходимым, чтобы он мог загружаться Grub’ом.
Для того что бы ядро было в формате multiboot, нужно что бы в первых 8-ми килобайтах образа ядра находилась следующая структура:

Если все указанные условия выполнены, то Grub через регистры %eax и %ebx передает указатель на структуру multiboot Information и значение 0x1BADB002 соответственно. Структура multiboot Information содержит различную информацию, в том числе список загруженных модулей и их расположение, что может понадобиться для дальнейшей загрузки системы.
Для того, чтобы файл с программой содержал необходимые сигнатуры создадим файл loader.s, со следующим содержимым:

Text .global loader # making entry point visible to linker # setting up the Multiboot header - see GRUB docs for details .set FLAGS, 0x0 # this is the Multiboot "flag" field .set MAGIC, 0x1BADB002 # "magic number" lets bootloader find the header .set CHECKSUM, -(MAGIC + FLAGS) # checksum required .align 4 .long MAGIC .long FLAGS .long CHECKSUM # reserve initial kernel stack space .set STACKSIZE, 0x4000 # that is, 16k. .lcomm stack, STACKSIZE # reserve 16k stack .comm mbd, 4 # we will use this in kmain .comm magic, 4 # we will use this in kmain loader: movl $(stack + STACKSIZE), %esp # set up the stack movl %eax, magic # Multiboot magic number movl %ebx, mbd # Multiboot data structure call main # call C code cli hang: hlt # halt machine should kernel return jmp hang

Рассмотрим код подробнее. Этот код в почти не измененном виде взят с wiki.osdev.org/Bare_Bones . Так как для компиляции используется gcc, то используется синтаксис GAS. Рассмотрим подробнее, что делает этот код.

Весь последующий код попадет в исполняемую секцию.text.

Global loader

Объявляем символ loader видимым для линковщика. Это требуется, так как линковщик будет использовать loader как точку входа.

Set FLAGS, 0x0 # присвоить FLAGS = 0x0 .set MAGIC, 0x1BADB002 # присвоить MAGIC = 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) # присвоить CHECKSUM = -(MAGIC + FLAGS) .align 4 # выровнять последующие данные по 4 байта.long MAGIC # разместить по текущему адресу значение MAGIC .long FLAGS # разместить по текущему адресу значение FLAGS .long CHECKSUM # разместить по текущему адресу значение CHECKSUM

Этот код формирует сигнатуру формата Multiboot. Директива.set устанавливает значение символа в выражение справа от запятой. Директива.align 4 выравнивает последующее содержимое по 4 байта. Директива.long сохраняет значение в четырех последующих байтах.

Set STACKSIZE, 0x4000 # присвоить STACKSIZE = 0x4000 .lcomm stack, STACKSIZE # зарезервировать STACKSIZE байт. stack ссылается на диапазон.comm mbd, 4 # зарезервировать 4 байта под переменную mdb в области COMMON .comm magic, 4 # зарезервировать 4 байта под переменную magic в области COMMON

В процессе загрузки grub не настраивает стек, и первое что должно сделать ядро это настроить стек, для этого мы резервируем 0x4000(16Кб) байт. Директива.lcomm резервирует в секции.bss количество байт, указанное после запятой. Имя stack будет видимо только в компилируемом файле. Директива.comm делает то же что и.lcomm, но имя символа будет объявлено глобально. Это значит что, написав в коде на Си следующую строчку, мы сможем его использовать.
extern int magic

И теперь последняя часть:

Loader: movl $(stack + STACKSIZE), %esp # инициализировать стек movl %eax, magic # записать %eax по адресу magic movl %ebx, mbd # записать %ebx по адресу mbd call main # вызвать функцию main cli # отключить прерывания от оборудования hang: hlt # остановить процессор пока не возникнет прерывание jmp hang # прыгнуть на метку hang

Первой инструкцией происходит сохранение значения верхушки стека в регистре %esp. Так как стек растет вниз, то в %esp записывается адрес конца диапазона отведенного под стек. Две последующие инструкции сохраняют в ранее зарезервированных диапазонах по 4 байта значения, которые Grub передает в регистрах %eax, %ebx. Затем происходит вызов функции main, которая уже написана на Си. В случае возврата из этой процедуры процессор зациклится.

Шаг 2. Подготовка дополнительного кода для программы (системная библиотека):

Поскольку вся программа пишется с нуля, то функцию printf нужно написать с нуля. Для этого нужно подготовить несколько файлов.
Создадим папку common и include:

Mkdir common mkdir include

Создадим файл commonprintf.c, который будет содержать реализацию привычной функции printf. Этот файл целиком можно взять из проекта www.bitvisor.org/ . Путь до файла в исходниках bitvisor: core/printf.c. В скопированном из bitvisor файле printf.c, для использования в целевой программе нужно заменить строки:

#include "initfunc.h" #include "printf.h" #include "putchar.h" #include "spinlock.h"

на строки:

#include "types.h" #include "stdarg.h" #include "screen.h"

Потом, удалить функцию printf_init_global и все ее упоминания в этом файле:

Static void printf_init_global (void) { spinlock_init (&printf_lock); } INITFUNC ("global0", printf_init_global);

Затем удалить переменную printf_lock и все ее упоминания в этом файле:

Static spinlock_t printf_lock; … spinlock_lock (&printf_lock); … spinlock_unlock (&printf_lock);

Функция printf использует функцию putchar, которую так же нужно написать. Для этого создадим файл commonscreen.с, со следующим содержимым:

#include "types.h" #define GREEN 0x2 #define MAX_COL 80 // Maximum number of columns #define MAX_ROW 25 // Maximum number of rows #define VRAM_SIZE (MAX_COL*MAX_ROW) // Size of screen, in short"s #define DEF_VRAM_BASE 0xb8000 // Default base for video memory static unsigned char curr_col = 0; static unsigned char curr_row = 0; // Write character at current screen location #define PUT(c) (((unsigned short *) (DEF_VRAM_BASE)) [(curr_row * MAX_COL) + curr_col] = (GREEN << 8) | (c)) // Place a character on next screen position static void cons_putc(int c) { switch (c) { case "t": do { cons_putc(" "); } while ((curr_col % 8) != 0); break; case "r": curr_col = 0; break; case "n": curr_row += 1; if (curr_row >= MAX_ROW) { curr_row = 0; } break; case "b": if (curr_col > 0) { curr_col -= 1; PUT(" "); } break; default: PUT(c); curr_col += 1; if (curr_col >= MAX_COL) { curr_col = 0; curr_row += 1; if (curr_row >= MAX_ROW) { curr_row = 0; } } }; } void putchar(int c) { if (c == "n") cons_putc("r"); cons_putc(c); } void clear_screen(void) { curr_col = 0; curr_row = 0; int i; for (i = 0; i < VRAM_SIZE; i++) cons_putc(" "); curr_col = 0; curr_row = 0; }

Указанный код, содержит простую логику печати символов на экран в текстовом режиме. В этом режиме для записи символа используется два байта (один с кодом символа, другой с его атрибутами), записываемые прямо в видео память отображаемую сразу на экране и начинающуюся с адреса 0xB8000. Разрешение экрана при этом 80x25 символов. Непосредственно печать символа осуществляется при помощи макроса PUT.
Теперь не хватает всего несколько заголовочных файлов:
1. Файл includescreen.h. Объявляет функцию putchar, которая используется в функции printf. Содержимое файла:

#ifndef _SCREEN_H #define _SCREEN_H void clear_screen(void); void putchar(int c); #endif

2. Файл includeprintf.h. Объявляет функцию printf, которая используется в main. Содержимое файла:

#ifndef _PRINTF_H #define _PRINTF_H int printf (const char *format, ...); #endif

3. Файл includestdarg.h. Объявляет функции для перебора аргументов, количество которых заранее не известно. Файл целиком берется из проекта www.bitvisor.org/ . Путь до файла в коде проекта bitvisor: includecorestdarg.h.
4. Файл includetypes.h. Объявляет NULL и size_t. Содержимое файла:

#ifndef _TYPES_H #define _TYPES_H #define NULL 0 typedef unsigned int size_t; #endif

Таким образом папки include и common содержат минимальный код системной библиотеки, которая необходима любой программе.

Шаг 3. Создание скрипта для компоновщика:

Создаем файл linker.ld, который будет использоваться компоновщиком для формирования файла целевой программы (kernel.bin). Файл должен содержать следующее:

ENTRY (loader) LMA = 0x00100000; SECTIONS { . = LMA; .multiboot ALIGN (0x1000) : { loader.o(.text) } .text ALIGN (0x1000) : { *(.text) } .rodata ALIGN (0x1000) : { *(.rodata*) } .data ALIGN (0x1000) : { *(.data) } .bss: { *(COMMON) *(.bss) } /DISCARD/ : { *(.comment) } }

Встроенная функция ENTRY() позволяет задать входную точку для нашего ядра. Именно по этому адресу передаст управление grub после загрузки ядра. Компоновщик при помощи этого скрипта создаст бинарный файл в формате ELF. ELF-файл состоит из набора сегментов и секций. Список сегментов содержится в Program header table, список секций в Section header table. Линковщик оперирует с секциями, загрузчик образа (в нашем случае это GRUB) с сегментами.


Как видно на рисунке, сегменты состоят из секций. Одним из полей, описывающих секцию, является виртуальный адрес, по которому секция должна находиться на момент выполнения. На самом деле, у сегмента есть 2 поля, описывающих его расположение: виртуальный адрес сегмента и физический адрес сегмента. Виртуальный адрес сегмента это виртуальный адрес первого байта сегмента в момент выполнения кода, физический адрес сегмента это физический адрес по которому должен быть загружен сегмент. Для прикладных программ эти адреса всегда совпадают. Grub загружает сегменты образа, по их физическому адресу. Так как Grub не настраивает страничную адресацию, то виртуальный адрес сегмента должен совпадать с его физическим адресом, поскольку в нашей программе виртуальная память так же не настраивается.

LMA;

Это выражение указывает линковщику, что все последующие секции находятся после адреса LMA.

ALIGN (0x1000)

Директива выше, означает, что секция выровнена по 0x1000 байт.

Multiboot ALIGN (0x1000) : { loader.o(.text) }

Отдельная секция multiboot, которая включает в себя секцию.text из файла loader.o, сделана для того, что бы гарантировать попадание сигнатуры формата multiboot в первые 8кб образа ядра.

Bss: { *(COMMON) *(.bss) }

*(COMMON) это область, в которой резервируется память инструкциями.comm и.lcomm. Мы располагаем ее в секции.bss.

/DISCARD/ : { *(.comment) }

Все секции, помеченные как DISCARD, удаляются из образа. В данном случае мы удаляем секцию.comment, которая содержит информацию о версии линковщика.

Теперь скомпилируем код в бинарный файл следующими командами:

As -o loader.o loader.s gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o kernel.o -c kernel.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o printf.o -c common/printf.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o screen.o -c common/screen.c ld -T linker.ld -o kernel.bin kernel.o screen.o printf.o loader.o

С помощью objdump’а рассмотрим, как выглядит образ ядра после линковки:

Objdump -ph ./kernel.bin



Как можно видеть, секции в образе совпадают с теми, что мы описали в скрипте линковщика. Линковщик сформировал 3 сегмента из описанных секций. Первый сегмент включает в себя секции.multiboot, .text, .rodata и имеет виртуальный и физический адрес 0x00100000. Второй сегмент содержит секции.data и.bss и располагается по адресу 0x00104000. Значит все готово для загрузки этого файла при помощи Grub.

Шаг 4. Подготовка загрузчика Grub:
Создать папку grub:

Mkdir grub

Скопировать в эту папку несколько файлов Grub, которые необходимы для его установки на образ (указанные далее файлы существуют, если в системе установлен Grub). Для этого нужно выполнить следующие команды:

Cp /usr/lib/grub/i386-pc/stage1 ./grub/ cp /usr/lib/grub/i386-pc/stage2 ./grub/ cp /usr/lib/grub/i386-pc/fat_stage1_5 ./grub/

Создать файл grub/menu.lst, со следующим содержимым:

Timeout 3 default 0 title mini_os root (hd0,0) kernel /kernel.bin

Шаг 5. Автоматизация и создание загрузочного образа:

Для автоматизации процесса сборки будем использовать утилиту make. Для этого создадим файл makefile, который будет собирать компилировать исходный код, собирать ядро и создавать загрузочный образ. Makefile должен иметь следующее содержимое:

CC = gcc CFLAGS = -Wall -fno-builtin -nostdinc -nostdlib LD = ld OBJFILES = loader.o common/printf.o common/screen.o kernel.o image: @echo "Creating hdd.img..." @dd if=/dev/zero of=./hdd.img bs=512 count=16065 1>/dev/null 2>&1 @echo "Creating bootable first FAT32 partition..." @losetup /dev/loop1 ./hdd.img @(echo c; echo u; echo n; echo p; echo 1; echo ; echo ; echo a; echo 1; echo t; echo c; echo w;) | fdisk /dev/loop1 1>/dev/null 2>&1 || true @echo "Mounting partition to /dev/loop2..." @losetup /dev/loop2 ./hdd.img --offset `echo `fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$3}"`*512 | bc` --sizelimit `echo `fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$4}"`*512 | bc` @losetup -d /dev/loop1 @echo "Format partition..." @mkdosfs /dev/loop2 @echo "Copy kernel and grub files on partition..." @mkdir -p tempdir @mount /dev/loop2 tempdir @mkdir tempdir/boot @cp -r grub tempdir/boot/ @cp kernel.bin tempdir/ @sleep 1 @umount /dev/loop2 @rm -r tempdir @losetup -d /dev/loop2 @echo "Installing GRUB..." @echo "device (hd0) hdd.img n root (hd0,0) n setup (hd0) n quitn" | grub --batch 1>/dev/null @echo "Done!" all: kernel.bin rebuild: clean all .s.o: as -o $@ $< .c.o: $(CC) -Iinclude $(CFLAGS) -o $@ -c $< kernel.bin: $(OBJFILES) $(LD) -T linker.ld -o $@ $^ clean: rm -f $(OBJFILES) hdd.img kernel.bin

В файле объявлены две основные цели: all – компилирует ядро, и image – которая создает загрузочный диск. Цель all подобно привычным makefile содержит подцели.s.o и.c.o, которые компилируют *.s и *.c файлы в объектные файлы (*.o), а так же цель для формирования kernel.bin, которая вызывает компоновщик с созданным ранее скриптом. Эти цели выполняют ровно те же команды, которые указаны в шаге 3.
Наибольший интерес здесь представляет создание загрузочного образа hdd.img (цель image). Рассмотрим поэтапно, как это происходит.

Dd if=/dev/zero of=./hdd.img bs=512 count=16065 1>/dev/null 2>&1

Эта команда создает образ, с которым будет происходить дальнейшая работа. Количество секторов выбрано не случайно: 16065 = 255 * 63. По умолчанию fdsik работает с диском так, как будто он имеет CHS геометрию, в которой Headers (H) = 255, Sectors (S) = 63, а Cylinders© зависит от размера диска. Таким образом, минимальный размер диска, с которым может работать утилита fdsik, без изменения геометрии по умолчанию, равен 512 * 255 * 63 * 1 = 8225280 байт, где 512 – размер сектора, а 1 – количество цилиндров.
Далее создается таблица разделов:

Losetup /dev/loop1 ./hdd.img (echo c; echo u; echo n; echo p; echo 1; echo ; echo ; echo a; echo 1; echo t; echo c; echo w;) | fdisk /dev/loop1 1>/dev/null 2>&1 || true

Первая команда монтирует файл hdd.img к блочному устройству /dev/loop1, позволяя работать с файлом как с устройством. Вторая команда создает на устройстве /dev/loop1 таблицу разделов, в которой находится 1 первичный загрузочный раздел диска, занимающий весь диск, с меткой файловой системы FAT32.
Затем форматируем созданный раздел. Для этого нужно примонтировать его как блочное устройство и выполнить форматирование.

Losetup /dev/loop2 ./hdd.img --offset `echo `fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$3}"`*512 | bc` --sizelimit `echo `fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$4}"`*512 | bc` losetup -d /dev/loop1

Первая команда монтирует ранее созданный раздел к устройству /dev/loop2. Опция –offset указывает адрес начала раздела, а –sizelimit адрес конца раздела. Оба параметра получаются с помощью команды fdisk.

Mkdosfs /dev/loop2

Утилита mkdosfs форматирует раздел в файловую систему FAT32.
Для непосредственной сборки ядра используются рассмотренные ранее команды в классическом синтаксисе makefile.
Теперь рассмотрим как установить GRUB на раздел:

Mkdir -p tempdir # создает временную директорию mount /dev/loop2 tempdir # монтирует раздел в директорию mkdir tempdir/boot # создает директорию /boot на разделе cp -r grub tempdir/boot/ # копируем папку grub в /boot cp kernel.bin tempdir/ # копирует ядро в корень раздела sleep 1 # ждем Ubuntu umount /dev/loop2 # отмонтируем временную папку rm -r tempdir # удаляем временную папку losetup -d /dev/loop2 # отмонтируем раздел

После выполнения вышеприведенных команд, образ будет готов к установке GRUB’а. Следующая команда устанавливает GRUB в MBR образа диска hdd.img.

Echo "device (hd0) hdd.img n root (hd0,0) n setup (hd0) n quitn" | grub --batch 1>/dev/null

Все готово к тестированию!

Шаг 6. Запуск:

Для компиляции, воспользуемся командой:

Make all

После которой должен появиться файл kernel.bin.
Для создания загрузочного образа диска, воспользуемся командой:

Sudo make image

В результате чего должен появиться файл hdd.img.
Теперь с образа диска hdd.img можно загрузиться. Проверить это можно с помощью следующей команды:

Qemu -hda hdd.img -m 32

Qemu-system-i386 -hda hdd.img




Для проверки на реальной машине нужно сделать dd этого образа на флэшку и загрузиться с нее. Например такой командой:

Sudo dd if=./hdd.img of=/dev/sdb

Подводя итоги, можно сказать, что в результате проделанных действий получается набор исходников и скриптов, которые позволяют проводить различные эксперименты в области системного программирования. Сделан первый шаг на пути создания системного программного обеспечения, такого как гипервизоры и операционные системы.

Не было достаточно подробно описано самого главного: как же запустить этот код на реальном железе? Как создать собственный загрузочный диск? В этой статье мы подробно ответим на все эти вопросы (частично данные вопросы разбирались в предыдущей статье, но для удобства чтения позволим себе небольшое дублирование материала).

В интернете существует огромное количество описаний и туториалов о для того как написать собственную мини-ОС, даже существуют сотни готовых маленьких хобби-ОС. Один из наиболее достойных ресурсов по этой тематике, который хотелось бы особо выделить, это портал osdev.org. Для дополнения предыдущей статьи про PCI (и возможности писать последующие статьи о различных функциях, которые присутствуют в любой современной ОС), мы опишем пошаговые инструкции по созданию загрузочного диска с привычной программой на языке С. Мы старались писать максимально подробно, чтобы во всем можно было разобраться самостоятельно.

Итак, цель: затратив как можно меньше усилий, создать собственную загрузочную флешку, которая всего-навсего печатает на экране компьютера классический “Hello World”.

Если быть более точным, то нам нужно “попасть” в защищенный режим с отключенной страничной адресацией и прерываниями – самый простой режим работы процессора с привычным поведением для простой консольной программы. Самый разумный способ достичь такой цели – собрать ядро поддерживающее формат multiboot и загрузить его с помощью популярного загрузчика Grub. Альтернативой такого решения является написание собственного volume boot record (VBR), который бы загружал написанный собственный загрузчик (loader). Приличный загрузчик, как минимум, должен уметь работать с диском, с файловой системой, и разбирать elf образы. Это означает необходимость написания множества ассемблерного кода, и немало кода на С. Одним словом, проще использовать Grub, который уже умеет делать все необходимое.

Начнем с того, что для дальнейших действий необходим определенный набор компиляторов и утилит. Проще всего воспользоваться каким-нибудь Linux (например, Ubuntu), поскольку он уже будет содержать все что нужно для создания загрузочной флэшки. Если вы привыкли работать в Windows, то можно настроить виртуальную машину с Linux (при помощи Virtual Box или VMware Workstation).

Если вы используете Linux Ubuntu, то прежде всего необходимо установить несколько утилит:
1. Grub. Для этого воспользуемся командой:
sudo apt-get install grub

2. Qemu. Он нужен, чтобы все быстро , для этого аналогично команда:
sudo apt-get install qemu

Теперь наш план выглядит так:
1. создать программу на C, печатающую строку на экране.
2. собрать из нее образ (kernel.bin) в формате miniboot, чтобы он был доступен для загрузки с помощью GRUB.
3. создать файл образа загрузочного диска и отформатировать его.
4. установить на этот образ Grub.
5. скопировать на диск созданную программу (kernel.bin).
6. записать образ на физический носитель или запустить его в qemu.

А процесс загрузки системы:

Чтобы все получилось, необходимо будет создать несколько файлов и каталогов:

Шаг 1. Создание кода целевой программы (ядра):

Создаем файл kernel.c, который будет содержать следующий код, печатающий сообщение на экране:

#include "printf.h" #include "screen.h" #include "types.h" void main(void) { clear_screen(); printf("\n>>> Hello World!\n"); }

Тут все привычно и просто. Добавление функций printf и clear_screen будет рассмотрено дальше. А пока надо дополнить этот код всем необходимым, чтобы он мог загружаться Grub’ом.
Для того что бы ядро было в формате multiboot, нужно что бы в первых 8-ми килобайтах образа ядра находилась следующая структура:

Если все указанные условия выполнены, то Grub через регистры %eax и %ebx передает указатель на структуру multiboot Information и значение 0x1BADB002 соответственно. Структура multiboot Information содержит различную информацию, в том числе список загруженных модулей и их расположение, что может понадобиться для дальнейшей загрузки системы.
Для того, чтобы файл с программой содержал необходимые сигнатуры создадим файл loader.s, со следующим содержимым:

Text .global loader # making entry point visible to linker # setting up the Multiboot header - see GRUB docs for details .set FLAGS, 0x0 # this is the Multiboot "flag" field .set MAGIC, 0x1BADB002 # "magic number" lets bootloader find the header .set CHECKSUM, -(MAGIC + FLAGS) # checksum required .align 4 .long MAGIC .long FLAGS .long CHECKSUM # reserve initial kernel stack space .set STACKSIZE, 0x4000 # that is, 16k. .lcomm stack, STACKSIZE # reserve 16k stack .comm mbd, 4 # we will use this in kmain .comm magic, 4 # we will use this in kmain loader: movl $(stack + STACKSIZE), %esp # set up the stack movl %eax, magic # Multiboot magic number movl %ebx, mbd # Multiboot data structure call main # call C code cli hang: hlt # halt machine should kernel return jmp hang

Рассмотрим код подробнее. Этот код в почти не измененном виде взят с wiki.osdev.org/Bare_Bones . Так как для компиляции используется gcc, то используется синтаксис GAS. Рассмотрим подробнее, что делает этот код.
.text
Весь последующий код попадет в исполняемую секцию.text.
.global loader
Объявляем символ loader видимым для линковщика. Это требуется, так как линковщик будет использовать loader как точку входа.
.set FLAGS, 0x0 # присвоить FLAGS = 0x0 .set MAGIC, 0x1BADB002 # присвоить MAGIC = 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) # присвоить CHECKSUM = -(MAGIC + FLAGS) .align 4 # выровнять последующие данные по 4 байта.long MAGIC # разместить по текущему адресу значение MAGIC .long FLAGS # разместить по текущему адресу значение FLAGS .long CHECKSUM # разместить по текущему адресу значение CHECKSUM
Этот код формирует сигнатуру формата Multiboot. Директива.set устанавливает значение символа в выражение справа от запятой. Директива.align 4 выравнивает последующее содержимое по 4 байта. Директива.long сохраняет значение в четырех последующих байтах.
.set STACKSIZE, 0x4000 # присвоить STACKSIZE = 0x4000 .lcomm stack, STACKSIZE # зарезервировать STACKSIZE байт. stack ссылается на диапазон.comm mbd, 4 # зарезервировать 4 байта под переменную mdb в области COMMON .comm magic, 4 # зарезервировать 4 байта под переменную magic в области COMMON
В процессе загрузки grub не настраивает стек, и первое что должно сделать ядро это настроить стек, для этого мы резервируем 0x4000(16Кб) байт. Директива.lcomm резервирует в секции.bss количество байт, указанное после запятой. Имя stack будет видимо только в компилируемом файле. Директива.comm делает то же что и.lcomm, но имя символа будет объявлено глобально. Это значит что, написав в коде на Си следующую строчку, мы сможем его использовать.
extern int magic

И теперь последняя часть:
loader: movl $(stack + STACKSIZE), %esp # инициализировать стек movl %eax, magic # записать %eax по адресу magic movl %ebx, mbd # записать %ebx по адресу mbd call main # вызвать функцию main cli # отключить прерывания от оборудования hang: hlt # остановить процессор пока не возникнет прерывание jmp hang # прыгнуть на метку hang

Первой инструкцией происходит сохранение значения верхушки стека в регистре %esp. Так как стек растет вниз, то в %esp записывается адрес конца диапазона отведенного под стек. Две последующие инструкции сохраняют в ранее зарезервированных диапазонах по 4 байта значения, которые Grub передает в регистрах %eax, %ebx. Затем происходит вызов функции main, которая уже написана на Си. В случае возврата из этой процедуры процессор зациклится.

Шаг 2. Подготовка дополнительного кода для программы (системная библиотека):

Поскольку вся программа пишется с нуля, то функцию printf нужно написать с нуля. Для этого нужно подготовить несколько файлов.
Создадим папку common и include:

Mkdir common mkdir include

Создадим файл common\printf.c, который будет содержать реализацию привычной функции printf. Этот файл целиком можно взять из проекта www.bitvisor.org . Путь до файла в исходниках bitvisor: core/printf.c. В скопированном из bitvisor файле printf.c, для использования в целевой программе нужно заменить строки:

#include "initfunc.h" #include "printf.h" #include "putchar.h" #include "spinlock.h"
на строки:
#include "types.h" #include "stdarg.h" #include "screen.h"

Потом, удалить функцию printf_init_global и все ее упоминания в этом файле:

Static void printf_init_global (void) { spinlock_init (&printf_lock); } INITFUNC ("global0", printf_init_global);

Затем удалить переменную printf_lock и все ее упоминания в этом файле:
static spinlock_t printf_lock; … spinlock_lock (&printf_lock); … spinlock_unlock (&printf_lock);

Функция printf использует функцию putchar, которую так же нужно написать. Для этого создадим файл common\screen.с, со следующим содержимым:
#include "types.h" #define GREEN 0x2 #define MAX_COL 80 // Maximum number of columns #define MAX_ROW 25 // Maximum number of rows #define VRAM_SIZE (MAX_COL*MAX_ROW) // Size of screen, in short"s #define DEF_VRAM_BASE 0xb8000 // Default base for video memory static unsigned char curr_col = 0; static unsigned char curr_row = 0; // Write character at current screen location #define PUT(c) (((unsigned short *) (DEF_VRAM_BASE)) \ [(curr_row * MAX_COL) + curr_col] = (GREEN << 8) | (c)) // Place a character on next screen position static void cons_putc(int c) { switch (c) { case "\t": do { cons_putc(" "); } while ((curr_col % 8) != 0); break; case "\r": curr_col = 0; break; case "\n": curr_row += 1; if (curr_row >= MAX_ROW) { curr_row = 0; } break; case "\b": if (curr_col > 0) { curr_col -= 1; PUT(" "); } break; default: PUT(c); curr_col += 1; if (curr_col >= MAX_COL) { curr_col = 0; curr_row += 1; if (curr_row >= MAX_ROW) { curr_row = 0; } } }; } void putchar(int c) { if (c == "\n") cons_putc("\r"); cons_putc(c); } void clear_screen(void) { curr_col = 0; curr_row = 0; int i; for (i = 0; i < VRAM_SIZE; i++) cons_putc(" "); curr_col = 0; curr_row = 0; }

Указанный код, содержит простую логику печати символов на экран в текстовом режиме. В этом режиме для записи символа используется два байта (один с кодом символа, другой с его атрибутами), записываемые прямо в видео память отображаемую сразу на экране и начинающуюся с адреса 0xB8000. Разрешение экрана при этом 80x25 символов. Непосредственно печать символа осуществляется при помощи макроса PUT.
Теперь не хватает всего несколько заголовочных файлов:
1. Файл include\screen.h. Объявляет функцию putchar, которая используется в функции printf. Содержимое файла:
#ifndef _SCREEN_H #define _SCREEN_H void clear_screen(void); void putchar(int c); #endif

2. Файл include\printf.h. Объявляет функцию printf, которая используется в main. Содержимое файла:
#ifndef _PRINTF_H #define _PRINTF_H int printf (const char *format, ...); #endif

3. Файл include\stdarg.h. Объявляет функции для перебора аргументов, количество которых заранее не известно. Файл целиком берется из проекта www.bitvisor.org . Путь до файла в коде проекта bitvisor: include\core\stdarg.h.
4. Файл include\types.h. Объявляет NULL и size_t. Содержимое файла:
#ifndef _TYPES_H #define _TYPES_H #define NULL 0 typedef unsigned int size_t; #endif
Таким образом папки include и common содержат минимальный код системной библиотеки, которая необходима любой программе.

Шаг 3. Создание скрипта для компоновщика:

Создаем файл linker.ld, который будет использоваться компоновщиком для формирования файла целевой программы (kernel.bin). Файл должен содержать следующее:

ENTRY (loader) LMA = 0x00100000; SECTIONS { . = LMA; .multiboot ALIGN (0x1000) : { loader.o(.text) } .text ALIGN (0x1000) : { *(.text) } .rodata ALIGN (0x1000) : { *(.rodata*) } .data ALIGN (0x1000) : { *(.data) } .bss: { *(COMMON) *(.bss) } /DISCARD/ : { *(.comment) } }

Встроенная функция ENTRY() позволяет задать входную точку для нашего ядра. Именно по этому адресу передаст управление grub после загрузки ядра. Компоновщик при помощи этого скрипта создаст бинарный файл в формате ELF. ELF-файл состоит из набора сегментов и секций. Список сегментов содержится в Program header table, список секций в Section header table. Линковщик оперирует с секциями, загрузчик образа (в нашем случае это GRUB) с сегментами.


Как видно на рисунке, сегменты состоят из секций. Одним из полей, описывающих секцию, является виртуальный адрес, по которому секция должна находиться на момент выполнения. На самом деле, у сегмента есть 2 поля, описывающих его расположение: виртуальный адрес сегмента и физический адрес сегмента. Виртуальный адрес сегмента это виртуальный адрес первого байта сегмента в момент выполнения кода, физический адрес сегмента это физический адрес по которому должен быть загружен сегмент. Для прикладных программ эти адреса всегда совпадают. Grub загружает сегменты образа, по их физическому адресу. Так как Grub не настраивает страничную адресацию, то виртуальный адрес сегмента должен совпадать с его физическим адресом, поскольку в нашей программе виртуальная память так же не настраивается.

SECTIONS
Говорит о том, что далее описываются секции.
. = LMA;
Это выражение указывает линковщику, что все последующие секции находятся после адреса LMA.
ALIGN (0x1000)
Директива выше, означает, что секция выровнена по 0x1000 байт.
.multiboot ALIGN (0x1000) : { loader.o(.text) }
Отдельная секция multiboot, которая включает в себя секцию.text из файла loader.o, сделана для того, что бы гарантировать попадание сигнатуры формата multiboot в первые 8кб образа ядра.
.bss: { *(COMMON) *(.bss) }
*(COMMON) это область, в которой резервируется память инструкциями.comm и.lcomm. Мы располагаем ее в секции.bss.
/DISCARD/ : { *(.comment) }
Все секции, помеченные как DISCARD, удаляются из образа. В данном случае мы удаляем секцию.comment, которая содержит информацию о версии линковщика.

Теперь скомпилируем код в бинарный файл следующими командами:
as -o loader.o loader.s gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o kernel.o -c kernel.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o printf.o -c common/printf.c gcc -Iinclude -Wall -fno-builtin -nostdinc -nostdlib -o screen.o -c common/screen.c ld -T linker.ld -o kernel.bin kernel.o screen.o printf.o loader.o
С помощью objdump’а рассмотрим, как выглядит образ ядра после линковки:
objdump -ph ./kernel.bin


Как можно видеть, секции в образе совпадают с теми, что мы описали в скрипте линковщика. Линковщик сформировал 3 сегмента из описанных секций. Первый сегмент включает в себя секции.multiboot, .text, .rodata и имеет виртуальный и физический адрес 0x00100000. Второй сегмент содержит секции.data и.bss и располагается по адресу 0x00104000. Значит все готово для загрузки этого файла при помощи Grub.

Шаг 4. Подготовка загрузчика Grub:
Создать папку grub:
mkdir grub

Скопировать в эту папку несколько файлов Grub, которые необходимы для его установки на образ (указанные далее файлы существуют, если в системе установлен Grub). Для этого нужно выполнить следующие команды:
cp /usr/lib/grub/i386-pc/stage1 ./grub/ cp /usr/lib/grub/i386-pc/stage2 ./grub/ cp /usr/lib/grub/i386-pc/fat_stage1_5 ./grub/

Создать файл grub/menu.lst, со следующим содержимым:
timeout 3 default 0 title mini_os root (hd0,0) kernel /kernel.bin

Шаг 5. Автоматизация и создание загрузочного образа:

Для автоматизации процесса сборки будем использовать утилиту make. Для этого создадим файл makefile, который будет собирать компилировать исходный код, собирать ядро и создавать загрузочный образ. Makefile должен иметь следующее содержимое:

CC = gcc CFLAGS = -Wall -fno-builtin -nostdinc -nostdlib LD = ld OBJFILES = \ loader.o \ common/printf.o \ common/screen.o \ kernel.o image: @echo "Creating hdd.img..." @dd if=/dev/zero of=./hdd.img bs=512 count=16065 1>/dev/null 2>&1 @echo "Creating bootable first FAT32 partition..." @losetup /dev/loop1 ./hdd.img @(echo c; echo u; echo n; echo p; echo 1; echo ; echo ; echo a; echo 1; echo t; echo c; echo w;) | fdisk /dev/loop1 1>/dev/null 2>&1 || true @echo "Mounting partition to /dev/loop2..." @losetup /dev/loop2 ./hdd.img \ --offset `echo \`fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$3}"\`*512 | bc` \ --sizelimit `echo \`fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$4}"\`*512 | bc` @losetup -d /dev/loop1 @echo "Format partition..." @mkdosfs /dev/loop2 @echo "Copy kernel and grub files on partition..." @mkdir -p tempdir @mount /dev/loop2 tempdir @mkdir tempdir/boot @cp -r grub tempdir/boot/ @cp kernel.bin tempdir/ @sleep 1 @umount /dev/loop2 @rm -r tempdir @losetup -d /dev/loop2 @echo "Installing GRUB..." @echo "device (hd0) hdd.img \n \ root (hd0,0) \n \ setup (hd0) \n \ quit\n" | grub --batch 1>/dev/null @echo "Done!" all: kernel.bin rebuild: clean all .s.o: as -o $@ $< .c.o: $(CC) -Iinclude $(CFLAGS) -o $@ -c $< kernel.bin: $(OBJFILES) $(LD) -T linker.ld -o $@ $^ clean: rm -f $(OBJFILES) hdd.img kernel.bin

В файле объявлены две основные цели: all – компилирует ядро, и image – которая создает загрузочный диск. Цель all подобно привычным makefile содержит подцели.s.o и.c.o, которые компилируют *.s и *.c файлы в объектные файлы (*.o), а так же цель для формирования kernel.bin, которая вызывает компоновщик с созданным ранее скриптом. Эти цели выполняют ровно те же команды, которые указаны в шаге 3.
Наибольший интерес здесь представляет создание загрузочного образа hdd.img (цель image). Рассмотрим поэтапно, как это происходит.
dd if=/dev/zero of=./hdd.img bs=512 count=16065 1>/dev/null 2>&1
Эта команда создает образ, с которым будет происходить дальнейшая работа. Количество секторов выбрано не случайно: 16065 = 255 * 63. По умолчанию fdsik работает с диском так, как будто он имеет CHS геометрию, в которой Headers (H) = 255, Sectors (S) = 63, а Cylinders(С) зависит от размера диска. Таким образом, минимальный размер диска, с которым может работать утилита fdsik, без изменения геометрии по умолчанию, равен 512 * 255 * 63 * 1 = 8225280 байт, где 512 – размер сектора, а 1 – количество цилиндров.
Далее создается таблица разделов:
losetup /dev/loop1 ./hdd.img (echo c; echo u; echo n; echo p; echo 1; echo ; echo ; echo a; echo 1; echo t; echo c; echo w;) | fdisk /dev/loop1 1>/dev/null 2>&1 || true
Первая команда монтирует файл hdd.img к блочному устройству /dev/loop1, позволяя работать с файлом как с устройством. Вторая команда создает на устройстве /dev/loop1 таблицу разделов, в которой находится 1 первичный загрузочный раздел диска, занимающий весь диск, с меткой файловой системы FAT32.
Затем форматируем созданный раздел. Для этого нужно примонтировать его как блочное устройство и выполнить форматирование.
losetup /dev/loop2 ./hdd.img \ --offset `echo \`fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$3}"\`*512 | bc` \ --sizelimit `echo \`fdisk -lu /dev/loop1 | sed -n 10p | awk "{print $$4}"\`*512 | bc` losetup -d /dev/loop1
Первая команда монтирует ранее созданный раздел к устройству /dev/loop2. Опция –offset указывает адрес начала раздела, а –sizelimit адрес конца раздела. Оба параметра получаются с помощью команды fdisk.
mkdosfs /dev/loop2
Утилита mkdosfs форматирует раздел в файловую систему FAT32.
Для непосредственной сборки ядра используются рассмотренные ранее команды в классическом синтаксисе makefile.
Теперь рассмотрим как установить GRUB на раздел:
mkdir -p tempdir # создает временную директорию mount /dev/loop2 tempdir # монтирует раздел в директорию mkdir tempdir/boot # создает директорию /boot на разделе cp -r grub tempdir/boot/ # копируем папку grub в /boot cp kernel.bin tempdir/ # копирует ядро в корень раздела sleep 1 # ждем Ubuntu umount /dev/loop2 # отмонтируем временную папку rm -r tempdir # удаляем временную папку losetup -d /dev/loop2 # отмонтируем раздел
После выполнения вышеприведенных команд, образ будет готов к установке GRUB’а. Следующая команда устанавливает GRUB в MBR образа диска hdd.img.
echo "device (hd0) hdd.img \n \ root (hd0,0) \n \ setup (hd0) \n \ quit\n" | grub --batch 1>/dev/null

Все готово к тестированию!

Шаг 6. Запуск:

Для компиляции, воспользуемся командой:
make all
После которой должен появиться файл kernel.bin.
Для создания загрузочного образа диска, воспользуемся командой:
sudo make image
В результате чего должен появиться файл hdd.img.
Теперь с образа диска hdd.img можно загрузиться. Проверить это можно с помощью следующей команды:
qemu -hda hdd.img -m 32
или:
qemu-system-i386 -hda hdd.img



Для проверки на реальной машине нужно сделать dd этого образа на флэшку и загрузиться с нее. Например такой командой:
sudo dd if=./hdd.img of=/dev/sdb

Подводя итоги, можно сказать, что в результате проделанных действий получается набор исходников и скриптов, которые позволяют проводить различные эксперименты в области системного программирования. Сделан первый шаг на пути создания системного программного обеспечения, такого как гипервизоры и операционные системы.

Некоторым приложениям для работы в Windows требуются повышенные права, и запускать их необходимо от имени администратора. При этом выводится запрос "Контроля учетных записей пользователя " (User Account Control или UAC ), в котором система просит Вашего согласия на запуск приложения.

Многие пользователи неправильно полагают, что "Контроль учетных записей пользователя" лишь мешает, и отключают его. При этом серьёзно страдает безопасность компьютера, т.к. согласия пользователя на запуск приложений больше не требуется, и любая вредоносная программа может беспрепятственно запускаться и работать. Наличие антивируса также не может на 100% гарантировать безопасность компьютера.

В этой статье я расскажу, как упростить процесс запуска избранных приложений от имени администратора, не отключая UAC (полностью или частично) и без вреда для безопасности.

Для запуска приложения от имени администратора можно воспользоваться несколькими способами:

В качестве примера будем запускать командную строку (cmd) от имени администратора.

Способ №1 (обычный) - запуск через правую клавишу мыши (запрос UAC отображается)

Нажмите правой клавишей мыши по значку нужного приложения и выберите пункт "Запуск от имени администратора ":

Способ №2 - запуск с использованием "Ctrl+Shift+Enter " (запрос UAC отображается)

Нажмите Пуск , в строке поиска наберите нужную команду и нажмите Ctrl+Shift+Enter .

Способ №3 - устанавливаем запуск от имени администратора в свойствах ярлыка (запрос UAC отображается)

Щелкните правой клавишей мыши по нужному ярлыку и выберите пункт "Свойства ".

Перейдите на вкладку "Ярлык ", нажмите "Дополнительно ", установите флажок "Запускать от имени администратора ":


Или перейдите на вкладку "Совместимость " и установите флажок "Выполнять эту программу от имени администратора ":

Способ №4 - упрощаем запуск для избранных приложений при помощи планировщика заданий (запрос UAC не отображается)

Важно! Этот способ работает только для учетных записей, входящих в группу Администраторы . У обычных пользователей он не сработает, потому что их потолком являются ограниченные права.

Переходим к самому интересному способу. Если есть приложение, которое Вы постоянно запускаете, и оно получено от надёжного производителя ПО, например, это приложение Windows - можно упростить запуск. Создание ярлыка для нужной программы не занимает более 2-х минут и это позволит избавиться от лишних действий в дальнейшем. Запускаем планировщик заданий (Пуск ---> Все программы ---> Стандартные ---> Служебные ---> Планировщик заданий ) и нажимаем "Создать задачу ":

Указываем Имя для новой задачи и ставим флажок "Выполнять с наивысшими правами ":

Переходим на вкладку Действия , нажимаем "Создать ", в следующем окне нажимаем "Обзор ":

Указываем путь к нужному приложению и нажимаем "Открыть ":



Увеличить рисунок

Нажимаем "ОК ":

Закрываем планировщик и переходим к созданию ярлыка.

Чтобы создать ярлык на рабочем столе, щёлкаем правой клавишей мыши, выбираем "Создать " ---> "Ярлык ":


В поле Расположение объекта вводим:

Schtasks /run /tn cmd_admin

где cmd_admin - имя созданной нами задачи. Если имя содержит пробелы, его необходимо указывать в кавычках.

Задаём название ярлыка:



Увеличить рисунок

Ярлык создан и готов к использованию.

Чтобы сменить значок - нажмите правой клавишей мыши по ярлыку, выберите "Свойства ":

Перейдите на вкладку "Ярлык "и нажмите "Сменить значок ":

"Обзор ..."

Указываем путь к программе:



Увеличить рисунок

Выбираем нужный значок и закрываем оба окна кнопкой "ОК ":

Теперь запуск нужного приложения от имени администратора выполняется двойным щелчком по созданному ярлыку, при этом запрос UAC не отображается и безопасность остаётся в сохранности.

Утилита для автоматизации "Способа №4"

В случае, если требуется создать ярлыки для большого количества программ, удобно воспользоваться утилитой .

Работа с утилитой сводится к двум простым шагам:

  • Установка
  • Перетаскивание исполняемого файла (*.exe, *.bat, *.cmd) на ярлык утилиты:


Автоперевод фокуса на запущенную программу

Специфика запуска приложений из планировщика состоит в том, что фокус на окно не переводится и, например чтобы набрать команду в командной строке приходится дополнительно щёлкать по окну. Такое поведение может помочь в автоматизации рутинных операций по расписанию, но для "Способа №4" это не всегда удобно.

Для "обхода" существует несколько методов. Работают они немного по-разному, так что выбирайте наиболее подходящий. Первый более удобен для запуска программ, а второй для запуска скриптов.

Добавляем при создании задачи:

Использование команды start

Программа или сценарий:

Аргументы:

/c start /d "путь_к_программе" имя_файла.exe

/c start /d "C:\Windows\System32\" cmd.exe

Использование утилиты NirCmd

Программа или сценарий:

Путь_к_nircmd\nircmd.exe

Аргументы:

Exec show "путь_к_программе\имя_файла.exe"

Exec show "C:\Windows\System32\cmd.exe"

Запуск диалога "Выполнить" от имени администратора

По аналогии с запуском командной строки можно настроить запуск диалогового окна "Выполнить ", и введённые в него команды также будут запущены от имени администратора. Удобство этого подхода заключается в том, что список ранее использованных команд сохраняется, и можно выбрать нужную из списка.


При создании задачи в планировщике, в окне "Создание действия " укажите:

в поле "Программа или сценарий ":

Rundll32

в поле "Добавить аргументы ":

Shell32.dll,#61

Скачиваем утилиту, распаковываем. Запускаем командную строку, вводим нужную команду, синтаксис совсем нехитрый:

<путь к утилите> <путь к нужному приложению>


Выведется запрос UAC и приложение запустится от имени администратора.

Примечание: В контекстном меню Windows 7 есть очень удобная функция копирования пути файла: зажмите Shift , щёлкните правой клавишей мыши по файлу, выберите пункт "Копировать как путь ".


Запуск программ пользователем от имени администратора без ввода пароля администратора

Важно! Этот способ небезопасен, так как позволяе пользователю с ограниченными правами запускать код с полными правами. Хитрый пользователь или вредоносное ПО могут этим воспользоваться и скомпрометировать систему.

Рассмотрим ещё одну интересную задачу: Ваша учётная запись Windows входит в группу администраторов, есть ещё одна или несколько учётных записей, входящих в группу пользователей. Пользователю необходимо запускать программу, требующую повышения прав. Обычно это выглядит так: пользователь нажимает правой клавишей мыши по файлу и выбирает "Запуск от имени Администратора", при этом выводится запрос на ввод пароля администратора:


Разумеется, раздать пользователям пароль администратора - не самая хорошая идея. Чтобы это "обойти" будем использовать утилиту AdmiLink Алексея Курякина. С её помощью администратор может создать для пользователя ярлык на запуск необходимой программы, при этом ввод пароля администратора требуется всего 1 раз - при создании ярлыка. Во время запуска программы пользователем пароль будет передаваться в зашифрованном виде.



Этот способ будет работать, если запуск программы возможен только от имени администратора и разработчик не забыл указать это условие в манифесте . Однако ещё остаётся большое количество старых программ или программ, запуск которых возможен как в обычном режиме, так и от имени администратора (при этом будет доступен разный набор функций). При попытке запуска такой программы с помощью AdmiLink - она запускается в обычном режиме (без административных привилегий). А если попытаться проставить флажок "Способом №3 . Оригинальный стиль автора сохранен.



gastroguru © 2017