LDM & ldmtool

在Windows系统中创建了一个带区动态卷,其实就是用两个磁盘以RAID0方式整合也一个大磁盘。但启动进入Ubuntu (14.04) 系统后并不能正确识别。下图是我在测试系统中创建了一个带区卷E:(由2个盘构成)和一个RAID5卷F:(由4个盘构成):

LDM-RAID-Volumes

这两个由Windows系统创建的动态卷,是LDM格式(Logical Disk Manager),Linux系统中不能正确识别。最初我尝试用mdadm强制加载带区卷,分别试了64K及128K chunk,但全部无效,尝试办法如下:
root@ubuntu:~# mdadm --build /dev/md0 --level=0 --chunk=128 --raid-devices=2 /dev/sd[cd]3
mdadm: array /dev/md0 built and started.
root@ubuntu:~# mdadm --detail /dev/md0
/dev/md0:
        Version :
  Creation Time : Thu Jun 25 16:08:11 2015
     Raid Level : raid0
     Array Size : 41680640 (39.75 GiB 42.68 GB)
   Raid Devices : 2
  Total Devices : 2

          State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
  Spare Devices : 0

     Chunk Size : 128K

    Number   Major   Minor   RaidDevice State
       0       8       35        0      active sync   /dev/sdc3
       1       8       51        1      active sync   /dev/sdd3
root@ubuntu:~# tune2fs -l /dev/md0
tune2fs 1.42.9 (4-Feb-2014)
tune2fs: Bad magic number in super-block while trying to open /dev/md0
Couldn't find valid filesystem superblock.
root@ubuntu:~# mdadm -S /dev/md0
mdadm: stopped /dev/md0
root@ubuntu:~# mdadm --build /dev/md0 --level=0 --chunk=128 --raid-devices=2 /dev/sd[dc]3
mdadm: array /dev/md0 built and started.
root@ubuntu:~# mdadm --detail /dev/md0
/dev/md0:
        Version :
  Creation Time : Thu Jun 25 16:08:57 2015
     Raid Level : raid0
     Array Size : 41680640 (39.75 GiB 42.68 GB)
   Raid Devices : 2
  Total Devices : 2

          State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
  Spare Devices : 0

     Chunk Size : 128K

    Number   Major   Minor   RaidDevice State
       0       8       51        0      active sync   /dev/sdd3
       1       8       35        1      active sync   /dev/sdc3
root@ubuntu:~# tune2fs -l /dev/md0
tune2fs 1.42.9 (4-Feb-2014)
tune2fs: Bad magic number in super-block while trying to open /dev/md0
Couldn't find valid filesystem superblock.
root@ubuntu:~# mdadm -S /dev/md0
mdadm: stopped /dev/md0
root@ubuntu:~#

后来几经搜索,发现解决方案原来很简单,只需要安装ldmtool。

root@ubuntu:~# parted -l
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: 85.9GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system     Flags
1      1049kB  1000MB  999MB   primary  ext2            boot
2      1000MB  81.0GB  80.0GB  primary  xfs
3      81.0GB  85.9GB  4898MB  primary  linux-swap(v1)


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 42.9GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
1      1049kB  42.9GB  42.9GB  primary  ext4


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdc: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   21.5GB  21.3GB               LDM data partition


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdd: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   21.5GB  21.3GB               LDM data partition


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sde: 64.4GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   64.4GB  64.3GB               LDM data partition


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdf: 64.4GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   64.4GB  64.3GB               LDM data partition


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdg: 64.4GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   64.4GB  64.3GB               LDM data partition


Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdh: 64.4GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system  Name                          Flags
1      17.4kB  1066kB  1049kB               LDM metadata partition
2      1066kB  134MB   133MB                Microsoft reserved partition  msftres
3      134MB   64.4GB  64.3GB               LDM data partition

