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

李錦俊(mybios)的blog

游戲開發 C++ Cocos2d-x OpenGL DirectX 數學 計算機圖形學 SQL Server

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  86 Posts :: 0 Stories :: 370 Comments :: 0 Trackbacks

公告

QQ:30743734
EMain:mybios@qq.com

常用鏈接

留言簿(16)

我參與的團隊

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 373919
  • 排名 - 67

最新評論

閱讀排行榜

評論排行榜

作者:任明漢

下載源代碼

前言

  你可能不希望在發布程序時附帶上一個外部的 DLL,因為可能會有些用戶在無意中把 DLL 刪除了而造成 EXE 不能正確運行,也有可能該 DLL 會被別人拿去使用,也有可能,此 DLL 會成為破解者破解你的程序的突破口。無論出于何種原因,如果你想把一個 DLL 合并到一個 EXE 中的話,本文向你介紹這種方法。


Win32 程序調用 DLL 的機制

   Win32 EXE 在調用一個外部 DLL 中的函數時,首先要調用 LoadLibary 函數來載入此 DLL 到程序的進程地址空間。 如果 LoadLibary 載入此 DLL 成功,將返回一個該 DLL 的句柄。 這個句柄實際上就是該 DLL 在內存中的起始地址。 在載入 DLL 成功后,還必須調用 GetProcAddress 函數來獲取要調用的函數的地址。然后再根據該地址來調用這個函數。
根據上述原理,我們可以把一個 DLL 作為資源文件放到 EXE 文件中,在程序運行時,分配一塊內存,然后將此資源復制到該分配的內存中,并根據該內存地址計算得到相關的導出函數地址,然后,當我們需要調用某一函數時,可以用該函數在內存中的地址來調用它。
程序實現。
  首先,把要合并的 DLL 作為資源加入到項目的資源文件中,然后在程序運行時,從資源中載入該資源,以得到該 DLL 在內存中的位置:
LPVOID sRawDll; // 資源文件在內存中的地址 
HRSRC hRes; 
HMODULE hLibrary; 
HGLOBAL hResourceLoaded; 
char lib_name[MAX_PATH]; 
GetModuleFileName(hInstance, lib_name, MAX_PATH ); // 得到運行程序的名字 
hLibrary = LoadLibrary(lib_name);                  // 就象載入一個 DLL 一樣載入運行程序到內存中 

