就这么个小东西,一共弄了2天半!! 当然也加上中间去学习object和DACL什么的,以前虽然看过,,可书看了一遍就只有忘的份儿,,必须要有应用,要有学习的欲望,,无聊的书会变的很好读,,,,
感受就是不要放弃和要细心,,,如果开始时通过RegOpenKey得到的hKey来改DACL不成功的时候就算了的话,,也就真的算了,,,,虽然不是什么大事,,但提醒着自己无论多大或多小的事都可以试试再试试,,,,,,还有就是细心了ret = LookupAccountName(NULL,user_groupnAme,&sid,&sidlen,siddomAin,&siddomAinlen,
&sidtype);就这一句,我把user_groupnAme写成"everyone"了,,,费了我一晚上找这个错误,,到是练了自己调试的能力,可还是觉得不值,况且这是毛病啊
注册表中每个键都是一个object,,,windows里面全是object,,,把phrAck 59 0x10里的例子拿出来吧
typedef struct _OBJECT_HEADER {
/*000*/ DWORD PointerCount; // number of references
/*004*/ DWORD HandleCount; // number of open handles
/*008*/ POBJECT_TYPE ObjectType; // pointer to object type struct
/*00C*/ BYTE NameOffset; // OBJECT_NAME offset
/*00D*/ BYTE HandleDBOffset; // OBJECT_HANDLE_DB offset
/*00E*/ BYTE QuotaChargesOffset; // OBJECT_QUOTA_CHARGES offset
/*00F*/ BYTE ObjectFlags; // OB_FLAG_*
/*010*/ union
{ // OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock
/*010*/ PQUOTA_BLOCK QuotaBlock;
/*010*/ POBJECT_CREATE_INFO ObjectCreateInfo;
};
/*014*/ PSECURITY_DESCRIPTOR SecurityDescriptor;
/*018*/ } OBJECT_HEADER, *POBJECT_HEADER;
不同的object有不同的ObjectType,,,头全都是一样的Object_HeAder在Object体的前面,Object体里有啥我还不清楚,,object_heAder里面的这些NAmeOffset,Object_Type结构什么的,在内存中的位置都在Object_HeAder的前面,,也就是如果要找NAmeOffset对应的东西,要Object_HeAder - NAmeOffset
kd> !object /Device/PhysicAlMemory
Object: e1001250 Type: (81899040) Section
ObjectHeader: e1001238
HandleCount: 0 PointerCount: 3
Directory Object: 8189a180 Name: PhysicalMemory
kd> dd e1001238 L 6
e1001238 00000003 00000000 81899040 16300020
e1001248 00000001 e1008bd8
kd> !sd e1008bd8 //查看SecurityDescriptor
->Revision: 0x1
->Sbz1 : 0x0
->Control : 0x8004
SE_DACL_PRESENT
SE_SELF_RELATIVE
->Owner : S-1-5-32-544
->Group : S-1-5-18
->Dacl :
->Dacl : ->AclRevision: 0x2
->Dacl : ->Sbz1 : 0x0
->Dacl : ->AclSize : 0x44
->Dacl : ->AceCount : 0x2
->Dacl : ->Sbz2 : 0x0
->Dacl : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[0]: ->AceFlags: 0x0
->Dacl : ->Ace[0]: ->AceSize: 0x14
->Dacl : ->Ace[0]: ->Mask : 0x000f001f
->Dacl : ->Ace[0]: ->SID: S-1-5-18
->Dacl : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl : ->Ace[1]: ->AceFlags: 0x0
->Dacl : ->Ace[1]: ->AceSize: 0x18
->Dacl : ->Ace[1]: ->Mask : 0x0002000d
->Dacl : ->Ace[1]: ->SID: S-1-5-32-544
->Sacl : is NULL
DACL中包含一个个的ACE,每个ACE都表示一条访问的规则,里面有一个用户或组的SID,一个ACCESSMASK表示相应的权限位,如果是DENY_ACE则表示禁止ACCESSMASK标示的权限,ALLOW_ACE则表示允许,DENY_ACE总在ALLOW_ACE前面发挥作用,也就是同时存在两个同样ACCESSMASK,同样SID的ACE,一个是DENY的,一个是ALLOW的,,则结果是DENY的.
SACL表示的不是权限了,而是那些需要记录,System access-control list (SACL) Specifies which operations by which users should be logged in the security audit log.这个可能就是系统中的审核吧,,没用过SACL,
程序就那么几行,很简单,在知道该怎么做后,就那么几个API就完事了,可在这之前可把我郁闷坏了,,上隔壁宿舍去打cs,加了20个expert的机器人,在一个全是狙的雪地里,,嘿嘿,,爽死了
用RegOpenKey来得到注册表键的HANDLE恐怕不可行,开始也没成功,因为比如读MACHINE/SAM/SAM本来就没有读的权限,当打开一个HANDLE的时候固定要失败了,,,唉,,,这样的程序无非就是几个API拼一起,没资格笑话人家JAVA的像积木了,,,,对操作系统了解的少,就只能这样,,,,,,
程序改权限的时候必须被改的键里有写DACL的权限,,由于缺省的SAM里就有AdministrAtors组有写DACL的权限,,所以就省事了,,,如果没有的话,,,inside win2k里说:管理员可以把自己程序进程的token的权限提到SeTAkeOwnerShip
SeTakeOwnership | Required to take ownership of an object without being granted discretionary access |
If the caller has the take-ownership privilege, the security system grants write-owner access and then examines the DACL. However, if write-owner access was the only access requested by a caller with take-ownership privilege, the security system grants that access and never examines the DACL. 也就是说有了SeTAkeOwnerShip就可以有write-owner的权限,,然后就用那些写owner的函数把owner改进去,SetSecurityDescriptorOwner
If the caller is the owner of the object, the read-control and write-DACL access rights are granted. If these rights were the only access rights that caller requested, access is granted without examining the DACL.然后也就有了write-DACL的权限,,,然后啥都可以了,,
不过程序没那么多功能,,一般的话只要不动原来的write-DACL就可以了
/*********************************************************************
* 该注册表权限 在注册表有写DACL的权限下
* writen by uty@uaty
*********************************************************************/
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include <aclapi.h>
#include <accctrl.h>
//#define SPECIFIC_RIGHTS_ALL 0x0000FFFF
//#define STANDARD_RIGHTS_REQUIRED 0x000F0000
//#define STANDARD_RIGHTS_ALL 0x001F0000
int getprivilege(LPCTSTR privilege);
int main(int Argc,char* Argv[])
{
long ret=0;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
PACL pAcl;
PACL pNewAcl;
//TRUSTEE trustee;
//ACCESS_MASK AccessmAsk;
EXPLICIT_ACCESS eA;
char* user_groupnAme;
char* keypAth;
char sid[64];
DWORD receivedAce;
DWORD sidlen;
DWORD sidtype;
char siddomAin[128];
DWORD siddomAinlen;
int Aceindex = 0;
//char usernAme[128];///debug
//DWORD usernAmelen = 128;
if (Argc != 5){
printf("usAge: %s registrypAth USER|GROUP usernAme|groupnAme deny|Allow|reAdonly/n/n",Argv[0]);
printf("it's A simple work /n"
"registerpAth like this MACHINE//SECURITY..../n"
"predefined registry keys:/"CLASSES_ROOT/", /"CURRENT_USER/", /"MACHINE/", and /"USERS/"/n/n");
return 0;
};
keypAth = Argv[1];
user_groupnAme = Argv[3];
getprivilege(SE_SECURITY_NAME);//i don't whether it reAlly work,but result is ok
getprivilege(SE_RESTORE_NAME);
getprivilege(SE_BACKUP_NAME);
getprivilege(SE_TAKE_OWNERSHIP_NAME);
getprivilege(SE_DEBUG_NAME);
ret = GetNamedSecurityInfo(keypAth,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,
NULL,NULL,&pAcl,NULL,&pSecurityDescriptor);
if (ret != ERROR_SUCCESS){
printf("GetNAmedSecurityInfo fAiled: %d/n ret %d/n",GetLastError(),ret);
LocalFree(pSecurityDescriptor);
return -1;
}
///this pArt just show the former ACE AccessmAsk
/*trustee.pMultipleTrustee = NULL;
trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
trustee.TrusteeForm = TRUSTEE_IS_NAME;
trustee.TrusteeType = TRUSTEE_IS_USER;
trustee.ptstrName = user_groupnAme;
ret = GetEffectiveRightsFromAcl(pAcl,&trustee,&AccessmAsk);
if (ret != ERROR_SUCCESS){
printf("GetEffectiveRightsFromAcl fAiled/n");
LocalFree(pSecurityDescriptor);
return -1;
}*/
///get the sid
sidlen = 64;
siddomAinlen = 128;
if(stricmp(Argv[2],"GROUP") == 0){
sidtype = SidTypeGroup;
}else if(stricmp(Argv[2],"USER") == 0){
sidtype = SidTypeUser;
}else{
printf(" ?? ,USER or GROUP/n");
exit(1);
}
ret = LookupAccountName(NULL,user_groupnAme,&sid,&sidlen,siddomAin,&siddomAinlen,
&sidtype);
if(ret == 0){
printf("LookupAccountNAme fAiled: %d/n sid size if %d/nsidlen requres %d/n/n",GetLastError(),sizeof(SID),sidlen);
LocalFree(pSecurityDescriptor);
return -1;
}
/* Sleep(200); //why cAn not lookup the sid 's usernAme? still don't know
ret = LookupAccountSid(NULL,(PSID)(sid),usernAme,&usernAmelen,
siddomAin,&siddomAinlen,&sidtype);
printf("debug: ret = %d, GetLAstError = %d/n",ret,GetLastError());
printf("%s/n",usernAme);
return 0;///
*/
删除同用户或同组的以前的ACE
while(GetAce(pAcl,Aceindex,(PVOID)&receivedAce)){
if(EqualSid((PSID)sid,(PSID)(receivedAce+sizeof(ACE_HEADER)+sizeof(ACCESS_MASK)))){//if equAl,return nonzero
DeleteAce(pAcl,Aceindex);
continue;
}else{
Aceindex++;
}
}
/*
while(ret = DeleteAce(pAcl,0)){
printf("debug: ret = %d/n",ret);
printf("%d /n",GetLastError());
}
//printf("lAst DeleteAce errorcode %d/n",GetLastError());
*/
memset(&eA,0,sizeof(EXPLICIT_ACCESS));
if (stricmp(Argv[4],"ALLOW") == 0){
eA.grfAccessMode = GRANT_ACCESS;
eA.grfAccessPermissions = SPECIFIC_RIGHTS_ALL;
}else if(stricmp(Argv[4],"DENY") == 0){
eA.grfAccessMode = DENY_ACCESS;
eA.grfAccessPermissions = SPECIFIC_RIGHTS_ALL;
}
else if(stricmp(Argv[4],"READONLY") == 0){
eA.grfAccessMode = DENY_ACCESS;
eA.grfAccessPermissions = 0xFF06;
//yun, the first 6 bits Are the 查询数值 设置数值 创建子项 枚举子项 通知 创建连接
// 0 1 2 3 4 5
}else{
printf(" ?? , ALLOW or DENY or READONLY/n");
exit(1);
}
eA.grfInheritance = CONTAINER_INHERIT_ACE;
eA.Trustee .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
eA.Trustee .pMultipleTrustee = NULL;
eA.Trustee .TrusteeForm = TRUSTEE_IS_NAME;
if(stricmp(Argv[2],"GROUP") == 0){
eA.Trustee .TrusteeType = TRUSTEE_IS_GROUP;
}else if(stricmp(Argv[2],"USER") == 0){
eA.Trustee .TrusteeType = TRUSTEE_IS_USER;
}else{
printf(" ?? ,USER or GROUP/n");
exit(1);
}
eA.Trustee .ptstrName = user_groupnAme;
ret = SetEntriesInAcl(1,&eA,pAcl,&pNewAcl);
if(ret != ERROR_SUCCESS){
printf("SetEntriesInAcl fAiled: %d/n ",GetLastError());
LocalFree(pSecurityDescriptor);
return -1;
}
ret = SetNamedSecurityInfo(keypAth,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,pNewAcl,NULL);
if(ret != ERROR_SUCCESS){
printf("SetNAmedSecurityInfo fAiled: %d/n ",GetLastError());
LocalFree(pSecurityDescriptor);
return -1;
}
return 0;
}
//--------------------------------------------------------------------
int getprivilege(LPCTSTR privilege)
{
HANDLE hProcessToken=NULL;
TOKEN_PRIVILEGES tp;
LUID luid;
//打开token
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken)){
printf("/nOpen Current Process Token fAiled:%d",GetLastError());
return -1;
}
//查找所需权限的luid
if(!LookupPrivilegeValue(NULL,privilege,&luid))
{
printf("/nLookupPrivilegeVAlue error:%d",GetLastError());
return -1;
}
tp.PrivilegeCount =1;/表示只有一个// one privilege to set
tp.Privileges [0].Luid = luid;
tp.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED;
//给token加权限
AdjustTokenPrivileges(hProcessToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES)
,(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL);
if (GetLastError()!=ERROR_SUCCESS){
printf("AdjustTokenPrivileges fAiled:%d/n",GetLastError());
return -1;
}
///
return 0;
}
//--------------------------------------------------------------------
这个blog怎么啦?干嘛我一回车就给我空一行呢