2014年3月30日星期日

给文件添加用户(组)及权限

/*
文件名:SetNamedSecurityInfo.cpp
功能:给一个文件/文件夹(其他的对象也可以)添加用户(组)及访问的权限.

这是一个基本的功能,岂能不会.
其实系统自带的文件有此功能,但是搞编程的,特别是系统编程的,岂能用脚本.
所以有此文,早就想有此文了.
微软的代码只是示例,自己想要的功能要自己动手.

微软的说明:
The following example tries to change the DACL of a file object by taking ownership of that object.
This will succeed only if the caller has WRITE_DAC access to the object or is the owner of the object.
If the initial attempt to change the DACL fails, an administrator can take ownership of the object.
To give the administrator ownership, the example enables the SE_TAKE_OWNERSHIP_NAME privilege in the caller's access token,
and makes the local system's Administrators group the owner of the object.
If the caller is a member of the Administrators group, the code will then be able to change the object's DACL.

参考:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379620(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa446619(v=vs.85).aspx

made by correy
made at 2014.03.30
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include <aclapi.h>
#include <Mq.h>

HRESULT GetSid(LPCWSTR wszAccName, PSID * ppSid)
{
    // Validate the input parameters.
    if (wszAccName == NULL || ppSid == NULL) {
        return MQ_ERROR_INVALID_PARAMETER;
    }

    // Create buffers that may be large enough.
    // If a buffer is too small, the count parameter will be set to the size needed.
    const DWORD INITIAL_SIZE = 32;
    DWORD cbSid = 0;
    DWORD dwSidBufferSize = INITIAL_SIZE;
    DWORD cchDomainName = 0;
    DWORD dwDomainBufferSize = INITIAL_SIZE;
    WCHAR * wszDomainName = NULL;
    SID_NAME_USE eSidType;
    DWORD dwErrorCode = 0;
    HRESULT hr = MQ_OK;

    // Create buffers for the SID and the domain name.
    *ppSid = (PSID) new BYTE[dwSidBufferSize];
    if (*ppSid == NULL)  {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(*ppSid, 0, dwSidBufferSize);
    wszDomainName = new WCHAR[dwDomainBufferSize];
    if (wszDomainName == NULL)  {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(wszDomainName, 0, dwDomainBufferSize*sizeof(WCHAR));

    // Obtain the SID for the account name passed.
    for ( ; ; )
    {
        // Set the count variables to the buffer sizes and retrieve the SID.
        cbSid = dwSidBufferSize;
        cchDomainName = dwDomainBufferSize;
        if (LookupAccountNameW(
            NULL,            // Computer name. NULL for the local computer
            wszAccName,
            *ppSid,          // Pointer to the SID buffer. Use NULL to get the size needed,
            &cbSid,          // Size of the SID buffer needed.
            wszDomainName,   // wszDomainName,
            &cchDomainName,
            &eSidType
            ))
        {
            if (IsValidSid(*ppSid) == FALSE)
            {
                wprintf(L"The SID for %s is invalid.\n", wszAccName);
                dwErrorCode = MQ_ERROR;
            }
            break;
        }
        dwErrorCode = GetLastError();

        // Check if one of the buffers was too small.
        if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER)
        {
            if (cbSid > dwSidBufferSize)
            {
                // Reallocate memory for the SID buffer.
                wprintf(L"The SID buffer was too small. It will be reallocated.\n");
                FreeSid(*ppSid);
                *ppSid = (PSID) new BYTE[cbSid];
                if (*ppSid == NULL) {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(*ppSid, 0, cbSid);
                dwSidBufferSize = cbSid;
            }
            if (cchDomainName > dwDomainBufferSize)
            {
                // Reallocate memory for the domain name buffer.
                wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
                delete [] wszDomainName;
                wszDomainName = new WCHAR[cchDomainName];
                if (wszDomainName == NULL) {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(wszDomainName, 0, cchDomainName*sizeof(WCHAR));
                dwDomainBufferSize = cchDomainName;
            }
        } else {
            wprintf(L"LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode);
            hr = HRESULT_FROM_WIN32(dwErrorCode);
            break;
        }
    }

    delete [] wszDomainName;
    return hr;
}

BOOL SetPrivilege(
    HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    )
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup
        &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.
    if ( !AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}


BOOL TakeOwnership(LPTSTR lpszOwnFile)
{  
    BOOL bRetval = FALSE;
    HANDLE hToken = NULL;
    PACL pACL = NULL;
    PSID pSIDEveryone = NULL;
    PSID pSIDAdmin = NULL;

    const int NUM_ACES  = 2;
    EXPLICIT_ACCESS ea[NUM_ACES];

    __try
    {
        // Specify the DACL to use.
        // Create a SID for the Everyone group.      
        SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
        if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSIDEveryone))
        {
            printf("AllocateAndInitializeSid (Everyone) error %u\n", GetLastError());
            __leave;
        }

        // Create a SID for the BUILTIN\Administrators group.      
        SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
        if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSIDAdmin))
        {
            printf("AllocateAndInitializeSid (Admin) error %u\n", GetLastError());
            __leave;
        }

        ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

        // Set read access for Everyone.
        ea[0].grfAccessPermissions = GENERIC_READ;
        ea[0].grfAccessMode = SET_ACCESS;
        ea[0].grfInheritance = NO_INHERITANCE;
        ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
        ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;

        // Set full control for Administrators.
        ea[1].grfAccessPermissions = GENERIC_ALL;
        ea[1].grfAccessMode = SET_ACCESS;
        ea[1].grfInheritance = NO_INHERITANCE;
        ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
        ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;

        if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES, ea, NULL, &pACL))
        {
            printf("Failed SetEntriesInAcl\n");
            __leave;
        }

        // Try to modify the object's DACL.
        DWORD dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (ERROR_SUCCESS == dwRes)
        {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;      
            __leave;// No more processing needed.
        }
        if (dwRes != ERROR_ACCESS_DENIED)
        {
            printf("First SetNamedSecurityInfo call failed: %u\n", dwRes);
            __leave;
        }

        // If the preceding call failed because access was denied, enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
        // the Administrators group, take ownership of the object, and disable the privilege. Then try again to set the object's DACL.      
        if (!OpenProcessToken(GetCurrentProcess(),  TOKEN_ADJUST_PRIVILEGES, &hToken)) // Open a handle to the access token for the calling process.
        {
            printf("OpenProcessToken failed: %u\n", GetLastError());
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE)) // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("You must be logged on as Administrator.\n");
            __leave;
        }

        // Set the owner in the object's security descriptor.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            OWNER_SECURITY_INFORMATION,  // change only the object's owner
            pSIDAdmin,                   // SID of Administrator group
            NULL,
            NULL,
            NULL);
        if (dwRes != ERROR_SUCCESS)
        {
            printf("Could not set owner. Error: %u\n", dwRes);
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE)) // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("Failed SetPrivilege call unexpectedly.\n");
            __leave;
        }

        // Try again to modify the object's DACL,now that we are the owner.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (dwRes == ERROR_SUCCESS) {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;
        } else {
            printf("Second SetNamedSecurityInfo call failed: %u\n", dwRes);
        }
    }
    __finally
    {
        if (pSIDAdmin)
            FreeSid(pSIDAdmin);

        if (pSIDEveryone)
            FreeSid(pSIDEveryone);

        if (pACL)
            LocalFree(pACL);

        if (hToken)
            CloseHandle(hToken);
    }

    return bRetval;
}


BOOL set_file_secure_attribute (IN LPTSTR lpszOwnFile, IN wchar_t * username, IN unsigned int attribute)
    /*
    功能:给一个文件添加一个用户(组),并给一定的权限.
    关于删除用户及删除用户(组)的某个权限,再说,应该很容易.
    */
{  
    if (!lpszOwnFile || !username) {
        return FALSE;
    }

    BOOL bRetval = FALSE;
    HANDLE hToken = NULL;
    PACL pACL = NULL;

    EXPLICIT_ACCESS ea = {0};

    __try
    {
        PSID ppSid;
        HRESULT r = GetSid(username, &ppSid) ;
        if (r != S_OK) {
            return FALSE;
        }

        ea.grfAccessPermissions = attribute;//GENERIC_READ;//GENERIC_ALL
        ea.grfAccessMode = SET_ACCESS;
        ea.grfInheritance = NO_INHERITANCE;
        ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
        ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;//是管理员时,这个值是TRUSTEE_IS_GROUP.不过不是这个值也成功了.
        ea.Trustee.ptstrName = (LPTSTR) ppSid;

        if (ERROR_SUCCESS != SetEntriesInAcl(1, &ea, NULL, &pACL))
        {
            printf("Failed SetEntriesInAcl\n");
            __leave;
        }

        // Try to modify the object's DACL.
        DWORD dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (ERROR_SUCCESS == dwRes)
        {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;      
            __leave;// No more processing needed.
        }
        if (dwRes != ERROR_ACCESS_DENIED)
        {
            printf("First SetNamedSecurityInfo call failed: %u\n", dwRes);
            __leave;
        }

        // If the preceding call failed because access was denied, enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for
        // the Administrators group, take ownership of the object, and disable the privilege. Then try again to set the object's DACL.      
        if (!OpenProcessToken(GetCurrentProcess(),  TOKEN_ADJUST_PRIVILEGES, &hToken)) // Open a handle to the access token for the calling process.
        {
            printf("OpenProcessToken failed: %u\n", GetLastError());
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE)) // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("You must be logged on as Administrator.\n");
            __leave;
        }

        // Set the owner in the object's security descriptor.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            OWNER_SECURITY_INFORMATION,  // change only the object's owner
            ppSid,                   // SID of Administrator group
            NULL,
            NULL,
            NULL);
        if (dwRes != ERROR_SUCCESS)
        {
            printf("Could not set owner. Error: %u\n", dwRes);
            __leave;
        }

        if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE)) // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
        {
            printf("Failed SetPrivilege call unexpectedly.\n");
            __leave;
        }

        // Try again to modify the object's DACL,now that we are the owner.
        dwRes = SetNamedSecurityInfo(
            lpszOwnFile,                 // name of the object
            SE_FILE_OBJECT,              // type of object
            DACL_SECURITY_INFORMATION,   // change only the object's DACL
            NULL, NULL,                  // do not change owner or group
            pACL,                        // DACL specified
            NULL);                       // do not change SACL
        if (dwRes == ERROR_SUCCESS) {
            printf("Successfully changed DACL\n");
            bRetval = TRUE;
        } else {
            printf("Second SetNamedSecurityInfo call failed: %u\n", dwRes);
        }
    }
    __finally
    {
        if (pACL)
            LocalFree(pACL);

        if (hToken)
            CloseHandle(hToken);
    }

    return bRetval;
}


int main()
{
    BOOL B = set_file_secure_attribute (L"f:\\test.exe", L"Everyone", GENERIC_READ);
    if (!B) {
        return 0;
    }

    B = set_file_secure_attribute (L"f:\\test.exe", L"Administrators", GENERIC_ALL);
    if (!B) {
        return 0;
    }

    B = set_file_secure_attribute (L"f:\\test.exe", L"guest", GENERIC_ALL);
    if (!B) {//经测试,这个成功了,Everyone的就没有了,啥原因还是啥规矩不知道.
        return 0;
    }
   
    B = set_file_secure_attribute (L"f:\\test2.exe", L"Everyone", GENERIC_ALL);
    if (!B) {
        return 0;
    }

    //B = TakeOwnership(L"f:\\test.exe");

    return 0;
}

2014年3月29日星期六

获取文件的所有者(用户)

/*
一个文件的所有者,大概也就是创建者,这是一个简单的问题,你想过吗?
一般人不会关注,只有安全的人才去关注,并有所获,深入深入再深入.
本文修改自MSDN的:Finding the Owner of a File Object in C++.
再次说明,改编自VS2008的MSDN,非网络上的MSDN的代码.

made by correy
made at 2014.03.29
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include "aclapi.h" //这个在VC及SDK和WDK都有.


bool get_owner_of_file(IN wchar_t * filename, OUT wchar_t * owner)
{
    if (!filename || !owner) {
        return false;
    }

    HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        _tprintf(TEXT("CreateFile error = %d\n"), GetLastError());
        return false;
    }
   
    PSID pSidOwner = (PSID)GlobalAlloc(GMEM_FIXED, sizeof(PSID));// Allocate memory for the SID structure.
    if (!pSidOwner) {//这两个内存申请,微软竟然不判断失败的情况.
        return false;
    }
    PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GMEM_FIXED, sizeof(PSECURITY_DESCRIPTOR));// Allocate memory for the security descriptor structure.
    if (!pSD) {//经测试.这个变量不用申请,没有用.
        GlobalFree(pSidOwner);
        return false;
    }

    // Get the owner SID of the file.
    DWORD dwRtnCode = GetSecurityInfo(hFile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSD);//除了签三个参数,剩余的都是OUT类型.
    if (dwRtnCode != ERROR_SUCCESS) {
        _tprintf(TEXT("GetSecurityInfo error = %d\n"), GetLastError());
        GlobalFree(pSidOwner);
        GlobalFree(pSD);
        return false;
    }

    // First call to LookupAccountSid to get the buffer sizes.
    DWORD dwAcctName = 1, dwDomainName = 1;
    SID_NAME_USE eUse = SidTypeUnknown;
    BOOL bRtnBool = LookupAccountSid(NULL, pSidOwner, 0, (LPDWORD)&dwAcctName, 0, (LPDWORD)&dwDomainName, &eUse); //返回两个值的大小.      
    LPTSTR AcctName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwAcctName);// Reallocate memory for the buffers.  
    if (AcctName == NULL) {// Check GetLastError for GlobalAlloc error condition.
        _tprintf(TEXT("GlobalAlloc error = %d\n"), GetLastError());
        GlobalFree(pSidOwner);
        GlobalFree(pSD);
        return false;
    }
    LPTSTR DomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwDomainName); //其实这个也不是我们想要的.但必须得有,不然下面的函数运行失败.
    if (DomainName == NULL) {// Check GetLastError for GlobalAlloc error condition.
        _tprintf(TEXT("GlobalAlloc error = %d\n"), GetLastError());
        GlobalFree(pSidOwner);
        GlobalFree(pSD);
        GlobalFree(AcctName);
        return false;
    }
   
    bRtnBool = LookupAccountSid(// Second call to LookupAccountSid to get the account name.
        NULL,                   // name of local or remote computer
        pSidOwner,              // security identifier
        AcctName,               // account name buffer
        (LPDWORD)&dwAcctName,   // size of account name buffer
        DomainName,             // domain name.这个域名也会返回
        (LPDWORD)&dwDomainName, // size of domain name buffer.
        &eUse);                 // SID type.这个也会返回.  
    if (bRtnBool == FALSE) {// Check GetLastError for LookupAccountSid error condition.
        if (GetLastError() == ERROR_NONE_MAPPED) {
            _tprintf(TEXT("Account owner not found for specified SID.\n"));
        } else {
            _tprintf(TEXT("Error in LookupAccountSid.\n"));
        }
    } else if (bRtnBool == TRUE) {      
        _tprintf(TEXT("Account owner = %s\n"), AcctName);// Print the account name.
        lstrcpy(owner, AcctName);
    }

    GlobalFree(pSidOwner);
    GlobalFree(pSD);
    //GlobalFree(AcctName);//释放出错.
    //GlobalFree(DomainName);//释放出错.

    return !!bRtnBool;
}


int main(int argc, char **argv)
{  
    wchar_t owner_user[MAX_PATH] = {0};
    bool b = get_owner_of_file(L"f:\\test.exe", owner_user);
    if (b) {
        _tprintf(TEXT("Account owner = %s\n"), owner_user);
    } else {
        _tprintf(TEXT("Account owner not found\n"));
    }

    return 0;
}

2014年3月28日星期五

内存/硬断点之编程实现

#include "stdafx.h"

/*
硬件断点很有用,它的原理就不说了。
在调试的时候很容易做到:ba wX 0xXXXXXXXX.
在编程的时候如何做到呢?
当然是改变内存的属性了。
这个包括全局的变量和堆上申请的内存。
栈上的内存被非法篡改,理论上不属于这个范畴了,是另一个说法:栈溢出等。
注意:全局的变量一般所在的节的内存属性都是可写的。
可以利用异常处理/或者自己发出异常,然后捕获,获取发生时的信息。

made by correy
made at 2014.03.28
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

觉得有效的利用此属性的办法还是老老实实的用VirtualAlloc 申请一片内存(当某个变量等).
至少申请的内存的大小是页的倍数.

全局的变量还得另想办法.修改PE文件的格式等.
*/

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h> 

