Как расположить форму и изменить ее размер (Windows Forms .NET)
При создании формы размер и расположение изначально задаются как значения по умолчанию. Размер формы по умолчанию обычно имеет ширину и высоту 800 x 500 пикселей. Начальное расположение, отображаемое при отображении формы, зависит от нескольких различных параметров.
Изменить размер формы можно во время разработки с помощью Visual Studio, а также во время выполнения с помощью кода.
Документация по рабочему столу для .NET 7 и .NET 6 находится в стадии разработки.
Изменение размера с помощью конструктора
После добавления новой формы в проект размер формы задается двумя разными способами. Во-первых, для него можно задать маркеры изменения размера в конструкторе. Перетаскивая правый край, нижний край или угол, можно изменить размер формы.

Второй способ изменения размера формы — в конструкторе на панели «Свойства». Выберите форму, а затем найдите панель Свойства в Visual Studio. Прокрутите вниз до раздела Размер и разверните его. Можно вручную задать параметры Ширина и Высота.

Изменение размера в коде
Несмотря на то, что начальный размер формы задается в конструкторе, его можно изменить с помощью кода. Использование кода для изменения размера формы полезно, когда в каком-либо приложении размера формы по умолчанию недостаточно.
Чтобы изменить размер формы, измените свойство Size, которое представляет ширину и высоту формы.
Изменение размера текущей формы
Размер текущей формы можно изменить, пока код выполняется в контексте формы. Например, если имеется Form1 с кнопкой, то при нажатии на нее вызывается обработчик событий Click для изменения размера формы:
private void button1_Click(object sender, EventArgs e) => Size = new Size(250, 200);
Private Sub Button1_Click(sender As Object, e As EventArgs) Size = New Drawing.Size(250, 200) End Sub
Изменение размера другой формы
Размер другой формы можно изменить после ее создания с помощью переменной, ссылающейся на форму. Например, предположим, что у вас есть две формы: Form1 (начальная форма в этом примере) и Form2 . В Form1 имеется кнопка, которая при нажатии вызывает событие Click . Обработчик этого события создает новый экземпляр формы Form2 , задает размер, а затем отображает его:
private void button1_Click(object sender, EventArgs e)
Private Sub Button1_Click(sender As Object, e As EventArgs) Dim form = New Form2 With < .Size = New Drawing.Size(250, 200) >form.Show() End Sub
Если свойство Size не задано вручную, размер формы по умолчанию — это размер, заданный во время разработки.
Расположение с помощью конструктора
При создании и отображении экземпляра формы начальное расположение формы определяется свойством StartPosition. Свойство Location содержит текущее положение в форме. Оба свойства можно задать с помощью конструктора.

| Перечисление FormStartPosition | Description |
|---|---|
| CenterParent | Форма находится в пределах родительской формы. |
| CenterScreen | Форма располагается по центру текущего экрана. |
| Вручную | Положение формы определяется свойством Расположение. |
| WindowsDefaultBounds | Форма размещается в расположении Windows по умолчанию и ее размер подгоняется под размер по умолчанию, который определен Windows. |
| WindowsDefaultLocation | Форма размещается в расположении Windows по умолчанию и не изменяется. |
Значение CenterParent работает только с формами, которые являются либо дочерними формами многодокументного интерфейса (MDI), либо обычными формами, отображаемыми с помощью метода ShowDialog. CenterParent не влияет на обычную форму, которая отображается с помощью метода Show. Чтобы разместить форму по центру (переменная form ) другой формы (переменная parentForm ), используйте следующий код:
form.StartPosition = FormStartPosition.Manual; form.Location = new Point(parentForm.Width / 2 - form.Width / 2 + parentForm.Location.X, parentForm.Height / 2 - form.Height / 2 + parentForm.Location.Y); form.Show();
form.StartPosition = Windows.Forms.FormStartPosition.CenterParent.Manual form.Location = New Drawing.Point(parentForm.Width / 2 - form.Width / 2 + parentForm.Location.X, parentForm.Height / 2 - form.Height / 2 + parentForm.Location.Y) form.Show()
Расположение с помощью кода
Несмотря на то, что для задания начального расположения формы можно использовать конструктор, изменить режим начальной позиции или задать расположение вручную можно с помощью кода. Использование кода для расположения формы полезно, если необходимо вручную разместить форму и изменить ее размер относительно экрана или других форм.
Перемещение текущей формы
Переместить текущую форму можно, пока код выполняется в контексте формы. Например, если имеется Form1 с кнопкой, то при нажатии на нее вызывается обработчик событий Click . Обработчик в этом примере изменяет расположение формы на верхнюю левую часть экрана путем задания свойства Location:
private void button1_Click(object sender, EventArgs e) => Location = new Point(0, 0);
Private Sub Button1_Click(sender As Object, e As EventArgs) Location = New Drawing.Point(0, 0) End Sub
Расположение другой формы
Расположение другой формы можно изменить после ее создания с помощью переменной, ссылающейся на форму. Например, предположим, что у вас есть две формы: Form1 (начальная форма в этом примере) и Form2 . В Form1 имеется кнопка, которая при нажатии вызывает событие Click . Обработчик этого события создает новый экземпляр Form2 формы и задает расположение:
private void button1_Click(object sender, EventArgs e)
Private Sub Button1_Click(sender As Object, e As EventArgs) Dim form = New Form2 With < .Location = New Drawing.Point(0, 0) >form.Show() End Sub
Если значение Location не задано, позиция формы по умолчанию основана на том, что StartPosition свойство было задано во время разработки.
См. также
- Как добавить форму в проект (Windows Forms .NET)
- Общие сведения о событиях (Windows Forms .NET)
- Размещение и компоновка элементов управления (Windows Forms .NET)
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Членство
С момента написания этой статьи поставщики членства ASP.NET были заменены ASP.NET Identity. Мы настоятельно рекомендуем обновить приложения для использования платформы ASP.NET Identity , а не поставщиков членства, которые были представлены на момент написания этой статьи. ASP.NET Identity имеет ряд преимуществ по сравнению с системой членства ASP.NET, в том числе :
- более высокая производительность;
- Улучшенная расширяемость и тестируемость
- Поддержка OAuth, OpenID Connect и двухфакторной проверки подлинности
- Поддержка удостоверений на основе утверждений
- Улучшенное взаимодействие с ASP.Net Core
ASP.NET членство основывается на успешном выполнении модели проверки подлинности с помощью форм ASP.NET 1.x. ASP.NET проверка подлинности с помощью форм позволяет легко включить форму входа в приложение ASP.NET и проверить пользователей на соответствие базе данных или другому хранилищу данных.
ASP.NET членство основывается на успешном выполнении модели проверки подлинности с помощью форм ASP.NET 1.x. ASP.NET проверка подлинности с помощью форм позволяет легко включить форму входа в приложение ASP.NET и проверить пользователей на соответствие базе данных или другому хранилищу данных. Члены класса FormsAuthentication позволяют обрабатывать файлы cookie для проверки подлинности, проверка для допустимого входа, выхода пользователя из системы и т. д. Однако для реализации проверки подлинности с помощью форм в приложении ASP.NET 1.x может потребоваться достаточное количество кода.
Членство в ASP.NET 2.0 является важным достижением по сравнению с использованием только проверки подлинности с помощью форм. (Членство является наиболее надежным в сочетании с проверкой подлинности с помощью форм, но использование проверки подлинности на основе форм не является обязательным требованием.) Как вы скоро увидите, вы можете использовать ASP.NET Членство и элементы управления для входа в ASP.NET 2.0 для реализации мощной системы членства без написания кода.
Реализация членства в ASP.NET 2.0
Членство реализуется путем выполнения четырех шагов. Имейте в виду, что существует множество под-шагов, которые используются, а также необязательная конфигурация, которую также можно реализовать. Эти шаги призваны проиллюстрировать общую картину настройки членства.
- Создайте базу данных членства (если в качестве хранилища членства используется SQL Server).
- Укажите параметры членства в файлах конфигурации приложений. (Членство включено по умолчанию.)
- Определите тип хранилища членства, которое вы хотите использовать. Доступные параметры описаны ниже.
- Microsoft SQL Server (версия 7.0 или более поздняя)
- Хранилище Active Directory
- Настраиваемый поставщик членства
- Настройте приложение для проверки подлинности ASP.NET forms. Еще раз членство предназначено для использования преимуществ проверки подлинности с помощью форм, но использование проверки подлинности на основе форм не является обязательным требованием.
- Определите учетные записи пользователей для членства и при необходимости настройте роли.
Создание базы данных членства
Если в качестве хранилища членства используется SQL Server 7.0 или более поздней версии, для настройки базы данных можно использовать служебную программу aspnet_regsql (доступную в командной строке Visual Studio .NET 2005). Служебную программу aspnet_regsql можно использовать в качестве средства командной строки или с помощью мастера графического пользовательского интерфейса. Самый простой способ настройки базы данных — это метод мастера. Чтобы получить доступ к мастеру, просто выполните следующую команду:
После выполнения этой команды вы получите мастер установки ASP.NET SQL Server, как показано ниже.