root@ubuntu:~# ldmtool scan
[
  "3ffea520-1b24-11e5-8565-000c293dbd64"
]
root@ubuntu:~# ldmtool show diskgroup 3ffea520-1b24-11e5-8565-000c293dbd64
{
  "name" : "WIN-FB20IXK90MU-Dg0",
  "guid" : "3ffea520-1b24-11e5-8565-000c293dbd64",
  "volumes" : [
    "Volume2",
    "Volume1"
  ],
  "disks" : [
    "Disk1",
    "Disk2",
    "Disk3",
    "Disk4",
    "Disk6",
    "Disk5"
  ]
}
root@ubuntu:~# ldmtool show volume 3ffea520-1b24-11e5-8565-000c293dbd64 Volume1
{
  "name" : "Volume1",
  "type" : "RAID5",
  "size" : 376688640,
  "chunk-size" : 128,
  "hint" : "F:",
  "partitions" : [
    "Disk1-01",
    "Disk2-01",
    "Disk3-01",
    "Disk4-01"
  ]
}
root@ubuntu:~# ldmtool show volume 3ffea520-1b24-11e5-8565-000c293dbd64 Volume2
{
  "name" : "Volume2",
  "type" : "striped",
  "size" : 83353600,
  "chunk-size" : 128,
  "hint" : "E:",
  "partitions" : [
    "Disk5-01",
    "Disk6-01"
  ]
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk1-01
{
  "name" : "Disk1-01",
  "start" : 2014,
  "size" : 125562880,
  "disk" : "Disk1"
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk2-01
{
  "name" : "Disk2-01",
  "start" : 2014,
  "size" : 125562880,
  "disk" : "Disk2"
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk3-01
{
  "name" : "Disk3-01",
  "start" : 2014,
  "size" : 125562880,
  "disk" : "Disk3"
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk4-01
{
  "name" : "Disk4-01",
  "start" : 2014,
  "size" : 125562880,
  "disk" : "Disk4"
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk5-01
{
  "name" : "Disk5-01",
  "start" : 2014,
  "size" : 41676800,
  "disk" : "Disk5"
}
root@ubuntu:~# ldmtool show partition 3ffea520-1b24-11e5-8565-000c293dbd64 Disk6-01
{
  "name" : "Disk6-01",
  "start" : 2014,
  "size" : 41676800,
  "disk" : "Disk6"
}

用ldmtool解析并创建动态卷只需要一个简单命令

root@ubuntu:~# ldmtool create all
[
  "ldm_vol_WIN-FB20IXK90MU-Dg0_Volume2",
  "ldm_vol_WIN-FB20IXK90MU-Dg0_Volume1"
]

root@ubuntu:~# ls -l /dev/mapper/
total 0
crw------- 1 root root 10, 236 Jun 25 16:29 control
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_part_WIN-FB20IXK90MU-Dg0_Disk1-01 -> ../dm-1
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_part_WIN-FB20IXK90MU-Dg0_Disk2-01 -> ../dm-2
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_part_WIN-FB20IXK90MU-Dg0_Disk3-01 -> ../dm-3
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_part_WIN-FB20IXK90MU-Dg0_Disk4-01 -> ../dm-4
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_vol_WIN-FB20IXK90MU-Dg0_Volume1 -> ../dm-5
lrwxrwxrwx 1 root root       7 Jun 25 16:29 ldm_vol_WIN-FB20IXK90MU-Dg0_Volume2 -> ../dm-0

root@ubuntu:~# ls -l /dev/dm*
brw-rw---- 1 root disk 252, 0 Jun 25 16:29 /dev/dm-0
brw-rw---- 1 root disk 252, 1 Jun 25 16:29 /dev/dm-1
brw-rw---- 1 root disk 252, 2 Jun 25 16:29 /dev/dm-2
brw-rw---- 1 root disk 252, 3 Jun 25 16:29 /dev/dm-3
brw-rw---- 1 root disk 252, 4 Jun 25 16:29 /dev/dm-4
brw-rw---- 1 root disk 252, 5 Jun 25 16:29 /dev/dm-5
root@ubuntu:~#
root@ubuntu:~# tune2fs -l /dev/dm-0
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          22a45231-ede2-4c60-9c93-ee841ae2f2ee
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex
_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              2605056
Block count:              10419200
Reserved block count:     520960
Free blocks:              10210674
Free inodes:              2605045
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1021
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
RAID stride:              16
RAID stripe width:        32
Flex block group size:    16
Filesystem created:       Thu Jun 25 15:58:29 2015
Last mount time:          n/a
Last write time:          Thu Jun 25 15:58:31 2015
Mount count:              0
Maximum mount count:      -1
Last checked:             Thu Jun 25 15:58:29 2015
Check interval:           0 (<none>)
Lifetime writes:          132 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      a472f2f6-a27b-4362-91e2-dce4ad48a700
Journal backup:           inode blocks
root@ubuntu:~# tune2fs -l /dev/dm-5
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          f0655359-b2e0-4732-8df0-b0ab24918ec1
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype extent flex
_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              11771904
Block count:              47086080
Reserved block count:     2354304
Free blocks:              46299313
Free inodes:              11771893
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1012
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
RAID stride:              16
RAID stripe width:        48
Flex block group size:    16
Filesystem created:       Thu Jun 25 15:13:55 2015
Last mount time:          n/a
Last write time:          Thu Jun 25 15:14:21 2015
Mount count:              6
Maximum mount count:      -1
Last checked:             Thu Jun 25 15:14:21 2015
Check interval:           0 (<none>)
Lifetime writes:          133 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      88ddd8a2-506a-4e9b-9109-ce9c171b2607
Journal backup:           inode blocks

至此就可以自由访问 /dev/dm-0和/dev/dm-5两个设备卷了。不过还要说的是,ldmtool是通过DM (Device Mapper) 产生的RAID卷(和LVM使用的是同样的机制),而不是最常用的MD方式(即Multiple Devices),特别对于RAID5/RAID6此类的数据卷,MD Raid做了较多的优化,除性能更好之外,稳定性应该也好于Device Mapper方式。

参考阅读:
1,http://manpages.ubuntu.com/manpages/trusty/man1/ldmtool.1.html
2,https://github.com/mdbooth/libldm
3,https://notesbytom.wordpress.com/2012/06/14/linux-support-for-windows-dynamic-disks/
4,http://stackoverflow.com/questions/8427372/windows-spanned-disks-ldm-restoration-with-linux/22108676#22108676 <ldmtool出现之前的办法 Smile>

Continue reading » · Rating: · Written on: 06-25-15 · No Comments »

脑残的PsSetCreateProcessNotifyRoutine

Vista之前的系统,XP及Server 2003只有8个坑,就是说前8个调用成功之后,后续的所有调用都会失败,看来通过注册callback的方式来监控进程非常不靠谱。

从内核角度来说,尽量少的调用不仅提高系统响应时间,也降低了不靠谱的驱动所可能带来问题,但限制为区区8个总不是解决办法吧,比如Symantec家的SEP动不动就占3个,腾讯家(Tencent)更牛B,安全管家要用几个,QQ也要用,就连浏览器也要搞个驱动并也要注册个进程创建的回调通知,这也太让人无语了吧。

好在从Vista开始,这个限制从8个变成了64个,翻了整整8倍,呵呵,这下够用了?!

下面是一个典型的XP系统实例,8个回调会被占满了,后起的驱动们只能想其它办法了:

0: kd> x nt!PspCreateProcessNotifyRoutine 80564a40 nt!PspCreateProcessNotifyRoutine = <no type information> 0: kd> dd 80564a40 80564a40  e101894f e15e4eb7 e2031ff6 e1e8b56f 80564a50  e20a8d9f e51c641f e52246b7 e5ad82cf 80564a60  00000008 00000000 86a85d58 8656fac0 80564a70  86b9b5a0 86be5208 86be45a0 00000000 80564a80  00000000 00000000 00000000 00000000 80564a90  00000000 00000000 00000000 00000000 80564aa0  00000000 6d6f7441 00000000 00000001 80564ab0  00000000 00000000 00000000 00000000 0: kd> .for (r $t0=0; $t0 < 8; r $t0=$t0+1) {r $t1 = poi($t0 * 4 + nt!PspCreateProcessNotifyRoutine); .if ($t1 == 0) {.continue;}; r $t1 = $t1 & 0xFFFFFFF8; r $t1 = poi($t1 + 4); r $t0; r $t1; u $t1; ln $t1;} $t0=00000000 $t1=f7310790 TsFltMgr+0x10790: f7310790 55              push    ebp f7310791 8bec            mov     ebp,esp f7310793 83e4f8          and     esp,0FFFFFFF8h f7310796 83ec14          sub     esp,14h f7310799 53              push    ebx f731079a 56              push    esi f731079b 8b35a07b31f7    mov     esi,dword ptr [TsFltMgr+0x17ba0 (f7317ba0)] f73107a1 57              push    edi $t0=00000001 $t1=f771a788 ghcore+0x3788: f771a788 8bff            mov     edi,edi f771a78a 55              push    ebp f771a78b 8bec            mov     ebp,esp f771a78d 33c0            xor     eax,eax f771a78f 390564b471f7    cmp     dword ptr [ghcore+0x4464 (f771b464)],eax f771a795 7508            jne     ghcore+0x379f (f771a79f) f771a797 39056cb471f7    cmp     dword ptr [ghcore+0x446c (f771b46c)],eax f771a79d 741a            je      ghcore+0x37b9 (f771a7b9) $t0=00000002 $t1=ed1a3b00 SYMEVENT+0xcb00: ed1a3b00 8bff            mov     edi,edi ed1a3b02 55              push    ebp ed1a3b03 8bec            mov     ebp,esp ed1a3b05 51              push    ecx ed1a3b06 53              push    ebx ed1a3b07 8b5d08          mov     ebx,dword ptr [ebp+8] ed1a3b0a 56              push    esi ed1a3b0b 33f6            xor     esi,esi $t0=00000003 $t1=ecfeb120 QQFrmMgr+0xe120: ecfeb120 8bff            mov     edi,edi ecfeb122 55              push    ebp ecfeb123 8bec            mov     ebp,esp ecfeb125 51              push    ecx ecfeb126 51              push    ecx ecfeb127 53              push    ebx ecfeb128 8b5d0c          mov     ebx,dword ptr [ebp+0Ch] ecfeb12b 56              push    esi $t0=00000004 $t1=ecd098a0 SysPlant+0x78a0: ecd098a0 55              push    ebp ecd098a1 8bec            mov     ebp,esp ecd098a3 83e4f8          and     esp,0FFFFFFF8h ecd098a6 51              push    ecx ecd098a7 53              push    ebx ecd098a8 56              push    esi ecd098a9 57              push    edi ecd098aa a12480d1ec      mov     eax,dword ptr [SysPlant+0x16024 (ecd18024)] $t0=00000005 $t1=866b41d0 866b41d0 90              nop 866b41d1 90              nop 866b41d2 e9e7c4f466      jmp     QMUdisk+0x26be (ed6006be) 866b41d7 90              nop 866b41d8 90              nop 866b41d9 90              nop 866b41da 90              nop 866b41db 90              nop $t0=00000006 $t1=ecaf8070 BHDrvx86+0x6c070: ecaf8070 8bff            mov     edi,edi ecaf8072 55              push    ebp ecaf8073 8bec            mov     ebp,esp ecaf8075 807d1000        cmp     byte ptr [ebp+10h],0 ecaf8079 750f            jne     BHDrvx86+0x6c08a (ecaf808a) ecaf807b 8b450c          mov     eax,dword ptr [ebp+0Ch] ecaf807e 8b0d48e0b8ec    mov     ecx,dword ptr [BHDrvx86+0x102048 (ecb8e048)] ecaf8084 50              push    eax $t0=00000007 $t1=ee461eba dekfs+0x4eba: ee461eba 8bff            mov     edi,edi ee461ebc 55              push    ebp ee461ebd 8bec            mov     ebp,esp ee461ebf 83ec10          sub     esp,10h ee461ec2 807d1000        cmp     byte ptr [ebp+10h],0 ee461ec6 53              push    ebx ee461ec7 56              push    esi ee461ec8 57              push    edi

Server 2008 X64系统已经可以支持64个注册回调了,这个限制是硬编码在

函数PsSetCreateProcessNotifyRoutine中的:

0: kd> u nt!PspSetCreateProcessNotifyRoutine nt!PspSetCreateProcessNotifyRoutine: fffff800`01c3fab0 48895c2408      mov     qword ptr [rsp+8],rbx fffff800`01c3fab5 48896c2410      mov     qword ptr [rsp+10h],rbp fffff800`01c3faba 4889742418      mov     qword ptr [rsp+18h],rsi …… fffff800`01c3fad4 bb01000000      mov     ebx,1 …… fffff800`01c3fb3e e89d3cf1ff      call    nt!ExDereferenceCallBackBlock (fffff800`01b537e0) fffff800`01c3fb43 4403e3          add     r12d,ebx fffff800`01c3fb46 4183fc40        cmp     r12d,40h fffff800`01c3fb4a 72ae            jb      nt!PspSetCreateProcessNotifyRoutine+0x4a (fffff800`01c3fafa) fffff800`01c3fb4c 66019fb4010000  add     word ptr [rdi+1B4h],bx fffff800`01c3fb53 7518            jne     nt!PspSetCreateProcessNotifyRoutine+0xbd (fffff800`01c3fb6d) ……

此系统上并未安装腾讯管家等类似的防毒程序,但是64个注册回调已有6个被使用,差不多全是M$自家给占用的:

0: kd> x nt!PspCreateProcessNotifyRoutine fffff800`019f8ee0 nt!PspCreateProcessNotifyRoutine = <no type information> 0: kd> dq fffff800`019f8ee0 fffff800`019f8ee0  fffff880`00008c4f fffff880`006d7acf fffff800`019f8ef0  fffff880`006f694f fffff880`007ff5cf fffff800`019f8f00  fffff880`098168af fffff880`0a30216f fffff800`019f8f10  00000000`00000000 00000000`00000000 fffff800`019f8f20  00000000`00000000 00000000`00000000 fffff800`019f8f30  00000000`00000000 00000000`00000000 fffff800`019f8f40  00000000`00000000 00000000`00000000 fffff800`019f8f50  00000000`00000000 00000000`00000000 0: kd> .for (r $t0=0; $t0 < 0x40; r $t0=$t0+1) {r $t1=poi($t0 * 8 + nt!PspCreateProcessNotifyRoutine); .if ($t1 == 0) {.continue}; r $t0; r $t1 = $t1 & 0xFFFFFFFFFFFFFFF0; r $t1 = poi($t1 + 8); r $t1; u $t1; ln $t1;} $t0=0000000000000000 $t1=fffff8000188dbd0 nt!ViCreateProcessCallback: fffff800`0188dbd0 fff3            push    rbx fffff800`0188dbd2 4883ec40        sub     rsp,40h fffff800`0188dbd6 833dc3a2160000  cmp     dword ptr [nt!ViVerifierEnabled (fffff800`019f7ea0)],0 fffff800`0188dbdd 0f8583b6fcff    jne     nt! ?? ::FNODOBFM::`string'+0x21140 (fffff800`01859266) fffff800`0188dbe3 4883c440        add     rsp,40h fffff800`0188dbe7 5b              pop     rbx fffff800`0188dbe8 c3              ret fffff800`0188dbe9 90              nop (fffff800`0188dbd0)   nt!ViCreateProcessCallback   |  (fffff800`0188dbf0)   nt!IopAllocateFileObjectExtension Exact matches: nt!ViCreateProcessCallback = <no type information> $t0=0000000000000001 $t1=fffffa6000e52ffc ksecdd!CredMarshalTargetInfo+0x8cc: fffffa60`00e52ffc 4883ec28        sub     rsp,28h fffffa60`00e53000 488364244800    and     qword ptr [rsp+48h],0 fffffa60`00e53006 4584c0          test    r8b,r8b fffffa60`00e53009 488bc2          mov     rax,rdx fffffa60`00e5300c 7546            jne     ksecdd!CredMarshalTargetInfo+0x924 (fffffa60`00e53054) fffffa60`00e5300e 488d542448      lea     rdx,[rsp+48h] fffffa60`00e53013 488bc8          mov     rcx,rax fffffa60`00e53016 ff15dc00feff    call    qword ptr [ksecdd!BCryptDestroySecret+0x191c8 (fffffa60`00e330f8)] (fffffa60`00e52730)   ksecdd!CredMarshalTargetInfo+0x8cc   |  (fffffa60`00e535f4)   ksecdd!AcquireCredentialsHandleW $t0=0000000000000002 $t1=fffffa600106f830 tcpip+0x69830: fffffa60`0106f830 4d85c0          test    r8,r8 fffffa60`0106f833 7405            je      tcpip+0x6983a (fffffa60`0106f83a) fffffa60`0106f835 e9860b0000      jmp     tcpip+0x6a3c0 (fffffa60`010703c0) fffffa60`0106f83a e911130000      jmp     tcpip+0x6ab50 (fffffa60`01070b50) fffffa60`0106f83f 90              nop fffffa60`0106f840 90              nop fffffa60`0106f841 90              nop fffffa60`0106f842 90              nop $t0=0000000000000003 $t1=fffffa600074e06c CI!I_PEProcessNotify: fffffa60`0074e06c 4584c0          test    r8b,r8b fffffa60`0074e06f 7528            jne     CI!I_PEProcessNotify+0x2d (fffffa60`0074e099) fffffa60`0074e071 53              push    rbx fffffa60`0074e072 4883ec20        sub     rsp,20h fffffa60`0074e076 488bda          mov     rbx,rdx fffffa60`0074e079 ff15f1d1f5ff    call    qword ptr [CI!_imp_IoGetCurrentProcess (fffffa60`006ab270)] fffffa60`0074e07f 488bc8          mov     rcx,rax fffffa60`0074e082 ff1530d0f5ff    call    qword ptr [CI!_imp_PsIsProtectedProcess (fffffa60`006ab0b8)] (fffffa60`0074e06c)   CI!I_PEProcessNotify   |  (fffffa60`0074e0a0)   CI!RSA32Alloc Exact matches: CI!I_PEProcessNotify = <no type information> $t0=0000000000000004 $t1=fffffa6002fac964 dekfs+0x6964: fffffa60`02fac964 48895c2408      mov     qword ptr [rsp+8],rbx fffffa60`02fac969 48896c2410      mov     qword ptr [rsp+10h],rbp fffffa60`02fac96e 56              push    rsi fffffa60`02fac96f 57              push    rdi fffffa60`02fac970 4154            push    r12 fffffa60`02fac972 4155            push    r13 fffffa60`02fac974 4156            push    r14 fffffa60`02fac976 4883ec50        sub     rsp,50h $t0=0000000000000005 $t1=fffffa600c545b2d peauth!I_PEProcessNotify: fffffa60`0c545b2d 48895c2408      mov     qword ptr [rsp+8],rbx fffffa60`0c545b32 57              push    rdi fffffa60`0c545b33 4883ec20        sub     rsp,20h fffffa60`0c545b37 e8cc6bfdff      call    peauth!WARBIRD::Stub_VerifyVerifierCheckSum (fffffa60`0c51c708) fffffa60`0c545b3c 90              nop fffffa60`0c545b3d 360000          add     byte ptr ss:[rax],al fffffa60`0c545b40 00fd            add     ch,bh fffffa60`0c545b42 140a            adc     al,0Ah (fffffa60`0c545b2d)   peauth!I_PEProcessNotify   |  (fffffa60`0c545fe1)   peauth!PEReturnCertChain Exact matches: peauth!I_PEProcessNotify = <no type information>
Continue reading » · Rating: · Written on: 06-22-15 · No Comments »

Security-Enhanced CRT,边界与潜规则

Windows Security-Enhanced CRT 相关函数(即_s后辍函数)并不是对老函数的直接替代,其中不仅有更严格的参数检查,还会有buffer的重置操作等,使用的时候要格外小心,一定要仔细阅读MSDN描述或者VC runtime源码 (以Visual Studio 2008为例: C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src)。

下面不妨测试3个代码片段:

测试代码【C1】:

void main() {
    char dst1[8];
    memcpy(dst1, NULL, 0);
    memcpy(NULL, NULL, 0);
}

测试代码【C2】:

void main() {

    char dst1[8];

    memcpy_s(dst1, 8, NULL, 0);
    memcpy_s(NULL, 0, NULL, 0);
    char *dst2 = (char *)malloc(0);
    if (dst2) {
        memcpy_s(dst2, 0, NULL, 0);
    free(dst2);
    }
}

测试代码【C3】:

void main() {

    char dst1[8];

    memcpy_s(NULL, 0, dst1, 8);

    char *dst2 = (char *)malloc(0);
    if (dst2) {
        memcpy_s(dst2, 0, dst1, 8);
        free(dst2);
    }
}

这几段代码实际上什么也没有做,只是参数有变化而已,但测试中会发现【C3】会导致程序崩溃。具体原因就是因为memcpy_s进行了更严格的参数检测,可对参考memcpy_s的源码,引用自Visual Studio 2008 runtime source memcpy_s.c:

/***
*  memcpy_s.c - contains memcpy_s routine
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*  Purpose:
*       memcpy_s() copies a source memory buffer to a destination buffer.
*       Overlapping buffers are not treated specially, so propagation may occur.
*
*******************************************************************/

#include <cruntime.h>
#include <string.h>
#include <internal.h>

/***
*  memcpy_s - Copy source buffer to destination buffer
*
*  Purpose:
*       memcpy_s() copies a source memory buffer to a destination memory buffer.
*       This routine does NOT recognize overlapping buffers, and thus can lead
*       to propagation.
*
*       For cases where propagation must be avoided, memmove_s() must be used.
*
*  Entry:
*       void *dst = pointer to destination buffer
*       size_t sizeInBytes = size in bytes of the destination buffer
*       const void *src = pointer to source buffer
*       size_t count = number of bytes to copy
*
*  Exit:
*       Returns 0 if everything is ok, else return the error code.
*
*  Exceptions:
*       Input parameters are validated. Refer to the validation section of the function.
*       On error, the error code is returned and the destination buffer is zeroed.
*
*******************************************************************/

errno_t __cdecl memcpy_s(
    void * dst,
    size_t sizeInBytes,
    const void * src,
    size_t count
)
{
    if (count == 0)
    {
        /* nothing to do */
        return 0;
    }

    /* validation section */
    _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
    if (src == NULL || sizeInBytes < count)
    {
        /* zeroes the destination buffer */
        memset(dst, 0, sizeInBytes);

        _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
        _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
        /* useless, but prefast is confused */
        return EINVAL;
    }

    memcpy(dst, src, count);
    return 0;
}

参考阅读:

1, _snwprintf_s的潜规则http://blog.dynox.cn/?p=791
2,   Security Features in the CRT:
      https://msdn.microsoft.com/zh-cn/library/vstudio/8ef0s5kh(v=vs.110).aspx

Continue reading » · Rating: · Written on: 06-04-15 · No Comments »

驱动的PE文件头校验和

众周所知,应用层PE程序的校验和一般为0,进程加载时系统并不检验,但驱动程序是要强制验证的,并且WinDDK在生成.sys文件时已经设置的校验和。

但是在写上篇blog时(http://blog.dynox.cn/?p=1391)发现系统并不必须对驱动程序文件进行CheckSum的验证。实验中发现系统只是针对 SERVICE_BOOT_START (0) 的驱动文件进行验证,而此时其实是Windows启动程序WinLoad.exe做的加载及验证。

Continue reading » · Rating: · Written on: 06-03-15 · No Comments »

签名文件的修改

已经签名的PE文件原则来说不再修改的,但总有需求要添加些数据在PE文件中,为了更文件分发等。经研究发现,签名的PE文件也是可以修改或追加数据的,当然追加的数据只能是纯数据,比如相关配置信息,或安装包的附加数据等。

我们先来看一下签名文件的格式及数据校验范围,此图引用自Microsoft的关于PE文件签名的文档[REF1]:

image

其中灰色部分是不进行签名校验的数据,但这三部分只有第三个区域才有追加数据的可能,因为第一部分是4个字节,是PE文件自有的校验数据,有兴趣的同学可以参阅 REF2;第二部分是PE文件头的数据目录,其结构是固定的8个字节(前4字节为偏移,后4字节为长度)。第三部分是签名数据部分,经有限观察,长度在3K字节左右。

实际实用中,最后“Remaining content”这部分并存在,签名数据就已经在文件尾了,所以这就给我们在签名数据中(亦是文件尾)加入我们自定义数据的可能。

下面不妨做个实验,以Intel显卡驱动igdkmd64.sys为例:

pic2.0

签名信息如下:

pic1

然后我们添加16个字符至文件尾: pic3

检查下文件长度,从3,828,152变为3,828,168:

image

此时右键打开文件属性就会发现签名信息认证没有了:

pic2

之后,我们还要修改数据目录,以增大签名数据区的大小。用PE Tool 1.0.0.5打开igdkmd64.sys,查看数据目录部分:image

所以我们只需要将文件偏移0x000001d0处的目录项中的长度从0x29B8改成029C8即可,即增加了16字节。修改好再来看文件属性,此时签名项的tab又出现了,即说明通过了Windows的签名检测:

image

不妨再用Windows签名工具检验一次,以确保签名数据的有效:

image

自此足以说明签过名的文件是可以修改的,当然只能做有限修改。对应用层PE程序,以上的修改便已足够,但对驱动程序来说,还要做一件事情,就是更新PE文件头的校验和。相关工具可以参见[REF2]中的工具,也可以通过我写了小程序[REF3]做校验和计算。

image

将新计算出的校验和 0x003A7A63更新至文件偏移0x180处即可,然后就可以用新文件替换掉老的,重启系统即可以加载新修改后的驱动了。

参考资料: REF1: Windows Authenticode Portable Executable Signature Format, Version 1.0  — March 21, 2008 http://www.microsoft.com/whdc/winlogo/drvsign/Authenticode_PE.mspx REF2:   An Analysis of the Windows PE Checksum Algorithm by Jeffrey Walton http://www.codeproject.com/Articles/19326/An-Analysis-of-the-Windows-PE-Checksum-Algorithm REF3:   PECheckSum: http://dynox.cn/soft/PECheckSum.zip

Continue reading » · Rating: · Written on: 06-03-15 · No Comments »