• <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>

            李錦俊(mybios)的blog

            游戲開發(fā) C++ Cocos2d-x OpenGL DirectX 數(shù)學(xué) 計(jì)算機(jī)圖形學(xué) SQL Server

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

            公告

            QQ:30743734
            EMain:mybios@qq.com

            常用鏈接

            留言簿(16)

            我參與的團(tuán)隊(duì)

            最新隨筆

            搜索

            •  

            積分與排名

            • 積分 - 372214
            • 排名 - 67

            最新評論

            閱讀排行榜

            評論排行榜

            作者:任明漢

            下載源代碼

            前言

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


            Win32 程序調(diào)用 DLL 的機(jī)制

               Win32 EXE 在調(diào)用一個(gè)外部 DLL 中的函數(shù)時(shí),首先要調(diào)用 LoadLibary 函數(shù)來載入此 DLL 到程序的進(jìn)程地址空間。 如果 LoadLibary 載入此 DLL 成功,將返回一個(gè)該 DLL 的句柄。 這個(gè)句柄實(shí)際上就是該 DLL 在內(nèi)存中的起始地址。 在載入 DLL 成功后,還必須調(diào)用 GetProcAddress 函數(shù)來獲取要調(diào)用的函數(shù)的地址。然后再根據(jù)該地址來調(diào)用這個(gè)函數(shù)。
            根據(jù)上述原理,我們可以把一個(gè) DLL 作為資源文件放到 EXE 文件中,在程序運(yùn)行時(shí),分配一塊內(nèi)存,然后將此資源復(fù)制到該分配的內(nèi)存中,并根據(jù)該內(nèi)存地址計(jì)算得到相關(guān)的導(dǎo)出函數(shù)地址,然后,當(dāng)我們需要調(diào)用某一函數(shù)時(shí),可以用該函數(shù)在內(nèi)存中的地址來調(diào)用它。
            程序?qū)崿F(xiàn)。
              首先,把要合并的 DLL 作為資源加入到項(xiàng)目的資源文件中,然后在程序運(yùn)行時(shí),從資源中載入該資源,以得到該 DLL 在內(nèi)存中的位置:
            LPVOID sRawDll; // 資源文件在內(nèi)存中的地址 
            HRSRC hRes; 
            HMODULE hLibrary; 
            HGLOBAL hResourceLoaded; 
            char lib_name[MAX_PATH]; 
            GetModuleFileName(hInstance, lib_name, MAX_PATH ); // 得到運(yùn)行程序的名字 
            hLibrary = LoadLibrary(lib_name);                  // 就象載入一個(gè) DLL 一樣載入運(yùn)行程序到內(nèi)存中 
            
            if (NULL != hLibrary) 
            {
            	// 得到指定的資源文件在內(nèi)存中的位置 
            	hRes = FindResource(hLibrary, MAKEINTRESOURCE(IDR_DATA1), RT_RCDATA); 
            	if (NULL != hRes) 
            	{
            		// 將資源文件載入內(nèi)存 
            		hResourceLoaded = LoadResource(hLibrary, hRes); 
            		if (NULL != hResourceLoaded) 
            		{
            			// 得到資源文件大小 
            			SizeofResource(hLibrary, hRes); 
            
            			// 鎖定資源以得到它在內(nèi)存中的地址 
            			sRawDll = (LPVOID)LockResource(hResourceLoaded); 
            		}
            	}
            	else return 1; 
            	FreeLibrary(hLibrary);
            }
            else return 1; 
            
            然后,從資源中載入 DLL 到內(nèi)存函數(shù) LoadPbDllFromMemory 將載入 DLL 到內(nèi)存中, 該函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是指向 DLL 資源在內(nèi)存中的地址的指針,也就是前面代碼中的 LockResource 函數(shù)的返回值。第二個(gè)參數(shù)是一個(gè)空的指針,如果函數(shù) LoadPbDllFromMemory 運(yùn)行成功,該指針將指向重新組合后的內(nèi)存中的 DLL 的起始地址。該函數(shù)還有一個(gè)功能就是如果運(yùn)行成功,它將手動(dòng)地用 DLL_PROCESS_ATTACH 參數(shù)調(diào)用 DLL 的入口函數(shù) DllMain 來初始化該 DLL。除此之外,它還會(huì)手動(dòng)地載入合并的 DLL 的入口表中導(dǎo)入的 DLL 并調(diào)整它們在內(nèi)存中的相對地址。以下是該函數(shù)代碼:
            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); 
            
            	// 節(jié)頭長度 
            	HdrLen = (DWORD)section - (DWORD)dosHeader + 
            			HeaderSize * pNTHeader->FileHeader.NumberOfSections; 
            
            	// 找出最大的節(jié)的長度,此節(jié)一般是代碼所在的節(jié)(.text 節(jié)) 
            	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++; 
            
            	// 分配所需的內(nèi)存 
            	DWORD NeededMemory = ImagePages * sSysInfo.dwPageSize; 
            	lpImageDll = VirtualAlloc(NULL, NeededMemory, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 
            
            	if (lpImageDll == NULL) return 6; // 分配內(nèi)存失敗 
            
            	MoveMemory( lpImageDll, lpRawDll, HdrLen ); // 復(fù)制節(jié)頭 
            
            	DWORD OrgAddr = 0; 
            	DWORD NewAddr = 0; 
            	DWORD Size = 0; 
            
            	// 復(fù)制 .text 節(jié)數(shù)據(jù) 
            	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); 
            		}
            	}
            
            	// 取得原始的內(nèi)存狀態(tài) 
            	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 
            		}
            	}
            
            	// 恢復(fù)原始的內(nèi)存狀態(tài) 
            	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 被正確地載入到內(nèi)存中,我們就可以通過自定義函數(shù) GetProcAddressDirectly 來獲取某函數(shù)在內(nèi)存中的地址,并根據(jù)該地址來調(diào)用該函數(shù),該函數(shù)也有兩個(gè)參數(shù),第一個(gè)參數(shù)是指向載入到內(nèi)存中的 DLL 的起始地址的指針,第二個(gè)是要調(diào)用的函數(shù)的函數(shù)名。以下是 GetProcAddressDirectly 函數(shù)代碼:
            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;  
            }
            
            
            
            在調(diào)用完函數(shù)后,不要忘記用 UnloadPbDllFromMemory 來從內(nèi)存中移去 DLL 以釋放分配的內(nèi)存,該函數(shù)還會(huì)用 DLL_PROCESS_DETACH 參數(shù)調(diào)用 DLL 的入口函數(shù) DllMain 來從調(diào)用進(jìn)程的地址空間卸載該 DLL。 以下是 UnloadPbDllFromMemory 函數(shù)代碼:
            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); 
            }
            


            關(guān)于示例代碼的說明

              在本文附帶的示例代碼中,合并了一個(gè)名為 hardware.dll 的動(dòng)態(tài)連接庫,該動(dòng)態(tài)連接庫是一個(gè)獲取系統(tǒng)硬件信息的庫文件,其中包括了以下函數(shù):

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

            局限
              
            在我進(jìn)行測試時(shí),發(fā)現(xiàn)對于有些含有資源的 DLL,在 9x 平臺(tái)下可能會(huì)有問題。

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

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


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

            不如打賞我一杯咖啡,鼓勵(lì)我繼續(xù)分享優(yōu)秀的文章。




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

            Feedback

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

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

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

            程序的路不好走~~,繼續(xù)加油~~
              回復(fù)  更多評論
              

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

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

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

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

            日韩精品久久久久久久电影蜜臀 | 亚洲伊人久久综合中文成人网| 高清免费久久午夜精品| 国产三级久久久精品麻豆三级| 久久国产精品-国产精品| 久久精品无码一区二区三区免费| 久久精品亚洲乱码伦伦中文| 亚洲国产香蕉人人爽成AV片久久 | 伊人热热久久原色播放www| 久久精品无码一区二区无码| 国产精品九九久久免费视频| 久久久亚洲欧洲日产国码二区| 久久综合久久伊人| 婷婷综合久久狠狠色99h| 99久久国产综合精品女同图片| 91超碰碰碰碰久久久久久综合| 无码国内精品久久人妻| 久久只有这精品99| 国内精品免费久久影院| 91精品国产乱码久久久久久| 久久久无码精品亚洲日韩蜜臀浪潮| 日本久久久久久中文字幕| 国产午夜福利精品久久2021 | 狠狠色婷婷久久综合频道日韩 | 久久人人爽人爽人人爽av| 亚洲午夜久久影院| 久久精品国产精品国产精品污| 久久久免费精品re6| 久久婷婷激情综合色综合俺也去| 精品久久人人爽天天玩人人妻| 欧美激情一区二区久久久| 香港aa三级久久三级老师2021国产三级精品三级在 | 久久精品无码一区二区WWW| 久久国产精品波多野结衣AV| 国产成人久久AV免费| 久久99久久99小草精品免视看| 国产精品久久久久久福利漫画 | 国产福利电影一区二区三区久久久久成人精品综合 | 91精品国产91久久久久久蜜臀| 99热精品久久只有精品| 精品无码久久久久久国产|