Рисунок 1
Мастер установки ASP.NET SQL Server создает веб-сайт в экземпляре, который вы указываете в мастере. Однако ASP.NET будет использовать строку подключения в файле machine.config для подключения к базе данных. По умолчанию эта строка подключения указывает на экземпляр SQL Server 2005, поэтому при использовании экземпляра SQL Server 2000 или SQL Server 7.0 необходимо изменить строку подключения в файле machine.config. Эта строка подключения может находиться здесь:
К сожалению, если вы не измените строку подключения, ASP.NET не приведет к описательной ошибке. Он будет продолжать жаловаться, говоря, что вы не создали базу данных. В приведенном выше случае я изменил строку подключения так, чтобы она указывала на локальный экземпляр SQL Server 2000.
Указание конфигурации и добавление пользователей и ролей
Следующим шагом в настройке членства является добавление необходимых сведений в файл web.config приложения. В ASP.NET 1.x изменение файла web.config иногда было затруднено из-за использования lowerCamelCase и отсутствия Intellisense. Visual Studio .NET 2005 значительно упрощает задачу с помощью Intellisense для файлов конфигурации, но ASP.NET 2.0 идет еще дальше, предоставляя веб-интерфейс для редактирования файлов конфигурации.
Чтобы запустить веб-интерфейс, нажмите кнопку ASP.NET Конфигурация на панели инструментов Обозреватель решения, как показано ниже. Вы также можете запустить веб-интерфейс через всплывающие окна, которые отображаются при вставке элементов управления «Вход».

Рис. 2
При этом запускается средство администрирования веб-сайтов ASP.NET, показанное ниже. Администрирование веб-сайта ASP.NET — это интерфейс с четырьмя вкладками, который упрощает управление параметрами приложения. Доступны следующие вкладки:
- Дом
- Безопасности Настройка пользователей, ролей и доступа.
- Приложения Настройка параметров приложения.
- Поставщика Настройте и проверьте поставщик членства в приложениях.
Средство администрирования веб-сайтов позволяет легко создавать новых пользователей, создавать новые роли и управлять пользователями и ролями. Эта возможность недоступна в интерфейсе Windows. Интерфейс Windows позволяет легко определять параметры авторизации, а также добавлять и удалять поставщиков, а также управлять ими, которые отсутствуют в средстве администрирования веб-сайтов.
Чтобы запустить интерфейс Windows, откройте оснастку Службы IIS, щелкните правой кнопкой мыши приложение и выберите пункт Свойства. Перейдите на вкладку ASP.NET и нажмите кнопку Изменить конфигурацию. (Для включения кнопки Изменить конфигурацию приложение должно быть запущено в ASP.NET 2.0. Версию ASP.NET можно также настроить в диалоговом окне ASP.NET.) Диалоговое окно параметров конфигурации ASP.NET отображается, как показано ниже.

