Защитить проект VBA – S.H.T.E.M.

Безопасность файлов

Microsoft, проявляя заботу о пользователях, всячески пытается предотвратить случайное распространение компьютерных вирусов, написанных на VBA. Основываясь на собственном опыте, можем предположить, что такая «забота» зачастую приносит больше проблем пользователям, чем повышает безопасность их работы.

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

Но плохо даже не то, что Microsoft перестраховывается в поиске потенциальных угроз. Огорчает непоследовательность и постоянное усложнение процедуры управления безопасностью проектов Excel-VBA. Кроме того, явно прослеживается тенденция, направленная на использование цифровой подписи надежных издателей.

Вот как исторически изменялись характеристики безопасности:

  • Excel 2007 (12.0) – переписан интерфейс параметров, появился так называемый «Центр управления безопасностью». Уровни безопасности изменились по поведению, хотя их также осталось четыре. По умолчанию при открытии файла с макросами под лентой появляется окошко с возможностью активизировать макросы. Условно говоря, это тот же диалог подключения макросов, но открывается он немодально. Решение с одной стороны кажется привлекательным по интерфейсу, но может привести к несовместимости со старым версиями: например, пользователь может поработать некоторое время без макросов, а затем их подключить. Появилась отдельная опция возможности управления объектом VBE на уровне кода, которая по умолчанию отключена. Также отдельно настраивается безопасность надстроек Excel, которые по умолчанию пока все-таки подключаются без дополнительных вопросов.

Учитывайте эти различия в настройках при разработке и распространении собственных приложений для Excel.

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

Кратко, как создается данная защита

Для создания данной защиты нужно, разархивировать файл Excel. Перейти в архиве в папку

xl

, открыть файл

vbaProject.bin

,  в конце файла находятся наши ключи, редактируем значения ключей на пусто, сохраняем файл. Переводим наш архив, обратно в файл Excel. Готово! 

Это самый простой вариант данной защиты, но существует множество модификаций.

Алгоритм снятия защиты Project is Unviewable.

1)  Разархивируем подопытный файл, переходим в файл  …xl_relsworkbook.xml.rels

2)      В файле workbook.xml.rels  ищем строку, содержащую слово  vbaProject, обычно имеет следующий вид:  />. В этой строке нас интересует ключ Target,иего значение. Значение является название файла, в котором находится проект VBA.

3)      Открываем на редактирование файл, указанный в  ключе Target, ищем в файле ключи  CMG, DPB, GC. И меняем в их названиях любую букву на любую другую, например: CMC, DPC, CC. При поиске нужно быть аккуратным, так как защищающий может поместить  в проект форму,  подписью повторяющую один из ключей, например такую:

4)      Переводим архив обратно в файл Excel.

5)      Запускаем приложение Excel, выполняем следующее: в Центре управления безопасностью -> Параметры макросов  -> Отключить все макросы без уведомления. Перезапускаем Excel. Данная операция нужна, для блокировки защиты, которую иногда ставят авторы макросов.

6)      Открываем файл. Если все правильно сделано то, Excel, будет ругаться на не правильные ключи, которые мы отредактировали, в пункте 3. Жмем, да, пока данные сообщения не закончатся и диалоговое окно закроется. 

      Если данное сообщение не появляется то, вы отредактировали не файл который содержит проект VBA.

7)      Открываем проект VBA. После всего, проект VBA должен быть доступен.

8)      Но иногда защита не снимается, тогда нужно сохранить файл, проверить, что он действительно сохранился! И проделать повторно операции с 1 по 7. Обычно так происходит когда в файле workbook.xml.rels в ключе Target  установлено printerSettings.bin.При сохранение,  Excel  исправляет это на значение на vbaProject.bin

Данную защиту можно установить и снять следующим инструментом:

Третий вид защиты — Hidden  Module, скрытые модули VBA