if (NULL != hLibrary) 
{
	// 得到指定的資源文件在內存中的位置 
	hRes = FindResource(hLibrary, MAKEINTRESOURCE(IDR_DATA1), RT_RCDATA); 
	if (NULL != hRes) 
	{
		// 將資源文件載入內存 
		hResourceLoaded = LoadResource(hLibrary, hRes); 
		if (NULL != hResourceLoaded) 
		{
			// 得到資源文件大小 
			SizeofResource(hLibrary, hRes); 

			// 鎖定資源以得到它在內存中的地址 
			sRawDll = (LPVOID)LockResource(hResourceLoaded); 
		}
	}
	else return 1; 
	FreeLibrary(hLibrary);
}
else return 1; 
然后,從資源中載入 DLL 到內存函數 LoadPbDllFromMemory 將載入 DLL 到內存中, 該函數有兩個參數,第一個參數是指向 DLL 資源在內存中的地址的指針,也就是前面代碼中的 LockResource 函數的返回值。第二個參數是一個空的指針,如果函數 LoadPbDllFromMemory 運行成功,該指針將指向重新組合后的內存中的 DLL 的起始地址。該函數還有一個功能就是如果運行成功,它將手動地用 DLL_PROCESS_ATTACH 參數調用 DLL 的入口函數 DllMain 來初始化該 DLL。除此之外,它還會手動地載入合并的 DLL 的入口表中導入的 DLL 并調整它們在內存中的相對地址。以下是該函數代碼:
DWORD LoadPbDllFromMemory(LPVOID lpRawDll, LPVOID lpImageDll) 
{
	SYSTEM_INFO sSysInfo; 
	PIMAGE_DOS_HEADER dosHeader; 
	PIMAGE_NT_HEADERS pNTHeader; 
	PIMAGE_SECTION_HEADER section; 
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
	PIMAGE_IMPORT_BY_NAME pOrdinalName; 
	PIMAGE_BASE_RELOCATION baseReloc; 
	PDWORD lpLink; 
	unsigned char Protection[4096]; 
	HINSTANCE hDll; 
	WORD i; 
	DWORD ImagePages,fOldProtect,j,MaxLen,HdrLen,Addr1,Addr2,Pg,Pg1,Pg2; 
	char * sDllName; 

	if(NULL == lpRawDll) return 1 ; 

	dosHeader = (PIMAGE_DOS_HEADER)lpRawDll; 

	// Is this the MZ header? 
	if ((TRUE == IsBadReadPtr(dosHeader,sizeof (IMAGE_DOS_HEADER))) ||
				 (IMAGE_DOS_SIGNATURE != dosHeader->e_magic)) 
		return 2; 

	// Get the PE header. 
	pNTHeader = MakePtr(PIMAGE_NT_HEADERS,dosHeader,dosHeader->e_lfanew); 

	// Is this a real PE image? 
	if((TRUE == IsBadReadPtr(pNTHeader,sizeof ( IMAGE_NT_HEADERS))) || 
				( IMAGE_NT_SIGNATURE != pNTHeader->Signature)) 
		return 3 ; 

	if(( pNTHeader->FileHeader.SizeOfOptionalHeader != 
			sizeof(pNTHeader->OptionalHeader)) || 
		(pNTHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)) 
		return 4; 

	if (pNTHeader->FileHeader.NumberOfSections < 1) return 5; 

	section = IMAGE_FIRST_SECTION( pNTHeader ); 
	int HeaderSize = sizeof(IMAGE_SECTION_HEADER); 

	// 節頭長度 
	HdrLen = (DWORD)section - (DWORD)dosHeader + 
			HeaderSize * pNTHeader->FileHeader.NumberOfSections; 

	// 找出最大的節的長度,此節一般是代碼所在的節(.text 節) 
	MaxLen = HdrLen; 
	int ii=0; 

	for (i = 0;i<(DWORD)pNTHeader->FileHeader.NumberOfSections;i++)// find MaxLen 
	{
		if(MaxLen < section[i].VirtualAddress + section[i].SizeOfRawData) 
		{
			MaxLen = section[i].VirtualAddress + section[i].SizeOfRawData; 
		}
		if(strcmp((const char *)section[i].Name,".rsrc") == 0) ii=i; 
	}

	GetSystemInfo(&sSysInfo);
	ImagePages = MaxLen / sSysInfo.dwPageSize; 
	if (MaxLen % sSysInfo.dwPageSize) ImagePages++; 

	// 分配所需的內存 
	DWORD NeededMemory = ImagePages * sSysInfo.dwPageSize; 
	lpImageDll = VirtualAlloc(NULL, NeededMemory, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 

	if (lpImageDll == NULL) return 6; // 分配內存失敗 

	MoveMemory( lpImageDll, lpRawDll, HdrLen ); // 復制節頭 

	DWORD OrgAddr = 0; 
	DWORD NewAddr = 0; 
	DWORD Size = 0; 

	// 復制 .text 節數據 
	for (i = 0;i<pNTHeader->FileHeader.NumberOfSections;i++) 
	{
		OrgAddr = (DWORD)lpImageDll + (DWORD)section[i].VirtualAddress; 
		NewAddr = (DWORD)lpRawDll + (DWORD)section[i].PointerToRawData; 
		Size = (DWORD)section[i].SizeOfRawData; 
		MoveMemory((void *)OrgAddr, (void *)NewAddr, Size ); 
	}

	// 把指針指向新的 DLL 映像 
	dosHeader = (PIMAGE_DOS_HEADER) lpImageDll; // Switch to new image 
	pNTHeader = (PIMAGE_NT_HEADERS) ((DWORD)dosHeader + dosHeader->e_lfanew); 
	section = (PIMAGE_SECTION_HEADER) ((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS)); 
	pImageBase = (PBYTE)dosHeader; 

	if((ii!=0) && (IsNT()==TRUE)) 
	{
		section[ii].VirtualAddress = section[ii].VirtualAddress + (DWORD)lpRawDll; 
		section[ii].PointerToRawData = section[ii].PointerToRawData + (DWORD)lpRawDll; 
	}

	DWORD importsStartRVA; 

	// Look up where the imports section is (normally in the .idata section) 
	// but not necessarily so. Therefore, grab the RVA from the data dir. 
	importsStartRVA = GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_IMPORT); 
	if ( !importsStartRVA ) 
	{
		VirtualFree(dosHeader,0, MEM_RELEASE); 
		return 7; 
	}

	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) pNTHeader->
		OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 

	if(pImportDesc!= 0) 
		pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ((DWORD)pImportDesc + (DWORD)dosHeader); 
	else 
	{
		VirtualFree(dosHeader,0, MEM_RELEASE); 
		return 8; 
	}

	while (1) // 處理各入口表中的 DLL 
	{
		// 檢查是否遇到了空的 IMAGE_IMPORT_DESCRIPTOR 
		if ((pImportDesc->TimeDateStamp==0 ) && (pImportDesc->Name==0)) break; 

		// 從磁盤載入必須的 Dll, 
		// 注意,載入的 DLL 是合并的 DLL 的入口表中的 DLL, 
		// 不是合并到 EXE 中的 DLL 
		sDllName = (char *) (pImportDesc->Name + (DWORD)pImageBase); 
		hDll = GetModuleHandle(sDllName); 

		if (hDll == 0 ) hDll = LoadLibrary(sDllName); 

		if (hDll == 0 ) 
		{
			MessageBox(NULL, "Can''t find required Dll",
					"Error in LoadPbDllFromMemory()",0); 
			VirtualFree(dosHeader,0, MEM_RELEASE); 
			return 9; 
		}

		DWORD *lpFuncNameRef = (DWORD *) (pImportDesc->OriginalFirstThunk +
								 (DWORD)dosHeader); 
		DWORD *lpFuncAddr = (DWORD *) (pImportDesc->FirstThunk +
								 (DWORD)dosHeader); 

		while( *lpFuncNameRef != 0) 
		{
			pOrdinalName = (PIMAGE_IMPORT_BY_NAME) (*lpFuncNameRef +
						 (DWORD)dosHeader); 
			DWORD pIMAGE_ORDINAL_FLAG = 0x80000000; 

			if (*lpFuncNameRef & pIMAGE_ORDINAL_FLAG) 
				*lpFuncAddr = (DWORD) GetProcAddress(hDll,
					 (const char *)(*lpFuncNameRef & 0xFFFF)); 
			else
				*lpFuncAddr = (DWORD) GetProcAddress(hDll,
						 (const char *)pOrdinalName->Name); 

			if (lpFuncAddr == 0) 
			{
				VirtualFree(dosHeader,0, MEM_RELEASE); 
				return 10;// Can''t GetProcAddress 
			}

			lpFuncAddr++;
			lpFuncNameRef++;
		}
		pImportDesc++;
	}

	DWORD TpOffset; 
	baseReloc = (PIMAGE_BASE_RELOCATION)((DWORD)pNTHeader->
     OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 

	if (baseReloc !=0) 
	{
		baseReloc = (PIMAGE_BASE_RELOCATION) ((DWORD)baseReloc + (DWORD)dosHeader); 
		while(baseReloc->VirtualAddress != 0) 
		{
			PWORD lpTypeOffset = (PWORD) ((DWORD)baseReloc +
					 sizeof(IMAGE_BASE_RELOCATION)); 
			while (lpTypeOffset < (PWORD)((DWORD)baseReloc +
						 (DWORD)baseReloc->SizeOfBlock)) 
			{
				TpOffset = *lpTypeOffset & 0xF000; 
				if(TpOffset == 0x3000) 
				{
					lpLink = (PDWORD) ((DWORD)dosHeader +
                                   baseReloc->VirtualAddress +
                                                      (*lpTypeOffset & 0xFFF)); 
					*lpLink = (DWORD)dosHeader + 
                                            (*lpLink) - pNTHeader->OptionalHeader.ImageBase; 
				}
				else
				{
					if (TpOffset != 0) 
					{
						VirtualFree(dosHeader,0, MEM_RELEASE); 
						return 10; 
					}
				}
				lpTypeOffset++;
			}
			baseReloc = (PIMAGE_BASE_RELOCATION)((DWORD)baseReloc + 
				(DWORD)baseReloc->SizeOfBlock); 
		}
	}

	// 取得原始的內存狀態 
	memset(Protection,0,4096);
	for (i = 0;i<=pNTHeader->FileHeader.NumberOfSections;i++) 
	{
		if (i == pNTHeader->FileHeader.NumberOfSections) 
		{
			Addr1 = 0; 
			Addr2 = HdrLen; 
			j = 0x60000000; 
		}
		else
		{
			Addr1 = section[i].VirtualAddress; 
			Addr2 = section[i].SizeOfRawData; 
			j = section[i].Characteristics; 
		}
		Addr2 += Addr1 - 1; 

		Pg1 = Addr1 / sSysInfo.dwPageSize; 
		Pg2 = Addr2 / sSysInfo.dwPageSize; 
		for(Pg = Pg1 ;Pg<=Pg2;Pg++) 
		{
			if (j & 0x20000000) Protection[Pg] |= 1; // Execute 
			if (j & 0x40000000) Protection[Pg] |= 2; // Read 
			if (j & 0x80000000) Protection[Pg] |= 4; // Write 
		}
	}

	// 恢復原始的內存狀態 
	Addr1 = (DWORD)dosHeader; 
	for (Pg = 0 ;Pg<= ImagePages;Pg++) 
	{
		switch(Protection[Pg])
		{
		case 2: 
			fOldProtect = PAGE_READONLY; 
			break;
		case 3: 
			fOldProtect = PAGE_EXECUTE_READ; 
			break;
		case 6: 
			fOldProtect = PAGE_READWRITE; 
			break;
		default: 
			// Ignore strange combinations
			fOldProtect = PAGE_EXECUTE_READWRITE;  
			break;
		}

		if (fOldProtect !=PAGE_EXECUTE_READWRITE) 
		{
			if (VirtualProtect((void *)Addr1, 
				sSysInfo.dwPageSize, 
				fOldProtect,
				&fOldProtect) == 0) 
			{
				VirtualFree(dosHeader,0, MEM_RELEASE); 
				return 11; 
			}
		}
		Addr1 += sSysInfo.dwPageSize; 
	}

	EntryPoint = (LPENTRYPOINT) ((DWORD)pNTHeader->OptionalHeader.AddressOfEntryPoint +
				 (DWORD)dosHeader); 
	LPVOID lpReserved = 0; 
	EntryPoint((HINSTANCE)dosHeader, DLL_PROCESS_ATTACH, lpReserved); 
	lpImageDll2=lpImageDll;
	return 0; 
}
  一但 DLL 被正確地載入到內存中,我們就可以通過自定義函數 GetProcAddressDirectly 來獲取某函數在內存中的地址,并根據該地址來調用該函數,該函數也有兩個參數,第一個參數是指向載入到內存中的 DLL 的起始地址的指針,第二個是要調用的函數的函數名。以下是 GetProcAddressDirectly 函數代碼:
DWORD GetProcAddressDirectly(PIMAGE_DOS_HEADER dosHeader, char * FuncName)  
{ 
	PIMAGE_NT_HEADERS pNTHeader;  
	PIMAGE_EXPORT_DIRECTORY pExportDir;  
	PWORD lpNameOrdinals;  
	LPDWORD lpFunctions;  
	DWORD * lpName;  
	char * lpExpFuncName;  
	DWORD i;  
	DWORD j;  
	char * lpFuncName;  

	if(dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return 0;  

	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader->e_lfanew);  

	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) return 0;  

	if ((pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(pNTHeader->OptionalHeader)) ||  
		(pNTHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC))  
		return 0;  

	DWORD exportsStartRVA, exportsEndRVA;  
	pImageBase = (PBYTE)dosHeader;  

	// Make pointers to 32 and 64 bit versions of the header.  
	pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,dosHeader->e_lfanew );  

	exportsStartRVA = GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_EXPORT);  
	exportsEndRVA = exportsStartRVA +  
		GetImgDirEntrySize(pNTHeader, IMAGE_DIRECTORY_ENTRY_EXPORT);  

	// Get the IMAGE_SECTION_HEADER that contains the exports. This is  
	// usually the .edata section, but doesn''t have to be.  
	PIMAGE_SECTION_HEADER header;  
	header = GetEnclosingSectionHeader( exportsStartRVA, pNTHeader );  
	if ( !header ) return 0;  

	INT delta;  
	delta = (INT)(header->VirtualAddress - header->PointerToRawData);  
	pExportDir = (PIMAGE_EXPORT_DIRECTORY)GetPtrFromRVA(exportsStartRVA, 
				pNTHeader, pImageBase);  


	pExportDir =(PIMAGE_EXPORT_DIRECTORY) (pNTHeader->
	OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);  

	if (pExportDir == 0)  
	{ 
		MessageBox(NULL,"Error in GetProcAddressDirectly()",0,0);  
		return 0;  
	} 

	pExportDir =(PIMAGE_EXPORT_DIRECTORY) ((DWORD)pExportDir + (DWORD)dosHeader);  
	lpNameOrdinals =(PWORD)((DWORD)pExportDir->AddressOfNameOrdinals + (DWORD)dosHeader);  
	lpName =(LPDWORD) (pExportDir->AddressOfNames + (DWORD)dosHeader);  
	lpFunctions =(LPDWORD) (pExportDir->AddressOfFunctions + (DWORD)dosHeader);  
	lpFuncName = FuncName;  

	if(HIWORD(lpFuncName)!=0 )  
	{ 
		for( i = 0;i<=pExportDir->NumberOfFunctions - 1;i++)  
		{ 
			DWORD entryPointRVA = *lpFunctions;  

			// Skip over gaps in exported function  
			if ( entryPointRVA == 0 ) continue; 
			for( j = 0;j<=pExportDir->NumberOfNames-1;j++)  
			{ 
				if( lpNameOrdinals[j] == i)  
				{ 
					lpExpFuncName = (char *) (lpName[j] + 
							(DWORD)dosHeader);  
					if(strcmp((char *)lpExpFuncName,(char *)FuncName)==0)  
						return (DWORD) (lpFunctions[i] + 
								(DWORD)dosHeader);  
				} 
			} 
		} 
	} 
	else 
	{ 
		for (i = 0 ;i<=pExportDir->NumberOfFunctions - 1;i++)  
		{ 
			if (lpFuncName == (char *)(pExportDir->Base + i))  
			{ 
				if (lpFunctions[i]) return (unsigned long) (lpFunctions[i] + 
							dosHeader);  
			} 
		} 
	} 
	return 0;  
}


在調用完函數后,不要忘記用 UnloadPbDllFromMemory 來從內存中移去 DLL 以釋放分配的內存,該函數還會用 DLL_PROCESS_DETACH 參數調用 DLL 的入口函數 DllMain 來從調用進程的地址空間卸載該 DLL。 以下是 UnloadPbDllFromMemory 函數代碼:
DWORD UnloadPbDllFromMemory(PIMAGE_DOS_HEADER dosHeader) 
{
	PIMAGE_NT_HEADERS pNTHeader; 
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + (DWORD)dosHeader->e_lfanew); 
	EntryPoint = (LPENTRYPOINT)(pNTHeader->OptionalHeader.AddressOfEntryPoint +
					 (DWORD)dosHeader); 
	EntryPoint((HINSTANCE)dosHeader, DLL_PROCESS_DETACH, 0); 
	return VirtualFree(dosHeader, 0, MEM_RELEASE); 
}


關于示例代碼的說明

  在本文附帶的示例代碼中,合并了一個名為 hardware.dll 的動態連接庫,該動態連接庫是一個獲取系統硬件信息的庫文件,其中包括了以下函數:

   getmac 		取得網卡 MAC 
   VolumeNumber 	取得硬盤卷標 
   changeres            改變屏幕分辯率 
   IsDiskInDrive        檢查軟驅中是否插有盤 
   DPGetDefaultPrinter  取得默認的打印機名 
   DPSetDefaultPrinter  設置默認的打印機 
   getserial            取得硬盤的出廠序列號 
   getmetric            取得顯示分辯率 
   PrintStringDirect    直接向打印機發送一個串 
   vfpbeep              讓 PC 喇叭發聲 
   getcpuid             取得 CPU ID 
   getbios              取得主板 BIOS ID 
  在示例代碼中,只調用了其中一個函數 getbios 來獲取主板 BIOS ID, 這里說明一下,該函數實際上好象只能檢測 AWARD 主板的 BIOS, 也就是說它是讀取的是系統內存 0x000fex71 處的值。因為其它牌子的主板 BIOS 的位置稍有不同,但在程序中沒有進行這方面的處理,所以在讀其它牌子的主板 BIOS 時可能會有些問題(讀出的內容可能不正確)。關于此 DLL 的內容和實現,也許我會在另一篇文章中論及。
 

局限
  
在我進行測試時,發現對于有些含有資源的 DLL,在 9x 平臺下可能會有問題。

題外話
  
另外,其它一些本文未提及的非主要的函數,請自行參見源代碼中的注釋。
再,本文涉及 PE 文件格式方面的知識,它們已經超出了本文的范圍,具體信息可參見 MSDM 中的:

  • Peering Inside the PE: A Tour of the Win32 Portable Executable File Format 一文和
  • Microsoft Portable Executable and Common Object File Format Specification 一文
  • 特別感謝盧春明(Aming)在我編寫本文時所作的一些技術方面的建議和指導


    如果本文對你的開發有所幫助,并且你手頭恰好有零錢。

    不如打賞我一杯咖啡,鼓勵我繼續分享優秀的文章。




    posted on 2006-11-21 00:45 李錦俊(mybios) 閱讀(9645) 評論(6)  編輯 收藏 引用 所屬分類: C++

    Feedback

    # re: 【轉貼】直接載入內存中的DLL 2006-12-10 10:33 表弟(鋒)
    這是什么來的表哥?很多都看不懂哦!  回復  更多評論
      

    # re: 【轉貼】直接載入內存中的DLL 2006-12-10 19:47 李錦俊
    @表弟(鋒)
    等你長大了就能看懂的了.現在你還小.  回復  更多評論
      

    # re: 【轉貼】直接載入內存中的DLL 2007-02-13 11:51 As
    有必要嗎?
    不如不要使用DLL,直接寫代碼得拉,
    (這樣不是更帥,讓別人直接破解PE結構)

    程序的路不好走~~,繼續加油~~
      回復  更多評論
      

    # re: 【轉貼】直接載入內存中的DLL 2008-06-18 16:00 sdfs
    不太清楚這樣做的意義,把dll drop出來不是更方便?  回復  更多評論
      

    # re: 【轉貼】直接載入內存中的DLL 2010-01-15 08:55 dibaplus@gmail.com
    很好的文章,推薦  回復  更多評論
      

    # re: 【轉貼】直接載入內存中的DLL 2010-02-22 23:54 表弟。鋒
    @表弟(鋒)
    等你長大了就能看懂的了.現在你還小.

    雖然現在還是看不明,但系突然看到這條留言我覺得超意外的,哈哈  回復  更多評論
      

    青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜精品成人在线| 狠狠v欧美v日韩v亚洲ⅴ| 亚洲区欧美区| 在线一区二区日韩| 国产精品视频在线观看| 在线欧美三区| 欧美激情一区二区久久久| 国产精品久久777777毛茸茸| 欧美激情在线有限公司| 国产视频欧美| 亚洲欧美日韩在线| 性欧美xxxx视频在线观看| 一区二区电影免费观看| 欧美一级淫片播放口| 在线综合+亚洲+欧美中文字幕| 欧美精品在线观看播放| 性18欧美另类| 亚洲成人在线免费| 国产精品捆绑调教| 免费成人激情视频| 小黄鸭精品密入口导航| 亚洲毛片av在线| 欧美精品首页| 亚洲三级电影全部在线观看高清| 欧美一区二区三区成人| 亚洲第一天堂无码专区| 黄色成人精品网站| 久久久.com| 你懂的国产精品| 亚洲韩国精品一区| 欧美日韩三级一区二区| 黄色亚洲大片免费在线观看| 亚洲日本一区二区| 国产午夜亚洲精品不卡| 欧美成人午夜剧场免费观看| 亚洲尤物视频在线| 夜夜夜久久久| 91久久久久久国产精品| 欧美国产激情二区三区| 欧美日韩免费在线视频| 欧美国产成人精品| 亚洲欧美日本国产专区一区| 国产日韩在线亚洲字幕中文| 久久久久久网站| 99精品国产在热久久| 欧美国产乱视频| 亚洲一区高清| 亚洲国产日韩欧美在线99| 欧美久久久久久久| 久久国产精品色婷婷| 99精品国产在热久久下载| 亚洲精美视频| 日韩亚洲欧美一区| 宅男精品视频| 欧美一级艳片视频免费观看| 久久综合网色—综合色88| 亚洲国产清纯| 一区二区日韩精品| 国产一级久久| 久久久久久免费| 亚洲视频在线播放| 亚洲欧洲久久| 噜噜噜躁狠狠躁狠狠精品视频| 一本大道久久精品懂色aⅴ| 国产曰批免费观看久久久| 国产精品成人v| 国产精品乱人伦一区二区| 欧美日韩精品一区二区在线播放 | 麻豆成人91精品二区三区| 亚洲精品日韩在线| 亚洲男人影院| 欧美日本免费一区二区三区| 国产精品一区二区久久精品| 亚洲一区二区三区欧美| 欧美在线亚洲在线| 午夜精品国产更新| 亚洲欧美综合国产精品一区| 在线视频你懂得一区二区三区| 夜夜狂射影院欧美极品| 99在线|亚洲一区二区| 一个人看的www久久| 亚洲欧美日韩国产另类专区| 亚洲欧美在线x视频| 免费成人av在线看| 最新亚洲电影| 亚洲无人区一区| 亚洲成色777777女色窝| 亚洲男人的天堂在线aⅴ视频| 欧美日韩国产成人| 亚洲精选在线观看| 久久本道综合色狠狠五月| 久久久之久亚州精品露出| 国产在线播放一区二区三区| 99在线精品视频在线观看| 一本久久青青| 老司机精品福利视频| 欧美日本二区| 国产精品私拍pans大尺度在线| 国产一区二区三区视频在线观看| 影音先锋亚洲精品| 亚洲欧美在线观看| 最新国产乱人伦偷精品免费网站| 99国内精品久久| 久久久久成人精品| 国产精品精品视频| 韩日精品视频一区| 国产亚洲午夜高清国产拍精品| 久久久国产精品亚洲一区| 欧美一区二区三区的| 国产一区日韩二区欧美三区| 久久偷窥视频| 蜜桃精品一区二区三区| 亚洲人精品午夜| 国产视频在线一区二区| 亚洲激情成人| 另类天堂av| 久久九九热re6这里有精品| 国产精品九九| 亚洲日本欧美| 欧美a一区二区| 久久青草欧美一区二区三区| 国产精品九九久久久久久久| 亚洲一区二区在线视频| 亚洲欧美国产制服动漫| 欧美日韩人人澡狠狠躁视频| 亚洲精品中文字| 一本到高清视频免费精品| 亚洲国产精品一区二区第四页av | 日韩图片一区| 国产在线欧美日韩| 在线性视频日韩欧美| 亚洲欧美日本国产有色| av成人免费在线观看| 美女脱光内衣内裤视频久久影院 | 国产欧美精品久久| 午夜视频在线观看一区二区三区| 一区二区欧美日韩视频| 国产一区二区三区久久久| 久久亚洲色图| 欧美成人黄色小视频| 99精品久久| 亚洲一区二区三区色| 激情欧美一区| 亚洲人久久久| 欧美国产精品人人做人人爱| 久久免费99精品久久久久久| 国产精品丝袜91| 亚洲午夜一区| 欧美尤物一区| 国内成人精品视频| 久久久99爱| 免费在线亚洲欧美| 亚洲国产精品小视频| 亚洲一区二区欧美日韩| 黄色一区二区在线观看| 亚洲欧洲在线看| 精品999日本| 欧美日韩国产精品| 久久嫩草精品久久久久| 欧美紧缚bdsm在线视频| 久久精品水蜜桃av综合天堂| 欧美精品一区二区蜜臀亚洲| 久久久噜噜噜| 国产精品久久久久久影院8一贰佰| 久久久精品五月天| 欧美日韩一区二区三区在线视频| 久久人人爽人人| 久久超碰97中文字幕| 久久久精品一区| 亚洲欧洲在线免费| 欧美日韩在线三区| 欧美亚洲免费高清在线观看| 久久久久久久久久看片| 在线观看91精品国产麻豆| 欧美精品一区二| 午夜久久久久久| 99v久久综合狠狠综合久久| 激情国产一区| 久久精品一区二区国产| 欧美一区二区三区在线视频| 欧美深夜影院| 亚洲深夜av| 欧美在线播放视频| 亚洲区第一页| 国产精品久久999| 国产精品99久久不卡二区 | 亚洲人成网站999久久久综合| 欧美综合二区| 欧美成人国产| 亚洲国内自拍| 中文在线不卡| 久久精品国产亚洲高清剧情介绍| 亚洲另类春色国产| 韩日视频一区| 国产精品婷婷午夜在线观看| 免费在线成人av| 久久久久国产一区二区| 亚洲一区二区三区精品视频| 亚洲人成精品久久久久| 亚洲国产成人高清精品|