当前位置: 首页 > 工具软件 > SCZ > 使用案例 >

SCZ的3篇有关sam的文章

百里嘉泽
2023-12-01
http://www.opencjk.org/~scz/


 SYSKEY机制的一个完整验证集及讨论

参看flashsky、Nicola Cuomo的文章([11]、[13])。

--------------------------------------------------------------------------
Class A                     : C5 1F 3D DE
                            : ("c51f3dde")
                            : (HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa/JD)
Class B                     : 3F 88 75 0D
                            : ("3f88750d")
                            : (HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa/Skew1)
Class C                     : EE F2 5F C1
                            : ("eef25fc1")
                            : (HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa/GBG)
Class D                     : 31 AF 75 4B
                            : ("31af754b")
                            : (HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa/Data)
Class                       : C5 1F 3D DE 3F 88 75 0D EE F2 5F C1 31 AF 75 4B
MIX                         : 08 0A 03 07 02 01 09 0F 00 05 0D 04 0B 06 0C 0E
BOOTKEY/SYSKEY              : EE 88 3F 3D C1 F2 AF DE C5 75 1F 31 75 5F 4B 0D
--------------------------------------------------------------------------
ACCOUNT_F_VALUE             : 02 00 01 00 00 00 00 00 C0 4D 55 34 10 BC C2 01
                            : D8 00 00 00 00 00 00 00 00 80 A6 0A FF DE FF FF
                            : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80
                            : 00 CC 1D CF FB FF FF FF 00 CC 1D CF FB FF FF FF
                            : 00 00 00 00 00 00 00 00 EC 03 00 00 00 00 00 00
                            : 00 00 00 00 00 00 00 00 01 00 00 00 03 00 00 00
                            : 01 00 00 00 01 00 01 00 01 00 00 00 38 00 00 00
                            : 0E 13 6D 8F 01 17 04 DE D8 71 1A 32 43 92 8A A0
                            : 54 30 21 81 56 76 7B D5 D6 EC 9D AD FE 7A 8E 16
                            : 50 7D 76 53 CC A3 54 CD 33 4D 67 BD C3 F0 C6 52
                            : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            : 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
                            : (HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account/F)
ACCOUNT_F_VALUE_A           : 0E 13 6D 8F 01 17 04 DE D8 71 1A 32 43 92 8A A0
MagicStringA                : 21 40 23 24 25 5E 26 2A 28 29 71 77 65 72 74 79
                            : 55 49 4F 50 41 7A 78 63 76 62 6E 6D 51 51 51 51
                            : 51 51 51 51 51 51 51 51 29 28 2A 40 26 25 00
                            : ("!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%")
BOOTKEY/SYSKEY              : EE 88 3F 3D C1 F2 AF DE C5 75 1F 31 75 5F 4B 0D
MagicStringB                : 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
                            : 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31
                            : 32 33 34 35 36 37 38 39 00
                            : ("0123456789012345678901234567890123456789")
MD5/RC4KEY                  : 83 B3 19 2F 34 41 FB 10 2D CB 8C AC 98 FE DD 8E
ACCOUNT_F_VALUE_B/RC4 IN    : 54 30 21 81 56 76 7B D5 D6 EC 9D AD FE 7A 8E 16
                            : 50 7D 76 53 CC A3 54 CD 33 4D 67 BD C3 F0 C6 52
RC4                         : CA 7C 56 6F 36 9F 17 64 CC 30 77 3E 00 A5 67 60
                            : 7E DC AC CD F7 D5 01 72 E8 63 4A 26 58 28 D5 BF
SampSecretSessionKey        : CA 7C 56 6F 36 9F 17 64 CC 30 77 3E 00 A5 67 60
--------------------------------------------------------------------------
SampSecretSessionKey        : CA 7C 56 6F 36 9F 17 64 CC 30 77 3E 00 A5 67 60
RID                         : E8 03 00 00 (1000)
SampMagicConstantStringA    : 4C 4D 50 41 53 53 57 4F 52 44 00 ("LMPASSWORD")
MD5/RC4KEY                  : 30 58 58 7D 01 14 0F FA BE 2C E3 99 8C F3 0D 10
Encrypted LM Hash/RC4 IN    : D3 B8 C2 84 97 05 50 83 B0 55 46 A3 C9 F4 5B C6
RC4/DES Encrypted Message   : ED 0E B6 92 76 8E 43 25 B1 52 28 32 18 05 43 32