Рис. 3
На вкладке Общие перечислены строки подключения и параметры приложения. Все параметры курсивом определяются в родительском файле конфигурации (machine.config или web.config на более высоком уровне), а параметры, не указанные курсивом, находятся в файле конфигурации приложений. Если параметр добавляется, удаляется или редактируется на уровне приложения, ASP.NET добавит, удалит или изменит параметр на уровнях приложения web.config вместо удаления параметра из файла конфигурации, из которого он наследуется.
Ниже показана вкладка Проверка подлинности. Здесь вы настроите параметры членства. Здесь можно настроить параметры проверки подлинности с помощью форм, поставщиков членства и поставщиков ролей.

Рис. 4
Реализация членства в приложении
Самый простой способ реализовать членство ASP.NET 2.0 в приложении — использовать предоставленные элементы управления Вход в систему. Этот метод позволяет реализовать основы членства ASP.NET 2.0 без написания кода.
В ASP.NET 2.0 доступны следующие элементы управления входом:
Управление входом
Элемент управления Вход предоставляет интерфейс для входа в систему членства. Он предоставляет текстовое поле имя пользователя и пароль, а также кнопку входа. Многие другие распространенные функции, такие как ссылка для регистрации для людей, которые еще не сделали этого, флажок, позволяющий пользователю автоматически входить в систему при последующих посещениях, ссылка для напоминания пароля и т. д. Все функции элемента управления «Вход» настраиваются с помощью свойств элемента управления .
В ASP.NET 1.x разработчикам приходилось писать достаточное количество кода, чтобы выполнить поиск при использовании проверки подлинности с помощью форм. С помощью членства ASP.NET 2.0 вы можете проверять пользователей, не написав код. ASP.NET автоматически выполнит поиск пользователя. (Если вы используете элемент управления «Вход» без ASP.NET членства, для проверки пользователя можно использовать метод OnAuthenticate .)
Элемент управления LoginView
Элемент управления LoginView — это шаблонный элемент управления, который по умолчанию предоставляет два шаблона; AnonymousTemplate и LoggedInTemplate. Отображаемый шаблон определяется тем, вошел ли пользователь в систему членства. Этот элемент управления обычно используется для отображения элемента управления Вход, когда пользователь еще не вошел в систему, и элемента управления LoginStatus и (или) других элементов управления для входа, когда пользователь выполнил вход. Если вы используете управление ролями в приложении ASP.NET, элемент управления LoginView может отображать определенный шаблон на основе роли пользователей. (Дополнительные сведения об управлении ролями ASP.NET будут рассмотрены позже.)
Управление восстановлением паролей
Элемент управления PasswordRecovery позволяет пользователям получать сообщения электронной почты с текущим паролем или сбрасывать пароль. Можно восстановить и отправить пользователям по электронной почте чистый текст и зашифрованные пароли. Если пароль хэширован, его невозможно восстановить. Вместо этого пользователю потребуется выполнить сброс пароля.
Элемент управления LoginStatus
Элемент управления LoginStatus используется для отображения индикатора входа для пользователей, которые не вошли в систему, и индикатора выхода для пользователей, которые вошли в систему в данный момент. Свойство Request.IsAuthenticated используется для определения отображаемого индикатора. Индикатор, отображаемый элементом управления LoginStatus, может быть текстовым (реализованным с помощью свойств LoginText и LogoutText ) или изображениями (реализованными с помощью свойств LoginImageUrl и LogoutImageUrl ).
Когда пользователь выходит из системы с помощью элемента управления LoginStatus, он перенаправляется по URL-адресу, указанному свойством LogoutPageUrl . Если это свойство не задано, текущая страница обновляется. Так как сайт, скорее всего, защищен проверкой подлинности с помощью форм, обновление текущей страницы перенаправит пользователя на страницу входа для сайта.
Элемент управления LoginName
Элемент управления LoginName отображает имя пользователя, выполнившего вход на сайт.
Элемент управления CreateUserWizard
Элемент управления CreateUserWizard предоставляет пользователям удобный способ регистрации в системе членства. Вы можете добавить шаги (реализованные в виде коллекции WizardSteps) с помощью интерфейса, показанного ниже.

Рис. 5
CreateUserWizard — это шаблонный элемент управления, производный от класса Wizard и предоставляющий следующие шаблоны:
- HeaderTemplate Этот шаблон управляет внешним видом заголовка мастера.
- Боковая панельTemplate Этот шаблон управляет внешним видом боковой панели мастера.
- StartNavigationTemplate Этот шаблон управляет внешним видом навигации мастера на начальном шаге.
- StepNavigationTemplate Этот шаблон управляет внешним видом области навигации, если не на начальном или завершаем шаге.
- FinishNavigationTemplate Этот шаблон управляет внешним видом области навигации на этапе завершения.
Кроме того, для каждого шага, добавляемого в мастер, ASP.NET создадут настраиваемый шаблон, содержащий contentTemplate и CustomNavigationTemplate для этого шага. Полные сведения о настройке CreateUserWizard см. в документации по VS.NET 2005:
Элемент управления ChangePassword
Элемент управления ChangePassword позволяет пользователям изменять свой пароль. Если свойство DisplayUserName имеет значение true (по умолчанию — false), пользователь может изменить свой пароль, если не выполнил вход. Если пользователь уже вошел в систему и свойство DisplayUserName имеет значение true, пользователь сможет изменить пароль другого пользователя, который не вошел в систему, если он знает идентификатор этого пользователя.
Имейте в виду, что если вы хотите, чтобы пользователи могли изменять пароли без необходимости входа в систему, необходимо убедиться, что страница, на которой отображается элемент управления ChangePassword, разрешает анонимный доступ. Очевидно, что пользователям придется указать свой старый пароль, чтобы изменить свой пароль.
Управление ролями
Управление ролями позволяет назначать пользователям определенную роль, а затем ограничивать доступ к определенным файлам или папкам на основе этой роли. Управление ролями также предоставляет API, позволяющий программно определить роль пользователей или всех пользователей в определенной роли и ответить соответствующим образом.
Управление ролями не является требованием в ASP.NET членства, и членство не является требованием для использования управления ролями. Тем не менее, два хорошо дополняют друг друга, и вполне вероятно, что разработчики будут использовать их в сочетании друг с другом.
Чтобы включить управление ролями в приложении, внесите следующие изменения в файл web.config:
Если атрибут cacheRolesInCookie имеет значение true, ASP.NET кэширует членство пользователей в файле cookie на клиенте. Это позволяет выполнять поиск ролей без вызовов RoleProvider. При использовании этого атрибута разработчикам рекомендуется убедиться, что для атрибута cookieProtection задано значение All. (Это параметр по умолчанию.) Это гарантирует шифрование данных файлов cookie и гарантирует, что содержимое файлов cookie не было изменено. Роли можно добавить с помощью средства администрирования веб-сайта. Она позволяет легко определять роли, настраивать доступ к частям сайта на основе этих ролей и назначать пользователям роли.

