Abstract
Keywords
Citation Yao Qing-sheng.用 C++ 修改本地安全策略.FUTURE & CIVILIZATION Natural/Social Philosophy & Infomation Sciences,20240324. https://yaoqs.github.io/20240324/yong-c-xiu-gai-ben-di-an-quan-ce-lue/

转载自 用 C++ 修改本地安全策略

(更新:注意编译运行文中程序后留意 administrator 可能会变成 active=no,undocument,undocument… 哈哈)
要写个修改本地安全策略的工具,本以为修改注册表就行了,没想到还挺复杂,改策略,对应的注册表项会变,倒过来,改对应的注册表项,策略没变,郁闷
[HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account]        |-------------------------------- 修改次数
“F”=hex:02,00,01,00,00,00,00,00,e0,7c,9e,21,1a,12,c6,01,43,00,00,00,00,00,00,\        00 ~ 22
  00,00,80,d2,16,47,b9,ff,ff,00,80,2c,ab,6d,fe,ff,ff,00,00,00,00,00,00,00,80,\        23 ~ 47
  00,cc,1d,cf,fb,ff,ff,ff,00,cc,1d,cf,fb,ff,ff,ff,00,00,00,00,00,00,00,00,f1,\        48 ~ 72
  03,00,00,00,00,00,00,02,00,18,00,00,00,00,00,01,00,00,00,03,00,00,00,01,00,\        73 ~ 97
         ^^        ^
       ||        |
       ||        |__ 密码长度最小值
       ||
       ||__    密码必须符合复杂性要求 (0 为禁止)
       |___ 用可还原的加密来存储密码

第 76 80 位

[HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\000001F5]
“F”=hex:02,00,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  00,80,c6,50,1f,2b,12,c6,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  f5,01,00,00,01,02,00,00,15,02,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
               ^
               |____ Guest 账号 (15 禁用,14 启用)

第 56 位

比如第 76 位,
0 的时候是 "密码必须符合复杂性要求 - 禁用" & “用可还原的加密来存储密码 - 禁用”
14 的时候 "密码必须符合复杂性要求 - 禁用" & “用可还原的加密来存储密码 - 启用”

有些比如密码长度,锁定什么的用 NetUserModalsSet 的 USER_MODALS_INFO_0 和 USER_MODALS_INFO_3 结构可以搞定。
审核策略用 LsaSetInformationPolicy 也好搞定,都有现成的代码。

账户策略 -> 密码策略中的 "密码必须符合复杂性要求" 和 "用可还原的加密来存储密码",还有安全选项中的内容,似乎没有公开文档

没想到写个这个破工具还要用到未公开 API 函数,之前在网上查了下有没有相关代码或文档什么的,查了 N 天 google 和 MSDN,有问的,没有答的,或者就是答非所问,没办法只能自己想办法了
之前使用 apimonitor(N 多此类工具,都不好用,这个也不咋样),在修改策略的时候获得了如下信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
API    Name    Return    Value    Module    Name    Time    Start    IsEntry    API  
Process:    c:\\windows\\system32\\mmc.exe(5052)    ,    Thread:2976
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceOpenProfile        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetSecurityProfileInfo    6    (0x6)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetSecurityProfileInfo    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:38    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:34    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:34    True
SceGetServerProductType    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:34    True
SceRollbackTransaction    12    (0xC)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
SceCloseProfile        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
SceFreeProfileMemory    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
SceFreeProfileMemory    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
SceFreeProfileMemory    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
SceFreeProfileMemory    1    (0x1)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:55    True
Process:    c:\\windows\\system32\\mmc.exe(5052)    ,    Thread:3928
SceOpenProfile        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:49    True
SceGetSecurityProfileInfo    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:49    True
SceCloseProfile        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:49    True
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:49    True
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:49    True
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:56    True
SceUpdateSecurityProfile    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:10:56    True
Process:    c:\\windows\\system32\\mmc.exe(5052)    ,    Thread:5472
SceFreeMemory        0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:43    True
SceUpdateSecurityProfile    0    (0x0)    C:\\WINDOWS\\system32\\SCECLI.dll    2008-1-27    23:11:43    True

Summary Information
API Name: SceOpenProfile
API Define: (Undefine API)
Time Start: 00:11:49.015
Duration: 0.000 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: 29449864 (0x1C15E88)
Pointer  Paramter1: 1 (0x1)
Pointer  Paramter2: 23981584 (0x16DEE10)
Pointer  Paramter3: (null)
Pointer  Paramter4: 8629392 (0x83AC90)
Pointer  Paramter5: (null)
After Call Parameters
Pointer  Paramter0: 29449864 (0x1C15E88)
Pointer  Paramter1: 1 (0x1)
Pointer  Paramter2: 23981584 (0x16DEE10)
Pointer  Paramter3: (null)
Pointer  Paramter4: 8629392 (0x83AC90)
Pointer  Paramter5: (null)
Return
0 (0x0)

