суббота, 4 марта 2023 г.

 

Сканер установленных перехватчиков в памяти процесса

 


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

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

Где-то полгода назад у нас появилась очередная идея, есть очень много разноплановых ошибок которые достаточно проблематично покрыть тестами, но по результатам накопленного методом проб и ошибок опыта было выяснено что большая часть из них происходит по причине вмешательства стороннего софта в тело нашего процесса. Это могут быть как антивирусы, так и всякие DLP, а то и вовсе зловреды, которые лезут к нам в процесс, перехватывают некоторые критичные для выполнения API на себя и в обработчиках перехваченных функций ломают полностью логику исполнения кода.

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

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

Правда при общей простоте идеи реализация получилось достаточно трудоемкая.
Самая большая проблема при этом была в том что утилита 32 битная, а софт, работающий у пользователя может быть как 32 бита, так и 64 (второе более вероятно), поэтому для работы с 64 битным процессом пришлось писать соответствующую обвязку.

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

Короче в итоге получилось такое, как бы это назвать... антивирусный сканер на минималках :)

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

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

вторник, 1 марта 2016 г.

Раннее исполнение кода в Delphi приложениях

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

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

Нет, не вирусы, зачем? Вполне легальные продукты, контролирующие все и вся.

Думаете - вру и считаете что при нажатии кнопки F7 (Trace Into) вы полностью контролируете процесс отладки?
Тогда я вас разочарую, есть множество способов выполнить код, до того момента, как вы приступили к его дебагу.

О нескольких я попробую рассказать.

среда, 29 апреля 2015 г.

Анализ задачи №18 от Александра Алексеева (ака GunSmoker)

Кажется я первый раз попал в тупик.
Не то, чтобы я сильно умный, но и задачка — не "Балтика 9".

Первая часть задачи выглядела вот так:

Что не так с этим кодом?

procedure TForm1.Button1Click(Sender: TObject);
var
  Wnd: HWND;
 
  function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
  begin
    if AWnd = Wnd then
      Caption := 'OK';
    Result := True;
  end;
 
begin
  Wnd := Handle;
  EnumWindows(@EnumWindowsProc, 0);
end;

Приступим.

пятница, 10 апреля 2015 г.

Чем меня порадовала ХЕ8

В последнее время я все чаще задумываюсь о смысле апдейта текущей версии Delphi на более новую. Есть ли в этом необходимость?
С учетом, что я разрабатываю 32 битные приложения только под Win - вся эта петрушка в виде возможности разработки под Андроид или iOS прямо на Delphi, ну... скажем так — не сильно востребована.
А вот что более востребовано — так это стабильная работа среды, отсутствие ошибок при работе с дженериками/лямдами и всем тем "синтаксическим сахаром", который внедряется уже какой год.
Вы будете смеяться, но я однажды вообще от инлайнов отказался по многим причинам, в частности одна из них была в том, что кодогенератор выдавал абсолютно невалидный асм код в определенных ситуациях, абсолютно переиначивая всю логику работы inline функции (банально не тот результат возвращала). Кажется это было на 2010 или ХЕ первой.

Впрочем посмотрим что мы имеем сейчас.

вторник, 31 марта 2015 г.

Работаем с Compound File

С составными файлами я работаю давно, больше 15 лет. За все время работы у меня накопилось достаточно информации о плюсах и минусах составных файлов.
С одной стороны они являются действительно очень удобным хранилищем информации, позволяющим менять данные на лету, с другой стороны это удобство частично нивелируется скоростью доступа к данным.
Вообще для чего обычно используют составные файлы?
Для всего, что нужно хранить в некоем контейнере.
К примеру, файлы старых версий Microsoft Office от 97 до 2003 включительно (состоящие на самом деле из нескольких десятков файлов), хранились как раз в составном файле. Сейчас тоже хранятся, только в качестве контейнера используется ZIP.

Инсталляционные пакеты MSI тоже являются составными файлами, и даже файл кэша эскизов папок Thumbs.db использует этот формат.

Правда для того же Word есть целый комплекс утилит (Recovery for Word, Word Recovery Toolbox, Munsoft Easy Word Recovery) восстанавливающих, ну или по крайней мере пытающихся восстановить, поврежденные документы. Выводы можете сделать сами.
Хотя, при должной работе с составными файлами проблему их повреждения можно решить (и я покажу как).

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

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

воскресенье, 22 февраля 2015 г.

Работаем с "заданиями" (Job)

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

Впрочем, давайте посмотрим на первый вопрос:
Запускаю в отдельном потоке некий процесс (не мой, переделывать его не имею возможности), который необходимо завершить вместе с завершением основной (моей) программы.Если моя программа завершается штатно - то ничего сложного нет. Но если не штатно (пользователь убил через диспетчер задач) - так как быть тут?
В голову пока приходит только CreateRemoteThread+LoadLibrary+моя dll, которая будет следить за основным процессом.Подскажите более изящные решения.
Попробуем подсказать...

