电脑教程中文网
首页  动态网站建设学习 程序  笑话  论坛 娱乐  交友 ADSL  峄城  成功者
中文名:电脑教程中文网,收集了大量的电脑教程! 编程技术文档 游戏开发 笑话站暂时关闭 设为首页
网页设计 HTML | Dreamweaver | CSS | Firework | FrontPage WEB开发 ASP | JSP | PHP | .NET | CGI | JS | VBS | XML | IIS6 | Apache | PWS
程序设计 Java | C++ |VC++ | C# | Delphi | VB | C语言 | 汇编 | Pascal | Perl 数据库 MSSQL | MySQL | Access | VF | Oracle | DB2 | SYBASE |
办公软件 Word | Excel | WPS | PowerPoint 动画平面 Photoshop | ACDSee | 3Dmax | Flash | Coreldraw |
操作系统 Windows 2000 | Windows XP | Windows 2003 | SCO Unix | Windows Vista | unix、Linux | 综合| 服务器 | 系统安全| 黑客技术
其  他 UltraDev | DOS | UML | PWS | Powerbuilder | 开发心得 | 设计理念 | 病毒库 | 其他 | LightTPD (分类排序给您带来不便请谅解)
推  荐: Java文档500篇》《ASP.NET与相关数据库技术高级指南》《TC图形函数详解》《C函数速查手册》《C语言编程宝典之一》《MFC深入浅出》《黑客零起点》《VC++ 编程指南》《JScript 用户指南》 《CSS教程宝典》《Microsoft Jet SQL 参考》《delphi技巧集合》《MySQL 4.1.0 中文参考手册》《MySQL中文手册
【导航】 您现在的位置 : 首页 - SystemSafety教程 - 《系统安全高级篇-本站收集整理》- 管理员组获取系统权限的完美解决方案 2

管理员组获取系统权限的完美解决方案 2

日期:2005-7-5 11:06:37    作者:佚名   人气:   来源:未知




在上面的代码中,请将TOKEN_OFFSET改成你的系统版本的偏移值.我们也可以想像到由于是操作了系统的内核空间,搞不好会出现蓝屏现象(尽管机率很小).

=========================================================================================================

第二种方法,我们不自己创建进程,而是直接用System进程的Token来创建进程.看到这,大家可能又想到了远线程。

这里不是。我的思路是:配置好桌面(desktop),工作区间(WindowStation)等信息,最后调用CreateProcessAsUser来创建子进程。

用这种方法极为稳定。这里一些关于获取SID的代码可以看我前一段时间写的"一种新的穿透防火墙的数据传输技术".

下面是源代码,这段代码也实现了RUNAS的功能,有兴趣可以研究一下,大部分都来自MSDN:

#include <windows.h>

#include <stdio.h>

#include <Tlhelp32.h>

#include <AccCtrl.h>

#include <Aclapi.h>

#include <wtsapi32.h>

#pragma comment(lib, "wtsapi32")

HANDLE OpenSystemProcess()

{

HANDLE hSnapshot = NULL;

HANDLE hProc = NULL;

__try

{

// Get a snapshot of the processes in the system

hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (hSnapshot == NULL)

{

printf("OpenSystemProcess CreateToolhelp32Snapshot Failed");

__leave;

}

PROCESSENTRY32 pe32;

pe32.dwSize = sizeof(pe32);

// Find the "System" process

BOOL fProcess = Process32First(hSnapshot, &pe32);

while (fProcess && (lstrcmpi(pe32.szExeFile, TEXT("SYSTEM")) != 0))

fProcess = Process32Next(hSnapshot, &pe32);

if (!fProcess)

{

printf("OpenSystemProcess Not Found SYSTEM");

__leave; // Didn't find "System" process

}

// Open the process with PROCESS_QUERY_INFORMATION access

hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,

pe32.th32ProcessID);

if (hProc == NULL)

{

printf("OpenSystemProcess OpenProcess Failed");

__leave;

}

}

__finally

{

// Cleanup the snapshot

if (hSnapshot != NULL)

CloseHandle(hSnapshot);

return(hProc);

}

}

BOOL EnablePrivilege (PCSTR name)

{

HANDLE hToken;

BOOL rv;

TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };

LookupPrivilegeValue (

0,

name,

&priv.Privileges[0].Luid

);

OpenProcessToken(

GetCurrentProcess (),

TOKEN_ADJUST_PRIVILEGES,

&hToken

);