int test[2];

void test_global_variable()
    /*
    功能:使全局变量不可以写.
    目的:以编程的手段实现一种断点.
    */
{
    DWORD OldProtect = 0;
    BOOL B = VirtualProtect(&test[0], sizeof(int), PAGE_READONLY, &OldProtect); 
    if (!B) {
        int x = GetLastError();
    }    

    /*
    这个也是不可以的.
    可能是内存属性的划分是以页为单位进行的.
    */
    test[1] = 1;

    /*
    把上面的测试给屏蔽了.
    运行到这里访问发生了异常.
    可以用异常处理的办法处理捕获然后再恢复内存属性.
    */
    test[0] = 1;    
}

void test_heap()
    /*
    功能:测试堆的非法访问的拦截.
    结果:测试成功,满足要求.
    */
{
    char * c = (char *) HeapAlloc(GetProcessHeap(), 0, 2);
    if (c == NULL) {
        return;
    }

    * c = 9;//测试应该成功.

    DWORD OldProtect = 0;
    BOOL B = VirtualProtect(c, 1, PAGE_READONLY, &OldProtect); 
    if (!B) {
        int x = GetLastError();
    }

    /*
    应该失败.
    假定这里是非法修改内存,如别的指令的内存溢出越界等.
    这里满足要求,弹出了异常界面.
    */
    * c = 1;

    /*
    把上面的测试给屏蔽了.
    运行到这里访问发生了异常.
    可能是内存属性的划分是以页为单位进行的.
    */
    c++;
    * c = 1;
}