пятница, 2 января 2015 г.

Ответ на предновогоднюю задачку

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

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

Примерное время на решение, около 3-4 часов (один вечер).
Именно столько было затрачено каждым из решивших задачу программистов, включая меня.

Ну и ответ на введенное максимальное пороговое число (10 в 12 степени) будет: $259814D6C9AAF914221E (это вам для самопроверки).

Пора перейти к самой сути.


четверг, 25 декабря 2014 г.

Предновогодняя задачка для разминки мозга

Пришлось тут на днях решать для студента (первого курса) задачку.
Дословно выглядит вот так:
2014 ACM-ICPC China Hunan Invitational Programming Contest
There is a simple problem. Given a number N.
You are going to calculate N%1+ N%2+ N%3+...+ N%N.
Input: The length N(1<=N<=10^12).
Output: Answer.
Sample input 5
Sample output 4
Вроде ничего сложного, однако-ж результат суммирования по модулю явно не уложится ни в один из поддерживаемых типов (int64 максимум 8 байт).

Сразу уточню: задачка олимпиадная, причем свежего 14-го года :)

вторник, 18 ноября 2014 г.

Пара слов о кэшировании данных при чтении и смартпойнтерах

Заначка - что-либо прибережённое, припрятанное про запас ◆ Опять же всё расставив по местам, как и было, достал из-за трюмо тёткину заначку — вскрытую пачку «Любительских», — закурил. Андрей Битов, «Сад», 1960–1963 г. (цитата из Национального корпуса русского языка, см. Список литературы)


Я не думаю что сильно ошибусь, если скажу, что у большинства читателей данной статьи на компьютере присутствует папка, в которой хранятся наработки кода, применяющиеся потом в боевых проектах. Маленькие такие кусочки алгоритмов, на которых проверяется сама возможность реализации той или иной идеи. Я их называю "ништячки" :)
Чем больше программист работает по своим задачам, тем больше эта папочка пухнет. Вот моя уже вылезла за пределы семи сотен различных демопримеров.
Но проблема в том, что в 99 процентов случаев все эти "ништячки" пишутся в стол, и о существовании оных наработок знает только владелец данной папки, а ведь там же иногда целые закрома идей, подходов к реализации, алгоритмических трюков, да и просто остановленных на взлете мыслей, которыми не грех бы и поделиться (а вдруг кто-то возьмет да и разовьет подход) :)

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

пятница, 31 октября 2014 г.

Поддержка MultiTouch + Gestures в XE4

Мультитач (рус. Множественное касание) — функция сенсорных систем ввода (сенсорный экрансенсорная панель), осуществляющая одновременное определение координат двух и более точек касания. © Wiki. 

Как-то незаметно для меня прошли все эти новые веяния в виде активных мониторов, на которые пользователь может тыкать пальцами. И знать бы о них не знал, кабы месяца три назад начальство не приобрело себе ноутбук, который можно порвать на две части (экран отдельно, клавиатура отдельно), причем не Surface какой-то, пропиаренный MS, а уже самый проходной у пользователей – от ASUS, за гораздо меньшие деньги (относительно).
Да и закуплен был данный девайс не просто так – задача выросла оттуда, откуда и не ждали.

Де юре: мы проводим огромное количество семинаров в месяц, и вот именно на них, нашим лекторам начали демонстрировать несовместимость нашего ПО с этим пресловутым тачем.

Де факто: на почту саппорта начали сыпаться гневные письма пользователей плана – "я два раза тапнула, а оно не тапнулось, может не так тапнула?"
А начальство все это скрупулезно отслеживало на своем "порватом" ноутбуке и готовило ТЗ :)

И вот настал тот день. Мне на рабочий стол был воздвигнут третий монитор, 23 дюйма от LG (с поддержкой Touch ввода аж 10 пальцами) и поставлена задача – это должно заработать в течении трех дней!!!

А работаю то я в XE4 – беда... ;)

среда, 9 апреля 2014 г.

Анализ приложения защищенного виртуальной машиной

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

К сожалению, статья будет достаточно тяжелая для обычного прикладного программиста, не интересующегося тематикой защиты ПО, но тут уж ничего не поделать.

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

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

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

В качестве реципиента, по совету одного достаточно компетентного товарища, я выбрал немножко старый (но не потерявший актуальности, в силу качества исполнения) keygenme от небезызвестного Ms-Rem.

