青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++研究

C++細節深度探索及軟件工程

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  37 隨筆 :: 0 文章 :: 74 評論 :: 0 Trackbacks
[reference from MSDN , Author:Christophe Nasarre]

SUMMARY DLL conflict problems can be tough to solve, but a large number of tools are available to help. There are also many Windows APIs that you can use to build custom debugging tools. Three such tools are discussed here and provided as samples. DllSpy lists all the DLLs loaded in the system and the processes that are using them. ProcessSpy enumerates the running processes and exposes the DLLs they are using, and ProcessXP displays the list of concurrent running sessions for Windows XP.

DLL Hell is nothing new. When you rely upon DLLs from external sources, you can get all kinds of problems, like missing entry points or incompatible versions of the library. .NET allows side-by-side execution of components, alleviating these versioning problems, but if you're not yet deploying to .NET, what do you do? Well, you can trace DLL dependencies using a variety of tools. But when you use standard tools to trace this information, you might not get all the information you're after. And many tools don't provide functionality you need, like automatic logging, trace analysis, console-only operation, and scriptability.
I'll take a look at some of the available tools for examining running processes, and describe three I've developed: DllSpy, ProcessSpy, and ProcessXP, which can be used in your own debugging and development efforts.

The Existing Tools
Depends.exe is one tool that comes with Visual C++. Perhaps the simplest tool, it lists the DLLs that an application or another DLL needs. (Look at http://www.dependencywalker.com for updated versions.) If you need the full path of the DLLs and executables, simply right-click on the DLL name in the list or the tree and select Full Path from the context menu, as shown in Figure 1.
While tools like Depends.exe are fine for static dependencies (those constructed during the link process), except with profiling in newer versions, they are useless if you are using COM objects instantiated by the runtime or dynamically loading a DLL to call a particular function via LoadLibrary and GetProcAddress. You don't know when or from which folder this type of DLL will be loaded.
One way to identify dynamically loaded DLLs is to find out which DLL is loaded by each process. The SysInternals Web site, at http://www.sysinternals.com, provides LISTDLLS.EXE, a console-mode tool, and a GUI tool called Process Explorer that does this and much more (see Figure 2).
In addition to listing the DLLs used by a process, Process Explorer lets you know which kernel objects are consumed. Since version 3.11, Process Explorer has allowed you to easily detect the new or unused objects between two snapshots.
Occasionally, a DLL is loaded for a short period of time and then released before you can detect it using Process Explorer. When this happens, you need another kind of tool, which I'll discuss in my next article.
To navigate through processes and DLLs, you first need to know which processes are using each loaded DLL. You can use my sample program, DllSpy, to discover them (see Figure 3). In DllSpy an upper pane lists every loaded DLL and a lower pane enumerates the processes that are using the selected DLL.
My ProcessSpy tool exposes the opposite relationship between processes and DLLs (see Figure 4). It enumerates the running processes in the upper pane; the lower pane lists each DLL that is used by a selected process, focusing on the real load address rather than the preferred load address, and static rather than dynamic dependencies.
These tools are available in the code download (available at the link at the top of this article). If these don't meet your needs but you want something similar, you'll need to know how to get information about and enumerate running processes. Then you can list their modules, whether statically or dynamically loaded.

Getting the List of Running Processes
When you need to enumerate Win32® running processes, the three methods shown in Figure 5 are available. I won't discuss TOOLHELP32 since MSDN® provides a lot of sample code that uses its functions. Performance counters provide much more information than the processes list. They're invaluable if you need to fetch information from remote computers. If you always wanted to get a process list from another machine, you have your solution!
The process status API (PSAPI) is a useful tool that's available in the Microsoft Platform SDK. The CProcessList class in my sample file, Process.cpp, wraps PSAPI to get the process list. Once Refresh has been called, a process description can be retrieved from a process ID and easily enumerated using GetFirst and GetNext (see Figure 6). Refresh is implemented using EnumProcesses (found in PSAPI), as shown in Figure 7.
If you are still supporting 16-bit code for Windows®, such as the applications listed under ntvdm.exe by the TaskManager, enumerating processes is more involved. The Knowledge Base articles referenced at the beginning of this article can help you, as well as two Under the Hood columns by Matt Pietrek in the August 1998 and September 1998 issues of MSJ.

Getting Information About a Process
Once you have a list of the running processes, you'll need to get as much information as possible from each of them, based on their IDs returned by EnumProcesses, to build a useful tool. Using a process handle obtained by calling OpenProcess with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as a parameter, the AttachProcess method (in the CProcessList class in Process.cpp) creates the description shown in Figure 8.
A few details about AttachProcess require explanation. First, to avoid being statically linked with OS-specific DLLs such as PSAPI or NTDLL, it is worth writing classes that wrap each function needed from these DLLs. (See Wrappers.h and Wrappers.cpp in the sample code for details.) For example, you only need to define a CPSAPIWrapper object and call its GetModuleFileNameEx method; you don't need to link with the PSAPI library. In addition, you should call its IsValid method to check that these DLLs are usable on the system you are running. This allows your code to run on any Windows platform without raising a system error such as undefined links. But check the Windows version or the result from IsValid before using a particular feature. (See DllSpyApp::InitInstance in DllSpy.cpp for an example.)
Notice that the GetModuleFileNameEx function from PSAPI returns strange file names such as "\SystemRoot\ System32\ smss.exe" or "\??\C:\WINNT\system32\winlogon.exe." The TranslateFilename function (in Helpers.cpp) gives you file names that are easier to read. More on this later.
When it's time to find the main window of a process, EnumWindows executes the callback as a parameter for each top-level window. In the callback function, GetWindowThreadProcessId retrieves the ID of the process that creates the corresponding window; if this window is visible, I stop the enumeration (see the GetMainWindow implementation). Note that GetWindowText can be used to get the title of a window from a different process.
Conversely, to get the name of the file name corresponding to the process that created a particular window, you'll run into problems using GetWindowModuleFileName. This function always returns the path name of the current running process.
The procedure for getting the main window of a process (for which you can use the GetWindowThreadProcessId API) is described in Jeff Prosise's Wicked Code column in the August 1999 issue of MSJ. You know how to get the full path name from a process ID using PSAPI. Taking the full path name and using GetWindowThreadProcessID will get you the file name of a process that created a particular window.
In AttachProcess, the call to OpenProcess that is needed to get most of the process information may return with an access denied error. In that case, I used the method presented by Keith Brown in his August 1999 Security Briefs column in MSJ for getting a process handle with high-level rights. (See the GetProcessHandleWithEnoughRights function in Helpers.cpp in the code for implementation details.)
One example where this behavior occurs is when a process is run as a scheduled task under another user account. Even the Windows Task Manager can't terminate such a process; it merely displays the dialog box shown in Figure 9.

Figure 9 Can't Terminate Process
Figure 9 Can't Terminate Process

If you double-click on a process in my sample application ProcessSpy, it will be terminated. You should take a look at SlayProcess in the same project. This helper function uses GetProcessHandleWithEnoughRights to obtain a process handle, but with PROCESS_TERMINATE as an access right instead of PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, as is used by AttachProcess.
Finally, GetProcessOwner finds the user account (in \\Domain\User format) under which the process is running. It does this by using GetTokenInformation with TokenUser as a parameter and then LookupAccountSid to transform the returned user SID into a human-readable domain and user. Sometimes, OpenProcessToken fails with an access denied error for some process such as System. Even PULIST.EXE from the Windows 2000 Resource Kit fails to display the owning user for the same processes. Only ProcessExplorer succeeds in finding the owner of such "secured" applications. You'll see later in this article how the Windows Terminal Services API can be used to get the owner of these processes under Windows XP.

Getting the Command Line for a Process
One method in the list in Figure 8, GetCmdLine, returns the command line of the process. Actually, it doesn't exactly return the command line, but rather the parameters received by the process at startup. Let's take an example. If you install TweakUI from the Microsoft® Power Toys (http://www.microsoft.com/ntworkstation/downloads), you get an additional Command Prompt Here entry in the context menu when you right-click on any folder in the Windows Explorer. And as if by magic, a command prompt appears with the folder as the current working directory.
But how do you know what parameter is used when cmd.exe is called? You could use TLIST.EXE from the Microsoft Debugging Tools (see http://www.microsoft.com/ddk/debugging/) to find out. This is a console-mode program that lists the running processes and information such as the command line, if called with a process ID as a parameter, as shown in Figure 10 in the case of a C: root.
The third line in Figure 10 shows the parameters /k cd "C:\" used by the shell extension to call cmd.exe. If you specify the parameter /k, then cmd.exe carries out the specified command but it does not exit. This doesn't work if you are building your own tool because this invokes an application, whereas you need to call functions from an API.
The source code for the TLIST tool is available on the MSDN Web site at "TList: Task List Application Sample". Unfortunately, with that code you can only retrieve the ID, name, and main window for a process.
So you have three options for getting the command line of a process. The first is brutal: dig into TLIST at the assembly level. The result is the function GetProcessCmdLine in Process.cpp, which navigates inside the process address space to find its command line. A pointer to the command line (in Unicode) is stored in a memory block pointed to by a field of the Process Environment Block (PEB), a kernel data structure that I'll discuss in my next article.
The second solution is to browse the Web and find someone who has already solved the problem! GetCommandLine tells you the command line, but only for the calling process. The best way around this is to execute this call within another process context using CreateRemoteThread, which Felix Kasza explains at http://www.mvps.org/win32/processes/remthread.html.
The last option is code reuse. Or, to be more accurate, output reuse. You could catch the output from TLIST so you only have to parse it in order to get the command line. I'll explain this method more fully in my next article.

Getting Process Information with WTS APIs
Windows XP has a new feature called Fast User Switching, which allows several users to be logged on at the same time on the same machine. Processes launched by one user can still run while another user is logged in. The magic behind this feature lies in the Windows Terminal Services (WTS) APIs. If you need a broad explanation of WTS, you should take a look at "Introducing the Terminal Services APIs for Windows NT Server and Windows 2000" in the October 1999 issue of MSJ.
Windows XP creates an instance of a WTS session for each logged-on user. A running process is always associated with such a session. The Windows XP TaskManager allows you to list processes either for all sessions or for only your own session using the "Show processes for all users" checkbox (see Figure 11).

Figure 11 Listing Processes
Figure 11 Listing Processes

If you need to learn the session ID under which a process is attached, call the ProcessIdToSessionId API exported by kernel32.dll. When given a process ID, it returns the corresponding session ID. It is interesting to note that this API is not exported by wtsapi32.dll, which implements all other Windows Terminal Services APIs, but by kernel32.dll. In fact, even when Windows Terminal Services are not enabled, the session ID is stored by Windows 2000 and Windows XP in the PEB.
Note that Windows NT® neither stores the session ID in its PEB nor exports ProcessIdToSessionId in kernel32.dll. When you call ProcessIdToSessionId on Windows 2000 without WTS enabled, you get 0 as session ID for all processes.
In addition to allowing you to list the open sessions, WTS has an API to enumerate running processes that is different from those in PSAPI and TOOLHELP32. I have written a class named CWTSWrapper to wrap the functions related to processes and sessions in WTS in order to avoid static linking with wtsapi32.dll. (See \Common\wrappers.cpp for implementation details.) Using CWTSWrapper, it is easy to build a console mode application such as ProcessXP (see Figure 12) that enumerates open sessions with the corresponding logged-on user and the running processes.
As you can see in Figure 12, three sessions are open on the MACHINE computer. The first session has an ID of 0, is active (since this is the one where ProcessXP is running), and serves the logged-on user called Administrator. The second one has 1 as its ID, is disconnected, and serves the Standard user who has started Notepad and Freecell by hand. Finally, Player has opened the session 2 to launch WordPad, but it's now disconnected.
The source code that uses the CWTSWrapper class to generate this output can be found in the download for this article. Like the Registry, the WTS allows you to grab information from another machine. That's why WTS enumeration APIs take a server handle as the first parameter. WTS_CURRENT_SERVER_HANDLE is used for the current machine. The second parameter is reserved and should be set to 0. The third is the expected version and should be 1. The last two parameters contain the meaningful information on return. The last one is the count of sessions or processes, while the second to last points to an array of structures describing either a session or a process. Since the array has been allocated by WTS, you must remember to release it using WTSFreeMemory.
A session is described by a WTS_SESSION_INFO structure:
typedef  struct _WTS_SESSION_INFO
            {
            DWORD SessionId;
            LPTSTR pWinStationName;
            WTS_CONNECTSTATE_CLASS State;
            } WTS_SESSION_INFO, * PWTS_SESSION_INFO;
            
In addition to its SessionId, this structure provides the session name in the variable pWinStationName. The current session receives the name "console"; while the others have no name. The session state is WTSActive for the current session and WTSDisconnected for the others.
A process is described by a WTS_PROCESS_ INFO:
   typedef struct _WTS_PROCESS_INFO
            {
            DWORD SessionId;
            DWORD ProcessId;
            LPTSTR pProcessName;
            PSID pUserSid;
            } WTS_PROCESS_INFO, * PWTS_PROCESS_INFO;
            
The SessionId is the same value as the one retrieved by ProcessIdToSessionId. The ProcessId contains the ID of the process. The pProcessName field is a pointer to the name of the process under a Name.EXE format.
The last pUserSid field points to the security identifier describing the user account under which the process is running. Using LookupAccountSid, you can get the name of the user from pUserSid. This information is already retrieved by the CProcess class in GetProcessOwner, but through the process token instead of through WTS. In some cases, it is not possible to get a process token, even though WTSEnumerateProcesses manages to provide it, which could be a reason to use this WTS API under Windows XP instead of PSAPI or TOOLHELP32.

Enumerating Loaded Modules
At any given time, it is possible to know the list of the DLLs loaded by a process using either PSAPI or TOOLHELP32. While researching this article, I found that the TOOLHELP32 implementation from an old Under The Hood column by Matt Pietrek, presented in Figure 13, misbehaves under Windows 2000 and Windows XP. Two reasons: one, the invalid usage of the if statement, and two, this code was published in MSJ in September 1998—long before Windows 2000.
First, the following error handling code is not valid since CreateToolhelp32Snapshot does not return NULL when it fails:
if ( !hSnapshotModule )
            continue;
            
Actually, in case of failure, hSnapshotModule receives INVALID_HANDLE_VALUE or -1 as the value, and the if statement will not catch it. This is not a big deal. The interesting part is how the bug was found. When ProcessSpy was tested on Windows 2000, everything worked fine except that some processes were not returning an error even though the list was empty. Since the error handling code was wrong, the execution jumped to the loop and the Module32First call failed without any real error. If you use the ModuleList tool from this particular article on Windows 2000, you'll get incorrect results.
To understand what is happening in this code, a GetLastErrorMessage helper function is useful (see Helpers.cpp). It calls GetLastError and FormatMessage to get the corresponding failure reason in plain text. The reason will always be the same: Access Denied. With PSAPI functions, however, there is no access problem when getting the modules list of the same processes.
When the access problem does occur, it's due to a lack of privileges. The SE_DEBUG_NAME privilege needs to be enabled for the TOOLHELP32 code to work perfectly. For more information on this problem, see Win32 Q&A in the March 1998 issue of MSJ and Security Briefs in the August 1999 issue.

Everything You Want to Know About a DLL
Both the PSAPI and TOOLHELP32 solutions for getting the list of modules loaded in a process provide only the address where the DLL is mapped into the address space. The next step in this process is to get as complete a description as possible. My implementation does not offer a single AttachModule method as has been done in CProcess. Since some details can be really expensive to get, I chose to split the detail gathering into different functions. The cheapest are retrieved in the CModule constructor and the others are delayed (through a Refresh helper) until the corresponding accessor methods are called. Look in Module.cpp at the constructor of CModule and its Refresh method after the Refresh/RefreshTOOLHELP32 methods of CModuleList for the implementation details. Figure 14 provides a list of these accessors and explains how each of them are implemented.
As I mentioned, there is a trick to getting the full path name of a module. For some reason, the path names returned by GetModuleFilenameEx or the TOOLHELP32 module functions are very strange; they don't follow the Win32 standard. For example, smss is retrieved as "\SystemRoot\System32\smss.exe"; "\SystemRoot must be replaced by the actual name of the Windows folder. For winlogon, you get "\??\C:\WINNT\system32\winlogon.exe," which should be translated into "C:\WINNT\system32\winlogon.exe." The \??\ prefix might be a leftover from the Windows NT namespace root, essential in kernel mode, even though it is rarely used at the Win32 programming level. I wrote a TranslateFilename helper function to convert these file names into more standard names. The implementation of TranslateFilename is in Helpers.cpp in the code download.
I collect the rest of the module description with my Refresh method, whose implementation is in Module.cpp and is summed up in Figure 15. Most of the description is extracted from the file itself, using the PE format knowledge provided by Matt Pietrek's various articles.
If you want more details from a PE file, you should take a closer look at Matt Pietrek's PE_EXE class and PEDUMP implementation found in the articles referenced in the download. This code is a goldmine of handy ideas!
An interesting use of GetBaseAddress is to compare its return value with the one from GetModuleHandle. The latter is the real address where the module is loaded in the process address space and the former is where the module expects to be loaded. This is perfect for finding loading conflicts and they make ideal targets for rebasing, as Figure 4 illustrates. In that figure you can see that WinRAR shell extensions need to be rebased from 0x400000.
When a process starts, the Windows loader automatically loads the static DLLs. These static links are quite easy to get programmatically using the PE format and the MODULE_DEPENDENCY_LIST class. There is no API that detects the difference between this kind of module and those dynamically loaded using LoadLibrary or CoCreateInstance. If a DLL is used by a process, but is not among its static links, it should be dynamically loaded.
In ProcessSpy, each module in the lower pane is prefixed by a small icon, a round D for dynamic and square S for Static. The color is also significant: red for a module with a base address that is different from its load address and blue otherwise (see Figure 4).
The rest of the module description is extracted from its resource version. Paul DiLascia provides CModuleVersion as a nice wrapper class to these resource version descriptions in his April 1998 MSJ C++ Q&A column. For each VS_VERSION_INFO detail, an accessor method has been added. It returns a CString reference, filled by a call to CModuleVersion::GetFileVersion with the corresponding string. GetCompanyName is a perfect example of such an accessor.
I would have to update Paul DiLascia's code for it to fit my needs since the GetFileVersionInfo method is supposed to receive a module name but not a true file name. To find the corresponding file name, GetModuleHandle is called. If it fails to find the module in the current process address space (this is rarely the case), it bails out. To solve this problem, when the given module name proves to be a real file name (using GetFileAttributes), it is used directly.
The Windows resource information usually provides more details than simply the name of the company. For example, it is easy to know if an application has been built in debug mode or if it is a private or a special build. You just have to take a look at the dwFileFlags field in the VS_FIXEDFILEINFO structure. As the MSDN Online documentation states, it contains a bitmask of the values listed in Figure 16. In the same version structure, the dwFileType field defines the file type (see Figure 17). These flags are used in ProcessSpy to update the version column with D for Debug and P for a patched version as Figure 4 shows for dbgeng.dll and DBGHLP.dll.

Looking Ahead
In an upcoming issue of MSDN Magazine, I'll present unusual ways to get additional sources of information. What other means can be used when there is no API to help you? I haven't yet mentioned a great source of information: the shell. Under a module hides a file, and no one knows more about a file than Windows Explorer, as shown in Figure 18.

Figure 18 Using Explorer to Glean Info
Figure 18 Using Explorer to Glean Info

It would be great to be able to show the Properties pages that Windows Explorer provides when you select Properties from a right mouse click. See the Knowledge Base article Q179377, or use ShellExecuteEx, as shown in this code:
SHELLEXECUTEINFO sei;
            ZeroMemory(&sei,sizeof(sei));
            sei.cbSize = sizeof(sei);
            sei.lpFile = szFilename;
            sei.lpVerb = _T("properties");
            sei.fMask  = SEE_MASK_INVOKEIDLIST;
            ShellExecuteEx(&sei);
            
This is exactly what you get when you double-click on any module in the ProcessSpy lower pane. Windows XP does not support more than one call to ShellExecuteEx. On the second execution, the thread freezes without any explanation.
As you can see, there are many ways to get information about loaded DLLs and active processes. The tools I've developed are a good place to start to learn about loaded DLLs and active processes, but you may need to develop custom tools for your own debugging scenarios. If so, you'll want to experiment with the various options I've described in this article and use the C++ classes I've provided. In my next article I will present new ways to get information from the system.
For more information, see the articles I mentioned. A list of their URLs is included with the code download at the link at the top of this article.

For related articles see:
HOWTO: Enumerate Applications Using Win32 APIs
HOWTO: Use VDMDBG Functions on Windows NT, Windows 2000, and Windows XP
HOWTO: Terminate an Application "Cleanly" in Win32
Starting and Terminating Windows-Based Applications
HOWTO: Invoke the Shell's File Properties Dialog Box

For background information see:
Inside Windows 2000, Third Edition by David Solomon & Mark Russinovitch (Microsoft Press, 2000)

posted on 2007-06-05 00:09 常興龍 閱讀(1393) 評論(0)  編輯 收藏 引用
> hi的博客
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品一区久久久| 亚洲欧美精品suv| 国内精品伊人久久久久av一坑| 一区二区冒白浆视频| 久久资源av| 免费黄网站欧美| 久久偷看各类wc女厕嘘嘘偷窃| 在线一区欧美| 在线综合亚洲欧美在线视频| 亚洲国产另类 国产精品国产免费| 国产性色一区二区| 狠狠久久综合婷婷不卡| 国产精品久久综合| 国产裸体写真av一区二区| 国产精品成人va在线观看| 欧美三级日本三级少妇99| 欧美日韩综合一区| 国产午夜精品视频| 国产亚洲第一区| 亚洲欧洲日本mm| 欧美中文字幕视频在线观看| 在线观看91精品国产入口| 欧美国产精品劲爆| 亚洲一区尤物| 国产精品一区二区你懂的| 国产精品成人在线| 尤物在线观看一区| 中文成人激情娱乐网| 欧美中文字幕久久| 亚洲第一精品电影| 欧美国产日本高清在线| 亚洲一区二区三区777| 久久成年人视频| 国产精品久久久久久亚洲毛片| 国产婷婷色一区二区三区四区| 亚洲精品日韩在线观看| 亚洲男人天堂2024| 欧美日韩国产在线观看| 亚洲国产欧美一区二区三区久久 | 亚洲国产精品久久久久秋霞蜜臀 | 亚洲国产成人av| 午夜精品福利在线观看| 欧美性猛交99久久久久99按摩| 国产婷婷成人久久av免费高清 | 亚洲精品视频免费| 久久婷婷蜜乳一本欲蜜臀| 亚洲欧美国产制服动漫| 国产精品国产三级国产a| 亚洲日本一区二区| 亚洲日本成人网| 麻豆免费精品视频| 亚洲精品视频免费观看| 亚洲日本一区二区三区| 欧美日韩久久不卡| 欧美一区二区三区在线免费观看| 亚洲免费观看视频| 国产婷婷色一区二区三区四区 | 国产亚洲精品成人av久久ww| 亚洲一级片在线看| 久久国内精品自在自线400部| 中文一区在线| 怡红院精品视频| 一区二区高清| 亚洲高清中文字幕| 欧美一级大片在线观看| 亚洲激情一区二区三区| 亚洲一区二区三区精品在线观看| 欧美四级电影网站| 欧美激情第一页xxx| 国产精品男女猛烈高潮激情| 欧美激情视频一区二区三区在线播放| 欧美国产一区在线| 久久影院午夜片一区| 国产精品乱码一区二三区小蝌蚪 | 日韩写真在线| 久久国产精品久久久久久电车| 一本大道久久a久久精二百| 欧美在线在线| 久久视频在线看| 国产精品一香蕉国产线看观看| 亚洲免费激情| 亚洲毛片网站| 欧美三级网址| 一区二区三区视频观看| 亚洲一区二区三区视频播放| 欧美精品99| 亚洲午夜成aⅴ人片| 欧美一区二区大片| 国内精品美女av在线播放| 欧美一区二区三区播放老司机| 亚洲精品视频免费在线观看| 亚洲午夜黄色| 欧美日韩另类综合| 久久久精品日韩| 亚洲欧美久久久久一区二区三区| 一区在线视频| 欧美午夜电影一区| 久久精品国产第一区二区三区| 久久天天躁狠狠躁夜夜av| 黄网站免费久久| 欧美日韩亚洲一区二区三区在线观看 | 国产欧美日韩不卡免费| 久久九九精品| 亚洲九九爱视频| 亚洲第一福利在线观看| 欧美—级在线免费片| 99日韩精品| 欧美激情精品久久久久久免费印度| 亚洲免费黄色| 在线观看av一区| 国产一区二区在线免费观看| 欧美日韩国产小视频在线观看| 欧美一区1区三区3区公司| 亚洲欧洲精品一区二区三区不卡 | 亚洲欧美美女| 在线亚洲伦理| 亚洲另类在线视频| 亚洲国产精品久久精品怡红院| 久久国产视频网| 免费在线欧美黄色| 久久精品国产第一区二区三区最新章节| 亚洲另类在线视频| 亚洲精品四区| 亚洲精品国产精品乱码不99| 激情小说亚洲一区| 亚洲黄网站在线观看| 亚洲精品乱码视频| 亚洲精品欧洲精品| 午夜一区二区三区在线观看| 亚洲一级高清| 久久久久久午夜| 欧美成人免费小视频| 亚洲电影有码| 99在线精品视频在线观看| 亚洲综合第一页| 久久久xxx| 欧美成人综合| 国产亚洲欧美日韩一区二区| 黄色精品一区二区| 亚洲视频电影在线| 久热成人在线视频| 亚洲毛片播放| 女女同性精品视频| 国产日产精品一区二区三区四区的观看方式| 国产欧美一区二区色老头 | 美女黄毛**国产精品啪啪| 久久激情视频久久| 午夜精品久久久久久久久久久久久| 一区二区高清视频| 免费久久精品视频| 欧美一进一出视频| 欧美日韩无遮挡| 亚洲国产精品成人综合色在线婷婷| 亚洲一区激情| 亚洲黑丝在线| 米奇777超碰欧美日韩亚洲| 国产日韩免费| 亚洲免费视频网站| 亚洲综合第一页| 国产视频自拍一区| 久久精品视频播放| 欧美中文字幕不卡| 久久深夜福利免费观看| 欧美日韩国产黄| 亚洲国产清纯| 91久久久亚洲精品| 欧美日产一区二区三区在线观看| 尤物视频一区二区| 免费成人黄色av| 久久精品人人做人人综合| 曰本成人黄色| 亚洲精品女人| 欧美精品激情| 久久aⅴ国产紧身牛仔裤| 欧美日韩视频在线第一区| 亚洲影视在线| 国产精品美女久久久久aⅴ国产馆| 日韩五码在线| 这里是久久伊人| 国产欧美一区二区三区视频| 欧美成年人视频网站| 欧美午夜宅男影院在线观看| 久久露脸国产精品| 国产精品红桃| 亚洲精品日韩在线| 在线观看欧美| 午夜日本精品| 欧美一区久久| 国产精品你懂的在线| 亚洲黄页视频免费观看| 在线免费不卡视频| 久久精品一区二区三区四区 | 国产精品在线看| 99在线热播精品免费| 99视频热这里只有精品免费| 美女尤物久久精品| 欧美xxx在线观看| 国产丝袜一区二区| 久久激情五月丁香伊人| 久久婷婷丁香|