Рис. 6
Как показано выше, новые роли можно добавить, просто введя имя роли и нажав кнопку Добавить роль. Существующими ролями можно управлять или удалять, щелкнув соответствующую ссылку в списке существующих ролей.
При управлении ролью можно добавлять или удалять пользователей, как показано ниже.

Рис. 7
Установив флажок User Is In Role (Пользователь в роли), можно легко добавить пользователя к определенной роли. ASP.NET автоматически обновит базу данных членства соответствующими записями. Вам также потребуется настроить правила доступа для приложения. ASP.NET 1.x разработчики знакомы с этим с помощью в файле web.config, и этот параметр по-прежнему доступен в ASP.NET 2.0. Однако проще управлять правилами доступа с помощью средства администрирования веб-сайтов, как показано ниже.

Рис. 8
В этом случае выделена папка «Администрирование» (ее трудно увидеть, так как средство выделяет ее светло-серым цветом), а роль «Администраторы» получила доступ. Все остальные пользователи отклоняются. Вы можете щелкнуть значок головки, чтобы выбрать правило, а затем использовать кнопки Переместить вверх и Вниз, чтобы упорядочить правила. Как и в случае с элементом авторизации> ASP.NET
ASP.NET 2.0 добавляет web.config файл в папку, для которой задано правило доступа. Правила доступа можно изменить с помощью файла конфигурации или средства администрирования веб-сайтов. Другими словами, средство администрирования веб-сайта — это просто интерфейс, с помощью которого файл конфигурации можно редактировать в удобной для пользователя среде.
Использование ролей в коде
API для управления ролями не изменялся с версии 1.x. Метод IsInRole используется для определения того, имеет ли пользователь определенную роль.
if (User.IsInRole(Administrators))
ASP.NET также создает экземпляр RolePrincipal в качестве члена текущего контекста. Объект RolePrincipal можно использовать для получения всех ролей, к которым принадлежит пользователь, следующим образом:
string[] userRoles = ((RolePrincipal)User).GetRoles();
Использование RoleGroups с элементом управления LoginView
Теперь, когда у вас есть представление об управлении ролями и членстве, давайте кратко обсудим, как элемент управления LoginView использует преимущества этой возможности в ASP.NET 2.0. Как уже говорилось ранее, элемент управления LoginView является шаблонным элементом управления, который по умолчанию содержит два шаблона. AnonymousTemplate и LoggedInTemplate. В диалоговом окне Задачи LoginView находится ссылка (показанная ниже), которая позволяет изменять группы ролей.

Рис. 9
Каждый объект RoleGroup содержит массив строк, определяющий, к каким ролям применяется RoleGroup. Чтобы добавить новую группу RoleGroup в элемент управления LoginView, щелкните ссылку Изменить группы ролей. На изображении выше видно, что добавлена новая группа ролей для администраторов. Выбрав roleGroup (RoleGroup[0]) в раскрывающемся списке Представления, я могу настроить шаблон, который будет отображаться только для членов роли «Администраторы». На рисунке ниже добавлена новая группа ролей, которая применяется к членам роли «Продажи» и роли «Распространителя». При этом в раскрывающемся списке Представления в диалоговом окне Задачи LoginView добавляется вторая группа ролей, и все, что добавлено в этот шаблон, будет отображаться любому пользователю с ролью «Продажи» или «Распространителя».