Время на снятие:  от 15 до 20 мин (нужен редактор OLE — объектов, Structured Storage Viewer, например.

Недостаток: доступ к коду модуля VBA

Менее распространенный вид  защиты обычно встречается в комбинации с защитой Project is Unviewable. При установке данной защиты модуль VBA не отображается в проекте книги Excel. О его существовании можно узнать, проанализировав код VBA (что требует время!) или открыть файл Excel в программе  OpenOffice  или  LibreOffice (так же можно смотреть код при защите Project is Unviewable, но данный способ не дает возможность получить рабочий файл, без пароля).

Просмотр кода VBA в 

LibreOffice

Обфускация кода

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

Например, имеется простейший код, который сравнивает две переменные и выводит сообщение:

Sub sravnenie()
Dim a As Double 
Dim b As Double
a = 50 'первая переменная
b = 30 'вторая переменная
If (a >= b) Then 'сравнение
    MsgBox a & " больше или равно " & b, "Сравнение"
Else
    MsgBox a & " меньше " & b, "Сравнение"
End If
End Sub

После обфускации получится следующий код:

Sub q3294ac481200c9f62b6a7dac981cea19()
Dim b17fea5c0191a5bc3c2640b8f16b14e98 As Double
Dim ea06f6764676da2a53039a8c582369215 As Double
b17fea5c0191a5bc3c2640b8f16b14e98 = 50
ea06f6764676da2a53039a8c582369215 = 30
If (b17fea5c0191a5bc3c2640b8f16b14e98 >= ea06f6764676da2a53039a8c582369215) Then
MsgBox b17fea5c0191a5bc3c2640b8f16b14e98 & " больше или равно " & ea06f6764676da2a53039a8c582369215, "Сравнение"
Else
MsgBox b17fea5c0191a5bc3c2640b8f16b14e98 & " меньше " & ea06f6764676da2a53039a8c582369215, "Сравнение"
End If
End Sub

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

Для того, чтобы защитить проект VBA с помощью обфускации, можно воспользоваться готовыми инструментами:

Обфускация — эффективный способ защиты VBA (и не только VBA). Его также можно использовать с первым способом: если пароль взломают, то с анализом и интерпретацией кода придется довольно долго потрудиться.

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

Получение цифрового удостоверения

Получение цифрового удостоверения для отправки сообщений с помощью Microsoft Exchange Server.

  1. Получите цифровое удостоверение S/MIME из центра сертификации.
  2. Выберите в меню Сервис команду Параметры и откройте вкладку Безопасность.
  3. Нажмите кнопку «Получить удостоверение».
  4. Установите переключатель Получить сертификат S/MIME из центра сертификации и нажмите кнопку «OK».
  5. Будет автоматически запущен web-обозреватель и открыта страница на web-узле Microsoft Office. Щелкните ссылку, наиболее близкую к расположению ваших страны или региона. Будет открыта страница со списком нескольких центров сертификации. Выберите любой из них и выполните указания на web-странице, чтобы зарегистрироваться для получения сертификата. Из центра сертификации будут высланы цифровое удостоверение и дополнительные указания.
  6. Выберите используемое цифровое удостоверение.
  7. Выберите в меню Сервис команду Параметры и откройте вкладку Безопасность.
  8. Нажмите кнопку «Настройка».
  9. Если цифровая подпись существует, она была автоматически настроена при создании. Если необходимо поменять используемую цифровую подпись, выполните следующие действия:
    • нажмите кнопку «Создать» раздела Настройки безопасности;
    • введите имя в поле «Имя конфигурации»;
    • в списке Формат криптографии выберите пункт «S/MIME». При другом типе сертификата может потребоваться выбрать пункт «Exchange server security»;
    • рядом с полем «Сертификат подписи» нажмите кнопку «Выбрать» и щелкните по цифровому удостоверению.
Читайте также:  Регистрация ООО с ЭЦП (электронно-цифровой подписью) - Consult Group

Чтобы узнать, поддерживает ли данный сертификат цифровые подписи и шифрование, в диалоговом окне Выбор сертификата нажмите кнопку «Просмотр сертификата». В сертификате, подходящем для шифрования сообщений (а значит, поддерживающем цифровые подписи), будет написано что-нибудь вроде «Обеспечивает безопасность сообщений электронной почты».

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

Примеры работы с range

Sheets("result").Activate
Dim r As Range
Set r = Range("A1")
r.Value = "123"
Set r = Range("A3,A5")
r.Font.Color = vbRed
r.Value = "456"
Set r = Range("A6:A7")
r.Value = "=A1 A3"

Теперь давайте поймем алгоритм работы нашего кода. Итак, у каждой строчки листа data, начиная со второй, есть некоторые данные, которые нас не интересуют (ID, название и цена) и есть две вложенные группы, к которым она принадлежит (тип и производитель).

  1. Считали группы из очередной строки.
  2. Пробегаемся по всем группам в порядке приоритета (вначале более крупные)
    1. Если текущая группа не совпадает, вызываем процедуру AddGroup(i, name), где i — номер группы (от номера текущей до максимума), name — её имя. Несколько вызовов необходимы, чтобы создать не только наш заголовок, но и всё более мелкие.
  3. После отрисовки всех необходимых заголовков делаем еще одну строку и заполняем её данными.

Для упрощения работы рекомендую определить следующие функции-сокращения:

Function GetCol(Col As Integer) As StringGetCol = Chr(Asc(“A”)   Col)End Function

Function GetCellS(Sheet As String, Col As Integer, Row As Integer) As RangeSet GetCellS = Sheets(Sheet).Range(GetCol(Col)   CStr(Row))End Function

Function GetCell(Col As Integer, Row As Integer) As RangeSet GetCell = Range(GetCol(Col)   CStr(Row))End Function

Далее определим глобальную переменную «текущая строчка»: Dim CurRow As Integer. В начале процедуры её следует сделать равной единице. Еще нам потребуется переменная-«текущая строка в data», массив с именами групп текущей предыдущей строк. Потом можно написать цикл «пока первая ячейка в строке непуста».

Примеры синтаксиса

' Процедура. Ничего не возвращает
' Перегрузка в VBA отсутствует
Sub foo(a As String, b As String)
' Exit Sub ' Это значит "выйти из процедуры"
    MsgBox a   ";"   b
End Sub

' Функция. Вовращает Integer
Function LengthSqr(x As Integer, y As IntegerAs Integer
' Exit Function
    LengthSqr = x * x   y * y
End Function

Sub FormatPrice()
Dim s1 As String, s2 As String
s1 = "str1"
s2 = "str2"
If s1 <> s2 Then
foo "123""456" ' Скобки при вызове процедур запрещены
    End If

    Dim res As sTRING ' Регистр в VB не важен. Впрочем, редактор Вас поправит
    Dim i As Integer
' Цикл всегда состоит из нескольких строк
    For i = 1 To 10
res = res   CStr(i) ' Конвертация чего угодно в String
        If i = 5 Then Exit For
Next i

    Dim x As Double
x = Val("1.234"' Парсинг чисел
    x = x   10
MsgBox x

    On Error Resume Next ' Обработка ошибок - игнорировать все ошибки
    x = 5 / 0
MsgBox x

    On Error GoTo Err ' При ошибке перейти к метке Err
    x = 5 / 0
MsgBox "OK!"
GoTo ne

Err:
MsgBox "Err!"

ne:
On Error GoTo 0 ' Отключаем обработку ошибок

' Циклы бывает, какие захотите
    Do While True
Exit Do

    Loop 'While True
    Do 'Until False
        Exit Do
Loop Until False
' А вот при вызове функций, от которых хотим получить значение, скобки нужны.
    ' Val также умеет возвращать Integer
    Select Case LengthSqr(Len("abc"), Val("4"))
Case 24
MsgBox "0"
Case 25
MsgBox "1"
Case 26
MsgBox "2"
End Select

    ' Двухмерный массив.
    ' Можно также менять размеры командой ReDim (Preserve) - см. google
    Dim arr(1 to 10, 5 to 6) As Integer
arr(1, 6) = 8

    Dim coll As New Collection
Dim coll2 As Collection
coll.Add "item""key"
Set coll2 = coll ' Все присваивания объектов должны производится командой Set
    MsgBox coll2("key")
Set coll2 = New Collection
MsgBox coll2.Count
End Sub

Создание самоподписанного сертификата средствами powershell – pki extensions

Самоподписанные сертификаты — это зло, за исключением сертификатов корневых CA. Я об этом говорил, говорю и буду говорить. Но в данном случае мы не преследуем цель создания самоподписанного сертификата. Нас по сути будет интересовать немного другое — рассмотрение принципа, который заложен во многих популярных тулзах как MakeCert или OpenSSL. Лично я не фанат ни первого, ни второго по своим сугубо личным причинам. Но, кроме этих двоих есть ещё утилита CertReq.exe, которая достаточно православная и вряд ли ей грозит вымирание (а жаль). Вобщем, сегодня предлагаю ещё раз поковырять CryptoAPI.

Как мы уже знаем, CryptoAPI обладает большим количеством всяческих COM интерфейсов, при помощи которых мы можем работать практически с любыми аспектами цифровых сертификатов. Некоторые из них бажные, а некоторые — не очень :-), но функционал у них впечатляющий. В настоящее время существует 2 основных набора API, которые реализуют клиентскую часть энроллмента — XEnroll и CertEnroll. Первый доступен только в системах начиная с Windows 2000 и до Windows Server 2003 включительно. В более новых версиях XEnroll был вырезан вместе с CAPICOM’ом полностью (куски CAPICOM’а ещё можно найти в висте) за ненадобностью. Семейство интерфейсов CertEnroll было значительно переработано и расширено, что делает его крайне гибким. Я не буду рассказывать про XEnroll, потому что это неинтересно и трупов пинать нехорошо.

Многие считают, что CryptoAPI — это очень сложно. Я могу возразить им. Я не программист совсем, но могу достаточно свободно их использовать. Нашей отправной точкой будет MSDN по адресу: Certificate Enrollment API Reference. Эта секция содержит всё самое необходимое — описание интерфейсов и перечисления. И самый первый интерфейс, который мы видим — IX509Enrollment. Этот интерфейс реализует нечто промежуточное между клиентом и сервером. Мы можем по описанию найти то, что нам нужно, а именно первую секцию — Out-of-band-enrollment. И мы видим, что для него надо сначала вызвать метод CreateRequest(). Но прежде чем вызывать метод, нам надо создать форму сертификата, на основе которой будет создан запрос. Как я уже упоминал, мы будем делать самоподписанный сертификат, поэтому следующий интерфейс подойдёт нам как нельзя кстати — IX509CertificateRequestCertificate2. Вот давайте с него и начнём.

Все указанные здесь и далее интерфейсы являются COM интерфейсами семейства X509Enrollment и эти объекты создаются следующим образом:

$Cert=New-Object-ComObjectX509Enrollment.CX509CertificateRequestCertificate.1

Примечание: как строятся такие команды? Поскольку это COM интерфейс, первую букву I в названии интерфейса меняем на букву C. Далее, если мы видим цифру 2 в конце названия интерфейса, в команде мы ставим точку и пишем число на единцу меньшее. Вот такие нехитрые правила.

Прежде чем его начать использовать, нам надо инициализировать его. К сожалению документация на MSDN далеко не полная, поэтому будем искать нужные методы через PowerShell и командлет Get-Member:

[↓] [vPodans] $cert | gm -MemberType methods


   TypeName: System.__ComObject#{728ab35a-217d-11da-b2a4-000e7bbb2b09}

Name                             MemberType Definition
----                             ---------- ----------
CheckPublicKeySignature          Method     void CheckPublicKeySignature (IX509PublicKey)
CheckSignature                   Method     void CheckSignature (Pkcs10AllowedSignatureTypes)
Encode                           Method     void Encode ()
GetCspStatuses                   Method     ICspStatuses GetCspStatuses (X509KeySpec)
GetInnerRequest                  Method     IX509CertificateRequest GetInnerRequest (InnerRequestLevel)
Initialize                       Method     void Initialize (X509CertificateEnrollmentContext)
InitializeDecode                 Method     void InitializeDecode (string, EncodingType)
InitializeFromCertificate        Method     void InitializeFromCertificate (X509CertificateEnrollmentContext, string...
InitializeFromPrivateKey         Method     void InitializeFromPrivateKey (X509CertificateEnrollmentContext, IX509Pr...
InitializeFromPrivateKeyTemplate Method     void InitializeFromPrivateKeyTemplate (X509CertificateEnrollmentContext,...
InitializeFromPublicKey          Method     void InitializeFromPublicKey (X509CertificateEnrollmentContext, IX509Pub...
InitializeFromTemplate           Method     void InitializeFromTemplate (X509CertificateEnrollmentContext, IX509Enro...
InitializeFromTemplateName       Method     void InitializeFromTemplateName (X509CertificateEnrollmentContext, string)
IsSmartCard                      Method     bool IsSmartCard ()
ResetForEncode                   Method     void ResetForEncode ()


[↓] [vPodans]

Из всех методов нам по сути доступен только InitializeFromPrivateKey(), поскольку остальные методы инициализации требуют наличие доступа к Certification Authority. Посмотрим что требуется для этого метода:

[↓] [vPodans] $cert | gm -MemberType methods | ?{$_.name -eq "InitializeFromPrivateKey"} | select definition

Definition
----------
void InitializeFromPrivateKey (X509CertificateEnrollmentContext, IX509PrivateKey, string)


[↓] [vPodans]

В качестве аргументов метода нам надо указать контекст энроллмента и объект закрытого ключа. Значения контекста находятся здесь: X509CertificateEnrollmentContext (просто включаете поиск на MSDN по названию перечисления). В качестве контекста мы можем выбрать контекст текущего пользователя или компьютера (остальное нас сейчас не волнует совсем). Контекст пользователя имеет значение 0x1. Так и запишем. Но этого мало. Надо ещё создать объект закрытого ключа:

$PrivateKey=New-Object-ComObjectX509Enrollment.CX509PrivateKey

Этот интерфейс позволяет задавать различные параметры закрытого ключа, но мы обойдёмся лишь самым необходимым:

$PrivateKey.ProviderName="Microsoft Base Cryptographic Provider v1.0"$PrivateKey.KeySpec=0x2$PrivateKey.Length=1024$PrivateKey.MachineContext=0x0$PrivateKey.Create()

Ура! Мы сгенерировали ключ. Теперь вернёмся к предыдущему интерфейсу и инициализируем его из закрытого ключа:

$Cert.InitializeFromPrivateKey(0x1,$PrivateKey,"")

Мы указываем контекст текущего пользователя и объект закрытого ключа. Там есть ещё один аргумент, который называется String. Я не знаю, что они этим хотели сказать, поэтому оставляем пустую строку. А теперь вернёмся к интерфейсу IX509CertificateRequestCertificate2 и посмотрим, что мы можем сделать сейчас. Например, используя свойства NotBefore и NotAfter мы зададим срок действия сертификата. Например, 1 год с сегодняшнего дня:

$Cert.NotBefore=[datetime]::Now$Cert.NotAfter=$Cert.NotBefore.AddDays(365)

Теперь нам надо добавить следующие свойства: EncancedKeyUsage (т.е. для каких целей вообще будет использоваться сертификат), Subject (на кого будет выписан сертификат) и Issuer (кто выдал этот сертификат). Поскольку у нас самоподписанный сертификат, поле Subject и Issuer будут одинаковые. На MSDN’е не хватает документации по свойствам Issuer и Subject, но у нас есть поиск, который нас приведёт сюда: IX500DistinguishedName. Поля Subject и Issuer должны заполняться в формате Distinguished Name и доступные префиксы для DN достаточно понятно расписаны в таблице. Нам нужно как-то активировать этот объект. Методов для инициализации здесь нет, поэтому будем использовать метод Encode().

Лирическое отступление: в подавляющем большинстве случаев вы не можете присваивать значения свойствам объектов после создания самих объектов. Предварительно их надо «активировать» одним из двух способов. Если у объекта есть метод Initialize или производное от него, необходимо сначала воспользоваться одним из доступных методов инициализации. Если объект не содержит явных методов инициализации, нужно воспользоваться методом Encode, который кодирует объект или строку в ASN.1 DER строку и инициализирует объект. Единственным исключением из этого правила являются коллекции объектов. Они как правило используют метод Add() для добавления уже инициализированных объектов.

Уже с главной страницы IX500DistinguishedName видно, что Encode кодирует строку, которая записана в DN формате. Поэтому вызываем этот метод:

$SubjectDN.Encode("CN=Some Subject,DC=lucernepublishing,DC=COM",0x0)

После строки нужно ещё указать флаг, в котором указана строка DN. Ставим дефолтный флаг. Теперь у нас готово поле Subject и Issuer (как мы договаривались, они будут одинаковые). Давайте их прицепим к нашему шаблону сертификата:

$Cert.Subject=$SubjectDN$Cert.Issuer=$Cert.Subject

Что нам осталось сделать? Нам надо создать расширение Enchanced Key Usage. Для этого нам надо использовать следующий интерфейс: IX509ExtensionEnhancedKeyUsage:

$EKU=New-Object-ComObjectX509Enrollment.CX509ExtensionEnhancedKeyUsage

Данный объект инициализируется из коллекции объектов IObjectIds. Давайте создадим эту коллекцию:

$OIDs=New-Object-ComObjectX509Enrollment.CObjectIDs

В эту коллекцию с использованием метода Add() надо добавить один или несколько объектов IObjectId, каждый из которых представляет конкретное предназначение сертификата. Например, Server Authentication, Client Authentication, Smart Card Logon, Secure e-mail и т.д. Но мы сделаем сертификат для Code Signing. OID этого EKU = 1.3.6.1.5.5.7.3.3. Вот и сделаем его:

$OID=New-Object-ComObjectX509Enrollment.CObjectID$OID.InitializeFromValue("1.3.6.1.5.5.7.3.3")$OIDs.Add($OID)$EKU.InitializeEncode($OIDs)

объект EKU у нас готов, теперь его надо добавить в наш шаблон сертификата. Поскольку это не стандартное поле сертификата, а расширение, добавляем этот объект в свойство X509Extensions, которое является аналогом интерфейса IX509Extensions и, который в свою очередь, является коллекцией расширений. Поэтому добавляем наше расширение методом Add():

$Cert.X509Extensions.Add($EKU)

Всё, мы собрали все минимально необходимые поля и расширения:

[↓] [vPodans] $cert


Type                        : 4
EnrollmentContext           : 1
Silent                      : False
ParentWindow                :
UIContextMessage            :
SuppressDefaults            : False
ClientId                    :
CspInformations             : System.__ComObject
HashAlgorithm               : System.__ComObject
AlternateSignatureAlgorithm : False
TemplateObjectId            :
PublicKey                   : System.__ComObject
PrivateKey                  : System.__ComObject
NullSigned                  : False
ReuseKey                    : False
Subject                     : System.__ComObject
CspStatuses                 : System.__ComObject
SmimeCapabilities           : False
SignatureInformation        : System.__ComObject
KeyContainerNamePrefix      : lp
CryptAttributes             :
X509Extensions              : System.__ComObject
CriticalExtensions          : System.__ComObject
SuppressOids                : System.__ComObject
Issuer                      : System.__ComObject
NotBefore                   : 16.04.2021 18:25:22
NotAfter                    : 16.04.2021 18:25:22
SignerCertificate           :
PolicyServer                :
Template                    :



[↓] [vPodans]

Теперь мы можем превращать наш шаблон сертификата в настоящй сертификат.

Лирическое отступление: а что такое запрос в техническом смысле? На самом деле запрос ничем не отличается от сертификата. Когда вы запрашиваете сертификат у CA, клиент использует эти же интерфейсы для генерации запроса. При этом получается самый настоящий самоподписанный сертификат, где Subject и Issuer одинаковые и равны имени текущего пользователя или компьютера, а так же содержит все необходимые расширения. Сам запрос подписывается закрытым ключом, который мы сгенерировали. По большому счёту, его уже можно использовать как настоящий самоподписанный сертификат. Если его отправить на сервер CA, то последний просто подменяет значения необходимых полей (как Issuer, в котором он ставит себя) и расширений, удаляет старую подпись и подписывает сертификат новой подписью. Вы можете убедиться в этом очень просто. Сгенерируйте запрос для сертификата, откройте оснастку Certificates и разверните секцию Certificate Enrollment Requests. Там будет этот самый запрос в виде уже готового сертификата. Просто там он ждёт, пока какой-нибудь CA не подпишет его.

Давайте вернёмся в самое начало текущего поста и вспомним про «исходный предмет» — IX509Enrollment. Вот этот интерфейс нам сконвертирует шаблон сертификата в настоящий сертификат с использованием метода CreateRequest(). Но прежде чем использовать метод, нам надо инициализировать объект:

$Request=New-Object-ComObjectX509Enrollment.CX509enrollment$Request.InitializeFromRequest($Cert)

И генерируем файл запроса, который ничем не отличается от самоподписанного сертификата:

$endCert=$Request.CreateRequest(0x0)

В аргументах метода указываем кодировку согласно этой страничке: EncodingType Enumeration. Мы выбираем Base64 с заголовками. $endCert будет содержать сам сертификат (открытую его часть). Фактически запрос хранится в контейнере Certificate Enrollment Requests. Поскольку этот интерфейс не был задуман специально для самоподписанных сертификатов мы проходим стандартную процедуру установки сертификата. Мы просто берём открытую часть нашего же сертификата и устанавливаем её. Вот, кстати, как он выглядит:

[↓] [vPodans] $endcert
-----BEGIN CERTIFICATE-----
MIICaTCCAdKgAwIBAgIQEzCS/mFIxLBAiGjz7 n0dDANBgkqhkiG9w0BAQUFADBP
MRMwEQYKCZImiZPyLGQBGRYDQ09NMSEwHwYKCZImiZPyLGQBGRYRbHVjZXJuZXB1
Ymxpc2hpbmcxFTATBgNVBAMMDFNvbWUgU3ViamVjdDAeFw0xMDA0MTgxMTI5MDla
Fw0xMTA0MTgxMTI5MDlaME8xEzARBgoJkiaJk/IsZAEZFgNDT00xITAfBgoJkiaJ
k/IsZAEZFhFsdWNlcm5lcHVibGlzaGluZzEVMBMGA1UEAwwMU29tZSBTdWJqZWN0
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBGa PnrhnOFO5 76c5zX5/ xh
Kb2hUYl/pRuIKzYcqrmkvqjpPK/McusibT1h70emUkED0TSZsAlSivdIFK6WSxn6
HsTCaGIHhyOSKAvzQkBsZ74BPEydGT5LiX0 MOTyxwFAHhb bqfbkdkXqUSkJAHK
Z6p fgX8uaJkKjL/kwIDAQABo0YwRDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNV
HQ4EFgQUzIFwoRTY6KjUiqmjWjSjlkxbNncwDgYDVR0PAQH/BAQDAgeAMA0GCSqG
SIb3DQEBBQUAA4GBACizodCpl/cF3OGLUx8HVag0yhr1e1P8 CLPc31FmCPAY1CO
T0yxyJPoafkbXKRjclevNJdvxE3ys9fyYigFUhgswh3oWmjanDaatPKa0kE4147k
SQHvN8JP20KeDDCJBk/FbS3xCn3jTix90ddzTa1uFoqBbBNbKOaDHIrqypTY
-----END CERTIFICATE-----

[↓] [vPodans]

Система приклеит этот сертификат к шаблону сертификата и переложит его уже в контейнер Personal:

$Request.InstallResponse(0x2,$endCert,0x0,"")

Всё, теперь мы увидим этот сертификат в нашем хранилище и который готов к использованию. Я немного переработал код и обернул его в красивую функцию, которая будет делать следующее:

  • Генерировать тестовый самоподписанный сертификат для подписи скриптов PowerShell
  • Устанавливать сертификат с закрытым ключом в контейнер Personal
  • Устанавливать открытую часть сертификата в Trusted Root CAs для обеспечения доверия этому сертификату
  • Устанавливать открытую часть сертификата в Trusted Publishers для задания явного доверия цифровым подписям, сделанные этим сертификатом.
functionNew-SigningCert{[CmdletBinding()]param([string]$Subject="CN=PowerShell User, OU=Test Signing Cert",[int][ValidateSet("1024","2048")]$KeyLength=1024,[datetime]$NotBefore=[DateTime]::Now,[datetime]$NotAfter=$NotBefore.AddDays(365),[switch]$Force)$OS=(Get-WmiObjectWin32_OperatingSystem).Versionif($OS[]-lt6){Write-Warning"Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!"return}$SubjectDN=New-Object-ComObjectX509Enrollment.CX500DistinguishedName$SubjectDN.Encode($Subject,0x0)$OID=New-Object-ComObjectX509Enrollment.CObjectID$OID.InitializeFromValue("1.3.6.1.5.5.7.3.3")$OIDs=New-Object-ComObjectX509Enrollment.CObjectIDs$OIDs.Add($OID)$EKU=New-Object-ComObjectX509Enrollment.CX509ExtensionEnhancedKeyUsage$EKU.InitializeEncode($OIDs)$PrivateKey=New-Object-ComObjectX509Enrollment.CX509PrivateKey$PrivateKey.ProviderName="Microsoft Base Cryptographic Provider v1.0"$PrivateKey.KeySpec=0x2$PrivateKey.Length=$KeyLength$PrivateKey.MachineContext=0x0$PrivateKey.Create()$Cert=New-Object-ComObjectX509Enrollment.CX509CertificateRequestCertificate$Cert.InitializeFromPrivateKey(0x1,$PrivateKey,"")$Cert.Subject=$SubjectDN$Cert.Issuer=$Cert.Subject$Cert.NotBefore=$NotBefore$Cert.NotAfter=$NotAfter$Cert.X509Extensions.Add($EKU)$Cert.Encode()$Request=New-Object-ComObjectX509Enrollment.CX509enrollment$Request.InitializeFromRequest($Cert)$endCert=$Request.CreateRequest(0x1)$Request.InstallResponse(0x2,$endCert,0x1,"")if($Force){[Byte[]]$bytes=[System.Convert]::FromBase64String($endCert)foreach($Containerin"Root","TrustedPublisher"){$x509store=New-ObjectSecurity.Cryptography.X509Certificates.X509Store$Container,"CurrentUser"$x509store.Open([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)$x509store.Add([Security.Cryptography.X509Certificates.X509Certificate2]$bytes)$x509store.Close()}}}

С виду кажется сложно, но на самом деле тут ничего сложного нет совсем. Просто представьте себе сертификат как большую матрёшку, в которую вы вкладываете другие маленькие матрёшки, которые представляют собой поля и расширения сертификатов. Начинаете собирать самые маленькие матрёшки, вкладываете в более большие и в конечном итоге собираете настоящий сертификат. Хоть документация на MSDN не очень полная, используя командлет Get-Member вы можете восполнить этот пробел.

Download FileDownload File1
PS1 file

13.1 KB
New-SigningCert


Создание шаблонов диалоговых окон

Зачастую при создании пользовательского диалогового окна каждый раз на форму добавляются одни и те же элементы управления. Например, все пользовательские диалоговые окна имеют два элемента управления CommandButton, используемых в качестве кнопок ОК и Отмена.

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

Начните с создания пользовательского диалогового окна, содержащего все элементы управления и настройки, которые необходимо повторно использовать в других проектах. После этого убедитесь, что диалоговое окно выделено. Выберите команду File –>

Export File (или нажмите комбинацию клавиш <Ctrl E>). После этого на экране появится запрос на ввод имени файла. Затем для создания проекта на основе шаблона выполните команду File –> lmport File, чтобы загрузить ранее сохраненное диалоговое окно.

Имитация диалоговых окон Excel. Внешний вид и поведение диалоговых окон Windows изменяются от программы к программе. При разработке приложений для Excel рекомендуется придерживаться стиля диалоговых окон Excel. Наилучшим методом изучения эффективных способов создания диалоговых окон является повторное создание одного из стандартных диалоговых окон Excel.

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

[1] По материалам книги Джон Уокенбах. Excel 2021. Профессиональное программирование на VBA. – М: Диалектика, 2021. – С. 405–438.

Добавить комментарий

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

Adblock
detector