Обновить
64K+

C# *

Объектно-ориентированный язык программирования

72,33
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

RCE из одного XML‑тега: разбираем небезопасную десериализацию XmlSerializer с нуля

Уровень сложностиСредний
Время на прочтение17 мин
Охват и читатели4.6K

Дисклеймер. Все описанное выполнялось в изолированной лаборатории на вымышленном приложении, которое я собрал специально для статьи. Совпадения имен с реальными продуктами случайны. Материал образовательный — для AppSec, .NET-разработчиков и всех, кому интересно, как «сохранить объект в файл» превращается в удаленное выполнение кода. Не применяйте это к системам, на которые у вас нет письменного разрешения.

Есть распространенный страх: анализ защищенности — это что-то темное, для избранных, с ассемблером и магией. На деле большая часть работы — это чтение кода по понятным правилам. Сейчас разберем реальный по механике баг (небезопасная десериализация в .NET → выполнение произвольной команды) так, будто читаем букварь: сначала буквы, потом слоги, потом целые слова.

К концу статьи вы будете уметь: декомпилировать .NET-приложение, находить в нем точки сериализации и десериализации, читать свойства и сеттеры, отличать безобидный класс от «gadget» и по одной строчке понимать, есть ли уязвимость. Все воспроизводится на приложенном стенде.

Про цвет. Листинги с подсветкой даны картинками. Цвета: желтый — имя класса/тип, синий — имя свойства, зеленый — значение (данные), красный — опасное место (sink, уязвимая строка, побочный эффект). В «было/стало» красный — что убираем, зеленый — что ставим.

Читать далее

Новости

50 минут руками — 5 минут автоматически. Или как я майнер удалял

Время на прочтение8 мин
Охват и читатели7.2K

Думаю, многие из вас знают, что такое майнер, а если нет, то вкратце — это программа, которая использует ресурсы компьютера для добычи (майнинга) криптовалюты. Сам по себе майнер не является вирусом, но есть те, кто им злоупотребляет, распространяя его скрытую вариацию под видом пиратского софта и сборок с играми.

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

Читать далее

AGR.Checker: что нового в плагине для проверки ЦИМ перед сдачей в АГР

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели5.8K

Это продолжение истории про AGR.Checker — плагин для Revit, который мы с Андреем Прохоровым сделали для проверки ЦИМ на соответствие требованиям IDS перед сдачей в составе АГР. В прошлой статье я рассказывала про архитектуру, лицензирование и регистрацию программы в Роспатенте. С тех пор плагин поработал на реальных объектах, и почти всё новое в этой версии выросло из одного вопроса: «а почему вот это приходится проверять руками?»

Ниже — что мы добавили и какие инженерные задачи пришлось решить по дороге.

Экспорт в IFC с постобработкой

В конце прошлой статьи я обещала выгрузку IFC для последующей загрузки на СтроимПросто. Сделали.

Экспорт идёт через стандартное окно Revit: мы сознательно не стали собирать настройки экспорта программно. Недокументированные опции IFC-экспортёра вели себя по-разному в разных версиях Revit, и надёжнее оказалось дать пользователю привычное окно со своей конфигурацией и файлом маппинга.

Самое интересное начинается после экспорта. Плагин подписан на событие Revit о завершении экспорта и сразу же обрабатывает готовый IFC-файл:

Читать далее

Как я перенёс сборку лексера в compile-time

Уровень сложностиПростой
Время на прочтение7 мин
Охват и читатели10K

Я написал source generator для лексера HydraScript. Он собирал регулярное выражение из описаний токенов. После этого мне оставалось скопировать регулярку и руками вставить её в другой файл.

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

Проблема была в том, что результат моего генератора требовался другому генератору — тому, который стоит за атрибутом [GeneratedRegex] в .NET. Хотелось описать токен один раз и поручить остальное сборке. Для этого пришлось разобраться, в каком порядке Roslyn вообще выполняет генераторы.

Читать далее

Два читмода за выходные: Mono против IL2CPP и восемь мест, где ломается моддинг Unity

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели6.9K

Поставил MelonLoader в демку на Unity 6, собрал мод — и он молчит: BadImageFormatException: Duplicate type with name '<>O'. За выходные я написал два чит-мода с почти одинаковым ТЗ: меню для Valheim (Mono, BepInEx) и трейнер для демки Go Next! (IL2CPP, MelonLoader). Код получился настолько разный, что набралось восемь мест, где всё ломается именно из-за отсутствия managed-кода: битая сгенерированная сборка, вырезанный GUILayout, падающий Input.GetKeyDown, цена интеропа. Плюс разбор того, где Unity на самом деле держит PlayerPrefs и почему SetGodMode() хуже собственного патча.

Читать далее

Я удалил классы, но оставил объекты с методами

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели17K

HydraScript — мой интерпретатор на C#. В нём есть объекты, статическая типизация и вызовы методов. А class, interface и constructor я вообще не добавлял.

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

Тут я вдохновлялся сразу двумя языками: структурной типизацией TypeScript и методами с явным получателем из Go. Подход Go заодно сильно упрощал жизнь мне самому — автору языка. Функции у меня уже работали, и методы можно было построить на их основе, не вдаваясь в реализацию классов.