AdjustTokenPrivileges (

hToken,

FALSE,

&priv,

sizeof priv,

0,

0

);

rv = GetLastError () == ERROR_SUCCESS;

CloseHandle (hToken);

return rv;

}

#define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0]))

BOOL ModifySecurity(HANDLE hProc, DWORD dwAccess)

{

PACL pAcl = NULL;

PACL pNewAcl = NULL;

PACL pSacl = NULL;

PSID pSidOwner = NULL;

PSID pSidPrimary = NULL;

BOOL fSuccess = TRUE;

PSECURITY_DESCRIPTOR pSD = NULL;

__try

{

// Find the length of the security object for the kernel object

DWORD dwSDLength;

if (GetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pSD, 0,

&dwSDLength) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))

{

printf("ModifySecurity GetKernelObjectSecurity Size Failed");

__leave;

}

// Allocate a buffer of that length

pSD = LocalAlloc(LPTR, dwSDLength);

if (pSD == NULL)

{

printf("ModifySecurity LocalAlloc Failed");

__leave;

}

// Retrieve the kernel object

if (!GetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pSD,

dwSDLength, &dwSDLength))

{

printf("ModifySecurity GetKernelObjectSecurity Failed");

__leave;

}

// Get a pointer to the DACL of the SD

BOOL fDaclPresent;

BOOL fDaclDefaulted;

if (!GetSecurityDescriptorDacl(pSD, &fDaclPresent, &pAcl,

&fDaclDefaulted))

{

printf("ModifySecurity GetSecurityDescriptorDacl Failed");

__leave;

}

// Get the current user's name

TCHAR szName[1024];

DWORD dwLen = chDIMOF(szName);

if (!GetUserName(szName, &dwLen))

{

printf("ModifySecurity GetUserName Failed");

__leave;

}

// Build an EXPLICIT_ACCESS structure for the ace we wish to add.

EXPLICIT_ACCESS ea;

BuildExplicitAccessWithName(&ea, szName, dwAccess, GRANT_ACCESS, 0);

ea.Trustee.TrusteeType = TRUSTEE_IS_USER;

// We are allocating a new ACL with a new ace inserted. The new

// ACL must be LocalFree'd

if(ERROR_SUCCESS != SetEntriesInAcl(1, &ea, pAcl, &pNewAcl))

{

printf("ModifySecurity SetEntriesInAcl Failed");

pNewAcl = NULL;

__leave;

}

// Find the buffer sizes we would need to make our SD absolute

pAcl = NULL;

dwSDLength = 0;

DWORD dwAclSize = 0;

DWORD dwSaclSize = 0;

DWORD dwSidOwnLen = 0;

DWORD dwSidPrimLen = 0;

PSECURITY_DESCRIPTOR pAbsSD = NULL;

if(MakeAbsoluteSD(pSD, pAbsSD, &dwSDLength, pAcl, &dwAclSize, pSacl,

&dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen)

|| (GetLastError() != ERROR_INSUFFICIENT_BUFFER))

{

printf("ModifySecurity MakeAbsoluteSD Size Failed");

__leave;

}

// Allocate the buffers

pAcl = (PACL) LocalAlloc(LPTR, dwAclSize);

pSacl = (PACL) LocalAlloc(LPTR, dwSaclSize);

pSidOwner = (PSID) LocalAlloc(LPTR, dwSidOwnLen);

pSidPrimary = (PSID) LocalAlloc(LPTR, dwSidPrimLen);

pAbsSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, dwSDLength);

if(!(pAcl && pSacl && pSidOwner && pSidPrimary && pAbsSD))

{

printf("ModifySecurity Invalid SID Found");

__leave;

}

// And actually make our SD absolute

if(!MakeAbsoluteSD(pSD, pAbsSD, &dwSDLength, pAcl, &dwAclSize, pSacl,

&dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen))

{

printf("ModifySecurity MakeAbsoluteSD Failed");

__leave;

}

// Now set the security descriptor DACL

if(!SetSecurityDescriptorDacl(pAbsSD, fDaclPresent, pNewAcl,

fDaclDefaulted))

{

printf("ModifySecurity SetSecurityDescriptorDacl Failed");

__leave;

}

// And set the security for the object

if(!SetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pAbsSD))

{

printf("ModifySecurity SetKernelObjectSecurity Failed");

__leave;

}

fSuccess = TRUE;

}

__finally

