zoukankan      html  css  js  c++  java
  • NT平台拨号连接密码恢复原理(转)

    创建时间:2004-11-08 更新时间:2004-11-12
    文章属性:原创
    文章提交:eyas (eyas_at_xfocus.org)

    NT平台拨号连接密码恢复原理

    Author : eyas
    Email  : eyas at xfocus.org
    Date   : 2004-11-08


        前段时间ADSL密码忘记了,但幸好还保存在拨号连接里面,于是到网上找了些星号密码
    显示工具,可惜不起作用。后来找到一种名为dialupass的工具,这家伙不负重望把密码给
    我还原出来了。(用的dialupass v2.42,我的系统是windows xp)

        看起来dialupass非普通的星号密码显示工具,那它的原理是什么呢?上GOOGLE查了
    一翻,没找到相关资料(可能是我用的关键字有问题)。 一生气便操起家伙(windbg)
    准备把它大卸八块。郁闷的是,用windbg加载后,密码就还原不出来了,显示是星号。换替
    补ollydbg上场,情况依旧。莫非这小工具有Anti-Debug功能?当时只是一丝怀疑,因为实
    在不相信这样的小工具作者会花心思来保护。

        后来在用s-ice跟踪的过程中,发现有这么一个调用:

        GetProcAddress(xx, "IsDebugPresent")。
        
        晕倒,原来真的有Anti-Debug功能,好在比较简单。统计了一下,总共有5处进行了
    Anti-Debug检查。
        
        情况查明了,便换回windbg来调试,在windbg里面下这么一个断点便可绕过Anti-Debug
    检测:

        bp KERNEL32!IsDebuggerPresent "g poi(esp);r eax=0;g"

        花了些时间跟踪了一下,把dialupass恢复密码的流程都搞清楚了。这小程序猫腻还
    挺多的,总结如下:

        1. 关键函数不直接调用,而是用LoadLibraryA和GetProcAddress来获取函数地址
    后再CALL。
        2. 函数名是经过编码的,反汇编后看字符串是看不到的。
        3. 关键地方一概用花指令来迷惑你和反汇编软件。
        
        其实原理很简单,就是用rasapi32.dll里面的一些函数来获取拨号连接的一些信息,
    再用 ADVAPI32!LsaRetrievePrivateData 函数来获取密码。

        根据dialupasss的原理,写了个类似的工具,源代码参见后面的x_dialupass.c。

        后来用"LsaRetrievePrivateData"和"RasDialParams"做关键字,重新在GOOGLE搜索了
    一遍,找到一些类似的代码。

        参考资源[1]和[2]的是俄罗斯人公布的演示代码,没有对LsaRetrievePrivateData返回
    的数据进行拆分用户名和密码。参考资源[3]是日本人公布的完整的应用程序的代码,可惜
    在对LsaRetrievePrivateData返回的数据进行拆分处理时存在BUG,导致有些情况下用户名
    和密码取的不正确。

        
        后来发现lsadump2 DUMP出来的数据里面包含了"LsaRetrievePrivateData"返回的数
    据。lsadump2的原理大致如下:

        1)插入一线程到lsass.exe进程
        2)打开LSA Policy database
        3)从注册表"HKLM\SECURITY\Policy\Secrets"中枚举子键
        4)LsarOpenSecret
        5)LsarQuerySecret

        进一步跟踪后发现,其实ADVAPI32!LsaRetrievePrivateData是通过NdrClientCall2
    发送RPC调用到lsass.exe进程,lsass.exe里面再调用LsarOpenSecret、LsarQuerySecret
    来完成获取拨号连接信息过程的。(注:LsarOpenSecret里面有权限判断,非ADMIN组用
    户是没有权限来调用ADVAPI32!LsaRetrievePrivateData的)

       跟踪了一下LsarQuerySecret,发现它返回的数据其实是从注册表中读取。保存拨号
    连接信息的注册表键值为:

        HKLM\SECURITY\Policy\Secrets\RasDialParams!SID#0\CurrVal

        SID对应的是用户的string SID。(“HKLM\SECURITY”这个键只有SYSTEM有权限读
    写,连admin都没有权限)

        LsarQuerySecret从注册表中读取出来数据后,接着调用LsapCrDecryptValue函数来
    解密,对于同一台机器来说,解密时用的KEY始终都是固定的,这个KEY在lsasrv.dll里面
    变量名为"_LsapDbSecretCipherKey"。在windows 2003里面,变量名不一样,对应的有两
    个,分别为"LsapDbSecretCipherKeyWrite"和"LsapDbSecretCipherKeyRead",但这两个
    变量里面的数据是一样的。

        LsapCrDecryptValue用的似乎是标准DES算法,解密时主要流程如下:

        lsasrv!LsapCrDecryptValue
            |_ advapi32!SystemFunction005
                |_ advapi32!DecryptDataLength
                    |_ advapi32!SystemFunction002
                        |_ advapi32!DES_ECB_LM
                            |_ advapi32!des

        解密后,在"<<"标示处还有一个判断:

        .text:785462F0                 call    _LsapCrDecryptValue@12
        .text:785462F5                 test    eax, eax
        .text:785462F7                 mov     [ebp+var_8], eax
        .text:785462FA                 jl      loc_785838E1
        .text:78546300 
        .text:78546300 loc_78546300:                          
        .text:78546300                 cmp     byte ptr [esi+45h], 0   <<<<<<<<<<<<
        .text:78546304                 jz      short loc_7854632E
        ......
        .text:7854632E loc_7854632E:
        .text:7854632E                 lea     eax, [ebp+var_10]
        .text:78546331                 push    eax
        .text:78546332                 push    [ebp+arg_8]
        .text:78546335                 push    [ebp+var_C]
        .text:78546338                 call    _LsapCrEncryptValue@12


        假如[esi+45h]为0的话(esi是LsarOpenSecret函数返回的HANDLE),它会把解密后的
    数据再进行一次加密,不管是2000还是2003,这时用的KEY始终都是固定为
    “SystemLibraryDTC”。

        lsadump2里面调用LsarOpenSecret得到的HANDLE,偏移0x45处值为1,所以
    LsarQuerySecret函数返回的就是解密后的数据了。

        而在调用ADVAPI32!LsaRetrievePrivateData时,LsarOpenSecret返回的HANDLE偏移
    0x45处值为0x0,所以LsarQuerySecret返回的是解密后又加密的数据,所以在
    ADVAPI32!LsaRetrievePrivateData里面还有一个对应的解密过程。相应的,
    LsapCrEncryptValue加密的主要流程如下:

        lsasrv!LsapCrEncryptValue
            |_ advapi32!SystemFunction004
                |_ advapi32!EncryptDataLength
                    |_ advapi32!SystemFunction001
                        |_ advapi32!DES_ECB_LM
                            |_ advapi32!des


        开始我以为在同一版本的windows里面,_LsapDbSecretCipherKey是固定的,后来
    发现我错了。那么这个_LsapDbSecretCipherKey是如何产生的?流程如下:

        (1)调用ntdll!NtConnectPort打开 L"\Security\WxApiPort"

        (2)调用ntdll!NtRequestWaitReplyPort得到一些数据

            ebp-40处为NtRequestWaitReplyPort返回的LPCMESSAGE

            kd> dd ebp-40
            0006fcb8  00400028 00000002 000000dc 000000d8
            0006fcc8  00000024 00000000 00000000 00000000
            0006fcd8  00000001 00000010 00000010 fd317e3e
            0006fce8  7e24e86d d12503d3 5f7d01a8 7665f528
            kd> db ebp-14
            0006fce4  3e 7e 31 fd 6d e8 24 7e-d3 03 25 d1 a8 01 7d 5f

        (3)将上述"ebp-14"处的0x10字节数据COPY到lsasrv.dll里面的"_LsapDbSysKey"变量。
    "_LsapDbSysKey"在不同的机器上面(即使版本相同)都是不一样的。它是怎么产生的?有
    幸拜读了flashsky的大作后(参考资源[4]),才明白这就是传说中的"SYSKEY"。用flashsky
    的代码验证一下:

            c:\>getsyskey
            3e 7e 31 fd 6d e8 24 7e d3 03 25 d1 a8 01 7d 5f

        跟踪系统启动过程,可知道"\Security\WxApiPort"是由winlogon.exe进程创建的,然
    后lsass进程通过这个LPC PORT从winlogon进程获取SYSKEY,随后winlogon进程会关闭这
    个LPC PORT。所以在系统启动完成之后,用"Process Explorer"等工具是看不到这个
    LPC PORT存在的,而且在winlogon和LSASS进程空间都搜索不到上述SYSKEY。

        (4)从注册表"HKLM\SECURITY\Policy\PolSecretEncryptionKey"中读取出来一段数据,
    调用函数_LsapDbDecryptKeyWithSyskey,把它用"_LsapDbSysKey"来解密,
    "_LsapDbSecretCipherKey"就在解密完后的数据里面。("LsapDbDecryptKeyWithSyskey"函
    数做的其实就是MD5和RC4运算)
            

        了解原理后,我们就可以直接从注册表里面来获取拨号连接中的密码等数据了。但
    有几个问题需要解决:

        (1)原料。
        Q:"HKLM\SECURITY"键只有SYSTEM有权限读写?
        A:我们可以把代码插入到SYSTEM进程里面去运行,或者把这个键修改为ADMIN有
    权限读,或者提升本进程权限。

        (2)催化剂:)
        Q: 如何获取"_LsapDbSysKey"?解密用的函数_LsapDbDecryptKeyWithSyskey为非导出函
    数,怎么办?
        A1: 用flashsky的代码来获取SYSKEY,利用公开的MD5和RC4库函数来解密。
        A2: 直接从lsass.exe进程里面搜索"_LsapDbSecretCipherKey",它的结构如下,

        typedef struct _LSA_BLOB {
                DWORD cbData;
                DWORD cbMaxData;
                BYTE* pbData;
        } LSA_BLOB;

        pbData指向存储KEY的地址,KEY长度固定为0x10字节,即cbData和cbMaxData都是固定
    为0x10。所以从lsass进程的空间里面搜索"\x10\x00\x00\x00\x10\x00\x00\x00"即可找到
    正确的KEY。结果可能会有多个,可以把所有搜索到的KEY都试一下,总有一个正确的。

        (3)工具
        Q: 解密函数LsapCrDecryptValue为非导出函数,怎么办?
        A: 或许可以根据特征码来搜索,但总觉得不太可靠。幸好,LsapCrDecryptValue
    调用的advapi32!SystemFunction005是导出函数:)。或者直接利用公开的DES库函数,
    自己来运算。


        x_dialupass2.cpp中的代码演示了直接从注册表中读取数据并解密之的过程,没有
    太多实际意义,just for fun!


    -=-=-=-=-=-=-=-=-=-=  x_dialupass.c  -=-=-=-=-=-=-=-=-=-=
    /*
    演示还原NT平台上拨号连接的密码
    可运行于windows 2000/xp/2003
    原理基于分析dialupass v2.42

    eyas at xfocus.org
    http://www.xfocus.net
    2004-10-01


    FileName: x_dialupass.c
    */
    #define WINVER 0x500
    #define _WIN32_WINNT 0x0500
    #include <windows.h>
    #include <stdio.h>

    #include <ras.h>
    #include <raserror.h>
    #include <Ntsecapi.h>
    #include <Userenv.h>
    #include <Sddl.h>

    #pragma comment(lib,"Rasapi32.lib")
    #pragma comment(lib,"advapi32.lib")
    #pragma comment(lib,"UserEnv.lib")

    unsigned char            private_data[0x500];
    int                        data_len;

    unsigned char * get_real_pass(unsigned char *user, DWORD dwDialParamsUID)
    {
        int    i, j;
        unsigned char *p, szDialParamsUID[52], *pass=NULL;

        _snprintf(szDialParamsUID, sizeof(szDialParamsUID), 
            "%d", dwDialParamsUID);

        p = private_data;

        for(i=0;i<data_len;i++)
        {
            if(strcmp(&p[i], szDialParamsUID) == 0 )
            {
                for(j=i;j<data_len;j++)
                {
                    if(strcmp(&p[j], user) == 0 )
                    {
                        pass = p + j + strlen(user) + 1;
                        break;
                    }
                }
                break;
            }
        }

        return pass;
    }

    void main()
    {
        LPRASENTRYNAME lpRasEntryName;
        LPRASDIALPARAMS lpRasDialParams;
        DWORD            cb, nRet, i, cEntries;
        BOOL            b;
        char            szPhoneBook1[512], szPhoneBook2[512], 
                        szUserName[128], szDomainName[128];
        DWORD            dwSize, dwDialParamsUID, dwTmp;
        PSID            pSid = NULL;
        SID_NAME_USE    peUse;

        LSA_OBJECT_ATTRIBUTES    lsa_object_attr;
        LSA_HANDLE                lsa_handle;
        PLSA_UNICODE_STRING        plsa_private_data;
        LSA_UNICODE_STRING        lsa_keyname;
        NTSTATUS                status;
        int                        ret;
        unsigned char            *pass;
        WCHAR                    *sid;

        printf("dialup password recover tool for win 2k/xp/2003\n"
                "code by eyas at xfocus.org\n"
                "http://www.xfocus.net\n"
                "2004-10-01\n\n");

        //get current user's string sid
        dwSize = sizeof(szUserName);
        GetUserName(szUserName, &dwSize);
        dwSize = 0;
        dwTmp = sizeof(szDomainName);
        LookupAccountName(NULL, szUserName, pSid, &dwSize, szDomainName, 
                        &dwTmp, &peUse);
        if(!dwSize)
        {
            printf("[-] LookupAccountName failed.\n");
            return;
        }
        pSid = (PSID)malloc(dwSize);
        LookupAccountName(NULL, szUserName, pSid, &dwSize, szDomainName,
                         &dwTmp, &peUse);
        ConvertSidToStringSidW(pSid, &sid);

        memset(&lsa_object_attr, 0, sizeof(lsa_object_attr));
        lsa_object_attr.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
        LsaOpenPolicy(0, &lsa_object_attr, 0x800, &lsa_handle);

        plsa_private_data = (PLSA_UNICODE_STRING)malloc(sizeof(LSA_UNICODE_STRING));
        plsa_private_data->Length = 0x500;
        plsa_private_data->MaximumLength = 0x500;
        plsa_private_data->Buffer = (PWSTR)malloc(0x500);

        lsa_keyname.MaximumLength = 0x200;
        lsa_keyname.Buffer = (PWSTR)malloc(0x200);
        wcscpy(lsa_keyname.Buffer,L"RasDialParams!");
        wcscat(lsa_keyname.Buffer, sid);
        wcscat(lsa_keyname.Buffer, L"#0");
        lsa_keyname.Length = wcslen(lsa_keyname.Buffer) * 2;

        //get current user's dialup info
        status = LsaRetrievePrivateData(lsa_handle, 
            &lsa_keyname,
            &plsa_private_data);
        LsaClose(lsa_handle);
        if(status != 0)
        {
            printf("[-] LsaRetrievePrivateData failed: %d\n",
                         LsaNtStatusToWinError(status));
            return;
        }
        ret = WideCharToMultiByte(0, 0, plsa_private_data->Buffer,
                                 plsa_private_data->Length, 
            private_data, sizeof(private_data), 0, 0);
        if(ret == 0)
        {
            printf("[-] WideCharToMultiByte failed:%d\n", GetLastError());
            return;
        }
        data_len = ret;

        //get phone book name
        GetEnvironmentVariable("ALLUSERSPROFILE", szPhoneBook1,
                                 sizeof(szPhoneBook1)-200);
        GetEnvironmentVariable("USERPROFILE", szPhoneBook2,
                                 sizeof(szPhoneBook2)-200);
        strcat(szPhoneBook1, 
            "\\Application Data\\Microsoft\\Network"
            "\\Connections\\pbk\\rasphone.pbk");
        strcat(szPhoneBook2, 
            "\\Application Data\\Microsoft\\Network"
            "\\Connections\\pbk\\rasphone.pbk");

        lpRasEntryName = (LPRASENTRYNAME)GlobalAlloc(GPTR, sizeof(RASENTRYNAME));
        lpRasEntryName->dwSize = sizeof(RASENTRYNAME);
        cb = sizeof(RASENTRYNAME);
        if ((nRet = RasEnumEntries(NULL, NULL, lpRasEntryName, &cb, &cEntries)) 
            == ERROR_BUFFER_TOO_SMALL)
        {
            lpRasEntryName = (LPRASENTRYNAME)GlobalAlloc(GPTR, cb);
            lpRasEntryName->dwSize = sizeof(RASENTRYNAME);
        }

        // Calling RasEnumEntries to enumerate the phone-book entries    
        nRet = RasEnumEntries(NULL, NULL, lpRasEntryName, &cb, &cEntries);

        if (nRet != ERROR_SUCCESS)
        {
            printf("[-] RasEnumEntries failed: Error %d\n", nRet);
            return;
        }

        for(i=0;i < cEntries;i++)
        {
            lpRasDialParams = malloc(sizeof(RASDIALPARAMS));
            strcpy(lpRasDialParams->szEntryName, lpRasEntryName->szEntryName);
            lpRasDialParams->dwSize = sizeof(RASDIALPARAMS);

            RasGetEntryDialParams(0, lpRasDialParams, &b);

            dwDialParamsUID = GetPrivateProfileInt(lpRasEntryName->szEntryName, 
                "DialParamsUID", 0, szPhoneBook1);
            if(dwDialParamsUID == 0)
            {
                dwDialParamsUID = GetPrivateProfileInt(lpRasEntryName->szEntryName, 
                                    "DialParamsUID", 0, szPhoneBook2);
                if(dwDialParamsUID == 0)
                {
                    printf("[-] Can't get DialParamsUID from PhoneBook.\n");
                    return;
                }
            }

            pass = get_real_pass(lpRasDialParams->szUserName, dwDialParamsUID);

            printf(
                "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"
                "EntryName : %s\n"
                "UserName  : %s\n"
                "PassWord  : %s\n\n",
                lpRasEntryName->szEntryName,
                lpRasDialParams->szUserName, 
                pass);

            free(lpRasDialParams);
            lpRasEntryName++;
        }
    }



    -=-=-=-=-=-=-=-=-=-= code end -=-=-=-=-=-=-=-=-=-=

    -=-=-=-=-=-=-=-=-=-= x_dialupass2.cpp -=-=-=-=-=-=-=-=-=-=
    /*
    演示还原NT平台拨号连接密码

    原理:直接从注册表中读取加密后的数据,解密之。

    可运行于windows 2000/xp/2003平台,必须有权限读取注册表 "HKLM\SECURITY"。

    eyas at xfocus.org
    http://www.xfocus.net
    2004-10-01
    */
    #include <Windows.h>
    #include <stdio.h>
    #include <Psapi.h>
    #pragma comment(lib, "Advapi32.lib")
    #pragma comment(lib, "psapi.lib")

    //抄袭tombkeeper的代码:)
    #define FCHK(a)     if (!(a)) {printf(#a " failed %d\n", GetLastError()); return 
    0;}

    typedef struct _LSA_BLOB {
        DWORD cbData;
        DWORD cbMaxData;
        BYTE* pbData;
    } LSA_BLOB;


    typedef int (WINAPI *PSystemFunction005)(
        LSA_BLOB* pDataIn,
        LSA_BLOB* pDataKey,
        LSA_BLOB* pDataOut
    );

    PSystemFunction005    SystemFunction005;
    DWORD                dwFlag=0;


    //来自lsadump2中的dumplsa.c
    int myisprint (int ch)
    {
        return ((ch >= ' ') && (ch <= '~'));
    }
    //来自lsadump2中的dumplsa.c
    void
    dump_bytes (unsigned char *p, size_t sz)
    {
        char szDumpBuff[256];

        if(sz==0)
            return;

        while (sz > 16) {
            _snprintf (szDumpBuff, sizeof (szDumpBuff),
                       " %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X 
    %02X %02X %02X %02X  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
                       p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
                       myisprint(p[0]) ? p[0] : '.',
                       myisprint(p[1]) ? p[1] : '.',
                       myisprint(p[2]) ? p[2] : '.',
                       myisprint(p[3]) ? p[3] : '.',
                       myisprint(p[4]) ? p[4] : '.',
                       myisprint(p[5]) ? p[5] : '.',
                       myisprint(p[6]) ? p[6] : '.',
                       myisprint(p[7]) ? p[7] : '.',
                       myisprint(p[8]) ? p[8] : '.',
                       myisprint(p[9]) ? p[9] : '.',
                       myisprint(p[10]) ? p[10] : '.',
                       myisprint(p[11]) ? p[11] : '.',
                       myisprint(p[12]) ? p[12] : '.',
                       myisprint(p[13]) ? p[13] : '.',
                       myisprint(p[14]) ? p[14] : '.',
                       myisprint(p[15]) ? p[15] : '.');
            printf ("%s", szDumpBuff);
            p+=16;
            sz -= 16;
        }

        if (sz) {
            char buf[17];
            int i = 0;
            int j = 16 - sz;
            memset (buf, 0, sizeof (buf));
            szDumpBuff[0] = 0;
            while (sz--) {
                _snprintf (szDumpBuff+strlen (szDumpBuff),
                           sizeof (szDumpBuff) - strlen (szDumpBuff),
                           " %02X", *p);
                if (myisprint (*p))
                    buf[i++] = *p;
                else
                    buf[i++] = '.';
                p++;
            }
            _snprintf (szDumpBuff+strlen (szDumpBuff),
                       sizeof (szDumpBuff)-strlen (szDumpBuff),
                       "%*s%s\n", j*3 + 2, "", buf);
            printf ("%s", szDumpBuff);
        }
    }

    DWORD search_LsapDbSecretCipherKey(BYTE **ppKey, DWORD pid)
    {
        HANDLE    hLsass, hLsasrv;
        DWORD    dwRead, i, dwAddr;
        BYTE    *pImage = NULL;
        MODULEINFO    mod;
        BOOL    bRet = FALSE;
        DWORD    dwCount = 0, dwMaxCount=100;

        FCHK ( (hLsasrv = LoadLibrary("lsasrv.dll")) );

        FCHK ( GetModuleInformation(GetCurrentProcess(), (HMODULE)hLsasrv, 
            &mod, sizeof(mod)) );

        FCHK ( hLsass = OpenProcess(PROCESS_VM_READ, FALSE, pid) );

        pImage = (BYTE*)malloc(mod.SizeOfImage);

        ReadProcessMemory(hLsass, (BYTE*)hLsasrv, 
                                pImage, mod.SizeOfImage-0x10, &dwRead);

        *ppKey = (BYTE*)malloc(dwMaxCount*0x10);
        
        __try
        {
            for(i=0;i<mod.SizeOfImage;i++)
            {
                if( memcmp(&pImage[i], "\x10\x00\x00\x00\x10\x00\x00\x00", 8) == 0)
                {
                    dwAddr = *(DWORD *)(&pImage[i+8]);
                    if( ReadProcessMemory(hLsass, (LPCVOID)dwAddr, 
                                &(*ppKey[dwCount*0x10]), 0x10, &dwRead) )
                    {
                            dwCount++;
                    }
                }
            }//end of for
        }
        __except(EXCEPTION_EXECUTE_HANDLER)
        {
            return dwCount;
        }

        return dwCount;
    }

    int main(int argc, char **argv)
    {
        int ret,i,j;
        HMODULE hAdvApi32;
        HKEY hKeySecrets;
        HKEY hKey;
        DWORD dwType;
        char Data[0x500] = {0};
        BYTE    *pKey;
        DWORD dwSize;
        LSA_BLOB LSADataIn;
        LSA_BLOB LSADataOut;
        LSA_BLOB LSADataKey;
        char szSecret[500];
        char szSubKey[0x500];
        DWORD dwErr, dwCount=0;

        if(argc!=2)
        {
            printf("Usage: %s <pid of lsass.exe>\n", argv[0]);
            return 0;
        }


        FCHK ((hAdvApi32 = LoadLibrary("advapi32.dll")));
        FCHK ((SystemFunction005 = (PSystemFunction005)
               GetProcAddress (hAdvApi32, "SystemFunction005")) != NULL);
        
        FCHK ((RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                          "SECURITY\\Policy\\Secrets",
                          0, KEY_READ, &hKeySecrets) == ERROR_SUCCESS))

        FCHK ( ( dwCount = search_LsapDbSecretCipherKey(&pKey, atoi(argv[1])) ) != 0 
    );
        printf("Search \"LsapDbSecretCipherKey\" return: %d\n", dwCount);

        for(j=0;j<dwCount;j++)
        {
            printf("LsapDbSecretCipherKey [%d]\n", j);
            dump_bytes(&pKey[j*0x10], 0x10);

            LSADataKey.cbData = LSADataKey.cbMaxData = 0x10;
            LSADataKey.pbData = &pKey[j*0x10];

            //search our target
            for (i=0; TRUE; i++)
            {
                dwErr = RegEnumKeyA (hKeySecrets, i, szSecret, sizeof (szSecret));
                if (dwErr != ERROR_SUCCESS)
                    //
                    // No More Secrets
                    //
                    break;

                printf("\n%s\n", szSecret);
                //open it
                _snprintf(szSubKey, sizeof(szSubKey), 
                    "SECURITY\\Policy\\Secrets\\%s\\CurrVal", szSecret);
                if (ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                                        szSubKey,
                                        0,
                                        KEY_READ,
                                        &hKey
                                        ) != ERROR_SUCCESS )
                    continue;

                dwSize = sizeof(Data);
                FCHK ((ret = RegQueryValueEx(hKey,
                                    "",
                                    NULL,
                                    &dwType,
                                    (LPBYTE)Data,
                                    &dwSize) == ERROR_SUCCESS ))

                LSADataIn.pbData = (BYTE *)Data + 0xC;  //密文从第0xC位开始
                LSADataIn.cbData = dwSize-0xC;
                LSADataIn.cbMaxData = LSADataIn.cbData;

                //dump_bytes(LSADataIn.pbData, LSADataIn.cbData);

                LSADataOut.cbData = 0;
                LSADataOut.cbMaxData = 0;
                LSADataOut.pbData = NULL;

                SystemFunction005(&LSADataIn, &LSADataKey, &LSADataOut);
                if (LSADataOut.cbData == 0)
                {
                    printf("null\n");
                    continue;
                }

                FCHK ((LSADataOut.pbData = (BYTE*)malloc(LSADataOut.cbData) ) != 
    NULL);
                LSADataOut.cbMaxData = LSADataOut.cbData;
                SystemFunction005(&LSADataIn, &LSADataKey, &LSADataOut);

                dump_bytes(LSADataOut.pbData, LSADataOut.cbData);
                free(LSADataOut.pbData);
            }//end of for
            printf("Press any key to use next \"LsapDbSecretCipherKey\", or Ctrl+C 
    to exit.\n");
            getchar();
        }

        if(pKey)
            free(pKey);
        return 0;
    }

    -=-=-=-=-=-=-=-=-=-= code end -=-=-=-=-=-=-=-=-=-=  

    参考资源:

    [1] http://www.lwteam.ru/modules/news/article.php?storyid=167
        2003-06-24 by Cmeptb

    [2] http://www.wasm.ru/forum/index.php?action=vthread&forum=12&topic=4873
        2004-01-10 by ??

    [3] http://homepage2.nifty.com/spw/software/rtrick/
        2004-01-05 by ???

    [4] SAM的散列存储加密解密算法以及SYSKEY的计算
        http://www.xfocus.net/articles/200306/550.html
        2003-06-04 by flashsky at xfocus.org

  • 相关阅读:
    weka 文本分类(1)
    python 笔记1
    PAT乙级 1028. 人口普查(20)
    PAT乙级 1027. 打印沙漏(20)
    PAT乙级 1026. 程序运行时间(15)
    Eclipse常用快捷键
    MyBatis源码分析(各组件关系+底层原理
    springmvc异常处理
    Elasticsearch学习(一)————简单命令
    mybatis传入参数类型parameterType详解
  • 原文地址:https://www.cnblogs.com/szyicol/p/2770897.html
Copyright © 2011-2022 走看看