Читать далее

Как мы перестали писать описания к merge request руками: AI Describer в GitLab CI и Jenkins

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели7.8K

Поле описания merge request пустое или содержит список commit messages. Ревьюер открывает diff на несколько десятков файлов и не понимает, с чего начать. Писать описание руками — рутина, на которую забивают, а задача при этом формализуется идеально: на входе diff, на выходе текст по шаблону. Идеальная работа для LLM.

Так появился AI Describer — CLI‑инструмент, который запускается одним шагом пайплайна, берёт git diff относительно целевой ветки, отдаёт его модели и публикует структурированное описание обратно в merge/pull request. Работает и в GitLab CI, и в Jenkins на Windows‑агентах: у нас два хостинга репозиториев и столько же систем сборки.

Читать далее

Native AOT заставил меня переписать весь .NET проект

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели11K

Мне хотелось, чтобы знакомство с HydraScript выглядело просто: скачал интерпретатор, запустил скрипт. Сомнительно предлагать человеку сначала установить подходящий .NET Runtime ради моего языка программирования.

Переход на Native AOT поначалу казался правкой .csproj. Включил настройку, опубликовал бинарник, пошёл дальше. На практике пришлось переписать всё. Досталось даже интеграционным тестам. А в процессе рефакторинга ещё и пропали логи.

Читать далее

Redis в маршрутах.NET: кэш, Pub/Sub, Streams с группами и Claim Check одним коннектором

Уровень сложностиСложный
Время на прочтение9 мин
Охват и читатели10K

Коннектор Redis для redb.Route: все структуры данных как шаги маршрута, Pub/Sub, Streams с группами потребителей, список как очередь и Claim Check на Redis.

В интеграционном проекте Redis редко бывает чем-то одним. Это кэш ответов внешних систем, счётчики и блокировки, шина событий через Pub/Sub, журнал сообщений через Streams, очередь задач на списке. Обычно каждая из этих ролей живёт в своём куске кода со своим подключением, своими повторами и своим логированием.

В redb.Route все они собраны в одном коннекторе redb.Route.Redis. Любая операция Redis становится шагом маршрута, а подписка, стрим или список становятся его входом. Подключение, телеметрия и плавная остановка при этом общие с остальными коннекторами. Под капотом StackExchange.Redis 2.11.8.

Потребители Redis описаны здесь начиная с ...

Читать далее

Почему "+=" сложнее реализовать, чем "+": опыт HydraScript

Уровень сложностиПростой
Время на прочтение5 мин
Охват и читатели12K

Мой язык программирования HydraScript, написанный на C#, уже умел выполнять такой код:

let x = 10 x = x + 1 >>> x

Получаем 11; >>> — это оператор вывода. Присваивание работает, сложение работает. Захотелось добавить привычное сокращение:

let x = 10 x += 1 >>> x

Результат должен остаться тем же — 11. Зачем учить весь компилятор ещё одной операции, если всё необходимое у него уже есть? Можно прямо в парсере превратить x += 1 в дерево для x = x + 1.

Эта часть уместилась в несколько строк. Основная работа досталась методу Clone().

Читать далее

Blazor против Vue.js: что замечает C#-разработчик

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели11K

Два фронтенда, один C#-мозг — что действительно различается, что похоже сильнее, чем принято считать, и что говорит рынок труда.

До 2019 года моим фронтендом были семантический HTML и CSS. Div'ы, классы, разметка, которую я мог удержать в голове. Я был бэкенд-разработчиком, и меня это вполне устраивало.

Потом случились две вещи. Компания попросила меня залезть в проект на Vue, а Microsoft выпустила Blazor. В следующие годы я плотно поработал с обоими: с Vue — у двух работодателей, с Blazor — на личном проекте, который до сих пор работает.

Это не статья с бенчмарками. Это про то, как эти две технологии ощущаются, когда мышление у тебя C#-овое.

Читать далее

XML‑маршруты в redb.Route: схема в редакторе, проверка на сборке и замена модуля на лету

Уровень сложностиСложный
Время на прочтение18 мин
Охват и читатели7.7K

Маршрут в .route.xml на том же движке, что и C#: подсказки в VS Code, проверка пакета в dotnet build, граф-редактор и горячая замена модуля.

Интеграционный маршрут живёт дольше, чем код вокруг него. Партнёр переезжает в другую папку на SFTP, аналитик просит отдельную ветку под новый тип файла, поддержка хочет понять, каким путём прошла заявка, которую ночью отклонили. Всё это вопросы к маршруту, и отвечать на них через C#-проект, сборку и выкладку модуля выходит дороже, чем сам вопрос.

В 4.0 у redb.Route появилась вторая запись маршрута: XML. Файл .route.xml кладётся в пакет, пакет в папку работающего сервиса, и меньше чем через полсекунды по новому маршруту идёт первое сообщение. При этом ...

Читать далее

Heartbeat: как мы создали систему управления системой вместо обычных сигналов