int wmain(int argc, wchar_t *argv[])
{   
    //test_global_variable();

    test_heap();

    /*
    相信:VirtualAlloc和GlobalAlloc/LocalAlloc/NEW的内存在理论上也应该成功.
    但是栈上的局部变量建议不要这样做,也不应该这样做.
    */

    return 0;
}

设置和改变用户密码

/*
在没有密码或者已知密码的情况下修改密码.
用途是可以用脚本或者编程以快速的方式改变密码.
本文简单修改自MSDN.
*/

#ifndef UNICODE
#define UNICODE
#endif

#include <stdio.h>
#include <windows.h>
#include <lm.h>

#pragma comment(lib, "Netapi32.lib")


int wmain(int argc, wchar_t *argv[])
{  
   if (argc != 4) {
      fwprintf(stderr, L"Usage: %s \\\\UserName OldPassword NewPassword\n", argv[0]);
      exit(1);
   }

   NET_API_STATUS nStatus = NetUserChangePassword(0, argv[1], argv[2], argv[3]);//在没有密码的情况下第三个参数可以为空即:L"".
   if (nStatus == NERR_Success) {
      fwprintf(stderr, L"User password has been changed successfully\n");
   } else {
      fprintf(stderr, "A system error has occurred: %d\n", nStatus);
   }

   return 0;
}