{

// Cleanup

if (pNewAcl == NULL)

LocalFree(pNewAcl);

if (pSD == NULL)

LocalFree(pSD);

if (pAcl == NULL)

LocalFree(pAcl);

if (pSacl == NULL)

LocalFree(pSacl);

if (pSidOwner == NULL)

LocalFree(pSidOwner);

if (pSidPrimary == NULL)

LocalFree(pSidPrimary);

if(!fSuccess)

{

printf("ModifySecurity exception caught in __finally");

}

return(fSuccess);

}

}

HANDLE GetLSAToken()

{

HANDLE hProc = NULL;

HANDLE hToken = NULL;

BOOL bSuccess = FALSE;

__try

{

// Enable the SE_DEBUG_NAME privilege in our process token

if (!EnablePrivilege(SE_DEBUG_NAME))

{

printf("GetLSAToken EnablePrivilege Failed");

__leave;

}

// Retrieve a handle to the "System" process

hProc = OpenSystemProcess();

if(hProc == NULL)

{

printf("GetLSAToken OpenSystemProcess Failed");

__leave;

}

// Open the process token with READ_CONTROL and WRITE_DAC access. We

// will use this access to modify the security of the token so that we

// retrieve it again with a more complete set of rights.

BOOL fResult = OpenProcessToken(hProc, READ_CONTROL | WRITE_DAC,

&hToken);

if(FALSE == fResult)

{

printf("GetLSAToken OpenProcessToken Failed");

__leave;

}

// Add an ace for the current user for the token. This ace will add

// TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY rights.

if (!ModifySecurity(hToken, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY

| TOKEN_QUERY | TOKEN_ADJUST_SESSIONID))

{

printf("GetLSAToken ModifySecurity Failed");

__leave;

}

// Reopen the process token now that we have added the rights to

// query the token, duplicate it, and assign it.

fResult = OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE

| TOKEN_ASSIGN_PRIMARY | READ_CONTROL | WRITE_DAC, &hToken);

if (FALSE == fResult)

{

printf("GetLSAToken OpenProcessToken Failed");

__leave;

}

bSuccess = TRUE;

}

__finally

{

// Close the System process handle

if (hProc != NULL) CloseHandle(hProc);

if(bSuccess)

return hToken;

else

{

::CloseHandle(hToken);

return NULL;

}

}

}

#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \

DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \

DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \

DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)

#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \

WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \

WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \

WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | \

WINSTA_READSCREEN | \

STANDARD_RIGHTS_REQUIRED)

#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)

BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid);

BOOL AddAceToDesktop(HDESK hdesk, PSID psid);

BOOL GetLogonSID(HANDLE hToken, PSID *ppsid)

{

PWTS_PROCESS_INFO pProcessInfo = NULL;

DWORD ProcessCount = 0;

BOOL ret=FALSE;

if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pProcessInfo, &ProcessCount))

{

// dump each process description

for (DWORD CurrentProcess = 0; CurrentProcess < ProcessCount; CurrentProcess++)

{

if( strcmp(pProcessInfo[CurrentProcess].pProcessName, "System") == 0 )

{

//*ppsid = pProcessInfo[CurrentProcess].pUserSid;

DWORD dwLength = GetLengthSid(pProcessInfo[CurrentProcess].pUserSid);

*ppsid = (PSID) HeapAlloc(GetProcessHeap(),

HEAP_ZERO_MEMORY, dwLength);

if (*ppsid == NULL)

break;

if (!CopySid(dwLength, *ppsid, pProcessInfo[CurrentProcess].pUserSid))

{

HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);

break;

}

ret=TRUE;

break;

}

}

WTSFreeMemory(pProcessInfo);

}

return ret;

}

BOOL GetLogonSID_1 (HANDLE hToken, PSID *ppsid)

{

BOOL bSuccess = FALSE;

DWORD dwIndex;

DWORD dwLength = 0;

PTOKEN_GROUPS ptg = NULL;

// Verify the parameter passed in is not NULL.

if (NULL == ppsid)

goto Cleanup;

// Get required buffer size and allocate the TOKEN_GROUPS buffer.

if (!GetTokenInformation(

hToken, // handle to the access token

TokenGroups, // get information about the token's groups

(LPVOID) ptg, // pointer to TOKEN_GROUPS buffer

0, // size of buffer

&dwLength // receives required buffer size

))

{

if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)

goto Cleanup;

ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),

HEAP_ZERO_MEMORY, dwLength);

if (ptg == NULL)

goto Cleanup;

}

// Get the token group information from the access token.