Summary Information
API Name: SceGetSecurityProfileInfo
API Define: (Undefine API)
Time Start: 00:11:49.015
Duration: 0.001 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: 688576 (0xA81C0)
Pointer  Paramter1: 302 (0x12E)
Pointer  Paramter2: 65535 (0xFFFF)
Pointer  Paramter3: 8629480 (0x83ACE8)
Pointer  Paramter4: 23981572 (0x16DEE04)
Pointer  Paramter5: 2088955995 (0x7C82F05B)
After Call Parameters
Pointer  Paramter0: 688576 (0xA81C0)
Pointer  Paramter1: 302 (0x12E)
Pointer  Paramter2: 65535 (0xFFFF)
Pointer  Paramter3: 8629480 (0x83ACE8)
Pointer  Paramter4: 23981572 (0x16DEE04)
Pointer  Paramter5: 2088955995 (0x7C82F05B)
Return
0 (0x0)
GetLastError
Value:3758096642
Description:

Summary Information
API Name: SceCloseProfile
API Define: (Undefine API)
Time Start: 00:11:49.109
Duration: 0.000 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: 23981584 (0x16DEE10)
Pointer  Paramter1: 2088955995 (0x7C82F05B)
Pointer  Paramter2: 8629392 (0x83AC90)
Pointer  Paramter3: 8570560 (0x82C6C0)
Pointer  Paramter4: 8629296 (0x83AC30)
Pointer  Paramter5: 302124616 (0x12020E48)
After Call Parameters
Pointer  Paramter0: 23981584 (0x16DEE10)
Pointer  Paramter1: 2088955995 (0x7C82F05B)
Pointer  Paramter2: 8629392 (0x83AC90)
Pointer  Paramter3: 8570560 (0x82C6C0)
Pointer  Paramter4: 8629296 (0x83AC30)
Pointer  Paramter5: 302124616 (0x12020E48)
Return
0 (0x0)

Summary Information
API Name: SceAddToNameStatusList
API Define: (Undefine API)
Time Start: 00:11:49.109
Duration: 0.000 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: 23981476 (0x16DEDA4)
Pointer  Paramter1: 787520 (0xC0440)
Pointer  Paramter2: 76 (0x4C)
Pointer  Paramter3: 1 (0x1)
Pointer  Paramter4: (null)
Pointer  Paramter5: 8629392 (0x83AC90)
After Call Parameters
Pointer  Paramter0: 23981476 (0x16DEDA4)
Pointer  Paramter1: 787520 (0xC0440)
Pointer  Paramter2: 76 (0x4C)
Pointer  Paramter3: 1 (0x1)
Pointer  Paramter4: (null)
Pointer  Paramter5: 8629392 (0x83AC90)
Return
0 (0x0)

Summary Information
API Name: SceFreeMemory
API Define: (Undefine API)
Time Start: 00:11:49.109
Duration: 0.000 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: 1514080 (0x171A60)
Pointer  Paramter1: 311 (0x137)
Pointer  Paramter2: (null)
Pointer  Paramter3: 8629392 (0x83AC90)
Pointer  Paramter4: (null)
Pointer  Paramter5: 4 (0x4)
After Call Parameters
Pointer  Paramter0: 1514080 (0x171A60)
Pointer  Paramter1: 311 (0x137)
Pointer  Paramter2: (null)
Pointer  Paramter3: 8629392 (0x83AC90)
Pointer  Paramter4: (null)
Pointer  Paramter5: 4 (0x4)
Return
0 (0x0)

Summary Information
API Name: SceUpdateSecurityProfile
API Define: (Undefine API)
Time Start: 00:11:52.203
Duration: 0.000 ms
Module Name: C:\\WINDOWS\\system32\\SCECLI.dll
Is Entry API: True
Process: C:\\WINDOWS\\system32\\mmc.exe
Thread: 4152
Before Call Parameters
Pointer  Paramter0: (null)
Pointer  Paramter1: 1 (0x1)
Pointer  Paramter2: 28866104 (0x1B87638)
Pointer  Paramter3: 4 (0x4)
Pointer  Paramter4: (null)
Pointer  Paramter5: 8629056 (0x83AB40)
After Call Parameters
Pointer  Paramter0: (null)
Pointer  Paramter1: 1 (0x1)
Pointer  Paramter2: 28866104 (0x1B87638)
Pointer  Paramter3: 4 (0x4)
Pointer  Paramter4: (null)
Pointer  Paramter5: 8629056 (0x83AB40)
Return
0 (0x0)

郁闷的是 before call 和 after call 参数都没变,不知道是软件问题还是未注册的原因
请教了 czy,帮忙逆向了一下,高手就是高手,没多久就给我一段 asm 代码解决了密码复杂度的策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
`.386
.model stdcall,flat option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\shlwapi.inc
include \masm32\include\shell32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\shlwapi.lib
includelib \masm32\lib\shell32.lib.const`

`.data`

