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

李錦俊(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)

我參與的團隊

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 373303
  • 排名 - 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) 閱讀(9638) 評論(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>
            久久国产夜色精品鲁鲁99| 一区二区三区高清不卡| 99精品视频一区二区三区| 亚洲视频一区| 亚洲免费观看高清完整版在线观看熊 | 欧美精品在线免费播放| 欧美在线观看一区| 久久免费视频一区| 日韩视频免费| 亚洲女人小视频在线观看| 影音先锋亚洲电影| 欧美中文字幕在线观看| 久久黄色级2电影| 欧美激情一区二区三区四区| 精品av久久久久电影| 性欧美8khd高清极品| 在线免费观看视频一区| 欧美丰满高潮xxxx喷水动漫| 欧美国产精品v| 日韩视频三区| 国产精品日韩欧美一区二区| 欧美一区视频| 亚洲激情网址| 亚洲精品一区二区三区在线观看| 欧美日韩精品免费观看| 欧美综合第一页| 欧美aa在线视频| 亚洲电影观看| 亚洲一区二区三区在线看| 欧美精品91| 久久精品国产久精国产一老狼| 午夜精品免费| 欧美日韩成人综合在线一区二区 | 亚洲一区二区三区免费视频| 亚洲桃色在线一区| 亚洲一区www| 欧美成人免费va影院高清| 国产一区二区日韩精品欧美精品 | 欧美人交a欧美精品| 亚洲免费观看在线观看| 久久久国产一区二区| 一本综合久久| 亚洲午夜伦理| 999亚洲国产精| 亚洲成色777777女色窝| 欧美日韩在线一区| 欧美h视频在线| 欧美日韩精品免费观看| 99re8这里有精品热视频免费| 亚洲一区二区三区在线| 亚洲一区二区久久| 99热在线精品观看| 欧美日韩在线免费视频| 亚洲丰满在线| 乱中年女人伦av一区二区| 亚洲综合第一页| 久久精品国产久精国产一老狼| 欧美成年人网| 欧美岛国激情| 你懂的国产精品| 国产精品视频在线观看| 日韩网站在线| 女人天堂亚洲aⅴ在线观看| 亚洲欧美日韩综合| 国产精品久久婷婷六月丁香| 亚洲一区不卡| 亚洲欧美综合网| 国产精品一区二区三区四区| 亚洲香蕉成视频在线观看| 亚洲青色在线| 欧美国产综合| 国产精品99久久99久久久二8| 亚洲国产视频a| 欧美激情1区| 91久久精品国产91久久性色tv| 欧美国产欧美综合| 欧美大尺度在线观看| 一区二区三区国产盗摄| 亚洲免费播放| 国产欧美日韩不卡免费| 久久精品一区中文字幕| 久久久一区二区三区| 亚洲电影在线看| 欧美bbbxxxxx| 欧美日产一区二区三区在线观看| 亚洲一区二区不卡免费| 日韩一级二级三级| 一本一本久久a久久精品牛牛影视| 欧美日韩一区二区三区| 欧美资源在线| 欧美jizz19hd性欧美| 亚洲一区二区精品| 欧美在线观看一二区| 亚洲黄一区二区三区| 99re亚洲国产精品| 国语对白精品一区二区| 亚洲精品久久久久| 国产精品任我爽爆在线播放| 老妇喷水一区二区三区| 欧美日韩黄色大片| 久久久久久久一区二区三区| 免费不卡亚洲欧美| 午夜精品久久久久久久久久久 | 欧美久久影院| 在线观看日韩欧美| 亚洲电影自拍| 欧美三级视频在线| 久久精品一本久久99精品| 久久婷婷国产综合国色天香 | 亚洲自拍偷拍色片视频| 久久免费精品视频| 欧美一区二区三区电影在线观看| 免费观看国产成人| 久久久999精品| 国产精品啊啊啊| 男人的天堂亚洲在线| 国产精品久久久久高潮| 欧美激情影院| 久久久久久久网站| 羞羞色国产精品| 日韩午夜激情av| 久久国产精品亚洲77777| 亚洲性感美女99在线| 免费在线亚洲欧美| 久久久久88色偷偷免费| 国产精品美女久久久免费| 日韩天堂av| 日韩视频免费大全中文字幕| 久久久精品网| 久久全国免费视频| 国产日本欧美一区二区| a4yy欧美一区二区三区| 一区二区高清视频| 欧美日韩精品久久久| 日韩午夜免费视频| 亚洲手机在线| 国产精品盗摄久久久| 亚洲视频精选| 欧美在线视频在线播放完整版免费观看| 国产精品国产福利国产秒拍| 欧美一区二区三区视频| 久久久久久伊人| 国产精品乱码| 亚洲天天影视| 亚洲一区黄色| 国产精品免费一区二区三区观看| 日韩视频在线免费观看| 亚洲婷婷综合久久一本伊一区| 麻豆国产精品777777在线| 欧美国产欧美亚洲国产日韩mv天天看完整 | 久久久久国产精品人| 亚洲图片欧美日产| 亚洲性感激情| 免费在线欧美黄色| 亚洲第一久久影院| 亚洲国产精品一区制服丝袜| 免费不卡在线视频| 亚洲久久一区| 欧美亚洲日本网站| 国内久久视频| 麻豆精品在线视频| 亚洲美女av网站| 欧美一级视频| 精品96久久久久久中文字幕无| 另类尿喷潮videofree | 欧美一区日韩一区| 国内成人精品视频| 欧美成人网在线| 亚洲私人影院在线观看| 久久野战av| 一本色道**综合亚洲精品蜜桃冫| 国产精品日韩欧美一区二区| 久久夜色撩人精品| 在线亚洲国产精品网站| 久久视频一区二区| 一本色道久久综合狠狠躁篇怎么玩| 国产女主播一区二区| 猫咪成人在线观看| 亚洲欧美日韩天堂一区二区| 亚洲高清在线精品| 久久久久在线| 亚洲一区二区在线免费观看视频 | 一个人看的www久久| 久久中文字幕一区| 一区二区三区视频免费在线观看| 国产麻豆综合| 亚洲乱码国产乱码精品精98午夜| 久久国产精品黑丝| 亚洲特级片在线| 亚洲黄色av一区| 国产在线视频欧美| 国产精品实拍| 欧美理论电影网| 欧美电影电视剧在线观看| 久久久91精品国产| 亚洲欧美清纯在线制服| 一区二区三区高清| 亚洲免费观看在线观看| 亚洲欧洲精品一区二区三区不卡 | 免费欧美高清视频|