if (!GetTokenInformation(

hToken, // handle to the access token

TokenGroups, // get information about the token's groups

(LPVOID) ptg, // pointer to TOKEN_GROUPS buffer

dwLength, // size of buffer

&dwLength // receives required buffer size

))

{

goto Cleanup;

}

// Loop through the groups to find the logon SID.

for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)

if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)

== SE_GROUP_LOGON_ID)

{

// Found the logon SID; make a copy of it.

dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);

*ppsid = (PSID) HeapAlloc(GetProcessHeap(),

HEAP_ZERO_MEMORY, dwLength);

if (*ppsid == NULL)

goto Cleanup;

if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))

{

HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);

goto Cleanup;

}

break;

}

bSuccess = TRUE;

Cleanup:

// Free the buffer for the token groups.

if (ptg != NULL)

HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);

return bSuccess;

}

VOID FreeLogonSID (PSID *ppsid)

{

HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);

}

BOOL StartInteractiveClientProcess (

LPTSTR lpszUsername, // client to log on

LPTSTR lpszDomain, // domain of client's account

LPTSTR lpszPassword, // client's password

LPTSTR lpCommandLine, // command line to execute

HANDLE Token = NULL

)

{

HANDLE hToken;

HDESK hdesk = NULL;

HWINSTA hwinsta = NULL, hwinstaSave = NULL;

PROCESS_INFORMATION pi;

PSID pSid = NULL;

STARTUPINFO si;

BOOL bResult = FALSE;

// Log the client on to the local computer.

if(Token!=NULL)

{

printf("%08x\n", Token);

hToken = Token;

}

else if (!LogonUser(

lpszUsername,

lpszDomain,

lpszPassword,

LOGON32_LOGON_INTERACTIVE,

LOGON32_PROVIDER_DEFAULT,

&hToken) )

{

goto Cleanup;

}

// Save a handle to the caller's current window station.

if ( (hwinstaSave = GetProcessWindowStation() ) == NULL)

goto Cleanup;

// Get a handle to the interactive window station.

hwinsta = OpenWindowStation(

"winsta0", // the interactive window station

FALSE, // handle is not inheritable

READ_CONTROL | WRITE_DAC); // rights to read/write the DACL

if (hwinsta == NULL)

goto Cleanup;

// To get the correct default desktop, set the caller's

// window station to the interactive window station.

if (!SetProcessWindowStation(hwinsta))

goto Cleanup;

// Get a handle to the interactive desktop.

hdesk = OpenDesktop(

"default", // the interactive window station

0, // no interaction with other desktop processes

FALSE, // handle is not inheritable

READ_CONTROL | // request the rights to read and write the DACL

WRITE_DAC |

DESKTOP_WRITEOBJECTS |

DESKTOP_READOBJECTS);

// Restore the caller's window station.

if (!SetProcessWindowStation(hwinstaSave))

goto Cleanup;

if (hdesk == NULL)

goto Cleanup;

// Get the SID for the client's logon session.

if (!GetLogonSID(hToken, &pSid))

goto Cleanup;

// Allow logon SID full access to interactive window station.

if (! AddAceToWindowStation(hwinsta, pSid) )

goto Cleanup;

// Allow logon SID full access to interactive desktop.

if (! AddAceToDesktop(hdesk, pSid) )

goto Cleanup;

// Impersonate client to ensure access to executable file.

if (! ImpersonateLoggedOnUser(hToken) )

goto Cleanup;

// Initialize the STARTUPINFO structure.

// Specify that the process runs in the interactive desktop.

ZeroMemory(&si, sizeof(STARTUPINFO));

si.cb= sizeof(STARTUPINFO);

si.lpDesktop = TEXT("winsta0\\default"); //You can use EnumWindowStations to enum desktop

// Launch the process in the client's logon session.

bResult = CreateProcessAsUser(

hToken, // client's access token

NULL, // file to execute

lpCommandLine, // command line

NULL, // pointer to process SECURITY_ATTRIBUTES

NULL, // pointer to thread SECURITY_ATTRIBUTES

FALSE, // handles are not inheritable

NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags

NULL, // pointer to new environment block

NULL, // name of current directory

&si, // pointer to STARTUPINFO structure

&pi // receives information about new process

);

// End impersonation of client.

RevertToSelf();

goto Cleanup;

//return bResult; <------------------------------------------------------------------------

if (bResult && pi.hProcess != INVALID_HANDLE_VALUE)

{

WaitForSingleObject(pi.hProcess, INFINITE);

CloseHandle(pi.hProcess);

}

if (pi.hThread != INVALID_HANDLE_VALUE)

CloseHandle(pi.hThread);

Cleanup:

if (hwinstaSave != NULL)

SetProcessWindowStation (hwinstaSave);

// Free the buffer for the logon SID.

if (pSid)

FreeLogonSID(&pSid);

// Close the handles to the interactive window station and desktop.

if (hwinsta)

CloseWindowStation(hwinsta);

if (hdesk)

CloseDesktop(hdesk);

// Close the handle to the client's access token.

if (hToken != INVALID_HANDLE_VALUE)

CloseHandle(hToken);

return bResult;

}

BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid)

{

ACCESS_ALLOWED_ACE *pace;

ACL_SIZE_INFORMATION aclSizeInfo;

BOOL bDaclExist;

BOOL bDaclPresent;

BOOL bSuccess = FALSE;

DWORD dwNewAclSize;

DWORD dwSidSize = 0;

DWORD dwSdSizeNeeded;

PACL pacl;

PACL pNewAcl;

PSECURITY_DESCRIPTOR psd = NULL;

PSECURITY_DESCRIPTOR psdNew = NULL;

PVOID pTempAce;

SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;

unsigned int i;

__try

{

// Obtain the DACL for the window station.

if (!GetUserObjectSecurity(

hwinsta,

&si,

psd,

dwSidSize,

&dwSdSizeNeeded)

)

if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)

{

psd = (PSECURITY_DESCRIPTOR)HeapAlloc(

GetProcessHeap(),

HEAP_ZERO_MEMORY,

dwSdSizeNeeded);

if (psd == NULL)

__leave;

psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(

GetProcessHeap(),

HEAP_ZERO_MEMORY,

dwSdSizeNeeded);

if (psdNew == NULL)

__leave;

dwSidSize = dwSdSizeNeeded;

if (!GetUserObjectSecurity(

hwinsta,

&si,

psd,

dwSidSize,

&dwSdSizeNeeded)

)

__leave;

}

else

__leave;

// Create a new DACL.

if (!InitializeSecurityDescriptor(

psdNew,

SECURITY_DESCRIPTOR_REVISION)

)

__leave;

// Get the DACL from the security descriptor.

if (!GetSecurityDescriptorDacl(

psd,

&bDaclPresent,

&pacl,

&bDaclExist)

)

__leave;

// Initialize the ACL.

ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));

aclSizeInfo.AclBytesInUse = sizeof(ACL);

// Call only if the DACL is not NULL.

if (pacl != NULL)

{

// get the file ACL size info

if (!GetAclInformation(

pacl,

(LPVOID)&aclSizeInfo,

sizeof(ACL_SIZE_INFORMATION),

AclSizeInformation)

)

__leave;

}

// Compute the size of the new ACL.

dwNewAclSize = aclSizeInfo.AclBytesInUse + (2*sizeof(ACCESS_ALLOWED_ACE)) + (2*GetLengthSid(psid)) - (2*sizeof(DWORD));

// Allocate memory for the new ACL.

pNewAcl = (PACL)HeapAlloc(

GetProcessHeap(),

HEAP_ZERO_MEMORY,

dwNewAclSize);

if (pNewAcl == NULL)

__leave;

// Initialize the new DACL.

if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))

__leave;

// If DACL is present, copy it to a new DACL.

if (bDaclPresent)

{

// Copy the ACEs to the new ACL.

if (aclSizeInfo.AceCount)

{

for (i=0; i < aclSizeInfo.AceCount; i++)

{

// Get an ACE.

if (!GetAce(pacl, i, &pTempAce))

__leave;

// Add the ACE to the new ACL.

if (!AddAce(

pNewAcl,

ACL_REVISION,

MAXDWORD,

pTempAce,

((PACE_HEADER)pTempAce)->AceSize)

)

__leave;

}

}

}

// Add the first ACE to the window station.

pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(

GetProcessHeap(),

HEAP_ZERO_MEMORY,


www.CLDE.net




网站首页 - 友情链接 - 公司简介 - 联系方式 - 广告投放 - 客户服务 - 错误报告 - 免责声明 - About us
CLDE.NET电脑教程中文网版权所有 未经许可禁止镜象和复制本站资料 MSN:CLDE_NET@hotmail.com
技术支持:CLDE.NET信息中心 鲁ICP备05039940号 友情链接QQ:784079(隐)