E8030000E8030000E8030000E803 (Derived From RID)
            |
        str_to_key()
            |
            V
E800C0000E400C00007400600006A006 (DESKEY Derived From RID)

DESKEY1 Derived From RID    : E8 00 C0 00 0E 40 0C 00
DESKEY2 Derived From RID    : 00 74 00 60 00 06 A0 06
DES/LM Hash                 : 42 2B 15 72 AE 4B 9C DE E2 C2 FA D4 5B 16 A0 FF
--------------------------------------------------------------------------
SampSecretSessionKey        : CA 7C 56 6F 36 9F 17 64 CC 30 77 3E 00 A5 67 60
RID                         : E8 03 00 00 (1000)
SampMagicConstantStringB    : 4E 54 50 41 53 53 57 4F 52 44 00 ("NTPASSWORD")
MD5/RC4KEY                  : 96 BE 87 40 08 8B 57 18 35 A0 E9 6E 50 95 C9 E7
Encrypted NTLM Hash/RC4 IN  : 93 75 EE 45 2C 8D E1 FD D3 50 F6 62 FC 5B 3C 5E
RC4/DES Encrypted Message   : D3 38 99 8E 85 03 DA 20 A6 D5 09 1C 48 2A 81 4A

E8030000E8030000E8030000E803 (Derived From RID)
            |
        str_to_key()
            |
            V
E800C0000E400C00007400600006A006 (DESKEY Derived From RID)

DESKEY1 Derived From RID    : E8 00 C0 00 0E 40 0C 00
DESKEY2 Derived From RID    : 00 74 00 60 00 06 A0 06
DES/NTLM Hash               : 6E AB 0E A8 EB 87 C8 E9 38 22 D6 D9 E5 59 87 81
--------------------------------------------------------------------------

提供这个完整验证集的目的在于让C程序员最快速度地搞清楚SYSKEY机制中的加密过
程。我是以学生的姿态学习[11]、[13]的,未做任何Hacking,荣誉归于二文之作者。

需要批评的是flashsky的自然语言描述太不精确,精确的C语言描述又因未使用标准
加密算法API接口而显得不够清晰,以致我被迫动用SoftICE远程调试getlmhashdll,
仅仅为了确认一些数据的16进制转储形式(这可能是最精确的演示方式)。瑕不掩瑜,
[11]是国内2003年不可多得的自Hacking高水平文章,此番学习收获颇大,谢谢作者
的文档共享。

我折腾这个的起因有点怪。写扫描插件时,涉及到操作远程注册表。一般套路是先用
Win32 API写一个应用程序,再用Ethereal抓包分析。既然要写应用程序,当然想写
一个有点实际意义的。tombkeeper曾告诉我微软Support Tools中的nltest可以远程
读取SAM数据,他还简单分析了一下,nltest并不像pwdump3那样利用远程线程注入以
及服务,而是直接操作远程注册表了。

> nltest /server:192.168.7.152 /user:test
User: test
Rid: 0x3eb
LmOwfPassword: bfac2f26 7a122258 a1ca9c44 fb0029fb
NtOwfPassword: 2dc1a2c8 2d82eb15 2511678a 9b5522ca

上述LM Hash、NTLM Hash是错误的,因为nltest不能对付SYSKEY机制,对于早期的NT
可以用nltest获取正确的LM Hash、NTLM Hash。nltest的算法就是pwdump.c的算法,
换句话说,nltest有点像远程版的pwdump.c。

我的想法就是写一个samdump.c,类似nltest的做法,只不过能对付SYSKEY机制,按
LC4(.lc文件)格式输出。

pwdump2在终端服务环境中不可用,pwdump3利用服务倒是继续可用,samdump.c并没
有太多必要存在,我只不过是练练手。由于LM Hash、NTLM Hash从未直接出现在网络
通信中,samdump.c不采用任何加密传输处理。如果目标的远程注册表服务未启动,
可用sc修理它:

> sc //192.168.7.152 config remoteregistry start= demand
> sc //192.168.7.152 start remoteregistry
> samdump -t 192.168.7.152
> sc //192.168.7.152 stop remoteregistry
> sc //192.168.7.152 config remoteregistry start= disabled

