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

NT平台ADSL拨号连接密码恢复原理的更多相关文章

  1. ADSL拨号连接

    dotras是一个提供远程访问服务的组件,使用它可以方便的 进行宽带拨号连接 由于不同的系统中dotras调用的底层api可能不同,所以使用时要根据不同的系统使用不同的dotras. dotras目前 ...

  2. centos ADSL 拨号上网设置

    下面主要介绍一下,在CentOS命令行环境下如何配置 ADSL 联网: 1.确保安装了网卡并能正常运行,使用命令查看一下网卡状态: [root@localhost simon]# /sbin/ifco ...

  3. Ubuntu ADSL拨号上网

    一直在家用接ADSL的无线wifi上网,最近用了很久的NetGear无线路由器被我毁了,只好暂时用有线了.在Ubuntu Linux下也可直接使用ADSL拨号上网. 1.连接设备 这没什么可多说的,一 ...

  4. Linux操作系统上ADSL拨号上网的方法详解

    1.安装 yum install rp-pppoe.x86_64 2.配置PPPOE客户端软件 安装完软件包后,必须配置pppoe的配置文件/etc/ppp/pppoe.conf,从而让ADSL拨号时 ...

  5. ADSL拨号上网或者光纤上网设置概要(原创)

    不管是在梧州设置光纤还是在太平设置ADSL拨号上网每次设置上网一体机的时候都是遇到各种麻烦...这次又是弄了N久,每次问题各不一样.总结一下操作过程,方便以后又遇问题回头查询自个微博.一.设置电话线的 ...

  6. Database基础(四):密码恢复及设置、 用户授权及撤销、数据备份与恢复、MySQL管理工具

    一.密码恢复及设置 目标: 本案例要求熟悉MySQL管理密码的控制,完成以下任务操作: 练习重置MySQL管理密码的操作 通过正常途径设置MySQL数据库的管理密码 步骤: 步骤一:重置MySQL管理 ...

  7. 跑PIN码破解无线网络WIFI密码的原理分析(转)

    你们家用的无线路由器安全吗?有人蹭网吗?无线路由器的漏洞在哪里?这么避免蹭网? 想要了解这些,必须要了解加密以及破解原理. 工具/原料 电脑 足够多足够好的wifi信号源 usb无线网卡(非必需) 一 ...

  8. 利用ADSL拨号上网方式如何搭建服务器

    序:搭建服务器需要两个条件硬件服务器和固定公网IP,随便一台个人电脑都可以作为硬件服务器,就剩下一个问题,如何获得一个固定公网IP. 第一章 扫盲:ADSL拨号上网方式,本地IP与公网IP的区别 一. ...

  9. PHP.2-LAMP平台介绍及网站的工作原理

    LAMP平台介绍及网站的工作原理 1.HTTP协议 URL(UniformResourceLocator)统一资源定位符,就是网页地址的意思.[格式:协议://主机.端口.文件.附加资源] ##URL ...

随机推荐

  1. Thread与ThreadPool的内存之战

    Thread与ThreadPool使用的时候在内存里对象是如何分布的呢? 今天我们就从内存堆的角度分析下两者. 先上小白鼠代码: static void Main(string[] args)     ...

  2. Task.Delay() 和 Thread.Sleep() 区别

    1.Thread.Sleep 是同步延迟,Task.Delay异步延迟. 2.Thread.Sleep 会阻塞线程,Task.Delay不会. 3.Thread.Sleep不能取消,Task.Dela ...

  3. 我发起了一个 .Net 平台上的 直播平台 开源项目 BalaBala

    直播平台, 需要解决的 技术点 是 2 个: 1  直播数据 的 传输 和 在 客户端 的 播放 2  大并发 关于 网络通信, 数据传输, 可以参考 <利用 MessageRPC 和 Shar ...

  4. MySQL 的日期类型有5个,分别是: date、time、year、datetime、timestamp。

    类型 字节 格式 用途 是否支持设置系统默认值 date 3 YYYY-MM-DD 日期值 不支持 time 3 HH:MM:SS 时间值或持续时间 不支持 year 1 YYYY 年份 不支持 da ...

  5. MAC上使用Enterprise Architecture,附带安装步骤及破解链接

    绪论 网上找了半天这个主题也没有详细的步骤的昂,所以自己来造轮子了. 还有,百度搜EA破解版不靠谱,大搜狗更给力哦! 一.背景 穷逼只有一台存储空间不大MACAir,分给虚拟机Virtual Box的 ...

  6. xilinx AXI相关IP核学习

    xilinx AXI相关IP核学习 1.阅读PG044 (1)AXI4‐Stream to Video Out Top‐Level Signaling Interface (2)AXI4‐Stream ...

  7. Delphi实现菜单项上出现提示

    type TMenuHintWindow = class(THintWindow) private FTimerShow: TTimer; FTimerHide: TTimer; procedure ...

  8. 黄聪:ffmpeg参数说明(转载)

    ffmpeg.exe -i F:\闪客之家\闪客之歌.mp3 -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\11.flv ffmpeg -i F:\01.wm ...

  9. 数据仓库专题(2)-Kimball维度建模四步骤

    一.前言 四步过程维度建模由Kimball提出,可以做为业务梳理.数据梳理后进行多维数据模型设计的指导流程,但是不能作为数据仓库系统建设的指导流程.本文就相关流程及核心问题进行解读. 二.数据仓库建设 ...

  10. pyqt4 利用信号槽在子线程里面操作Qt界面

    转载:ABigCaiBird #-*- coding:utf-8 -*- ####### from PyQt4.QtCore import * from PyQt4.QtGui import * im ...