Вот первоначальная ссылка, где он появился: http://exelab.ru/f/index.php?action=vthread&forum=1&topic=4732
А потом он попал вот сюда: http://www.crackmes.de/users/ms_rem/keygenme_by_ms_rem/
Где данному keygenme был выставлена сложность 8 из 10 (*VERY VERY* hard).
Хотя, если честно, это слегка завышенная оценка - я бы поставил в районе 5-6 баллов.

Пожалуй, начнем.


понедельник, 24 февраля 2014 г.

Ошибка загрузки в RichEdit большого блока данных

Давеча пришлось дорабатывать одну из утилит сбора информации о системе и как-то неожиданно для меня от отдела тестирования пришел багрепорт плана:
Утилита формирует и сохраняет данные правильно, но загружает их в искаженном виде.


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

Но та работа была в виде хобби, а тут собственно рабочий проект.

пятница, 14 февраля 2014 г.

Есть ли жизнь после триала?

Предпродажная демонстрация возможностей ПО обычно сводится к двум решениям:
  1. Ограничение функциональности ПО, так называемый демо-комплект.
  2. Введение временного (тестового) периода, в течении которого ПО работает с полным функционалом, так называемая триальная версия (или попросту - триал).
Есть, конечно, варианты демонстрации возможностей в офисе разработчика/продавца, но это не относится к программированию и скорее всего называется менеджментом (или как там это умное слово называются?) :)

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

А это, как правило, сделать довольно просто.
Есть такая старая поговорка: если что-то запустилось и работает, можно запустить и заставить работать неограниченное количество раз :)

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

понедельник, 20 января 2014 г.

Здравствуйте, я ошибка 217 и я вам ничего не скажу

Вероятно многие встречались с таким вот "партизаном" при старте или завершении приложения:


Очень информативное сообщение, сразу понятна причина ошибки, место и способ ее решения :)
Впрочем, если без шуток, что это вообще такое?
Конечно-же это исключение, но ни тип исключения, ни его описание нам не доступны - просто "Runtime error 217" и адрес, а дальше сами...

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

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


понедельник, 23 декабря 2013 г.

Ответ на задачку №2, часть первая

Попробуем разобраться.

Изначально в условии задачи уточнялось - OnPaint не используем.
Правильно это или нет - за условиями задачи, цель была прояснить, понимает ли собеседник поведение VCL в данном случае или нет.
Для упорствующих, конечно, готов очередной подводный камень, к которому мы придем в процессе объяснения, но впрочем по порядку.

Что было предложено в процессе обсуждения вопроса:
1. Зависимость от версий Delphi
2. Выравнивание текста или его многострочность.
3. Смена/пересоздание DC при вызове Memo.Lines[0]
4. Нарушение очереди сообщений из-за вызова обработчика OnClick и как следствие прочие неприятности...
5. Неправильное место вызова, DC "не готов" для вывода (про готовность я не понял, честно, ибо если канва не готова - будет ошибка, все прочее для эстетов :)

Начнем с первого пункта.

пятница, 20 декабря 2013 г.

Задачка на понимание №2

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

Итак, на скорую руку ваяем приложение в котором есть форма, кнопка и TMemo.
Дано 4 варианта реализации кода обработчика кнопки:

var
  ACanvas: THandle;
  AText: string;
begin
  ACanvas := Canvas.Handle;
  AText := Memo1.Lines[0];
  TextOut(ACanvas, Button1.Left, 20, PChar(AText), Length(AText));
end;

...

begin
  ACanvas := Canvas.Handle;
  AText := Memo1.Text;
  TextOut(ACanvas, Button1.Left, 20, PChar(AText), Length(AText));
end;

...

begin
  AText := Memo1.Lines[0];
  ACanvas := Canvas.Handle;
  TextOut(ACanvas, Button1.Left, 20, PChar(AText), Length(AText));
end;

...

begin
  AText := Memo1.Text;
  ACanvas := Canvas.Handle;
  TextOut(ACanvas, Button1.Left, 20, PChar(AText), Length(AText));
end;

Суть данного кода проста - берем текст, который содержится в Memo и тупо выводим его на канву формы.
Вариант того, что отрисовка должна быть в OnPaint, не рассматриваем, он тут лишний.

В результате на форме будет либо выведен текст, либо он будет не выведен, либо уплывет бэкграунд (ХР и ниже), но текст все равно отобразится.

Задача выглядит следующим образом:

четверг, 19 декабря 2013 г.

Ответ на задачу №1