2014年3月6日星期四

获取Windows用户登录的密码

#include "stdafx.h"

/*
获取Windows的登录用户的密码
这是一个项伟大而神奇的操作,始见于《黑客防线》,仔细一看,他是从这个网址精简的.
http://www.codeproject.com/Articles/12146/Login-password-filters-in-WinXP

当然还有别的办法,如分析Winlogon进程和暴力破解,不过这都有局限性,而这个办法是官方公布的通用的办法.
参考信息如下:

NPLogonNotify:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378804(v=vs.85).aspx
NPGetCaps:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378794(v=vs.85).aspx
:NPPasswordChangeNotify:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378806(v=vs.85).aspx

Authentication Registry Keys:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa374737(v=vs.85).aspx

Authentication Return Values:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa374738(v=vs.85).aspx

Installing and Registering a Password Filter DLL:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms721766(v=vs.85).aspx

Registering to Receive Connection Notifications
http://msdn.microsoft.com/en-us/library/windows/desktop/aa379397(v=vs.85).aspx

主要的设置是操作注册表,不过这可以编程实现:
1.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider的order的ProviderOrder后加入一个值,注意逗号.
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider的HwOrder的ProviderOrder后可以不加入.
2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services下创建刚才键入的值.
3.再在上面(第二步)的路径下创建networkprovider.
4.再在上面(第三步)的路径下创建类型为REG_DWORD的键名Class.
5.再在上面(第三步)的路径下创建类型为REG_MULTI_SZ的键名Name.
6.再在上面(第三步)的路径下创建类型为REG_MULTI_SZ的键名ProviderPath.
7.可以没有:HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Lsa"的Notification Packages后添加一个值.
8.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Notifyees这个没有实验.

注意:
1.Make sure that you create a 32-bit password filter DLL for 32-bit computers and a 64-bit password filter DLL for 64-bit computers
  不然DLL加载失败.
2.调试方法:内核调试,如COM。本地调试和用户层的网络调试都不行的。
3.最好每次注册之后都重启,而不是注销再登录。主要是下的断点没有断下来。但是可以通过各种途径修改密码等操作。
4.最好不要改DLL的名字,这关系到调试的符号加载问题。
以上每个问题都浪费了我半天的时间。

made by correy
made at 2014.03.06
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

后来(2014.03.10)发现SDK里面也有这东西,路径在:
Microsoft SDK\Samples\security\NetProviders。
工程的名字叫:LogonNP。
*/

