VS2017编译可在Win2000上运行的程序
微軟最后一個可以原生編譯Win2000應用程序IDE是Visual Studio 2008,后續版本只能支持到WinXP。那么有什么辦法讓高版本的VS編譯出可以在Win2000上運行的程序呢?
首先我們要了解為什么編譯出的程序無法在Win2000上運行,首先一個原因是EXE可執行文件NTHEADER中的可選頭有一個操作系統版本和子系統版本,這個如果是支持XP,則值為5.1,如果是2000,則必須是5.0。
另外一個原因就是Win2000上kernel32.dll,缺失了一些關鍵的API,例如EncodePointer、DecodePointer等等。
有一個方案是安裝多個版本的VS,然后配置Daffodil.ENU.msi這個補丁來讓高版本的VS能夠使用低版本的Toolset。但是這有兩個個問題,首先如果讓高版本的VS識別VC2008的工具集就必須安裝VS2010,這樣就導致你的機器至少有3個版本的VS。其次就是雖然你可以使用VC2008的工具集了,但是你的編譯器也是VC2008,并不能享受高版本VC的特性,例如C99,VC++11等等。而且據我所知VC2013是第一個完整支持C99的版本,VC2015是第一個完整支持VC++11的版本。
此文給出老外的一個解決辦法,這里只做整理,原理很簡單,就是通過鏈接時符號替換。
首先創建一個最簡單的控制臺工程。只打印出hello world即可。
添加impapi.asm文件,內容如下
.586 .MODEL FLAT, STDCALLEXTERN STDCALL i__GetModuleHandleExW@12:PROC EXTERN STDCALL i__SetFilePointerEx@20:PROC EXTERN STDCALL i__InitializeSListHead@4:PROC EXTERN STDCALL i__EncodePointer@4:PROC EXTERN STDCALL i__DecodePointer@4:PROC EXTERN STDCALL i__HeapSetInformation@16:PROC.DATA__imp__InitializeSListHead@4 DWORD i__InitializeSListHead@4__imp__InterlockedPushEntrySList@8 DWORD RtlInterlockedPushEntrySList__imp__GetModuleHandleExW@12 DWORD i__GetModuleHandleExW@12__imp__EncodePointer@4 DWORD i__EncodePointer@4__imp__DecodePointer@4 DWORD i__DecodePointer@4__imp__HeapSetInformation@16 DWORD i__HeapSetInformation@16__imp__SetFilePointerEx@20 DWORD i__SetFilePointerEx@20EXTERNDEF STDCALL __imp__InitializeSListHead@4:DWORDEXTERNDEF STDCALL __imp__InterlockedPushEntrySList@8:DWORDEXTERNDEF STDCALL __imp__GetModuleHandleExW@12:DWORDEXTERNDEF STDCALL __imp__EncodePointer@4:DWORDEXTERNDEF STDCALL __imp__DecodePointer@4:DWORDEXTERNDEF STDCALL __imp__HeapSetInformation@16:DWORDEXTERNDEF STDCALL __imp__SetFilePointerEx@20:DWORD.CODE InterlockedPushEntrySList PROCpush ebxpush ebpmov ebp, ecxmov ebx, edxmov edx, [ebp+4]mov eax, [ebp+0]Epsh:mov [ebx], eaxlea ecx, [edx+10001h]lock cmpxchg8b qword ptr [ebp+0]jnz Epshpop ebppop ebxretn InterlockedPushEntrySList ENDPRtlInterlockedPushEntrySList PROCmov edi, edipush ebpmov ebp, espmov edx, [ebp+0Ch] ; ListEntrymov ecx, [ebp+08h] ; ListHeadcall InterlockedPushEntrySListpop ebpretn 8 RtlInterlockedPushEntrySList ENDPEND添加extapi.c,內容如下
#include <windows.h>typedef BOOL (WINAPI *PFN_GET_MODULE_HANDLE_EX_W)(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE *phModule); typedef BOOL (WINAPI *PFN_SET_FILE_POINTER_EX)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); typedef VOID (WINAPI *PFN_INITIALIZE_SLIST_HEAD)(PSLIST_HEADER ListHead); typedef PVOID (WINAPI *PFN_ENCODE_POINTER)(PVOID Pointer); typedef PVOID (WINAPI *PFN_DECODE_POINTER)(PVOID Pointer); typedef BOOL (WINAPI *PFN_HEAP_SET_INFORMATION)(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength);PFN_GET_MODULE_HANDLE_EX_W pfnGetModuleHandleExW; PFN_SET_FILE_POINTER_EX pfnSetFilePointerEx; PFN_INITIALIZE_SLIST_HEAD pfnInitializeSListHead; PFN_ENCODE_POINTER pfnEncodePointer; PFN_DECODE_POINTER pfnDecodePointer; PFN_HEAP_SET_INFORMATION pfnHeapSetInformation; BOOL HasAlreadyTryGetFunction;static VOID TryGetFunction(VOID) {HANDLE hKernel32 = GetModuleHandleA("kernel32");if(HasAlreadyTryGetFunction)return;pfnGetModuleHandleExW = (PFN_GET_MODULE_HANDLE_EX_W)GetProcAddress(hKernel32, "GetModuleHandleExW");pfnSetFilePointerEx = (PFN_SET_FILE_POINTER_EX)GetProcAddress(hKernel32, "SetFilePointerEx");pfnInitializeSListHead = (PFN_INITIALIZE_SLIST_HEAD)GetProcAddress(hKernel32, "InitializeSListHead");pfnEncodePointer = (PFN_ENCODE_POINTER)GetProcAddress(hKernel32, "EncodePointer");pfnDecodePointer = (PFN_DECODE_POINTER)GetProcAddress(hKernel32, "DecodePointer");pfnHeapSetInformation = (PFN_HEAP_SET_INFORMATION)GetProcAddress(hKernel32, "HeapSetInformation");HasAlreadyTryGetFunction = TRUE; }BOOL WINAPI i__GetModuleHandleExW(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE *phModule) {TryGetFunction();if(pfnGetModuleHandleExW){return pfnGetModuleHandleExW(dwFlags, lpModuleName, phModule);}//NOT FULLY IMPLEMENTED//BasepGetModuleHandleExParameterValidationif( phModule == NULL ||(dwFlags & ~(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) ||(dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN && dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) ||(lpModuleName == NULL && dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) ){SetLastError(ERROR_INVALID_PARAMETER);return FALSE;}*phModule = NULL;//BasepGetModuleHandleExWif(dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS){MEMORY_BASIC_INFORMATION mbi;SIZE_T size;size = VirtualQuery(lpModuleName, &mbi, sizeof(mbi));if(size >= sizeof(PVOID) * 2){*phModule = (HANDLE)mbi.AllocationBase;}}else{*phModule = GetModuleHandleW(lpModuleName);}return TRUE; }BOOL WINAPI i__SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) {LARGE_INTEGER liDistanceToMoveTmp;DWORD dwRet;TryGetFunction();if(pfnSetFilePointerEx){return pfnSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod);}liDistanceToMoveTmp = liDistanceToMove;dwRet = SetFilePointer(hFile, liDistanceToMoveTmp.LowPart, &liDistanceToMoveTmp.HighPart, dwMoveMethod);if(dwRet != INVALID_SET_FILE_POINTER){lpNewFilePointer->LowPart = dwRet;lpNewFilePointer->HighPart = liDistanceToMoveTmp.HighPart;return TRUE;}return FALSE; }VOID WINAPI i__InitializeSListHead(PSLIST_HEADER ListHead) {ListHead->Alignment = 0; }PVOID WINAPI i__EncodePointer(PVOID Pointer) {TryGetFunction();if(pfnEncodePointer){return pfnEncodePointer(Pointer);}//NOT IMPLEMENTEDreturn Pointer; }PVOID WINAPI i__DecodePointer(PVOID Pointer) {TryGetFunction();if(pfnDecodePointer){return pfnDecodePointer(Pointer);}//NOT IMPLEMENTEDreturn Pointer; }BOOL WINAPI i__HeapSetInformation(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength) {TryGetFunction();if(pfnHeapSetInformation)return pfnHeapSetInformation(HeapHandle, HeapInformationClass, HeapInformation, HeapInformationLength);//NOT IMPLEMENTEDreturn TRUE; }解決方案資源管理器,在項目上右鍵菜單選擇生成自定義,勾選masm。
在extapi1.asm右鍵屬性,配置常規項類型為 Microsoft Macro Assembler。
編譯該項目,修改上述所說的版本號為5.0。
嘗試在win2000上運行通過。
?
另外還有一些在Win2000上的VC運行庫,包括VC2010 VC2012 VC2012 VC2015 VC2017
http://i430vx.net/files/Win2k/Extended%20kernel%20ONLY/
上述代碼參考來源
https://stackoverflow.com/questions/19516796/visual-studio-2012-win32-project-targeting-windows-2000
?
?
?
總結
以上是生活随笔為你收集整理的VS2017编译可在Win2000上运行的程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一些恶意软件的分析收集整理
- 下一篇: 减少静态链接库的体积