📄 pwdump.c
字号:
/*
* (C) Jeremy Allison 1997. All rights reserved.
*
* This program is free for commercial and non-commercial use.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* THIS SOFTWARE IS PROVIDED BY JEREMY ALLISON ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "des.h"
/*
* Program to dump the Lanman and NT MD4 Hashed passwords from
* an NT SAM database into a Samba smbpasswd file. Needs Administrator
* privillages to run.
* Takes one arg - the name of the machine whose SAM database you
* wish to dump, if this arg is not given it dumps the local machine
* account database.
*/
/*
* Convert system error to char. Returns
* memory allocated with LocalAlloc.
*/
char *error_to_string(DWORD error)
{
char *msgbuf;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(char *)&msgbuf,
0,
NULL
) == 0)
return 0;
return msgbuf;
}
/*
* Return a pointer to a string describing an os error.
* error_to_string returns a pointer to LocalAlloc'ed
* memory. Cache it and release when the next one is
* requested.
*/
char *str_oserr(DWORD err)
{
static char *lastmsg = 0;
if(lastmsg)
LocalFree((HLOCAL)lastmsg);
lastmsg = error_to_string(err);
return lastmsg;
}
/*
* Utility function to get allocate a SID from a name.
* Looks on local machine. SID is allocated with LocalAlloc
* and must be freed by the caller.
* Returns TRUE on success, FALSE on fail.
*/
BOOL get_sid(const char *name, SID **ppsid)
{
SID_NAME_USE sid_use;
DWORD sid_size = 0;
DWORD dom_size = 0;
char *domain;
*ppsid = 0;
if(LookupAccountName(0, name, 0, &sid_size, 0, &dom_size, &sid_use) == 0) {
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
fprintf( stderr, "get_sid: LookupAccountName for size on name %s failed. Error was %s\n",
name, str_oserr(GetLastError()));
return FALSE;
}
}
*ppsid = (SID *)LocalAlloc( LMEM_FIXED, sid_size);
domain = (char *)LocalAlloc( LMEM_FIXED, dom_size);
if( *ppsid == 0 || domain == 0) {
fprintf( stderr, "get_sid: LocalAlloc failed. Error was %s\n",
str_oserr(GetLastError()));
if(*ppsid)
LocalFree((HLOCAL)*ppsid);
if(domain)
LocalFree((HLOCAL)domain);
*ppsid = 0;
return FALSE;
}
if(LookupAccountName(0, name, *ppsid, &sid_size, domain, &dom_size, &sid_use) == 0) {
fprintf( stderr,
"get_sid: LookupAccountName failed for name %s. Error was %s\n",
name, str_oserr(GetLastError()));
LocalFree((HLOCAL)*ppsid);
LocalFree((HLOCAL)domain);
*ppsid = 0;
return FALSE;
}
LocalFree((HLOCAL)domain);
return TRUE;
}
/*
* Utility function to setup a security descriptor
* from a varargs list of char *name followed by a DWORD access
* mask. The access control list is allocated with LocalAlloc
* and must be freed by the caller.
* returns TRUE on success, FALSE on fail.
*/
BOOL create_sd_from_list( SECURITY_DESCRIPTOR *sdout, int num, ...)
{
va_list ap;
SID **sids = 0;
char *name;
DWORD amask;
DWORD acl_size;
PACL pacl = 0;
int i;
if((sids = (SID **)calloc(1,sizeof(SID *)*num)) == 0) {
fprintf(stderr, "create_sd_from_list: calloc fail.\n");
return FALSE;
}
acl_size = num * (sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) +
sizeof(DWORD));
/* Collect all the SID's */
va_start( ap, num);
for( i = 0; i < num; i++) {
name = va_arg( ap, char *);
amask = va_arg(ap, DWORD);
if(get_sid( name, &sids[i]) == FALSE)
goto cleanup;
acl_size += GetLengthSid(sids[i]);
}
va_end(ap);
if((pacl = (PACL)LocalAlloc( LMEM_FIXED, acl_size)) == 0) {
fprintf( stderr, "create_sd_from_list: LocalAlloc fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
if(InitializeSecurityDescriptor( sdout, SECURITY_DESCRIPTOR_REVISION) == FALSE) {
fprintf( stderr, "create_sd_from_list: InitializeSecurityDescriptor fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
if(InitializeAcl( pacl, acl_size, ACL_REVISION) == FALSE) {
fprintf( stderr, "create_sd_from_list: InitializeAcl fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
va_start(ap, num);
for( i = 0; i < num; i++) {
ACE_HEADER *ace_p;
name = va_arg( ap, char *);
amask = va_arg( ap, DWORD);
if(AddAccessAllowedAce( pacl, ACL_REVISION, amask, sids[i]) == FALSE) {
fprintf( stderr, "create_sd_from_list: AddAccessAllowedAce fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
/* Make sure the ACE is inheritable */
if(GetAce( pacl, 0, (LPVOID *)&ace_p) == FALSE) {
fprintf( stderr, "create_sd_from_list: GetAce fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
ace_p->AceFlags |= ( CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
}
/* Add the ACL into the sd. */
if(SetSecurityDescriptorDacl( sdout, TRUE, pacl, FALSE) == FALSE) {
fprintf( stderr, "create_sd_from_list: SetSecurityDescriptorDacl fail. Error was %s\n",
str_oserr(GetLastError()));
goto cleanup;
}
for( i = 0; i < num; i++)
if(sids[i] != 0)
LocalFree((HLOCAL)sids[i]);
free(sids);
return TRUE;
cleanup:
if(sids != 0) {
for( i = 0; i < num; i++)
if(sids[i] != 0)
LocalFree((HLOCAL)sids[i]);
free(sids);
}
if(pacl != 0)
LocalFree((HLOCAL)pacl);
return FALSE;
}
/*
* Function to go over all the users in the SAM and set an ACL
* on them.
*/
int set_userkeys_security( HKEY start, const char *path, SECURITY_DESCRIPTOR *psd,
HKEY *return_key)
{
HKEY key;
DWORD err;
char usersid[128];
DWORD indx = 0;
/* Open the path and enum all the user keys - setting
the same security on them. */
if((err = RegOpenKeyEx( start, path, 0, KEY_ENUMERATE_SUB_KEYS, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to open key %s to enumerate. \
Error was %s.\n",
path, str_oserr(err));
return -1;
}
/* Now enumerate the subkeys, setting the security on them all. */
do {
DWORD size;
FILETIME ft;
size = sizeof(usersid);
err = RegEnumKeyEx( key, indx, usersid, &size, 0, 0, 0, &ft);
if(err == ERROR_SUCCESS) {
HKEY subkey;
indx++;
if((err = RegOpenKeyEx( key, usersid, 0, WRITE_DAC, &subkey)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to open key %s to set security. \
Error was %s.\n",
usersid, str_oserr(err));
RegCloseKey(key);
return -1;
}
if((err = RegSetKeySecurity( subkey, DACL_SECURITY_INFORMATION,
psd)) != ERROR_SUCCESS) {
fprintf(stderr, "set_userkeys_security: Failed to set security on key %s. \
Error was %s.\n",
usersid, str_oserr(err));
RegCloseKey(subkey);
RegCloseKey(key);
return -1;
}
RegCloseKey(subkey);
}
} while(err == ERROR_SUCCESS);
if(err != ERROR_NO_MORE_ITEMS) {
RegCloseKey(key);
return -1;
}
if(return_key == 0)
RegCloseKey(key);
else
*return_key = key;
return 0;
}
/*
* Function to travel down the SAM security tree in the registry and restore
* the correct ACL on them. Returns 0 on success. -1 on fail.
*/
int restore_sam_tree_access( HKEY start )
{
char path[128];
char *p;
HKEY key;
DWORD err;
SECURITY_DESCRIPTOR sd;
DWORD admin_mask;
admin_mask = WRITE_DAC | READ_CONTROL;
if(create_sd_from_list( &sd, 2, "SYSTEM", GENERIC_ALL,
"Administrators", admin_mask) == FALSE)
return -1;
strcpy( path, "SECURITY\\SAM\\Domains\\Account\\Users");
/* Remove the security on the user keys first. */
if(set_userkeys_security( start, path, &sd, 0) != 0)
return -1;
/* now go up the path, restoring security */
do {
if((err = RegOpenKeyEx( start, path, 0, WRITE_DAC, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "restore_sam_tree_access:Failed to open key %s to set \
security. Error was %s.\n",
path, str_oserr(err));
return -1;
}
if((err = RegSetKeySecurity( key, DACL_SECURITY_INFORMATION,
&sd)) != ERROR_SUCCESS) {
fprintf(stderr, "restore_sam_tree_access: Failed to set security on key %s. \
Error was %s.\n",
path, str_oserr(err));
RegCloseKey(key);
return -1;
}
RegCloseKey(key);
p = strrchr(path, '\\');
if( p != 0)
*p = 0;
} while( p != 0 );
return 0;
}
/*
* Function to travel the security tree and add Administrators
* access as WRITE_DAC, READ_CONTROL and READ.
* Returns 0 on success. -1 on fail if no security was changed,
* -2 on fail if security was changed.
*/
int set_sam_tree_access( HKEY start, HKEY *return_key)
{
char path[128];
char *p;
HKEY key;
DWORD err;
BOOL security_changed = FALSE;
SECURITY_DESCRIPTOR sd;
DWORD admin_mask;
BOOL finished = FALSE;
admin_mask = WRITE_DAC | READ_CONTROL | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
if(create_sd_from_list( &sd, 2, "SYSTEM", GENERIC_ALL,
"Administrators", admin_mask) == FALSE)
return -1;
strcpy( path, "SECURITY\\SAM\\Domains\\Account\\Users");
p = strchr(path, '\\');
do {
if( p != 0)
*p = 0;
else
finished = TRUE;
if((err = RegOpenKeyEx( start, path, 0, WRITE_DAC, &key)) !=
ERROR_SUCCESS) {
fprintf(stderr, "set_sam_tree_access:Failed to open key %s to set \
security. Error was %s.\n",
path, str_oserr(err));
return (security_changed ? -2: -1);
}
if((err = RegSetKeySecurity( key, DACL_SECURITY_INFORMATION,
&sd)) != ERROR_SUCCESS) {
fprintf(stderr, "set_sam_tree_access: Failed to set security on key %s. \
Error was %s.\n",
path, str_oserr(err));
RegCloseKey(key);
return (security_changed ? -2: -1);
}
security_changed = TRUE;
RegCloseKey(key);
if(p != 0) {
*p++ = '\\';
p = strchr(p, '\\');
}
} while( !finished );
if(set_userkeys_security( start, path, &sd, &key) != 0)
return -2;
if(return_key == 0)
RegCloseKey(key);
else
*return_key = key;
return 0;
}
/*
* Function to get a little-endian int from an offset into
* a byte array.
*/
int get_int( char *array )
{
return ((array[0]&0xff) + ((array[1]<<8)&0xff00) +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -