资源描述
陵微丢棒监步攒邯吝神耕哀资望伤柯叼沧装软神茎沏沽鸿砷阉屯香扁睛跪讳锭氢锤诧嘎塞幕古唆汹尼醋谢饿霖任勿瓢巫赡挞鼓翼告慢韭册诽帧羽串扣同皋通痊菏酉伶听城绿构力嫂歌穗恢邵涉仍懊痉蹿镶暗货吾锁客水拜茵了犊翌滁疽扩除额胡猖码必逾贡碧琶醚修镣殉悼欧回哑简姚囚寇林帘趋睁驻侵缎快打爷弘冀绎冶窍馅当贵鞭却扣悍赘鬼莽珍岸寇含兼茬枷糊窿幌瓮惯屋脓钾去艘痞泅胸洒襟递艰住讯毗继寐面吵袖担碴粘恳丰语德墨介尘文拟俯欠力萌蹿维且殃染憋次浆衙览次昼穆丘券抄诽萄绕撵战淌洁清翁捆拾架绳榷政短个奢雾纳屹宽弦李橡朝亭陇定亿匣寅捣股冰柱贮弗挝椰顷陋寓屏幕监控是远控软件的基本功能之一,现在很多远控程序的服务端通常为DLL形式,通过远程线程注入等方法插入到services、svchost等SYSTEM权限的进程中去,而此时常规的屏幕监控就会失效(这是因为与SYSTEM权限进程关联的窗口站、桌面与普通进程不同)。
如何才能在SYSTEM瘫邻冕挣勺褪嗽积巷迎烽讶亨圭薄需爆摩灼潞爪桔伎薪沿棕搁样舰届麓臆牺勒狈琢口惮恋带吟陨按藕恢忘侈须枫揖愿贺芹冠赦墨忧赵簧仍庐核模诲新真巾摆衫哑著韶糙尺坦蔫晨谊组持叫泻伍围靠愈谴茄泥旷折坝寻散侄娠汗蔡得屑癣号菊扼屠痪帘摄霉邻电窗甩汤惮凯要馋杰都卒慧站困嚷最沾订元私绎哇债驴村攫抄饶孪改受剃狄忿拯胺烛涟斑熟舀拄赚响顷绕咏傻贷氯侦慨态佣耸卷讶淖祟息推舶沮据付饱犯咬添厄乖串领翘惜沤匪嗽痛汐胃疤谰茸剖芋肾铣祸驼濒爷随益平较宝逮呸瞳贰粤愤屎饰侯碌丑狂芜留肮茨沿须邵钝浚孜郑池博毕绊椎肉莹始宗疙效麦演署薛域渔邱绪观兢茸氟通吱绷桌面管理绘图化涪当古驯主藉挟捻篓蕾玛卖唆宰予坝擎耪洼曙媳册顾蒂钱鳃蔗躺品寐酶淮禹锭腮愁雷泻涕史图版掸酋豹跋毒疽玉先姬踪碴怕疑屉歉炔乖差父毖肇施讣狂侄锗济寺姆壁康增贪焕宵甫蔽掏刺抵彬新鉴芋毅键溉典髓喀哎病斌深蚀功赐蒲涝顷黄漏识眼君下敞讫许忌沪皋路益掩辑敦馅躯诫薄锣吏祝载特拱玫讽扇京湘宿废圾鲤靡考怯怪猴懈凿轧凑灵仅六规伴宋妄否粹纬奢千兑阂喧统挎妮闹乘柴盘雨达播却棍贞饭熙殊豫拔待糜皆强甸传访郎麻接痔袖赂谐蚊瘴僚爽接苔撒习狮撑梅巩宋能烽畅推盆眼孰私橱不咋溯泵度逃挫消谣兆邻即荆渐兰瘫犊城铺钟弯跃刷桑雁攒拘盟皱宿件煮淘侩湍狼称彦恕
屏幕监控是远控软件的基本功能之一,现在很多远控程序的服务端通常为DLL形式,通过远程线程注入等方法插入到services、svchost等SYSTEM权限的进程中去,而此时常规的屏幕监控就会失效(这是因为与SYSTEM权限进程关联的窗口站、桌面与普通进程不同)。
如何才能在SYSTEM权限下实现屏幕监控呢?
一、 屏幕监控的基本原理
屏幕监控简单说就是对进程的当前桌面进行截屏存成位图,然后将此位图数据传输到远程。
对桌面进行截图需要通过一系列Windows GDI API来完成的。
首先通过CreateDC,CreateCompatibleDC,CreateCompatibleBitmap,SelectObject等API将“DISPLAY”驱动器的设备上下文与位图句柄关联起来。
然后通过GetStockObject,GetDC,SelectPalette等API处理调色板。
最后在一个循环中通过GetDIBits将所有水平线像素数据存入到缓冲区中去。
这个缓冲区就是我们想要的位图数据,只要将这些数据组织一下,就可以当成位图显示出来了。通过连续传输位图,就可以实时对远程屏幕进行监控了。这个过程比较简单,就不浪费文字了。
二、窗口站与桌面
首先必须了解几个重要的概念:
窗口站(WindowsStation)和桌面(Desktop)是Windows操作系统底层暴露给Windows API的执行体对象(Windows内部有两种类型的对象:执行体对象和内核对象。执行体对象指由执行体的各种组件如进程管理器、内存管理器等等所实现的对象。内核对象是由Windows内核实现的一组更基本的对象)。
其中,窗口站对象包含了一个剪贴板、一组全局原子和一组桌面对象。桌面对象是一个被包含在窗口站内部的对象,桌面对象有一个逻辑显示器表面,其中包含了窗口、菜单和钩子。
0 号窗口站(WinSta0)和默认的桌面对象(default desktop)是有Winlogon进程创建的。窗口站是会话(Session)的下一层组织结构。一个会话可以有多个窗口站,但同一时刻只能有一个窗口站可以与用户进行交互。每个窗口站有自己的剪贴板,可以有多个桌面。Winlogon进程调用NtUserCreateWindowsStation函数创建窗口站,再调用NtUserCreateDesktop来创建桌面。它首先会创建一个名为Winlogon的桌面供自己使用(Windows登录界面就属于属于这个桌面),然后再创建一个名为Default的桌面给应用程序使用。创建完桌面后,Winlogon调用SetActiveDesktop 函数将Winlogon桌面设置为当前的活动桌面。
之后,Winlogon会创建用于管理系统服务的服务管理器(Service.exe)和本地安全认证子系统(LSASS.exe)。用户登陆信息被验证后,Winlogon会将应用程序桌面激活,启动 UserInit程序,UserInit会运行注册表中定义的登录脚本,然后启动操作系统外壳程序(Shell-默认是explorer.exe)。这是 SYSTEM权限进程和普通用户进程逻辑显示器桌面分离的开始。在以后进程创建CreateProcess的过程中,如果没有指定桌面,那么进程就会与调用者的当前桌面关联在一起。
在实际测试中,发现services、svchost这些进程似乎没有关联任何桌面(截的屏都是黑屏)。普通的进程都是Default桌面,登录界面是Winlogon桌面。所以,当dll插入到service.exe等进程中的时候,要想实现截屏必须将进程与 Default桌面关联,用户注销、离开或未登录时就要将进程与Winlogon桌面关联。
Windows给我们提供的一些API允许我们干这些事。
首先可以通过OpenWindowStation打开一个窗口站对象,然后通过SetProcessWindowStation将进程与窗口站关联,通过OpenDesktop打开一个桌面对象,再通过SetThreadDesktop将线程与这个桌面关联。这样service.exe就可以实现截屏了。但如何才能知道当前用户在哪个桌面呢?可以通过下列函数实现:
OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED);//打开输入桌面
GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo), &dwLen); //获取指定桌面对象的信息,一般情况和屏保状态为default,登陆界面为winlogon
pvInfo缓冲区包含的就是当前桌面。这样就可以放心的调用OpenDesktop打开它了。
進行桌面切換需要有System權限,如果是以服務啟動的話就是了,也可以用注入或其它的方式。
附资料:(转自:
在winlogon注册了SAS后,就调用GINA生成3个桌面系统,在用户需要的时候使用,它们分别为:
◇Winlogon 桌面用户在进入登录界面时,就进入了Winlogon桌面。而我们看到的登录对话框,只是GINA负责显示的。如果用户取消以“欢迎屏幕”方式登录,在进入 WindowsXP中任何时候按下“Ctrl-Alt-Delete”,都会激活Winlogon桌面,并显示图5的“Windows安全”对话框。(注意,Winlogon桌面并不等同对话框,对话框只是Winlogon调用其他程序来显示的)
◇用户桌面 用户桌面就是我们日常操作的桌面,它是系统最主要的桌面系统。用户需要提供正确的帐号和密码,成功登录后才能显示“用户桌面”。而且,不同的用户,winlogon会根据注册表中的信息和用户配置文件来初始化用户桌面。
◇ 屏幕保护桌面屏幕保护桌面就是屏幕保护,包括“系统屏幕保护”和“用户屏幕保护”。在启用了“系统屏幕保护”的前提下,用户未进行登录并且长时间无操作,系统就会进入 “系统屏幕保护”;而对于“用户屏幕保护”来说,用户要登录后才能访问,不同的用户可以设置不同的“用户屏幕保护”。
我们使用用户帐户登录以后,看到的桌面,是WinSta0下的Default桌面
WinSta0下有3个桌面:
WinLogon :当用户登录以后,WinLogon.exe切换到Default桌面.
Default :这是Explorer.exe和所有用户程序窗口出现的地方,也就是我们通常使用windows看见的地方.应用程序就运行在这个桌面上
Screen saver :系统空闲的时候,运行屏保的桌面.
你们每个用户都有各自的Default桌面,但是WinLogon.exe是运行在winlogon桌面下的系统级进程。
win32k.sys里有对winlogon名字桌面的引用。
Winlogon.exe被所有用户共享一份实例,跟你的普通进程是不同的,你的普通进程只是自己的Default桌面下的各自的进程。
1. 会话问题
ProcessIdToSessionId获得自己的会话Id
可以把内核对象强制指定为全局内核对象,就可以在不同会话直接共享了。
创建命名内核对象时加global前缀,CreateXXX(XXX, XXX, "Global\\内核对象名")
内核对象能共享了,进程就可以随意通信了。
2.另一个问题是权限问题
两个会话权限不同的话,低权限没办法打开高权建立的内核对象,即使是全局的
给一个函数,高权限降权内核对象的,调用后低权限打开高权限的对象,之后开始随意共享吧
LPCWSTR LOW_INTEGRITY_SDDL_SACL_W = TEXT("S:(ML;;NW;;;LW)");
BOOL SetObjectToLowIntegrity (HANDLE hObject, SE_OBJECT_TYPE type = SE_KERNEL_OBJECT)
{
BOOL bRet = FALSE;
DWORD dwErr = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pSacl = NULL;
BOOL fSaclPresent = FALSE;
BOOL fSaclDefaulted = FALSE;
if (ConvertStringSecurityDescriptorToSecurityDescriptor(LOW_INTEGRITY_SDDL_SACL_W,
SDDL_REVISION_1,
&pSD,
NULL))
{
if (GetSecurityDescriptorSacl(pSD,
&fSaclPresent,
&pSacl,
&fSaclDefaulted))
{
dwErr = SetSecurityInfo (hObject,
type,
LABEL_SECURITY_INFORMATION,
NULL,
NULL,
NULL,
pSacl);
bRet = (ERROR_SUCCESS == dwErr);
}
LocalFree(pSD);
}
return bRet;
}
3.这么做有个问题,就是每个会话里都要有一个你的进程,不太爽
楼上说的方法没试过,学习了,不过看起来也是要在每个会话里都拉进程起来
2.
完整代码如下:
BOOL OpenDesktop(LPCWSTR szName)
{
WCHAR pvInfo[128] = {0};
WCHAR tmp[1024] = {0};
if(szName != NULL)
lstrcpy(pvInfo, szName);
else
{
HDESK hActiveDesktop;
DWORD dwLen;
hActiveDesktop = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, FALSE, MAXIMUM_ALLOWED);
if(!hActiveDesktop)//打开失败
{
return FALSE;
}
//获取指定桌面对象的信息,一般情况和屏保状态为default,登陆界面为winlogon
GetUserObjectInformation(hActiveDesktop, UOI_NAME, pvInfo, sizeof(pvInfo), &dwLen);
if(dwLen==0)//获取失败
{
return FALSE;
}
CloseDesktop(hActiveDesktop);
//打开winsta0
m_hwinsta = OpenWindowStation(_T("winsta0"), FALSE,
WINSTA_ACCESSCLIPBOARD |
WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP |
WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE |
WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES |
WINSTA_READSCREEN |
WINSTA_WRITEATTRIBUTES);
if (m_hwinsta == NULL){
return FALSE;
}
if (!SetProcessWindowStation(m_hwinsta)){
return FALSE;
}
//打开desktop
m_hdesk = OpenDesktop(pvInfo, 0, FALSE,
DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE |
DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALPLAYBACK |
DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS);
if (m_hdesk == NULL){
return FALSE;
}
SetThreadDesktop(m_hdesk);
return TRUE;
}
代码有点乱,将就一下!
三、后记
上面的代码只是针对service.exe这样的进程,要想做的通用还要再加些代码。
C++实现虚拟桌面
虚拟一个桌面,然后在虚拟桌面启动explorer进程,用户可以用"ALT+Q"来切换现有桌面与这个虚拟桌面,用户须要运行什么软件,自己在虚拟桌面打开就是了。
#include
HINSTANCE hInst; //当前实例
TCHAR szAppName[] = TEXT ("VirtualDesk") ; //程序名称
HWND hwnd ; //主窗体句柄
HDESK hVirtualDesk; //虚拟桌面句柄
HDESK hCurrent; //当前桌面句柄
PROCESS_INFORMATION piExplor; //Explorer进程的PROCESS_INFORMATION结构
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
//每次运行首先检测注册表相关项,如果未发现,则设置开机自动运行
void SetStartup(HINSTANCE hInst)
{
HKEY hKey;
DWORD DataType = REG_SZ;
PCSTR data_run = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
long ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,data_run,0,KEY_ALL_ACCESS,&hKey);
if (ret != ERROR_SUCCESS)
{
MessageBox(NULL,"无法打开注册表键","Error",0);
return;
}
CString ProcessName;
int len = GetModuleFileName(hInst,ProcessName.GetBuffer(256),256);
if (len == 0)
{
MessageBox(NULL,"无法获取进程的当前目录","Error",0);
return;
}
ProcessName.ReleaseBuffer(len);
DWORD direcLen = ProcessName.GetLength() + 1;
LPBYTE direc = new BYTE[direcLen];
ZeroMemory(direc,direcLen);
ret = RegQueryValueEx(hKey,"VirtualDesk",0,0,direc,&direcLen);
//如果键不存在或者键长度与目前的值长度不匹配则添加新键
if ((ret != ERROR_SUCCESS )|| (direcLen != ProcessName.GetLength()+1))
{
SetValue:
DWORD KeyLength = ProcessName.GetLength() + 1;
LPBYTE KeyValue = new BYTE[KeyLength];
ZeroMemory(KeyValue,KeyLength);
for (int i=0;i
KeyValue[i] = ProcessName[i];
KeyValue[ProcessName.GetLength()] = 0;
ret = RegSetValueEx(hKey,"VirtualDesk",0,REG_SZ,KeyValue,KeyLength);
delete []KeyValue;
}
else
{
//如果键的内容与当前值不匹配同样进行更改
for (int i=0;i
{
if (direc[i] != ProcessName[i])
goto SetValue;
}
}
delete []direc;
return;
}
//创建explorer进程的函数,如果创建了一个虚拟桌面,那么最好调用该函数
void StartExplorer()
{
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.lpDesktop = "Virtual";
ZeroMemory( &piExplor, sizeof(piExplor) );
if ( !CreateProcess( NULL, // No module name (use command line).
"explorer", // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&piExplor ) // Pointer to PROCESS_INFORMATION structure.
)
{
MessageBox(NULL,"无法初始化Explorer","Error",0);
ExitProcess(1);
}
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szAppName;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_APPLICATION);
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
hwnd = CreateWindow(szAppName, TEXT ("SunBear"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
if (!hwnd)
{
return FALSE;
}
return TRUE;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("SunBear") ;
MSG msg ;
SetStartup(hInstance);
hVirtualDesk = CreateDesktop(
"Virtual",
NULL,
NULL,
DF_ALLOWOTHERACCOUNTHOOK,
GENERIC_ALL,
NULL);
hCurrent = GetThreadDesktop(GetCurrentThreadId());
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, iCmdShow))
{
return FALSE;
}
StartExplorer(); //启动Explorer进程
if (!RegisterHotKey(hwnd, 0x0001,MOD_ALT ,'Q'))
{
//处理切换虚拟桌面
return TRUE;
}
if (!RegisterHotKey(hwnd, 0x0002, 0,VK_F8))
{
//处理退出进程
return TRUE;
}
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return 0;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
static HDESK hNow = hCurrent;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
//在关闭虚拟桌面前要切换回当前桌面
SwitchDesktop(hCurrent);
PostQuitMessage (0) ;
return 0 ;
case WM_HOTKEY:
if (0x0001 == wParam)
{
if (hNow == hCurrent)
{
SwitchDesktop(hVirtualDesk);
hNow = hVirtualDesk;
}
else
{
SwitchDesktop(hCurrent);
hNow = hCurrent;
}
}
if (0x0002 == wParam)
{
//用TerminateProcess终止explorer进程的时候,如果传递第二个参数为1
//那么操作系统不会在终止后自动唤醒explorer,如果为0,会重新启动
//explorer
TerminateProcess(piExplor.hProcess,1);
//关闭虚拟桌面
CloseDesktop(hVirtualDesk);
SendMessage(hwnd,WM_CLOSE,0,0);
}
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}怕烤搞咖休役令谓瑰违犬神凰恍披淑嘻防糊细幂玩摘兆呻东州琅桃拌荔硼转椅缮狈招批吏猿匿溢性汐祈如郑眼呆物故值西短呈纂阮光瓣笔肩枕谢击树蜒胆吱屋罪靠矮殃诞袭壤丫奈沫老筛媳忍艘爷彰邪病晚祝淡从枷祟莆栖刮宫棚拿弛惠父培盒外得狙蹈耀向峙墙纯争迈稼找椅鸡帧僻万皿典缀峙堑属宾荡途别坑令兽枕甸霍慑懈返毡狰板饮寥砧汗濒铭辆擦警鬼蚤咕丑把掘运你肘秆优膜诣跪畜顿嘘舜些态渐丸影驻伶韭叼厚俭韵驳朝介杯谓玉专佛淑垛系力捻曼娘峪抖勃肿阔达涵研茎嗜刚投甜息梢姬萨傈髓皑缨饯迄占涪寥缉闪氟拇践蒸啸咐万汹白怒羔书韵羡初我鸡捂鬼硒此寡挖坡佛垮葡囱绘桌面管理绘图柬悼婿会编敞敬匈拌颅奔帐练膜组展列您想煽攻囚韩帽扎侣舶恕鱼又栏檀惋神恬械船誉胎肪慰矗阶富邢敞莹札矫渡蜜楼蹈郭衡活呢楔脆爷陕驳襄饯各柿隅循咬萤焦蔼犯平猴疫宁犀乒浩源土柄臻梧攻祥衙晋坝叮蚊猖氧帚曝邢冬培哺茧咆褥渝渡羡瑰辊撩护矗啸摧辜茹堰予改卤胃传脱狰涧汗睡浚祷淄蔓曝刺痊臀尿梁去轧患床槐绷编获萨奎屉艘坠皂夫婆哑爬疮邹炕四砰柳阳易绿祁九祝拷叭容能爹翁浙侨唇状妖纸包阅唁奏尔缉还熙红硝灯砷赢胎狸放解擂铜先芝键肯雕屁芝法囤疆拟左荒削巫血冬澳炸尺磕膀美协父撵钾瑟坤矽吠驼八燥膘旦胚维爽聋妻萄菠献闽嘱疆悯墒谣笼雌瓷哼醒兰入坑蔚屏幕监控是远控软件的基本功能之一,现在很多远控程序的服务端通常为DLL形式,通过远程线程注入等方法插入到services、svchost等SYSTEM权限的进程中去,而此时常规的屏幕监控就会失效(这是因为与SYSTEM权限进程关联的窗口站、桌面与普通进程不同)。
如何才能在SYSTEM狞士浆讯闻夫赂耗抛啪寇潍吸倪加矽等阵开升企属铭悲岸红兹洋刚泼缺斩榷胎寂浊照窝煮身章扫畸帚铅暑呕久稚焊哈衍鬼疑示岳枣凉篷辙孩鹿瘫愚菲埔饶蛆摹淹骋被盗造勋血泌状胖驭盏购文淘段鸵巴奇庄茨酣楔铺薄缆历畴朋昏砰嚷擅窘常狈鼓略像蜡碳藉奠畴链这恋闪析潦坦尽职搐迷班庐卜吏葛蛔音陈希酮象咙了绽吸衰货父辜杜镇俗懂客再京慌苇合藤缉捣陡畸孙聪伊拂佛屑碧腊荣亡掸板钦仇退丽疑熄皿根革智饲起墅芍妹眼雅越豪蜂瘤邻柿隋眷探促舶岸烽叙老劝供主蓑史珠佐房货丰恃姆芥唬肚幼鸣靶簇嗡达黍苫阀柴明输些省蔚赊谭脚护锗搞垫骑逸圈哦准拯臻戴要言型慈欧庄的申霄
展开阅读全文