NT平台拨号连接密码恢复原理 :: 『孤光剑隐』

来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=485827 存档链接: https://web.archive.org/web/20041129054449id_/http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=485827


Cisco路由器安全配置方案 Linux下用gdb检测内核rootkit 对RedHat系统的一些概括性描述 如何检测和隔离内存泄漏 使用iptables建置Linux防火墙 控制台下修改系统驱动状态的程序源代码 Hook钩子攻略 利用%5c绕过验证 ASP中FSO的神奇功能 一次溢出之旅 dreamtheater Angel showlife tx7do charcs chensun netsky jpxiong Flier KKQQ Ziqi redsaga spy88B8 Luzhu NetKnave eVan SUNU Taynni wuhui CAT Neeao Iceberg kaspersky KusTa Hoky eviloctal lam Net・PoliCe Jace Hardy Gusu・Lanye swap lilo xiaolu knIfe mifor kaka Lo7e4L Super・Hei lichdr yysun testnet soul Archonwang lamp FlyWeb evilhsu hackfree powers Sunlion EvilPhive xeric icyfoxlovelace GuoMing swords an85 ring zwx <<<基于Apache2.0.50的cgi php论坛架设全攻略 | 首页 | 拒绝DDOS.从我做起!>>> NT平台拨号连接密码恢复原理 时间: 2004-11-09 前段时间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 _blank>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" "_blank>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 _blank>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", j3 + 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(dwMaxCount0x10); __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[dwCount0x10]), 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 \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[j0x10], 0x10); LSADataKey.cbData = LSADataKey.cbMaxData = 0x10; LSADataKey.pbData = &pKey[j0x10]; //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 -=-=-=-=-=-=-=-=-=-= 孤光剑隐 发表于 2004-11-09 08:28 引用Trackback(0) | 编辑 评论 发表评论