Откуда вообще появляются такие вот непонятные куски кода в которых различные авторы предлагают искать ошибки? Вопрос по сути философский - народное творчество :)
Благодаря народному творчеству и неким "неизвестным" товарищам, чьи произведения подхватываются и расползаются на лету по многочисленным форумам, мы можем наблюдать такие перлы как WParam в обработчике хука объявленный типом Word, либо реализацию метода Execute класса TThread обернутую в Synhronize да, в прочем, можно увидеть даже перекрытие штатной DLLEntryPoint с соглашением вызова stdcall (какая разница что это только обертка над DllMain - пусть и у нас будет так, как у "взрослых дядек" :)
Особенно обидно становится тогда, когда это приобретает массовый характер.
Очень сложно объяснить человеку на форуме, что тот код, который он прочитал в очередной книжке "для хакеров", по сути не верен чуть менее чем полностью, ведь кто я такой - по сути некий неизвестный аноним в интернет пространстве, а у автора вопроса на руках есть целая книга, выпущенная серьезной издательской конторой, к которой доверия будет явно больше чем к моим ответам :)

Сейчас мы будем рассматривать один из образцов такого кода.

Он достаточно популярен в интернете, к примеру:
http://theroadtodelphi.wordpress.com/2009/10/26/detect-aero-glass-using-delphi/
или вот так:
http://www.sql.ru/forum/900738/kak-uznat-vkluchen-li-aero-v-window-7-vista
Где посреди прочих разумных вариантов звучит и такой: "Этот код не приводит к крешу приложения, ищи причину в другом месте."

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

Впрочем... к нашим баранам.

вторник, 17 декабря 2013 г.

Задачка на понимание №1

Основную идею задачек я подсмотрел у Александра Алексеева (более известного как GUNSMOKER), и подумал - а почему бы и мне не открыть такой подраздел, ибо  таких у меня накопилось предостаточно от собеседований кандидатов на вакансию :)

Итак, дана функция, реализованная в классическом стиле :

function IsAeroEnabledCheck: Boolean;
type
  _DwmIsCompositionEnabledFunc = function(IsEnabled: PBool): HRESULT; stdcall;
var
  DllHandle: THandle;
  Flag: Boolean;
  DwmIsCompositionEnabledFunc: _DwmIsCompositionEnabledFunc;
begin
  DllHandle := LoadLibrary('dwmapi.dll');
  if DllHandle > HINSTANCE_ERROR then
  try
    @DwmIsCompositionEnabledFunc := GetProcAddress(DllHandle, 'DwmIsCompositionEnabled');
    if (@DwmIsCompositionEnabledFunc <> nil) then
    begin
      DwmIsCompositionEnabledFunc(@Flag);
      Result := Flag;
    end;
  finally
    FreeLibrary(DllHandle);
  end;
end;

Задача, описать что в данном коде не верно.

четверг, 14 ноября 2013 г.

Карта памяти процесса

Задумывались ли вы над тем, как именно используется память, доступная вашей программе, да и вообще, что именно размещается в этих двух-трех гигабайтах виртуальной памяти, с которыми работает ваше ПО?

Спросите, зачем?
Ну как же, для 32-битного приложения 2-3 гигабайта – это ваш лимит за пределы которого без использования AWE вы выбраться не сможете, а контролировать собственные ресурсы все же желательно. Но даже и без этого просто с целью разобраться...

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

Давайте посмотрим, как именно программист работает с памятью при отладке (особенно при отладке стороннего приложения, проще говоря, при реверсе):

1. Как правило, самой частой операцией будет поиск значения в памяти приложения и, к сожалению, данный функционал почему-то не предоставлен в отладчике Delphi (собственно, как и в MS VC++).
2. Модификация системных структур (PEB/TEB/SEHChain/Unwind/директорий PE-файлов etc...) будет происходить гораздо проще, когда поля структур размаплены на занимаемые ими адреса и представлены в читабельном виде.
3. Отслеживание изменений в памяти процесса (практически никем не предоставляемый функционал, реализованный в виде плагинов к популярным отладчикам). Действительно, зачем трассировать до посинения, когда достаточно сравнить два снимка карты памяти, чтобы понять, тут ли происходит нужная нам модификация данных или нет?

Да, собственно, вариантов использования много.

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

Самая удобная реализация от OllyDebug 2, но, к сожалению, она не отображает данные по 64 битам (все еще ждем).

OllyDebug 2 - Process Environment Block Dump

VMMap от Марка Руссиновича выполняет чисто декоративные свойства, да красиво, да за подписью Microsoft, но практически применить выводимые ей данные тяжеловато.

VMMap отображает только самую базовую информацию не вникая в детали.

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

Process Hacker - Memory Dump

Ну а к карте памяти от IDA Pro за столько лет работы с ней я так и не привык (мне не удобно) :)

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

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

суббота, 1 июня 2013 г.

Сортировка списка по аналогу "Проводника Windows"

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

В данной мини-статье я рассмотрю одну из таких "хотелок".

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


Не красиво, почему это второй элемент с именем "101" находится не на своем месте? Ведь это число, а стало быть место ему как минимум после элемента с именем "2". Да и "New Folder (101)" явно должна быть после "New Folder (2)". Ведь в проводнике все выглядит нормально.


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