Рис. 10
Переопределение существующего поставщика членства
Существует несколько способов расширения функциональных возможностей ASP.NET членства. Прежде всего, можно изменить существующую функциональность класса SqlMembershipProvider, наследуя от него и переопределяя его методы. Например, если вы хотите реализовать собственные функциональные возможности при создании пользователей, можно создать собственный класс, наследующий от SqlMembershipProvider следующим образом:
public class jForumMembershipProvider : SqlMembershipProvider < public jForumMembershipProvider() < >public override MembershipUser CreateUser( string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) < // your own implementation return base.CreateUser( username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status); >>
Если, с другой стороны, вы хотите создать собственного поставщика (например, для хранения сведений о членстве в базе данных Access), можно создать собственного поставщика.
Создание собственного поставщика членства
Чтобы создать собственный поставщик членства, сначала необходимо создать класс, наследующий от класса MembershipProvider. Если вы используете VB.NET, Visual Studio 2005 добавит заглушки для всех методов, которые необходимо переопределить. Если вы используете C#, добавьте заглушки.
Вам потребуется переопределить следующее:
- Свойство ApplicationName
- Функция ChangePassword
- Функция ChangePasswordQuestionAndAnswer
- Функция CreateUser
- Функция DeleteUser
- Свойство EnablePasswordReset
- Свойство EnablePasswordRetrieval
- Функция FindUsersByEmail
- Функция FindUsersByName
- Функция GetAllUsers
- Функция GetNumberOfUsersOnline
- Функция GetPassword
- Функция GetUser
- Функция GetUserNameByEmail
- Свойство MaxInvalidPasswordAttempts
- Свойство MinRequiredNonAlphanumericCharacters
- Свойство MinRequiredPasswordLength
- Свойство PasswordAttemptWindow
- Свойство PasswordFormat
- Свойство PasswordStrengthRegularExpression
- Свойство RequiresQuestionAndAnswer
- Свойство RequiresUniqueEmail
- Функция ResetPassword
- Разблокировка пользовательской функции
- Функция UpdateUser
- Функция ValidateUser
Это довольно большой список для реализации в качестве разработчика C#. Вам может быть проще создать класс в VB.NET без какой-либо реализации, а затем использовать .NET Reflector или аналогичное средство для преобразования кода в C#.
Строка подключения и другие свойства должны иметь значения по умолчанию в методе Initialize. (Метод Initialize запускается при загрузке поставщика во время выполнения.) Второй параметр метода Initialize имеет тип System.Collections.Specialized.NameValueCollection и является ссылкой на , связанный с настраиваемым поставщиком в файле web.config. Эта запись выглядит следующим образом:
Ниже приведен пример метода Initialize.
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
Чтобы проверить пользователя при отправке формы входа, необходимо использовать метод ValidateUser. Этот метод срабатывает, когда пользователь нажимает кнопку входа в элементе управления Вход. Вы поместите код, который выполняет поиск пользователя в этом методе.
Как видите, создание собственного поставщика членства не сложно и позволяет расширить эту мощную функциональность ASP.NET 2.0.
Обратная связь
Были ли сведения на этой странице полезными?
Реверс-инжиниринг NET-приложений. Часть вторая: Введение в Byte Patching
В первой статье мы рассмотрели самые основы, касающиеся работы NET-приложений, механизма компиляции (его мы коснемся вновь более подробно) и декомпиляции кода при помощи утилиты Reflector.
В первой статье мы рассмотрели самые основы, касающиеся работы NET-приложений, механизма компиляции (его мы коснемся вновь более подробно) и декомпиляции кода при помощи утилиты Reflector. Теперь мы знаем, насколько просто обойти защиты, основанные на проверке конкретных серийных номеров (или паролей). На самом деле, это самые азы, и когда мы сталкиваемся с реальными защитами, приходится делать намного больше телодвижений.
Если говорить в общем об исследовании программ (а не только NET-приложений) — это целая наука, а не просто набор техник получения серийных номеров или паролей. Реверс-инжиниринг – искусство манипуляции байтами. Мы можем изменять, активировать или деактивировать отдельные функций программы, а в некоторых случаях, добавлять новый функционал в приложение (что не всегда простая задача). Необходимо отличное знание ассемблера, но не только его. Также требуется точно знать, где и какие байты необходимо изменить в приложении, что, обычно, не так просто.
В этой и следующей статьях мы рассмотрим некоторые техники изменения байтов (или «патчинга» байтов) в различных «доморощенных» программах. Первая цель – наш CrackMe#1-InfoSecInstitute-dotNET-Reversing (который мы изучали в первой статье), второй – «ReverseMe#1-InfoSecInstitute-dotNET-Reversing».
Компиляция NET-приложений
Из первой статьи мы знаем, что каждая NET-программа создается при помощи некоторого высокоуровнего языка (vb.NET, C#), и далее во время компиляции происходит преобразование к низкоуровнему языку Microsoft Intermediate Language (MSIL), который можно считать наименьшим общим знаменателем NET. Мы можем создать приложение, используя только MSIL, и хотя это не так интересно с точки зрения разработчика, но может быть полезно для понимания, как среда Common Language Runtime (CLR) работает и запускает наш высокоуровневый код.
Сродни Java и виртуальной машине Java любая NET-программа сначала компилируется (если можно так выразиться) в промежуточный язык IL (или MSIL), запускается в среде выполнения Common Language Runtime (CLR), а затем преобразуется в native-инструкции x86 или x86-64 в зависимости от того, какой процессор используется в системе. Это делается средой CLR посредством компиляции Just In Time (JIT).
Подводя итог, можно сказать, что CLR использует компилятор JIT для преобразования IL- (или MSIL) кода, который хранится в PE-формате (скомпилированный высокоуровневый NET-код), в платформо-зависимые инструкции, а затем происходит их выполнение. Все это означает, что .NET не является интерпретатором, а использование IL и JIT позволяет добиться переносимости NET-кода.
Наглядное изображение всего процесса показано на рисунке:


Понимание MSIL
Цель данной статьи – познакомить вас с некоторыми новыми инструкциями IL. Помимо очевидного любопытства, понимание IL и механизмов управления им откроет перед вами многие двери при исследовании NET-приложений. Конкретно в нашем случае – позволит выявить дыры в системах безопасности программ.
Перед тем как идти дальше, нелишним будет напомнить, что CLR исполняет IL-код. Учитывая такой механизм выполнения операций и обработки данных, CLR не управляет памятью напрямую. Вместо этого используется стек, представляющий из себя абстрактную структуру данных, которая работает по принципу LIFO (last in first out; последний зашел, первый вышел). Когда речь идет о стеке, мы может выполнять следующие действия: загружать и извлекать данные. После извлечения одного элемента из стека, все остальные перемещаются вверх в начало стека. Мы может управлять только самым верхним элементом.
А теперь вернемся к нашему «CrackMe#1-InfoSecInstitute-dotNET-Reversing». Если мы ввели неправильный пароль, Crack Me выводить сообщение об ошибке:

В прошлой статье мы обнаружили функцию, в которой введеное значение сравнивалось с определенной комбинацией символов. В этой статье мы изменим байты так, чтобы Crack Me принимал все возможные пароли.
Вернемся к декомпилированному Crack Me. Вот функция, которая проверяет введенный пароль:
private
void
btn.Chk.Click(object sender, EventArgs e)
<
if (this.txt.Pwd.Text == “p@55w0rd!”)
<
Interaction.MsgBox(“Congratulations !”, MsgBoxStyle.Information, “Correct!”);
>
else
<
Interaction.MsgBox(“Invalid password”, MsgBoxStyle.Critical, “Error!”);
>
>
Если мы переключим режим просмотра на IL-код, то увидим следующее:
.method
private
instance
void
btn.Chk.Click(object sender, class [mscorlib]System.EventArgs e) cil managed
<
.maxstack 3
L.0000: ldarg.0
L.0001: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.TextBox
InfoSecInstitute.dotNET.Reversing.Form1::get.txt.Pwd()
L.0006: callvirt instance
string [System.Windows.Forms]System.Windows.Forms.TextBox::get.Text()
L.000b: ldstr “p@55w0rd!”
L.0010: ldc.i4.0
L.0011: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::CompareString(string, string, bool)
L.0016: ldc.i4.0
L.0017: bne.un.s L.002d
L.0019: ldstr “Congratulations !”
L.001e: ldc.i4.s 0×40
L.0020: ldstr “Correct!”
L.0025: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object, valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)
L.002a: pop
L.002b: br.s L.003f
L.002d: ldstr “Invalid password”
L.0032: ldc.i4.s 0×10
L.0034: ldstr “Error!”
L.0039: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object, valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)
L.003e: pop
L.003f: ret
>
Это прямое представление внутреннего языка IL, с этим уровнем мы будем работать при внесении каких-либо изменений. Как было сказано выше, по существу, NET представляет собой стековую машину, и нам нужно понять, что означают отдельные инструкции IL-кода. Мы можем легко найти описание всех ассемблерных инструкций IL-кода. Я буду объяснять лишь те, которые относятся к реверс-инжинирингу.
IL-инструкции начинаются сразу после строки «.maxstack». Первая инструкция: L.0000: ldarg.0, которая загружает в стек аргумент 0. Эту инструкцию можно сравнить с инструкцией NOP традиционного ассемблерного кода, однако байт-код ldarg равен «00», а не «90». Если мы откроем любую программу в шестнадцатеричном редакторе, то найдем серии байт-кодов, каждый из который обозначает определенную IL-инструкцию нашей программы. Как раз эти байт-коды мы можем менять для изменения функционала программы (например, инвертировать некоторые проверки, переходы и, в общем, менять любые участки кода).
Традиционно, использование шестнадцатеричного редактора в некотором смысле является «грязным» способом для изменения необходимых байтов; позже мы рассмотрим, как это сделать, а также я покажу более «чистые» методы работы. Чтобы узнать смещение байтов, которые мы хотим изменить в редакторе, нам нужно преобразовать последовательность инструкций в набор байт-кодов (чем длиннее строка, тем лучше), а затем найти эту последовательность в файле (средствами редактора).
Каждая IL-инструкция имеет свое байтовое представление. Ниже представлен неполный перечень наиболее важных IL-инструкций и их байтовое представление. Можно использовать этот список в качестве справочника:
IL-инструкция
Байтовое представление
Реверс-инжиниринг NET-приложений. Часть третья: Продвинутые методы Byte Patching
В двух первых статьях мы изучили некоторые основы, которые помогут вам при исследовании NET-приложений; мы рассмотрели механизм компиляции, немного узнали о языке Microsoft Common Intermediate Language, проанализировали низкоуровневый IL-код, используя «отражение» кода (code reflection), узнали назначение некоторых IL-инструкций и их байтовое представление.
- Статья 1: Реверс-инжиниринг NET-приложений. Часть первая: Введение
- Статья 2: Реверс-инжиниринг NET-приложений. Часть вторая: Введение в Byte Patching
В двух первых статьях мы изучили некоторые основы, которые помогут вам при исследовании NET-приложений; мы рассмотрели механизм компиляции, немного узнали о языке Microsoft Common Intermediate Language, проанализировали низкоуровневый IL-код, используя «отражение» кода (code reflection), узнали назначение некоторых IL-инструкций и их байтовое представление.
Также мы рассмотрели базовые техники поиска и замены последовательности байтов в шестнадцатеричном редакторе (byte patching).
В этой статье мы рассмотрим более продвинутые техники byte patching, базовые концепции защит, которые основаны на проверке лицензии, методы исследования подобных защит (по просьбам читателей) и познакомимся с новыми инструментами из арсенала реверс-инженера.
В этом примере я попытался учесть некоторые вопросы и пожелания читателей, касающиеся первых двух статей. Во втором Crack Me я смоделировал «реальную» защиту с неактивными кнопками и функциями, а также с проверкой лицензии; Crack Me выглядит так:

Для начала нам нужно активировать первую кнопку (с надписью «Enable me»), кликнув на которую, станет доступна кнопка «Save as…», которая позволит нам симулировать сохранение файла. Позже мы рассмотрим, где происходит проверка лицензии.
Дизассемблировать приложение будем утилитой ILSpy. Она очень похожа на Reflector, поэтому нет необходимости дополнительно рассказывать об этом инструменте (ссылка для загрузки находится в разделе «Ссылки»). После анализа наш Crack Me помещается в дерево (очень похожее на дерево в Reflector). Развернув узлы, мы увидим следующую картину:

Глядя на имена методов (которые, как вы помните, сохраняются), можно легко догадаться об их назначении. В нашем Crack Me только одна форма с именем MainForm. Рассмотрим логику работы метода «Form1_Load(object, EventArgs) : void». Кликнув на имя метода, мы увидим его код:

Если у вас есть базовые представления о программировании, вы можете легко догадаться, что строка «this.btnEnableMe.Enabled = false;» деактивирует компонент «btnEnableMe», который в нашем случае является кнопкой. Теперь посмотрим, что представляет собой IL-код и байтовое представление составляющих его инструкций.
.method private
instance void Form1_Load (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
<
// Method begins at RVA 0x1b44c
// Code size 29 (0x1d)
.maxstack 2
.locals init (
[0] valuetype [System.Drawing]System.Drawing.Color
)
IL_0000: ldarg.0
IL_0001: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnEnableMe()
IL_0006: ldc.i4.0
IL_0007: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
IL_000c: ldarg.0
IL_000d: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
IL_0012: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Red()
IL_0017: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)
IL_001c: ret
> // end of method MainForm::Form1_Load
Теперь рассмотрим подробнее каждую IL-инструкцию вышеупомянутого кода (в порядке их следования):
- ldarg.0 Помещает значение 0 в стек вычисления.
- callvirt Вызывает метод get(), связанные с объектом btnEnableMe.
- ldc.i4.0 Помещает 0 в стек как 32-битное целое число.
- callvirt Вызывает метод set(), связанные с объектом btnEnableMe.
Мы видим, что перед вызовом метода set_Enabled(bool) в стек помещается значение 0; Обычно в программировании значение 0 ассоциируется с булевым значением «False». Таким образом, чтобы активировать кнопку, нам нужно вместо нуля передать единицу (что означает «True») как параметр в метод set_Enabled(bool). IL-инструкция, которая помещает в стек значение 1 — ldc.i4.1.
Из предыдущей статьи мы знаем, как важно знать байтовое представление последовательности инструкций для точного определения их местонахождения, а также инструкций, на которые эту последовательность следует заменить. Обращаясь к справочнику, смотрим список необходимых инструкций:
IL-инструкция
Байтовое представление
Помещает целочисленное значение 0 в стек вычислений как int32.
Помещает целочисленное значение 1 в стек вычислений как int32.
Вызывает метод, связанный с объектом.
Загружает в стек аргумент 0.
Для поиска IL-инструкции, которую необходимо изменить, нам нужно преобразовать последовательность IL-инструкций (ldc.i4.0, callvirt, ldarg.0, callvirt) в их байтовое представление и поискать эту последовательность в файле при помощи шестнадцатеричного редактора.
Комбинация байтов вышеупомянутой последовательности: 166F??026F??; «??» означает, что мы не знаем байтовое представление instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool) (строка IL_0007) и байтовое представление instance class [System.Windows.Forms]System.Windows.Forms.Label CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat() (строка IL_000d).
Примеры становятся все более сложными, и мы будем использовать дополнительные утилиты. Первая из них – ILDasm, которая входит в состав .NET Framework SDK. Если у вас установлен Microsoft Visual Studio, вы можете найти ILDasm в папке SDK; на моем компьютере ILDasm находится в папке C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

