|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "code", |
| 5 | + "execution_count": null, |
| 6 | + "metadata": {}, |
| 7 | + "outputs": [], |
| 8 | + "source": [ |
| 9 | + "\"\"\"Processing hashes and PE (ELF) files in Python.\"\"\"" |
| 10 | + ] |
| 11 | + }, |
| 12 | + { |
| 13 | + "cell_type": "markdown", |
| 14 | + "metadata": {}, |
| 15 | + "source": [ |
| 16 | + "# Обработка hashes и PE (ELF)-файлов на языке Python" |
| 17 | + ] |
| 18 | + }, |
| 19 | + { |
| 20 | + "cell_type": "markdown", |
| 21 | + "metadata": {}, |
| 22 | + "source": [ |
| 23 | + "Исходные файлы для блокнота находятся по [ссылке](https://github.com/dm-fedorov/infosec/tree/master/re-tools/samples)." |
| 24 | + ] |
| 25 | + }, |
| 26 | + { |
| 27 | + "cell_type": "markdown", |
| 28 | + "metadata": {}, |
| 29 | + "source": [ |
| 30 | + "Скачиваем весь архив с файлами для работы в Colab:" |
| 31 | + ] |
| 32 | + }, |
| 33 | + { |
| 34 | + "cell_type": "code", |
| 35 | + "execution_count": null, |
| 36 | + "metadata": {}, |
| 37 | + "outputs": [], |
| 38 | + "source": [ |
| 39 | + "!wget https://dfedorov.spb.ru/infosec/re/samples.zip" |
| 40 | + ] |
| 41 | + }, |
| 42 | + { |
| 43 | + "cell_type": "markdown", |
| 44 | + "metadata": {}, |
| 45 | + "source": [ |
| 46 | + "!unzip samples.zip" |
| 47 | + ] |
| 48 | + }, |
| 49 | + { |
| 50 | + "cell_type": "code", |
| 51 | + "execution_count": null, |
| 52 | + "metadata": {}, |
| 53 | + "outputs": [], |
| 54 | + "source": [ |
| 55 | + "!ls samples" |
| 56 | + ] |
| 57 | + }, |
| 58 | + { |
| 59 | + "cell_type": "markdown", |
| 60 | + "metadata": {}, |
| 61 | + "source": [ |
| 62 | + "## Определение сигнатуры файла" |
| 63 | + ] |
| 64 | + }, |
| 65 | + { |
| 66 | + "cell_type": "markdown", |
| 67 | + "metadata": {}, |
| 68 | + "source": [ |
| 69 | + "В системах GNU/Linux, чтобы найти сигнатуру файла (уникальная последовательность байтов), можно использовать команду [xxd](https://www.opennet.ru/man.shtml?topic=xxd&category=1&russian=0), которая генерирует шестнадцатеричный дамп файла, как показано ниже:" |
| 70 | + ] |
| 71 | + }, |
| 72 | + { |
| 73 | + "cell_type": "code", |
| 74 | + "execution_count": null, |
| 75 | + "metadata": {}, |
| 76 | + "outputs": [], |
| 77 | + "source": [ |
| 78 | + "!xxd samples/task-1.exe" |
| 79 | + ] |
| 80 | + }, |
| 81 | + { |
| 82 | + "cell_type": "markdown", |
| 83 | + "metadata": {}, |
| 84 | + "source": [ |
| 85 | + "Видим, что исполняемые файлы ОС Windows, также называемые [PE-файлами](https://ru.wikipedia.org/wiki/Portable_Executable) (например, .exe, .dll, .com, .drv, .sys и т. д.), имеют подпись файла ```MZ``` или шестнадцатеричные символы ```4D 5A``` в первых двух байтах файла." |
| 86 | + ] |
| 87 | + }, |
| 88 | + { |
| 89 | + "cell_type": "markdown", |
| 90 | + "metadata": {}, |
| 91 | + "source": [ |
| 92 | + "Выполним команду для [ELF-файла](https://ru.wikipedia.org/wiki/Executable_and_Linkable_Format) (подпись файла `ELF`):" |
| 93 | + ] |
| 94 | + }, |
| 95 | + { |
| 96 | + "cell_type": "code", |
| 97 | + "execution_count": null, |
| 98 | + "metadata": {}, |
| 99 | + "outputs": [], |
| 100 | + "source": [ |
| 101 | + "!xxd samples/test_01" |
| 102 | + ] |
| 103 | + }, |
| 104 | + { |
| 105 | + "cell_type": "markdown", |
| 106 | + "metadata": {}, |
| 107 | + "source": [ |
| 108 | + "В следующем примере команда [file](https://www.opennet.ru/man.shtml?topic=file&category=1&russian=4) была запущена для двух разных файлов:" |
| 109 | + ] |
| 110 | + }, |
| 111 | + { |
| 112 | + "cell_type": "code", |
| 113 | + "execution_count": null, |
| 114 | + "metadata": {}, |
| 115 | + "outputs": [], |
| 116 | + "source": [ |
| 117 | + "!apt-get install file" |
| 118 | + ] |
| 119 | + }, |
| 120 | + { |
| 121 | + "cell_type": "code", |
| 122 | + "execution_count": null, |
| 123 | + "metadata": {}, |
| 124 | + "outputs": [], |
| 125 | + "source": [ |
| 126 | + "!file samples/task-1.exe" |
| 127 | + ] |
| 128 | + }, |
| 129 | + { |
| 130 | + "cell_type": "code", |
| 131 | + "execution_count": null, |
| 132 | + "metadata": {}, |
| 133 | + "outputs": [], |
| 134 | + "source": [ |
| 135 | + "!file samples/test_01" |
| 136 | + ] |
| 137 | + }, |
| 138 | + { |
| 139 | + "cell_type": "markdown", |
| 140 | + "metadata": {}, |
| 141 | + "source": [ |
| 142 | + "В Python модуль [python-magic](https://github.com/ahupp/python-magic) может использоваться для определения типа файла:" |
| 143 | + ] |
| 144 | + }, |
| 145 | + { |
| 146 | + "cell_type": "code", |
| 147 | + "execution_count": null, |
| 148 | + "metadata": {}, |
| 149 | + "outputs": [], |
| 150 | + "source": [ |
| 151 | + "!pip3 install python-magic" |
| 152 | + ] |
| 153 | + }, |
| 154 | + { |
| 155 | + "cell_type": "code", |
| 156 | + "execution_count": null, |
| 157 | + "id": "79c036c8", |
| 158 | + "metadata": {}, |
| 159 | + "outputs": [], |
| 160 | + "source": [ |
| 161 | + "import hashlib\n", |
| 162 | + "\n", |
| 163 | + "import magic\n", |
| 164 | + "import pefile" |
| 165 | + ] |
| 166 | + }, |
| 167 | + { |
| 168 | + "cell_type": "code", |
| 169 | + "execution_count": null, |
| 170 | + "id": "908836d4", |
| 171 | + "metadata": {}, |
| 172 | + "outputs": [], |
| 173 | + "source": [ |
| 174 | + "magic.from_file(\"samples/test_01\")" |
| 175 | + ] |
| 176 | + }, |
| 177 | + { |
| 178 | + "cell_type": "code", |
| 179 | + "execution_count": null, |
| 180 | + "id": "ff877b14", |
| 181 | + "metadata": {}, |
| 182 | + "outputs": [], |
| 183 | + "source": [ |
| 184 | + "magic.from_file(\"samples/task-1.exe\")" |
| 185 | + ] |
| 186 | + }, |
| 187 | + { |
| 188 | + "cell_type": "markdown", |
| 189 | + "id": "03bea2db", |
| 190 | + "metadata": {}, |
| 191 | + "source": [ |
| 192 | + "## Обработка хеш-суммы на Python" |
| 193 | + ] |
| 194 | + }, |
| 195 | + { |
| 196 | + "cell_type": "markdown", |
| 197 | + "id": "97418b75", |
| 198 | + "metadata": {}, |
| 199 | + "source": [ |
| 200 | + "В системе Linux хеш-суммы могут быть сгенерированы с использованием утилит [md5sum](https://www.opennet.ru/man.shtml?topic=md5sum&category=1&russian=0), [sha256sum](https://www.opennet.ru/man.shtml?topic=sha256sum&russian=0) и [sha1sum](https://www.opennet.ru/man.shtml?topic=sha1sum&russian=0):" |
| 201 | + ] |
| 202 | + }, |
| 203 | + { |
| 204 | + "cell_type": "code", |
| 205 | + "execution_count": null, |
| 206 | + "id": "e7bc88b0", |
| 207 | + "metadata": {}, |
| 208 | + "outputs": [], |
| 209 | + "source": [ |
| 210 | + "!md5sum samples/task-1.exe" |
| 211 | + ] |
| 212 | + }, |
| 213 | + { |
| 214 | + "cell_type": "code", |
| 215 | + "execution_count": null, |
| 216 | + "id": "a5aa2f5d", |
| 217 | + "metadata": {}, |
| 218 | + "outputs": [], |
| 219 | + "source": [ |
| 220 | + "!sha256sum samples/task-1.exe" |
| 221 | + ] |
| 222 | + }, |
| 223 | + { |
| 224 | + "cell_type": "code", |
| 225 | + "execution_count": null, |
| 226 | + "id": "e9363496", |
| 227 | + "metadata": {}, |
| 228 | + "outputs": [], |
| 229 | + "source": [ |
| 230 | + "!sha1sum samples/task-1.exe" |
| 231 | + ] |
| 232 | + }, |
| 233 | + { |
| 234 | + "cell_type": "markdown", |
| 235 | + "id": "3bca3a9b", |
| 236 | + "metadata": {}, |
| 237 | + "source": [ |
| 238 | + "В Python можно генерировать хеш-суммы, используя модуль [hashlib](https://docs.python.org/3/library/hashlib.html), как показано ниже:" |
| 239 | + ] |
| 240 | + }, |
| 241 | + { |
| 242 | + "cell_type": "code", |
| 243 | + "execution_count": null, |
| 244 | + "id": "93a97536", |
| 245 | + "metadata": {}, |
| 246 | + "outputs": [], |
| 247 | + "source": [ |
| 248 | + "with open(\"samples/task-1.exe\", \"rb\") as f:\n", |
| 249 | + " content = f.read()\n", |
| 250 | + "\n", |
| 251 | + "print(hashlib.md5(content).hexdigest())" |
| 252 | + ] |
| 253 | + }, |
| 254 | + { |
| 255 | + "cell_type": "code", |
| 256 | + "execution_count": null, |
| 257 | + "id": "660c283e", |
| 258 | + "metadata": {}, |
| 259 | + "outputs": [], |
| 260 | + "source": [ |
| 261 | + "print(hashlib.sha256(content).hexdigest())" |
| 262 | + ] |
| 263 | + }, |
| 264 | + { |
| 265 | + "cell_type": "code", |
| 266 | + "execution_count": null, |
| 267 | + "id": "d59187d8", |
| 268 | + "metadata": {}, |
| 269 | + "outputs": [], |
| 270 | + "source": [ |
| 271 | + "print(hashlib.sha1(content).hexdigest())" |
| 272 | + ] |
| 273 | + }, |
| 274 | + { |
| 275 | + "cell_type": "markdown", |
| 276 | + "id": "5652fa9e", |
| 277 | + "metadata": {}, |
| 278 | + "source": [ |
| 279 | + "## Извлечение строк" |
| 280 | + ] |
| 281 | + }, |
| 282 | + { |
| 283 | + "cell_type": "markdown", |
| 284 | + "id": "aa84cd95", |
| 285 | + "metadata": {}, |
| 286 | + "source": [ |
| 287 | + "Извлечение строк может подсказать, как функционирует программа, и рассказать об индикаторах, указывающих на подозрительный двоичный код. Например, если вредоносная программа создает файл, имя файла сохраняется в виде строки в двоичном файле. Или если вредоносная программа разрешает доменное имя, контролируемое злоумышленником, это имя впоследствии хранится в виде строки.\n", |
| 288 | + "\n", |
| 289 | + "Чтобы извлечь строки из подозрительного двоичного файла, вы можете использовать утилиту [strings](https://www.opennet.ru/man.shtml?topic=strings) в системах GNU/Linux.\n", |
| 290 | + "\n", |
| 291 | + "Команда `strings` по умолчанию извлекает ASCII-строки, длина которых составляет минимум четыре символа. С помощью опции ```-a``` можно извлечь строки из целого файла." |
| 292 | + ] |
| 293 | + }, |
| 294 | + { |
| 295 | + "cell_type": "code", |
| 296 | + "execution_count": null, |
| 297 | + "id": "c5b541e0", |
| 298 | + "metadata": {}, |
| 299 | + "outputs": [], |
| 300 | + "source": [ |
| 301 | + "!strings -a samples/task-1.exe" |
| 302 | + ] |
| 303 | + }, |
| 304 | + { |
| 305 | + "cell_type": "markdown", |
| 306 | + "id": "223c72e0", |
| 307 | + "metadata": {}, |
| 308 | + "source": [ |
| 309 | + "В образцах вредоносных программ также используются Юникод-строки (2 байта на символ). Чтобы получить полезную информацию из двоичного файла, иногда нужно извлечь как ASCII-, так и Юникод-строки. Чтобы извлечь Юникод-строки с помощью команды `strings`, используйте опцию ```-el```:" |
| 310 | + ] |
| 311 | + }, |
| 312 | + { |
| 313 | + "cell_type": "code", |
| 314 | + "execution_count": null, |
| 315 | + "id": "bb896e4d", |
| 316 | + "metadata": {}, |
| 317 | + "outputs": [], |
| 318 | + "source": [ |
| 319 | + "!strings -a -el samples/task-1.exe" |
| 320 | + ] |
| 321 | + }, |
| 322 | + { |
| 323 | + "cell_type": "markdown", |
| 324 | + "id": "04ecbe05", |
| 325 | + "metadata": {}, |
| 326 | + "source": [ |
| 327 | + "Модуль [FLOSS](https://github.com/fireeye/flare-floss) автоматически извлекает запутанные строки из вредоносных программ." |
| 328 | + ] |
| 329 | + }, |
| 330 | + { |
| 331 | + "cell_type": "markdown", |
| 332 | + "id": "27eaf25f", |
| 333 | + "metadata": {}, |
| 334 | + "source": [ |
| 335 | + "Исполняемые файлы ОС Windows должны соответствовать формату PE/COFF (Portable Executable/Common Object File Format – Переносимый исполняемый/стандартный формат объектного файла).\n", |
| 336 | + "\n", |
| 337 | + "Фактическое содержимое PE-файла разделено на секции. За ними сразу же следует PE-заголовок. Эти секции представляют либо код, либо данные, они имеют ```in-memory-атрибуты```, такие как чтение/запись. Секция, представляющая код, содержит инструкции, которые будут выполняться процессором, тогда как секция, содержащая данные, может представлять различные типы данных, такие как чтение/запись данных программы (глобальные переменные), таблицы импорта/экспорта, ресурсы и т. д. У каждой секции есть свое имя, которое передает ее назначение.\n", |
| 338 | + "\n", |
| 339 | + "Например, секция с именем ```.text``` указывает на код и имеет атрибут ```read-execute```; раздел с именем ```.data``` указывает на глобальные данные и имеет атрибут ```read-write```.\n", |
| 340 | + "\n", |
| 341 | + "Следующий скрипт Python демонстрирует использование модуля [pefile](https://github.com/erocarrera/pefile) для отображения секции и её характеристик:" |
| 342 | + ] |
| 343 | + }, |
| 344 | + { |
| 345 | + "cell_type": "code", |
| 346 | + "execution_count": null, |
| 347 | + "id": "bcbd27d6", |
| 348 | + "metadata": {}, |
| 349 | + "outputs": [], |
| 350 | + "source": [ |
| 351 | + "!pip3 install pefile" |
| 352 | + ] |
| 353 | + }, |
| 354 | + { |
| 355 | + "cell_type": "code", |
| 356 | + "execution_count": null, |
| 357 | + "id": "43575f29", |
| 358 | + "metadata": {}, |
| 359 | + "outputs": [], |
| 360 | + "source": [ |
| 361 | + "pe = pefile.PE(\"samples/task-1.exe\")\n", |
| 362 | + "for section in pe.sections:\n", |
| 363 | + " print(\n", |
| 364 | + " f\"{section.Name.decode()} \\\n", |
| 365 | + " {hex(section.VirtualAddress)} \\\n", |
| 366 | + " {hex(section.Misc_VirtualSize)} \\\n", |
| 367 | + " {section.SizeOfRawData}\"\n", |
| 368 | + " )" |
| 369 | + ] |
| 370 | + }, |
| 371 | + { |
| 372 | + "cell_type": "markdown", |
| 373 | + "metadata": {}, |
| 374 | + "source": [ |
| 375 | + "Скрипт [Pescanner](https://github.com/hiddenillusion/AnalyzePE/blob/master/pescanner.py) использует эвристику вместо сигнатур и может помочь идентифицировать упакованные двоичные файлы, даже если для них нет сигнатур." |
| 376 | + ] |
| 377 | + } |
| 378 | + ], |
| 379 | + "metadata": { |
| 380 | + "language_info": { |
| 381 | + "name": "python" |
| 382 | + } |
| 383 | + }, |
| 384 | + "nbformat": 4, |
| 385 | + "nbformat_minor": 5 |
| 386 | +} |
0 commit comments