#include <Npapi.h>
#include <Ntsecapi.h>


BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    DebugBreak();
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls((HMODULE)hModule);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


DWORD WINAPI NPGetCaps(DWORD nIndex)
{
    DWORD dwRes;

    switch (nIndex)
    {
    case WNNC_NET_TYPE:
        dwRes = WNNC_CRED_MANAGER; // credential manager
        break;
    case WNNC_SPEC_VERSION:
        dwRes = WNNC_SPEC_VERSION51;  // We are using version 5.1 of the spec.
        break;
    case WNNC_DRIVER_VERSION:
        dwRes = 1;  // This driver is version 1.
        break;
    case WNNC_START:
        dwRes = 1;  // We are already "started"
        break;
    default:
        dwRes = 0;  // We don't support anything else
        break;
    }

    return dwRes;
}


DWORD WINAPI NPLogonNotify (PLUID lpLogonId, LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType,
                            LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, LPWSTR *lpLogonScript)
{
    PMSV1_0_INTERACTIVE_LOGON pAuthInfo;  

    // If the primary authenticator is not MSV1_0, return success.
    // Why? Because this is the only auth info structure that we understand and we don't want to interact with other types.
    if (lstrcmpiW (L"MSV1_0:Interactive", lpAuthentInfoType))
    {
        MessageBox(NULL,(char *)pAuthInfo->Password.Buffer ,(char *)pAuthInfo->UserName.Buffer,0);
        SetLastError(NO_ERROR);
        return NO_ERROR;
    }

    // Do something with the authentication information
    pAuthInfo = (PMSV1_0_INTERACTIVE_LOGON) lpAuthentInfo;
    if(pAuthInfo->LogonDomainName.Length>0)
    {
        if(pAuthInfo->Password.Length>0)
        {
            if(pAuthInfo->UserName.Length>0)
            {
                TCHAR szBuf[1024];
                char *FormateInfo = "StationName=%lS DomainName = %lS UserName=%lS Password=%lS\r\n";
                wsprintf(szBuf, FormateInfo, lpStationName, pAuthInfo->LogonDomainName.Buffer, pAuthInfo->UserName.Buffer, pAuthInfo->Password.Buffer);
                //MessageBox(NULL,szBuf,"Info",0);在登录界面和控制面板里面修改也会走到这里,并且停止在这里,消息框没有弹出.
            } else {
                MessageBox(NULL,"No Username","",0);
            }
        } else {
            MessageBox(NULL,"No Password","",0);
        }
    }  else {
        MessageBox(NULL,"No domain Name","",0);
    }

    // Let's utilize the logon script capability to display our logon information      
    *lpLogonScript = (LPWSTR)LocalAlloc(LPTR,1024);// The Caller MUST free this memory

    return NO_ERROR;
}


DWORD WINAPI NPPasswordChangeNotify (LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType,
                                     LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, DWORD dwChangeInfo)
 /*
在登录界面的修改密码会走到这里.
控制面板的修改密码发现没有走到这里.
命令行的修改密码没有测试.
*/
{
    PMSV1_0_INTERACTIVE_LOGON pAuthInfo = (PMSV1_0_INTERACTIVE_LOGON)lpAuthentInfo;//这里有修改后的密码.

    return NO_ERROR;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//def文件内容如下:

LIBRARY NPLogonNotify
EXPORTS
    NPGetCaps @1
    NPLogonNotify @2
    NPPasswordChangeNotify @3