ILDasm может служить альтернативой Reflector и ILSpy, за исключением того, что у него менее дружественный интерфейс и нет возможности трансляции в высокоуровневый код. Однако вы можете поэкспериментировать с ним. Давайте загрузим наш Crack ME (File -> Open) и развернем деревья:

По умолчания ILDasm не показывает байтовое представление. Для того чтобы увидеть байты, вам нужно выполнить команду View -> Show Bytes:

Далее кликните по нужному методу (в нашем случае Form1_Load…) для получения IL-кода и соответствующих байтов:

Рисунок 1. ILDasm IL и байтовое представление инструкций метода Form1_Load()
Теперь у нас есть более полная информация об IL-инструкциях и их байтовом представлении. Для использования новой информации вы должны знать, что после символа «|» находится младший байт числа, хранимый в PE-файле по младшему адресу. Старший же байт хранится по старшему адресу. Такой порядок хранения называется «От младшего к старшему» (Little Endian).
Так что же все это означает?
Когда мы смотрим внутрь метода Form1_Load( ) в ILDasm, то видим следующее:
IL_0006: /* 16 |
IL_0007: /* 6F | (0A)000040
IL_000c: /* 02 |
IL_000d: /* 6F | (06)000022
Эти байты хранятся в файле так: 166F4000000A026F22000006.
Возвращаемся к нашей задаче
Последовательности байтов, полученной выше, вполне достаточно для поиска в шестнадцатеричном редакторе. В реальных случаях вы можете столкнуться с рутинной работой по получению большего количества таких последовательностей. В этом случае вместо поиска последовательности байтов, мы переходим по смещению, которое можно рассчитать.
Термин «смещение» по-другому называемый «относительным адресом», который используется для получения определенного абсолютного адреса. Мы может рассчитать смещение для инструкций, которые мы хотим изменить. Глядя на рисунки отображения IL-кода для метода Form1_Load (в ILDasm и ILSpy), мы видим Относительный Виртуальный Адрес (Relative Virtual Address, RVA) в строке // Method begins at RVA 0x1b44c. Чтобы преобразовать виртуальный адрес в смещение (или местонахождение в файле), мы должны определить топологию нашего файла, чтобы увидеть различные секции и смещения / размеры. Можно использовать PEiD или любую другую утилиту для работы с PE-файлами, однако я расскажу вам об утилите dumpbin, которая идет в комплекте с Microsoft Visual C++. Dumpbin можно использовать для просмотра PE-секций (если у вас ее нет, обратитесь к разделу «Ссылки»).
Dumpbin – утилита, которая работает в режиме командной строки. Для просмотра информации о файле вводим следующую команду: dumpbin -headers target_name.exe.

Прокрутив вниз, находим интересную информацию:
SECTION HEADER #1
.text name
1C024 virtual size
2000 virtual address
1C200 size of raw data
400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
Заметим, что метод Form1_Load() начинается с RVA-адреса 0x1b44c (см. Рисунок 1), а у секции .text виртуальный размер (virtual size) 0x1c024, а виртуальный адрес 0×2000. Таким образом, наш метод должен находиться внутри этой секции. Секция, в которой находится наш метод, начинается с адреса 0X400 (File pointer to raw data) в исполняемом файле. Используя эти адреса и размеры, мы можем вычислить смещение для нашего метода.
(Виртуальный адрес метода – Виртуальный адрес секции) + File pointer to raw data (все значения являются шестнадцатеричными).
Используя калькулятор в Windows (или любой другой, позволяющий производить шестнадцатеричные операции), получаем искомое смещение: (1B44C – 2000) + 400 = 1984C.

Число 0x1984C – смещение нашего метода в исполняемом файле. Теперь мы можем перейти к местонахождению нашего метода, используя любой шестнадцатеричный редактор. Сейчас наша задача – поменять несколько байт, находящихся после смещения.
Вспоминая ранее полученную последовательность байтов 166F4000000A026F22000006 и переходя по рассчитанному смещению, получаем:

Мы хотим поменять ldc.i4.0, что эквивалентно 16, на ldc.i4.1, что эквивалентно 17. Внесем изменения и посмотрим на результат (повторюсь, не забывайте делать резервные копии файлов).

Итак, первая задача решена, однако все еще присутствует надпись «Unregistered Crack Me» и не протестирована функция сохранения файлов (кнопка «Save as…»). Как только мы нажмем на кнопку «Enable Me», разблокируется вторая кнопка, что означает получение доступа к главной функции программы.
Однако затем происходит следующее:


Перед сохранением программа проверяет наличие лицензии; если лицензия не найдена, процесс сохранения останавливается и происходит блокировка кнопок.
Механизм защиты программы всегда зависит от разработчика. Существует как множество защит, так и способов их обхода. Тем не менее, мы можем отнести защиту к определенному «типу» или «виду». Один из таких видов – проверка лицензии. В зависимости от механизма работы и алгоритма проверки лицензии варьируется трудоемкость обхода защиты.
Вернемся к нашему Crack ME:

Метод btn_EnableMe_Click _1() вызывается при нажатии на кнопку «Enable Me»; метод btn_About_Click() показывает информацию при нажатии на кнопку «About». Также у нас есть еще два метода, заслуживающих внимания: btn_EnableMe_Click () и checkLicence().
Заглянем внутрь метода btn_EnableMe_Click():

При нажатии на кнопку «Save» вместо сохранения Crack Me проверяет «статус регистрации» программы, что можно рассматривать как дополнительную защиту; Crack Me проверяет корректность регистрации перед сохранением даже в случае доступности кнопки «Save as…». Рассмотрим поближе метод checkRegStat():

Рисунок 2. Исходный код метода checkReStat().
Понятно, что переменная isRegistered типа Boolean, и она меняется. Однако при нажатии на кнопку «Save as…» мы ее не меняли. Если isRegistered = false (if (!this.isRegistered)…) в Crack Me происходит вызов метода checkLicense(). Если мы кликнем на метод .ctor, то увидим место инициализации переменной isRegistered:

Рисунок 3. Метод .ctor().
Метод .ctor() – обычный конструктор, в котором происходит инициализация переменных.
Теперь рассмотрим логику работы метода checkLicense():

Рисунок 4. Метод checkLicense().
Естественно, это самый простой механизм защиты, которая проверяет лицензию. Crack Me проверяет присутствие файла «lic.dat» в той же директории, где находится исполняемый файл;
Теперь, когда мы изучили логику работы защиты, можно разработать механизм ее обхода. Если мы удалим вызов метода checkLicense(), будет недоступна функция сохранения файла (основная функция программы), поскольку эта функция срабатывает во время проверки лицензии (см. рисунок 2).
Если мы во время инициализации принудительно выставим у переменной isRegistered значение True (см. рисунок 3), тогда не будет вызван метод checkLicense(), внутри которого происходит сохранение файла. Из рисунка 2 видно, что checkLicense() запускается только если isRegistered = false:
public void checkRegStat()
<
this.LblStat.ForeColor = Color.Green;
this.LblStat.Text = “Saving…”;
if (!this.isRegistered)
<
this.checkLicence();
>
>
Мы можем изменить проверочное выражение в операторе ветвления (if… else… endif, рисунок 4) и, таким образом, сможем сохранять файлы, если лицензия не найдена.
Прежде мы рассматривали «классический» метод изменения байтов, используя смещение и шестнадцатеричный редактор. Сейчас я покажу вам более простой и способ, который может существенно сэкономить ваше время.
Переходим обратно в Reflector (за дополнительной информацией об этой утилите обращайтесь к предыдущим статьям). Функционал этой программы можно расширять при помощи плагинов. Мы будем использовать плагин Reflexil (дополнение к Reflector), который позволяет отредактировать IL-код, а затем сохранить изменения на диск. После загрузки Reflexil вам нужно его установить. Откройте Reflector и выполните команду Tools -> Add-ins (в некоторых версиях View -> Add-ins):

Далее кликните на «Add…» и выберите файл «Reflexil.Reflector.dll»:

После этого вы увидите добавленный плагин в окне Add-ins, которое теперь можно закрыть:

Загрузим наш измененный Crack-Me в Reflector и перейдем к методу checkLicence():

Наша задача – изменить Crack Me так, чтобы мы могли сохранять файлы. Рассмотрим IL-код метода checkLicence():
.method
public
instance
void
checkLicence() cil managed
<
.maxstack 3
.locals
init (
[0] string
str,
[1] valuetype [System.Drawing]System.Drawing.Color
color)
L_0000: call string [System.Windows.Forms]System.Windows.Forms.Application::get_StartupPath()
L_0005: ldstr “\\lic.dat”
L_000a: call string [mscorlib]System.String::Concat(string, string)
L_000f: stloc.0
L_0010: ldloc.0
L_0011: call bool [mscorlib]System.IO.File::Exists(string)
L_0016: brtrue.s L_006b
L_0018: ldstr “license file missing. Cannot save file.”
L_001d: ldc.i4.s 0×10
L_001f: ldstr “License not found”
L_0024: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object, valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)
L_0029: pop
L_002a: ldarg.0
L_002b: ldc.i4.0
L_002c: stfld bool
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::isRegistered
L_0031: ldarg.0
L_0032: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
L_0037: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Red()
L_003c: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)
L_0041: ldarg.0
L_0042: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
L_0047: ldstr “Unregistered Crack Me”
L_004c: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
L_0051: ldarg.0
L_0052: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Button
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnEnableMe()
L_0057: ldc.i4.0
L_0058: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
L_005d: ldarg.0
L_005e: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Button
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnSaveAs()
L_0063: ldc.i4.0
L_0064: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
L_0069: br.s L_0092
L_006b: ldarg.0
L_006c: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
L_0071: call valuetype [System.Drawing]System.Drawing.Color
[System.Drawing]System.Drawing.Color::get_Green()
L_0076: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)
L_007b: ldarg.0
L_007c: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
L_0081: ldstr “File saved !”
L_0086: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
L_008b: ldarg.0
L_008c: ldc.i4.1
L_008d: stfld bool
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::isRegistered
L_0092: ret
>
В справочнике находим описание нужных инструкций:
IL-инструкция
Байтовое представление