`nini    db 'a',0
seclib  db 'scecli.dll',0
myapi   db 'SceUpdateSecurityProfile',0
mydata  db 2eh,01h,00h,00h,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,00h,00h,00h,00h,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,0feh,0ffh,0ffh,0ffh,00h,00h,00h,00h ;偏移10H如为0就是禁用,为1就是启用
.data?
.code
start:         
invoke    MessageBox,0,offset nini,offset nini,1      
invoke  LoadLibraryA,offset seclib    
invoke  GetProcAddress,eax,offset myapi    
mov     esi,eax    
push    4    
mov     eax,offset mydata    
push    eax    
xor     edi,edi    
inc     edi    
push    edi        
xor     ebx,ebx    
push    ebx    
call    esi
invoke    ExitProcess,0
end start`

编译执行没问题,OK,改成 C 的版本,老是提示内存不能写(内嵌汇编也不行),还请教了小榕,貌似变量定义的问题
使用 OD 动态跟踪,发现 asm 版本的生成 exe 后执行 mydata 变量是在.data 可读写数据段里面,而 C
的版本是在.rdata 只读数据段里面,使用 OD 的时候修改数据测试可以成功,然后再修改 C++ 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
`#include <stdio.h>   
#include <windows.h>
char *sam2;
int main() {    
sam2 = new char[99];    
char *sam =     "\x2e\x01\x00\x00\x0fe\x0ff\x0ff\x0ff"         "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"         "\x00\x00\x00\x00\x0fe\x0ff\x0ff\x0ff"         "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"         "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"         "\xfe\x0ff\x0ff\x0ff\x00\x00\x00\x00";    
memcpy(sam2, sam, 49);    
HINSTANCE hInst;    
hInst=LoadLibraryA("scecli.dll");   
 typedef BOOL (__stdcall *MYFUNC)(intintchar*, int);    
MYFUNC fun=NULL;    
fun=(MYFUNC)GetProcAddress(hInst,"SceUpdateSecurityProfile");    
int i = 4;    
fun(NULL,TRUE,sam2,i);
/*    __asm     {         mov esi,fun         push 4         mov eax,sam2         push eax         xor edi,edi         inc edi         push edi         xor ebx,ebx         push ebx         call esi     } */    
return 0;
}`

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
`#include <stdio.h>   
#include <windows.h>
char sam[]=    "\x2e\x01\x00\x00\x0fe\x0ff\x0ff\x0ff"     "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"     "\x10\x00\x00\x00\x0fe\x0ff\x0ff\x0ff"     "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"     "\x0fe\x0ff\x0ff\x0ff\x0fe\x0ff\x0ff\x0ff"     "\xfe\x0ff\x0ff\x0ff\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00"     "\x00\x00\x00\x00\x00\x00\x00\x00";
int main() {    
HINSTANCE hInst;    
hInst=LoadLibraryA("scecli.dll");    
typedef BOOL (__stdcall *MYFUNC)(intint,char*, int);    
MYFUNC fun=NULL;    
fun=(MYFUNC)GetProcAddress(hInst,"SceUpdateSecurityProfile");    
printf("sam=0x%08X\n",&sam);    
printf("%s",sam);    
fun(NULL,TRUE,sam,4);
/*    __asm     {         mov esi,fun         push 4         mov eax,sam2         push eax         xor edi,edi         inc edi         push edi         xor ebx,ebx         push ebx         call esi     } */    
return 0;
}`

发现如果 SceUpdateSecurityProfile 函数的第三个参数,后面如果有其它数据,会报错,要是后面大段 \x00 数据的话,就通过,undocument api 只能这样了,估计第三个参数应该是个什么结构。在我的 Windows2003 CN SP1 上测试成功(执行后,会让本地策略 “密码复杂度” 那项变成禁用,还有其它一些策略如审核策略也会更改,应该是第三个参数的每个位对应着不同的策略,安全选项中的似乎不会变),小榕的 Windows2003 EN SP1 上不能成功,估计是这个函数太底层了,应该有更高一层的函数先判断不同的操作系统版本,选择不同的参数,然后在调用 SceUpdateSecurityProfile 函数。
还有安全选项里面的内容,估计是其它函数,有空我也 softice 一下。

最后帖下关于变量定义后在内存什么地方的一段代码,不一定什么时候有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//main.cpp  
int a = 0; 全局初始化区
char \*p1; 全局未初始化区
main()
{
int b; 栈
char s\[\] = "abc"; 栈
char \*p2; 栈
char \*p3 = "123456"; 123456\\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char \*)malloc(10);
p2 = (char \*)malloc(20);
分配得来得1020字节的区域就在堆区。
strcpy(p1, "123456"); 123456\\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

全局
char *str=“\x20\x20\x20\x20\x20\x20\x20\x20”;
str 存在.data 段,是一个指针,内容为一个地址(地址在.rdata 区段),这个地址指向的内容为字符串

全局
char str[]=“\x20\x20\x20\x20\x20\x20\x20\x20”;
str 存在.data 段,是一个指针,指针指向字符串

References