Время на прочтение13 мин
Охват и читатели7.4K

Привет! Меня зовут Александр Илларионов, я бэкенд‑разработчик в Altenar. Мы работаем на довольно сложном и при этом очень интересном рынке: собираем данные о спортивных матчах со всего мира — например, время и место их проведения, описания чемпионатов и участников, а также вероятности наступления ключевых событий вроде голов, аутов и пенальти. И всё это в live‑режиме. 

В этой статье рассказываю, как мы переосмыслили роль Heartbeat‑компонента в нашей системе — от обычного сигнала до инструмента, который реально управляет работой всей системы. Наш опыт будет полезен тем, кто работает с .NET, распределёнными системами или строит инфраструктуру под высоконагруженные real‑time потоки данных. 

Читать далее

Ближайшие события

А чё, так можно было? Три места в.NET, которые не развидеть

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели9.1K

Пустой наследник Random работает медленнее родителя. string[] и object[] оказываются одним объектом. А Matrix4x4 до сих пор держит шестнадцать полей float вместо четырёх векторов.

Ни одно из трёх уже не переделать, и на то есть причины.

Читать далее

А чё, так можно было? Опечатка в исходниках .NET, которой больше 20 лет

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели6.8K

В System.Random кто-то двадцать лет назад написал 21 вместо 31. Опечатку заметили, разобрали и оставили как есть — исправить, и new Random(42) начнёт выдавать другие числа.

А ещё new Random() и new Random(42) — вообще разные генераторы. Разница на некоторых методах доходит до 10 раз.

Читать далее

А чё, так можно было? Три недооценённых атрибута.NET

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели10K

Три атрибута, которые меняют результат компиляции. Один запускает метод раньше Main. Второй передаёт текст выражения вместо результата. Третий ускоряет stackalloc в 50 раз.

Все три описаны в документации и применяются внутри .NET. А в рабочем коде я их ни разу не видел.

Читать далее

redb 4.0: XML-маршруты, ленивые ссылки, уникальные ключи и WS-Trust в одном мажоре

Время на прочтение12 мин
Охват и читатели8.5K

Мажор всей экосистемы: что появилось в redb.Core, redb.Route, redb.Tsak и redb.Identity, что закрыто по безопасности и что ломает обновление.

Много работы было сделано ночами при свечах. Обратная связь от людей давала пищу для размышлений и фиксов: комментарии к статьям, обсуждения на GitHub, отчёты с живых стендов. И вот, отработав по-стахановски, выпускаю 4.0.0.

Это мажор всей экосистемы разом. Хранилище redb.Core, интеграционный движок redb.Route, рантайм redb.Tsak и OpenID-сервер redb.Identity выходят одним номером: 76 пакетов на NuGet (у 3.7 было 66), семь образов в GHCR, архивы под Windows и Linux. Pro-издание по-прежнему бесплатно и не требует лицензионного ключа на всей линии 4.x.

Изменений столько, что подробный разбор любого из продуктов тянет на отдельную статью, и такие статьи будут. Здесь коротко, почти списком: что появилось, что закрыто по безопасности и что нужно знать перед обновлением. Полные списки изменений лежат на redb.ru/releases.

Читать далее

Тернарная нейронка на C#

Уровень сложностиПростой
Время на прочтение18 мин
Охват и читатели22K

Мода на квантизацию скоро закончится...когда появятся они: модели, обученные на тернарной/тритовой/троичной логике.

Или нет?

Пройдемся по форматам обучения от FP32 до FP4, а потом сделаем аналог модели Microsoft Bitnet 1.58 на C#, размером 29Кб (в экстремальном варианте — 17,1 КБ).

Читать далее

Что стоит за простым уведомлением: история разработки шаблонизатора на C#

Уровень сложностиПростой
Время на прочтение41 мин
Охват и читатели6.4K

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

Что стоит за уведомлением →

Отбор акций на .NET: 14,5 млн баров в SQLite, фильтр, который мерил не в тех единицах, и перестановочный тест

Уровень сложностиСредний
Время на прочтение22 мин
Охват и читатели6.3K

Каждый вечер мне нужно ответить на один вопрос: на какие бумаги из примерно тринадцати тысяч имеет смысл потратить время сегодня. Не «какие вырастут» — этого никто не знает, — а на каких стоит нарисовать уровень и поставить заявку.

Год назад я написал под эту задачу программу и с тех пор работаю только через неё. Ниже — её устройство: как читаются 14,5 миллиона баров, как считается ранг относительной силы, как устроена воронка фильтров, какой из них год работал неправильно и почему, чем разбирается исход сделки и чем я проверяю, что отбор вообще чего-то стоит. Кода будет много: половина статьи именно про то, где решения оказались не такими, как выглядели на бумаге.

Стек, чтобы дальше не отвлекаться: .NET 10, C#, WinForms для окна, SQLite (Microsoft.Data.Sqlite) вместо сервера, ScottPlot для графиков, xUnit — 867 тестов на три проекта. Ни одного внешнего сервиса, кроме поставщика котировок, ключ к которому вводит пользователь.

Читать далее
1
23 ...