本来samdump.c可以自己完成sc的上述功能,不过实在没兴趣堆积木了,正经活是抓
包分析网络通信。

☆ 参考资源

[11] SAM的散列存储加密解密算法以及SYSKEY的计算 - flashsky[2003-06-04]
     http://www.xfocus.net/releases/200306/a550.html

[13] Windows 2k/NT/XP's syskey encryption - Nicola Cuomo
     http://studenti.unina.it/~ncuomo/syskey/syskey.txt



☆ 对"F"的Hacking

HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account/Users/000001F4
F   REG_BINARY
V   REG_BINARY

缺省情况下只有SYSTEM有权读、写"HKEY_LOCAL_MACHINE/SECURITY"。Administrator
有READ_CONTROL、WRITE_DAC这两种权限,因此可以先改变注册表权限设置,再读访
问之。

写了一个小程序,一条龙式地完成修改注册表权限,读访问"F"、"V",以16进制方式
转储数据,恢复注册表设置。发现"F"的数据固定长80字节,"V"的数据则长度不定。

--------------------------------------------------------------------------
0x000001F4

byteArray [ 80 bytes ] ->
00000000  02 00 01 00 00 00 00 00-80 05 EB 31 D6 D5 C3 01    ...........1....
00000010  00 00 00 00 00 00 00 00-80 59 BA 6C CC BF C3 01    .........Y.l....
00000020  FF FF FF FF FF FF FF 7F-60 66 EE 15 B7 D5 C3 01    ........`f......
00000030  F4 01 00 00 01 02 00 00-10 02 00 00 00 00 00 00    ................
00000040  00 00 F1 00 01 00 00 00-00 00 0D 00 0A 00 00 00    ................

0x000001F5

byteArray [ 80 bytes ] ->
00000000  02 00 01 00 00 00 00 00-70 36 52 72 C1 9D C3 01    ........p6Rr....
00000010  00 00 00 00 00 00 00 00-10 EA 66 2D C0 9D C3 01    ..........f-....
00000020  00 00 00 00 00 00 00 00-E0 36 27 F5 B5 D5 C3 01    .........6'.....
00000030  F5 01 00 00 01 02 00 00-15 02 00 00 00 00 00 00    ................
00000040  04 00 00 00 00 00 00 00-00 00 0D 00 0A 00 00 00    ................

0x000003E8

byteArray [ 80 bytes ] ->
00000000  02 00 01 00 00 00 00 00-10 6C 93 92 64 77 C3 01    .........l..dw..
00000010  00 00 00 00 00 00 00 00-A0 C7 04 0C CB D4 C3 01    ................
00000020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000030  E8 03 00 00 01 02 00 00-11 02 00 00 00 00 00 00    ................
00000040  00 00 09 00 00 00 00 00-00 00 00 00 00 84 44 00    ..............D.

0x000003EA

byteArray [ 80 bytes ] ->
00000000  02 00 01 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000010  00 00 00 00 00 00 00 00-70 E0 89 CB 57 BC C2 01    ........p...W...
00000020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
00000030  EA 03 00 00 01 02 00 00-11 02 00 00 00 00 00 00    ................
00000040  00 00 00 00 00 00 00 00-00 00 00 00 00 84 44 00    ..............D.

0x000003EB

byteArray [ 80 bytes ] ->
00000000  02 00 01 00 00 00 00 00-70 90 88 6E 86 CA C3 01    ........p..n....
00000010  00 00 00 00 00 00 00 00-30 AA 02 36 CA D4 C3 01    ........0..6....
00000020  00 00 00 00 00 00 00 00-C0 4A 54 9F CA BF C3 01    .........JT.....
00000030  EB 03 00 00 01 02 00 00-11 00 00 00 00 00 00 00    ................
00000040  00 00 05 00 00 00 00 00-00 00 00 00 00 84 44 00    ..............D.
--------------------------------------------------------------------------

参"SamrQueryInformationUser(36) level 21查询的响应报文解码":

http://www.opencjk.org/~scz/200312241426.txt

对一连串的0x01C3...太敏感了,毕竟是自己费心计算过的数据。试着手工解码"F",
以0x000001F4为例:

--------------------------------------------------------------------------
02 00 01 00 00 00 00 00     意义不明
                            观察上述5组数据,这8个字节未变化
80 05 EB 31 D6 D5 C3 01     FILETIME型的"Last logon time"
00 00 00 00 00 00 00 00     FILETIME型的未知时间
                            总为0,似乎是"Last logoff time"
80 59 BA 6C CC BF C3 01     FILETIME型的"Password last set time",注意不是
                            Ethereal解码中的那个"PWD Last Set",Ethereal解
                            错了,实际对应Ethereal解码中的"Kickoff Time"
FF FF FF FF FF FF FF 7F     FILETIME型的未知时间
                            开始误以为对应"Password must change time"
60 66 EE 15 B7 D5 C3 01     FILETIME型的未知时间
                            开始误以为对应"Password can change time"
F4 01 00 00                 DWORD型的"User RID",500
01 02 00 00                 DWORD型的"User primary group RID",513
10 02 00 00                 DWORD型的"User flags",
                            也就是Ethereal解码中的"Account Control"
00 00 00 00                 意义不明
00 00                       总为0,似乎是USHORT型的"Bad Pwd Count"
F1 00                       USHORT型的"Num of user logged on ok",241
01 00 00 00                 对于Administrator,这里是0x00000001,观察上述
                            5组数据,其它帐号,这里是0x00000000,不清楚是
                            什么意义,也可能是填充数据
00 00                       未知
0D 00 0A 00 00 00           意义不明
                            观察上述5组数据,另一种可能是00 00 00 84 44 00
--------------------------------------------------------------------------

为了写程序方便,Hacking一个C风格的结构出来:

--------------------------------------------------------------------------
#pragma pack( push, 1 )

/*
 * 自己Hacking得到的结构,不可靠。注意,起名SAM_RID_F_VALUE,对应
 * HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account/Users/000001F4
 * 以区别如下位置的"F"、"V"
 * HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account
 */
typedef struct _SAM_RID_F_VALUE
{
    BYTE        Unknown_000[8];     // +0x000,似乎总为"02 00 01 00 00 00 00 00"
    FILETIME    LastLogonTime;      // +0x008
    FILETIME    LastLogoffTime;     // +0x010,似乎总为0
    FILETIME    PwdLastSetTime;     // +0x018,以修正后的解码为准,Ethereal解错了
    FILETIME    Unknown_020;        // +0x020
    FILETIME    Unknown_028;        // +0x028
    DWORD       UserRid;            // +0x030,比如0x000001F4/500
    DWORD       UserPrimaryGid;     // +0x034,比如0x00000201/513
    DWORD       UserFlags;          // +0x038,参Ethereal解码中的"Account Control"
    DWORD       Unknown_03C;        // +0x03c
    WORD        BadPwdCount;        // +0x040,the number of times the user
                                    // tried to log on to the account using
                                    // an incorrect password
    WORD        NumLogonsOk;        // +0x042,Num of user logged on ok
    BYTE        Unknown_044[12];    // +0x044
                                    // +0x050
} SAM_RID_F_VALUE, *PSAM_RID_F_VALUE, **PPSAM_RID_F_VALUE;

#pragma pack( pop )
--------------------------------------------------------------------------

Petter Nordahl-Hagen在他的sam.h中也Hacking了"F"的结构([20]),几个时间域并
不正确,此外没有找出UserPrimaryGid。不过我在此处又多了一个教训,手边的文档
一定要多翻,留在那里不看的,不如不收集。正准备Hacking "V"结构,发现sam.h中
已经有了,可以少走很多弯路。

☆ 参考资源

[20] Offline NT Password & Registry Editor - Petter Nordahl-Hagen
     http://home.eunet.no/~pnordahl/ntpasswd/







☆ 对"V"的Hacking

HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account/Users/000001F4
F   REG_BINARY
V   REG_BINARY

这次我不犯傻了,在Petter Nordahl-Hagen的基础上([20])Hacking "V"结构,从头
造轮子不划算。用同样的程序以16进制方式转储数据如下:

--------------------------------------------------------------------------
0x000003EB

byteArray [ 548 bytes ] ->
00000000  00 00 00 00 D4 00 00 00-02 00 01 00 D4 00 00 00    ................
00000010  08 00 00 00 00 00 00 00-DC 00 00 00 12 00 00 00    ................
00000020  00 00 00 00 F0 00 00 00-16 00 00 00 00 00 00 00    ................
00000030  08 01 00 00 00 00 00 00-00 00 00 00 08 01 00 00    ................
00000040  00 00 00 00 00 00 00 00-08 01 00 00 00 00 00 00    ................
00000050  00 00 00 00 08 01 00 00-00 00 00 00 00 00 00 00    ................
00000060  08 01 00 00 00 00 00 00-00 00 00 00 08 01 00 00    ................
00000070  00 00 00 00 00 00 00 00-08 01 00 00 00 00 00 00    ................
00000080  00 00 00 00 08 01 00 00-15 00 00 00 A8 00 00 00    ................
00000090  20 01 00 00 08 00 00 00-01 00 00 00 28 01 00 00     ...........(...
000000A0  14 00 00 00 00 00 00 00-3C 01 00 00 14 00 00 00    ........<.......
000000B0  00 00 00 00 50 01 00 00-04 00 00 00 00 00 00 00    ....P...........
000000C0  54 01 00 00 04 00 00 00-00 00 00 00 01 00 14 80    T...............
000000D0  B4 00 00 00 C4 00 00 00-14 00 00 00 44 00 00 00    ............D...
000000E0  02 00 30 00 02 00 00 00-02 C0 14 00 44 00 05 01    ..0.........D...
000000F0  01 01 00 00 00 00 00 01-00 00 00 00 02 C0 14 00    ................
00000100  FF 07 0F 00 01 01 00 00-00 00 00 05 07 00 00 00    ................
00000110  02 00 70 00 04 00 00 00-00 00 14 00 5B 03 02 00    ..p.........[...
00000120  01 01 00 00 00 00 00 01-00 00 00 00 00 00 18 00    ................
00000130  FF 07 0F 00 01 02 00 00-00 00 00 05 20 00 00 00    ............ ...
00000140  20 02 00 00 00 00 18 00-FF 07 0F 00 01 02 00 00     ...............
00000150  00 00 00 05 20 00 00 00-24 02 00 00 00 00 24 00    .... ...$.....$.
00000160  44 00 02 00 01 05 00 00-00 00 00 05 15 00 00 00    D...............
00000170  92 E0 3C 77 35 8A 02 1A-43 17 0A 32 EB 03 00 00    ..<w5...C..2....
00000180  01 02 00 00 00 00 00 05-20 00 00 00 20 02 00 00    ........ ... ...
00000190  01 02 00 00 00 00 00 05-20 00 00 00 20 02 00 00    ........ ... ...
000001A0  74 00 65 00 73 00 74 00-74 00 65 00 73 00 74 00    t.e.s.t.t.e.s.t.
000001B0  20 00 75 00 73 00 65 00-72 00 01 00 6F 00 6E 00     .u.s.e.r...o.n.
000001C0  6C 00 79 00 20 00 61 00-20 00 74 00 65 00 73 00    l.y. .a. .t.e.s.
000001D0  74 00 38 F0 FF FF FF FF-FF FF FF FF FF FF FF FF    t.8.............
000001E0  FF FF FF FF FF FF FF FF-FF 93 38 F0 01 02 00 00    ..........8.....
000001F0  07 00 00 00 01 00 01 00-XX XX XX XX XX XX XX XX    ................
00000200  XX XX XX XX XX XX XX XX-01 00 01 00 XX XX XX XX    ................
00000210  XX XX XX XX XX XX XX XX-XX XX XX XX 01 00 01 00    ................
00000220  01 00 01 00                                        ....
--------------------------------------------------------------------------

对"V"的Hacking首先参考1997年Jeremy Allison编写的pwdump.c([5]),结合[20]。
试着手工解码"V",以0x000003EB为例:

--------------------------------------------------------------------------
00 00 00 00                 未知Offset,0x00000000/0,相对0x000000CC的偏移,
                            最终位置是0x000000CC
D4 00 00 00                 未知Length,0x000000D4/212
02 00 01 00                 未知,不像是简单的对齐填充字段
D4 00 00 00                 Username Offset,0x000000D4/212,相对0x000000CC
                            的偏移,最终位置是0x000001A0。换个角度来理解,
                            前面0xCC字节是固定的头结构,后面是数据区。
08 00 00 00                 Username Length,Unicode串的字节数,靠长度标识
                            结尾,不依赖NUL字符,0x00000008/8,"test"
00 00 00 00                 未知
DC 00 00 00                 User full name Offset,0x000000DC/220,最终位
                            置是0x000001A8
12 00 00 00                 User full name Length,Unicode串的字节数,靠长
                            度标识结尾,0x00000012/18,"test user"
00 00 00 00                 未知
F0 00 00 00                 User comment Offset,0x000000F0/240,最终位置
                            是0x000001BC
16 00 00 00                 User comment Length,Unicode串的字节数,靠长度
                            标识结尾,0x00000016/22,"only a test"
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
00 00 00 00                 未知Length,0字节
00 00 00 00                 未知
08 01 00 00                 未知Offset,0x00000108,最终位置是0x000001D4
15 00 00 00                 未知Length,0x00000015/21,本例中是21个0xFF
A8 00 00 00                 未知,为何此次不为0了
20 01 00 00                 0x00000120/288,最终位置是0x000001EC
08 00 00 00                 0x00000008/8
01 00 00 00                 未知
28 01 00 00                 加密存放的LM Hash,0x00000128/296,最终位置是
                            0x000001F4
14 00 00 00                 0x00000014/20
00 00 00 00                 未知
3C 01 00 00                 加密存放的NTLM Hash,0x0000013C/316,最终位置
                            是0x00000208
14 00 00 00                 0x00000014/20
00 00 00 00                 未知
50 01 00 00                 0x00000150/336,最终位置是0x0000021C
04 00 00 00                 0x00000004/4
00 00 00 00                 未知
54 01 00 00                 0x00000154/340,最终位置是0x00000220
04 00 00 00                 0x00000004/4
00 00 00 00                 未知

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
前面总共0xCC字节的固定头结构,后面是变长数据区,靠头结构定位各字段。头结构
简单点讲,就是17组Offset/Length,每组占12字节。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

01 00 14 80 B4 00 00 00     212字节未知数据,其实我对这块数据很好奇,可惜
C4 00 00 00 14 00 00 00     完全看不出明堂来。不同帐号,该块数据长度不同。
44 00 00 00 02 00 30 00
02 00 00 00 02 C0 14 00
44 00 05 01 01 01 00 00
00 00 00 01 00 00 00 00
02 C0 14 00 FF 07 0F 00
01 01 00 00 00 00 00 05
07 00 00 00 02 00 70 00
04 00 00 00 00 00 14 00
5B 03 02 00 01 01 00 00
00 00 00 01 00 00 00 00
00 00 18 00 FF 07 0F 00
01 02 00 00 00 00 00 05
20 00 00 00 20 02 00 00
00 00 18 00 FF 07 0F 00
01 02 00 00 00 00 00 05
20 00 00 00 24 02 00 00
00 00 24 00 44 00 02 00
01 05 00 00 00 00 00 05
15 00 00 00 92 E0 3C 77
35 8A 02 1A 43 17 0A 32
EB 03 00 00 01 02 00 00
00 00 00 05 20 00 00 00
20 02 00 00 01 02 00 00
00 00 00 05 20 00 00 00
20 02 00 00
74 00 65 00 73 00 74 00     Unicode串"test",靠长度标识结尾,不依赖NUL字符
                            Username
74 00 65 00 73 00 74 00     Unicode串"test user"
                            User full name
20 00 75 00 73 00 65 00
72 00
01 00                       这两个字节是填充字节,为了确保后面的数据对齐在
                            四字节边界上
6F 00 6E 00 6C 00 79 00     Unicode串"only a test"
                            User comment
20 00 61 00 20 00 74 00
65 00 73 00 74 00
38 F0                       这两个字节是填充字节,为了确保后面的数据对齐在
                            四字节边界上
FF FF FF FF FF FF FF FF     21字节
FF FF FF FF FF FF FF FF
FF FF FF FF FF
93 38 F0                    这三个字节是填充字节,为了确保后面的数据对齐在
                            四字节边界上
01 02 00 00 07 00 00 00     8字节,不知是何数据
01 00 01 00                 20字节,前面这4字节不清楚是何含义
XX XX XX XX XX XX XX XX     加密存放的LM Hash
XX XX XX XX XX XX XX XX
01 00 01 00                 20字节,前面这4字节不清楚是何含义
XX XX XX XX XX XX XX XX     加密存放的NTLM Hash
XX XX XX XX XX XX XX XX
01 00 01 00                 4字节
01 00 01 00                 4字节
--------------------------------------------------------------------------

注意到Ethereal、Jeremy Allison、Petter Nordahl-Hagen多解析出几个字段,比如
Home、Script、Profile,但在我的测试环境中始终没有看到这几个字段出现过实际
数据,因此宁可将之视为Unknown_XXX。若是某天看到实际数据了,再回头修正也不
迟。反正我是不相信Kickoff Time这种以讹传讹还被引了无数次的字段,难说"V"中
情形不类似。

为了写程序方便,Hacking一个C风格的结构出来:

--------------------------------------------------------------------------
#pragma pack( push, 1 )

typedef struct _OFFSET_LENGTH
{
    DWORD   Offset;         // +0x000
                            // 偏移是相对于头结构尾部、变长数据区首部的
    DWORD   Length;         // +0x004
                            // 以字节为单位
    DWORD   Unknown_008;    // +0x008
                            // 不像是简单的对齐填充字段
                            // +0x00c
} OFFSET_LENGTH, *POFFSET_LENGTH, **PPOFFSET_LENGTH;

/*
 * 自己Hacking得到的结构,不可靠。注意,起名SAM_RID_V_VALUE,对应
 * HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account/Users/000001F4
 * 以区别如下位置的"F"、"V"
 * HKEY_LOCAL_MACHINE/SECURITY/SAM/Domains/Account
 *
 * 头结构简单点讲,就是17组Offset/Length,每组占12字节。
 */
typedef struct _SAM_RID_V_VALUE
{
    OFFSET_LENGTH   Unknown_000;        // +0x000
    OFFSET_LENGTH   Username;           // +0x00c
    OFFSET_LENGTH   Userfullname;       // +0x018
    OFFSET_LENGTH   Usercomment;        // +0x024
    OFFSET_LENGTH   Unknown_030;        // +0x030
    OFFSET_LENGTH   Unknown_03C;        // +0x03c
    OFFSET_LENGTH   Unknown_048;        // +0x048
    OFFSET_LENGTH   Unknown_054;        // +0x054
    OFFSET_LENGTH   Unknown_060;        // +0x060
    OFFSET_LENGTH   Unknown_06C;        // +0x06c
    OFFSET_LENGTH   Unknown_078;        // +0x078
    OFFSET_LENGTH   Unknown_084;        // +0x084
    OFFSET_LENGTH   Unknown_090;        // +0x090
    OFFSET_LENGTH   EncryptedLMHash;    // +0x09c
    OFFSET_LENGTH   EncryptedNTLMHash;  // +0x0a8
    OFFSET_LENGTH   Unknown_0B4;        // +0x0b4
    OFFSET_LENGTH   Unknown_0C0;        // +0x0c0
                                        // +0x0cc
} SAM_RID_V_VALUE, *PSAM_RID_V_VALUE, **PPSAM_RID_V_VALUE;

#pragma pack( pop )
--------------------------------------------------------------------------

看样子NetUserGetInfo()获取的信息分别源自"F"、"V"。折腾了一趟,原来不明白的
还是不明白,别人没搞出来的,我照样没搞出来,不爽。暂且不管这里了,好歹跟着
Jeremy Allison的脚步完整捋了一遍"F"、"V",下次有谁搓我,就没那么容易了。

SampRetrieveUserPasswords()中调用SampGetUnicodeStringAttribute()获取加密后
的LM Hash、NTLM Hash,SampGetUnicodeStringAttribute()的第二形参是个索引,
分别取值0x0D、0x0E,对照上述SAM_RID_V_VALUE结构,就会发现这两个索引的意义。

☆ 参考资源

嘿嘿,那些个写"原创"的伙计们,千万别被我看到你的原创,最主要的是你得保证你
参考的东西不会被我用Google搜到,要不你就老实交待了参考资源。我没别的长处,
除了能把别人十八代祖宗的历史信息从Google中翻出来,//Grin

[ 5] http://us1.samba.org/samba/ftp/pwdump/pwdump.c - Jeremy Allison[1997]

[20] Offline NT Password & Registry Editor - Petter Nordahl-Hagen
     http://home.eunet.no/~pnordahl/ntpasswd/














 类似资料: