簡體   English   中英

針對Windows 2000的Visual Studio 2012 Win32項目

[英]visual studio 2012 win32 project targeting windows 2000

我需要修改幾年前在win32中編寫的非常老的項目,該項目必須在Windows 2000服務器上運行。

最近升級了計算機后,我搬到了Visual Studio 2012,因此遇到了問題。

我在這里讀了很多文章,我有點困惑。

首先使用平台工具集,我需要安裝vs2008和vs2010對嗎? 這是無法接受的。

第二,一些帖子說我需要覆蓋DecodePointer / EncodePointer函數。

第三,只是使用定義

#ifndef WINVER
#define WINVER 0x0501
#endif

#ifndef _WIN32_WINNT   // Specifies that the minimum required platform is Windows XP.
#define _WIN32_WINNT 0x0501
#endif

選項1不可接受。 其他兩個選項中的哪個與vs2012一起使用???

謝謝大家。

VS2012編譯器的運行時支持目標XP,但不支持早期版本。 實際上,在發行時,不支持XP定位,並且在以后的更新中添加了XP定位。 如果必須支持Win2k,則必須使用不支持Win2k的VS早期版本中的工具集。

這是Cody Gray的VS2017代碼的擴展。 它可能會使用一些額外的工具以確保其正常工作。 截至目前,應用程序將在VS2017內置的NT4上啟動並運行。 如果使用MS Layer for Unicode(unicows),它也將在Win98上工作。

.386
.MODEL flat, stdcall

    USE_W_STRINGS EQU 1                 ; Flag on which GetModuleHandle version to use
    USE_WIN9X     EQU 1                 ; Flag on if to include Win9x specific requirements

   EXTRN STDCALL ImplementGetModuleHandleExW@12 : PROC
   EXTRN STDCALL ImplementSetFilePointerEx@20 : PROC

   ;; Declare functions that we will call statically
   IF USE_W_STRINGS
    EXTRN STDCALL _imp__GetModuleHandleW@4  : DWORD
   ELSE
    EXTRN STDCALL _imp__GetModuleHandleA@4  : DWORD
   ENDIF

   EXTRN STDCALL _imp__GetProcAddress@8    : DWORD


.DATA
   ;; Override the import symbols from kernel32.dll
   __imp__InitializeSListHead@4    DWORD DownlevelInitializeSListHead
   __imp__GetModuleHandleExW@12    DWORD DownlevelGetModuleHandleExW
   __imp__EncodePointer@4          DWORD DownlevelEncodeDecodePointer
   __imp__DecodePointer@4          DWORD DownlevelEncodeDecodePointer
   ;__imp__HeapSetInformation@16 dd DownlevelHeapSetInformation
   __imp__SetFilePointerEx@20      DWORD ImplementSetFilePointerEx@20

   EXTERNDEF STDCALL __imp__InitializeSListHead@4 : DWORD
   EXTERNDEF STDCALL __imp__GetModuleHandleExW@12 : DWORD
   EXTERNDEF STDCALL __imp__EncodePointer@4 : DWORD
   EXTERNDEF STDCALL __imp__DecodePointer@4 : DWORD
   ;EXTERNDEF STDCALL __imp__HeapSetInformation@16 : DWORD
   EXTERNDEF STDCALL __imp__SetFilePointerEx@20 : DWORD


   ; For Win9x support - need to change return value to TRUE for the crt startup
   IF USE_WIN9X
    __imp__InitializeCriticalSectionAndSpinCount@8 DWORD DownlevelInitializeCriticalSectionAndSpinCount
    EXTERNDEF STDCALL __imp__InitializeCriticalSectionAndSpinCount@8 : DWORD
   ENDIF

CONST SEGMENT
   IF USE_W_STRINGS
     kszKernel32            DB 'k', 00H, 'e', 00H, 'r', 00H, 'n', 00H, 'e', 00H, 'l', 00H, '3', 00H, '2', 00H, 00H, 00H
     kszAdvApi32            DB 'a', 00H, 'd', 00H, 'v', 00H, 'a', 00H, 'p', 00H, 'i', 00H, '3', 00H, '2', 00H, 00H, 00H
   ELSE
     kszKernel32            DB "kernel32", 00H
     kszAdvApi32            DB "advapi32", 00H
   ENDIF

   kszInitializeSListHead DB "InitializeSListHead", 00H
   kszGetModuleHandleExW  DB "GetModuleHandleExW", 00H

   kszInitializeCriticalSectionAndSpinCount DB "InitializeCriticalSectionAndSpinCount", 00H
   kszGetVersion DB "GetVersion", 00H

  ; Windows XP and Server 2003 and later have RtlGenRandom, which is exported as SystemFunction036.
  ; If needed, we could fall back to CryptGenRandom(), but that will be much slower
  ; because it has to drag in the entire crypto API.
  ; (See also: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/)
;   kszSystemFunction036   DB "SystemFunction036", 00H
CONST ENDS

.CODE

   ; C++ translation:
   ;    extern "C" VOID WINAPI DownlevelInitializeSListHead(PSLIST_HEADER pHead)
   ;    {
   ;       const HMODULE hmodKernel32 = ::GetModuleHandleW(L"kernel32");
   ;       typedef decltype(InitializeSListHead)* pfnInitializeSListHead;
   ;       const pfnInitializeSListHead pfn = reinterpret_cast<pfnInitializeSListHead>(::GetProcAddress(hmodKernel32, "InitializeSListHead"));
   ;       if (pfn)
   ;       {
   ;          // call WinAPI function
   ;          pfn(pHead);
   ;       }
   ;       else
   ;       {
   ;          // fallback implementation for downlevel
   ;          pHead->Alignment = 0;
   ;       }
   ;    }
   DownlevelInitializeSListHead PROC
      ;; Get a handle to the DLL containing the function of interest.
      push  OFFSET kszKernel32
   IF USE_W_STRINGS
      call  DWORD PTR _imp__GetModuleHandleW@4  ; Returns the handle to the library in EAX.
   ELSE
      call  DWORD PTR _imp__GetModuleHandleA@4  ; Returns the handle to the library in EAX.
   ENDIF

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszInitializeSListHead       ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; Test for success, and call the function if we succeeded.
      test  eax, eax                            ; See if we successfully retrieved a pointer to the function.
      je    SHORT FuncNotSupported              ; Jump on failure (ptr == 0), or fall through in the most-likely case.
      jmp   eax                                 ; We succeeded (ptr != 0), so tail-call the function.

      ;; The dynamic call failed, presumably because the function isn't available.
      ;; So do what _RtlInitializeSListHead@4 (which is what we jump to on uplevel platforms) does,
      ;; which is to set pHead->Alignment to 0. It is a QWORD-sized value, so 32-bit code must
      ;; clear both of the DWORD halves.
    FuncNotSupported:
      mov   edx, DWORD PTR [esp+4]      ; get pHead->Alignment
      xor   eax, eax
      mov   DWORD PTR [edx],   eax      ; pHead->Alignment = 0
      mov   DWORD PTR [edx+4], eax
      ret   4
   DownlevelInitializeSListHead ENDP


   ; C++ translation:
   ;     extern "C" BOOL WINAPI DownlevelGetModuleHandleExW(DWORD dwFlags, LPCTSTR lpModuleName, HMODULE* phModule)
   ;     {
   ;        const HMODULE hmodKernel32 = ::GetModuleHandleW(L"kernel32");
   ;        typedef decltype(GetModuleHandleExW)* pfnGetModuleHandleExW;
   ;        const pfnGetModuleHandleExW pfn = reinterpret_cast<pfnGetModuleHandleExW>(::GetProcAddress(hmodKernel32, "GetModuleHandleExW"));
   ;        if (pfn)
   ;        {
   ;           // call WinAPI function
   ;           return pfn(dwFlags, lpModuleName, phModule);
   ;        }
   ;        else
   ;        {
   ;           // fallback for downlevel: return failure
   ;           return FALSE;
   ;        }
   ;     }
   DownlevelGetModuleHandleExW PROC
      ;; Get a handle to the DLL containing the function of interest.
      push  OFFSET kszKernel32
   IF USE_W_STRINGS
      call  DWORD PTR _imp__GetModuleHandleW@4  ; Returns the handle to the library in EAX.
   ELSE
      call  DWORD PTR _imp__GetModuleHandleA@4  ; Returns the handle to the library in EAX.
   ENDIF

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszGetModuleHandleExW        ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; Test for success, and call the function if we succeeded.
      test  eax, eax                            ; See if we successfully retrieved a pointer to the function.
      je    SHORT FuncNotSupported              ; Jump on failure (ptr == 0), or fall through in the most-likely case.
      jmp   eax                                 ; We succeeded (ptr != 0), so tail-call the function.

      ;; The dynamic call failed, presumably because the function isn't available.
      ;; The basic VS 2015 CRT (used in a simple Win32 app) only calls this function
      ;; in try_cor_exit_process(), as called from common_exit (both in exit.cpp),
      ;; where it uses it to attempt to get a handle to the module mscoree.dll.
      ;; Since we don't care about managed apps, that attempt should rightfully fail.
      ;; If this turns out to be used in other contexts, we'll need to revisit this
      ;; and implement a proper fallback.
    FuncNotSupported:
      jmp   ImplementGetModuleHandleExW@12

   DownlevelGetModuleHandleExW ENDP

   DownlevelEncodeDecodePointer proc
      mov eax, [esp+4]
      ret 4
   DownlevelEncodeDecodePointer endp

;   DownlevelHeapSetInformation proc
;      mov eax, 1
;      ret 10h
;   DownlevelHeapSetInformation endp

;   DownlevelSystemFunction036 PROC
;      int 3   ; break --- stub unimplemented
;      ret 8
;   DownlevelSystemFunction036 ENDP


; Win9x section
IF USE_WIN9X

   ; here we need to return 1 for the crt startup code which checks the return value which on 9x is "none" (throws exception instead)
   ; This section will change the imported function on the first call for NT based OS so that every call doesn't require additional processing.

   DownlevelInitializeCriticalSectionAndSpinCount proc

      push  OFFSET kszKernel32
   IF USE_W_STRINGS
      call  DWORD PTR _imp__GetModuleHandleW@4  ; Returns the handle to the library in EAX.
   ELSE
      call  DWORD PTR _imp__GetModuleHandleA@4  ; Returns the handle to the library in EAX.
   ENDIF

       ;; Save copy of handle
      push  eax

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszInitializeCriticalSectionAndSpinCount ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; Test for success, and call the function if we succeeded.
      test  eax, eax                            ; See if we successfully retrieved a pointer to the function.
      jz    SHORT FuncNotSupported              ; Jump on failure (ptr == 0), or fall through in the most-likely case.

      ;; save address and get back kernel32 handle
      xchg  dword ptr [esp],eax

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszGetVersion                ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; See if function exists
      test  eax,eax
      jz    SHORT FuncNotSupported

      ;; call GetVersion
      call  eax

      ;; check if win9x
      test  eax,80000000h
      pop   eax                                 ; get back address of InitializeCriticalSectionAndSpinCount function
      jz    WinNT

      ;; for Win9x we need to call and then change return code
      push  [esp+8]                             ; Copy the 1st parameter (+4 for IP return address, +4 for fist param)
      push  [esp+8]                             ; Copy the 2nd parameter (recall esp moves on push)
      call  eax
      mov   eax,1
      ret   8

WinNT:
      ;; Change the call address for next calls and call directly
      mov   __imp__InitializeCriticalSectionAndSpinCount@8,eax
      jmp   eax


      ;; We should never end up here but if we do, fail the call
    FuncNotSupported:
      pop  eax
      xor  eax,eax
      ret  8

   DownlevelInitializeCriticalSectionAndSpinCount endp

ENDIF

END

還有第二部分:

// Win9x:
//
// The CRT now uses several "W" versions of functions which is more practial to require
// the use of the Microsoft Layer for Unicode (MSLU) for Windows 9x to implement it.  The 
// unicows.dll (for 9x) should be placed in the program folder with the .exe if using it.
// unicows.dll is only loaded on 9x platforms. The way Win9x works without the MSLU is 
// that several "W" version of functions are located in kernel32.dll but they are just a
// stub that returns failure code. To implement the unicode layer (unicows) the unicode.lib
// must be linked prior to the other libs that should then linked in after unicode.lib.  
// The libraries are:
//
//    kernel32.lib advapi32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib 
//    version.lib mpr.lib rasapi32.lib winmm.lib winspool.lib vfw32.lib 
//    secur32.lib oleacc.lib oledlg.lib sensapi.lib
//


#include <windows.h>

// pull items from ntdef.h
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;

//
// implementation of replacement function for GetModuleHandleExW
//
extern "C" BOOL WINAPI ImplementGetModuleHandleExW(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE* phModule)
{
  // check flag combinations
  if (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;
  }


  // check if to get by address
  if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) {
    *phModule = NULL;

    typedef PVOID (NTAPI *LPFN_RtlPcToFileHeader)(PVOID PcValue, PVOID * BaseOfImage);

    const HMODULE hmodkernel32 = GetModuleHandleW(L"kernel32");
    const LPFN_RtlPcToFileHeader pfnRtlPcToFileHeader = reinterpret_cast<LPFN_RtlPcToFileHeader>(GetProcAddress(hmodkernel32, "RtlPcToFileHeader"));

    if (pfnRtlPcToFileHeader) {
      // use RTL function (nt4+)
      pfnRtlPcToFileHeader((PVOID)lpModuleName, (PVOID*)phModule);
    }
    else {
      // query memory directly (win9x)
      MEMORY_BASIC_INFORMATION mbi; 
      if (VirtualQuery((PVOID)lpModuleName, &mbi, sizeof(mbi)) >= offsetof(MEMORY_BASIC_INFORMATION, AllocationProtect)) {
        *phModule = reinterpret_cast<HMODULE>(mbi.AllocationBase);
      }
    }
  }
  else {
    // standard getmodulehandle - to see if loaded
    *phModule = GetModuleHandleW(lpModuleName);
  }


  // check if module found
  if (*phModule == NULL) {
    SetLastError(ERROR_DLL_NOT_FOUND);
    return FALSE;
  }

  // check if reference needs updating
  if ((dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0) {

    typedef NTSTATUS(NTAPI *LPFN_LdrAddRefDll)(ULONG Flags, PVOID BaseAddress);
    #define LDR_ADDREF_DLL_PIN   0x00000001

    const HMODULE hmodntdll = GetModuleHandleW(L"ntdll");
    const LPFN_LdrAddRefDll pfnLdrAddRefDll = reinterpret_cast<LPFN_LdrAddRefDll>(GetProcAddress(hmodntdll, "LdrAddRefDll"));

    if (pfnLdrAddRefDll) {
      // update dll reference
      if (!NT_SUCCESS(pfnLdrAddRefDll((dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) ? LDR_ADDREF_DLL_PIN : 0, *phModule))) {
        SetLastError(ERROR_GEN_FAILURE);
        return FALSE;
      }
    }
    else if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) {
      SetLastError(ERROR_NOT_SUPPORTED);
      return FALSE;
    }
    else {
      WCHAR *filename;
      if ((filename=reinterpret_cast<WCHAR*>(VirtualAlloc(NULL, MAX_PATH*sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE)))!=NULL) {
        DWORD ret = GetModuleFileNameW(*phModule, filename, MAX_PATH);
        if (ret < MAX_PATH) {
          *phModule = LoadLibraryW(filename);
        }
        else *phModule = NULL;
        VirtualFree(filename, 0, MEM_RELEASE);
        // ensure load library success
        if (*phModule == NULL) {
          return FALSE;
        }
      }
      else {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;
      }
    }
  }
  return TRUE;
}

//
// implementation of replacement function for SetFilePointerEx
//
extern "C" BOOL WINAPI ImplementSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
{
  DWORD ret=SetFilePointer(hFile, liDistanceToMove.LowPart, &liDistanceToMove.HighPart, dwMoveMethod);
  if (ret == INVALID_SET_FILE_POINTER) {
    if (GetLastError() != NO_ERROR) {
      return FALSE;
    }
  }
  // check if provide file location
  if (lpNewFilePointer) {
    lpNewFilePointer->LowPart = ret;
    lpNewFilePointer->HighPart = liDistanceToMove.HighPart;
  }
  // success
  return TRUE;
}

如您所說,VS 2008可以將Windows 2000作為目標。 您不需要任何額外的東西。 如果您希望使用更新版本的IDE,則可以同時安裝多個Visual Studio版本(始終首先安裝最舊的版本,並及時進行“轉發”), 例如 ,可以在VS 2010中工作,但告訴它進行構建使用VS 2008工具鏈。 顯然,您將無法從VS 2010引入的編譯器功能中受益,但是您將可以使用較新的IDE。

您可以使用VS 2010通過EncodePointer / DecodePointer技巧將Windows 2000定位為目標。 這里的問題是,VS 2010 C運行時庫(CRT)需要這些函數(內部調用它們),但是在Windows XP SP2之前的OS版本中不存在這些函數。 但是,如果編寫存根並將它們鏈接到可執行文件(同時還靜態鏈接到CRT,因此它實際上會找到並使用這些存根),則可以在Windows 2000上運行VS 2010編譯的EXE。請注意,您將還需要在鏈接器設置中將最低要求版本設置為5.0。 (這樣做時,您會得到一個鏈接時警告,它不是有效的受支持版本,但您可以忽略此警告。它確實起作用,並且確實在PE標頭中設置了該字段。)無疑是一個骯臟的把戲,但我知道它的效果很好。 我在幾個項目中都這樣做。 如果存根在當前操作系統上可用,我的存根會動態調用真正的EncodePointer / DecodePointer函數,如果沒有,則基本上退回到無操作狀態(放棄了這些下層OS的安全性優勢)。 蘇馬在回答相關問題時已經很好地涵蓋了這個技巧

WINVER_WIN32_WINNT定義確實與此無關。 它們僅控制Windows SDK標頭實際定義的功能原型。 想法是將這些設置為目標Windows版本,然后您將只能靜態鏈接到該Windows版本上實際存在的功能。 在適當版本的Windows上運行時,您仍然可以動態調用(通過GetModuleHandle / LoadLibrary→GetProcAddress)較新的函數,如果不支持,則可以適當地回退。 如果您嘗試靜態鏈接到不存在的功能,則當您嘗試運行應用程序時,加載程序將生成錯誤。 不過,這很容易,因為作為開發人員,這完全在您的控制范圍之內。 問題是當CRT(您無法控制的庫)調用不存在的函數(例如EncodePointer)時。 這就是為什么需要上述解決方法的原因。 WINVER_WIN32_WINNT的值對編譯器或鏈接器沒有實際影響。

也許可以蒙混過關了類似的伎倆VS 2012年我開始做這項工作了一段時間后與VS 2015年使用內置在XP定向支持,我還是設法得到一個“Hello World”應用程序在Windows 2000上運行如果有的話,VS 2012比VS 2015應該更容易。但這並不容易,這可能是任何現實應用程序的支持夢night。 盡管如此,這還是一個有趣的實驗,它證實了每個人都已經知道的問題:這里的問題不是編譯器或鏈接器。 PE格式仍然相同; 任何針對Win32的編譯器或鏈接器都可以生成在任何版本的Windows NT上運行的二進制文件。 問題只是C運行時庫試圖調用下層操作系統上不存在的函數。

測試此方法的方法是使用上述EncodePointer / DecodePointer技巧,使用VS 2012編譯EXE。 當然,您還需要確保已在鏈接器設置中將所需的最低版本設置為5.0。 (如果這不起作用,也可能不起作用,那么您將需要使用editbin.exe構建后的步驟中手動進行更改。)然后,只需嘗試在Windows 2000上運行該可執行文件即可。無疑,您會收到一條錯誤消息。指示由於缺少靜態鏈接功能而導致應用程序無法啟動。 然后,您需要研究該功能並將其存根,就像對EncodePointer / DecodePointer所做的一樣。 可能會更加困難,因為它可能會執行有意義的工作,這意味着您不能簡單地將其淘汰。 解決了對該函數的依賴性后,請對W2K加載程序抱怨的每個函數再次重復該過程。 (您也可以使用Dependency Walker或等效的實用程序來獲取此信息。)一旦完成所有不存在的功能,您最終將運行一個EXE。

對於VS 2015,除了EncodePointer和DecodePointer之外,我還必須為InitializeSListHead,GetModuleHandleEx和SystemFunction036(這是RtlGenRandom的導出名稱)編寫存根。 我希望您在VS 2012上也有類似的經驗。替換前兩個實際上相對簡單。 對於InitializeSListHead,我只是對Windows XP上的相應功能進行了反向工程,並為下層OS版本編寫了自己的實現。 對於GetModuleHandleEx,它僅由CRT在啟用對托管應用程序的支持的上下文中調用。 由於我不在乎這些,因此我將其變成了無操作的返回失敗的操作。 SystemFunction036(RtlGenRandom)更加困難,但是如果您不使用rand(並且您可能不應該使用),那么您也不需要它。 我只是將其存為斷點( int 3 )。 您也可以將其存根以調用CryptGenRandom。 如果您在代碼方面的表現勝於散文,這是我在“ Hello world”應用中使用的存根的近似值:

.386
.MODEL flat, stdcall


.DATA
   ;; Override the import symbols from kernel32.dll
   __imp__InitializeSListHead@4    DWORD DownlevelInitializeSListHead
   __imp__GetModuleHandleExW@12    DWORD DownlevelGetModuleHandleExW
   EXTERNDEF STDCALL __imp__InitializeSListHead@4 : DWORD
   EXTERNDEF STDCALL __imp__GetModuleHandleExW@12 : DWORD

   ;; Declare functions that we will call statically
   EXTRN STDCALL _imp__GetModuleHandleW@4  : DWORD
   EXTRN STDCALL _imp__GetProcAddress@8    : DWORD

CONST SEGMENT
   kszKernel32            DB 'k', 00H, 'e', 00H, 'r', 00H, 'n', 00H, 'e', 00H, 'l', 00H, '3', 00H, '2', 00H, 00H, 00H
   kszAdvApi32            DB 'a', 00H, 'd', 00H, 'v', 00H, 'a', 00H, 'p', 00H, 'i', 00H, '3', 00H, '2', 00H, 00H, 00H
   kszInitializeSListHead DB "InitializeSListHead", 00H
   kszGetModuleHandleExW  DB "GetModuleHandleExW", 00H

  ; Windows XP and Server 2003 and later have RtlGenRandom, which is exported as SystemFunction036.
  ; If needed, we could fall back to CryptGenRandom(), but that will be much slower
  ; because it has to drag in the entire crypto API.
  ; (See also: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/)
   kszSystemFunction036   DB "SystemFunction036", 00H
CONST ENDS

.CODE

   ; C++ translation:
   ;    extern "C" VOID WINAPI DownlevelInitializeSListHead(PSLIST_HEADER pHead)
   ;    {
   ;       const HMODULE hmodKernel32 = ::GetModuleHandleW(L"kernel32");
   ;       typedef decltype(InitializeSListHead)* pfnInitializeSListHead;
   ;       const pfnInitializeSListHead pfn = reinterpret_cast<pfnInitializeSListHead>(::GetProcAddress(hmodKernel32, "InitializeSListHead"));
   ;       if (pfn)
   ;       {
   ;          // call WinAPI function
   ;          pfn(pHead);
   ;       }
   ;       else
   ;       {
   ;          // fallback implementation for downlevel
   ;          pHead->Alignment = 0;
   ;       }
   ;    }
   DownlevelInitializeSListHead PROC
      ;; Get a handle to the DLL containing the function of interest.
      push  OFFSET kszKernel32
      call  DWORD PTR _imp__GetModuleHandleW@4  ; Returns the handle to the library in EAX.

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszInitializeSListHead       ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; Test for success, and call the function if we succeeded.
      test  eax, eax                            ; See if we successfully retrieved a pointer to the function.
      je    SHORT FuncNotSupported              ; Jump on failure (ptr == 0), or fall through in the most-likely case.
      jmp   eax                                 ; We succeeded (ptr != 0), so tail-call the function.

      ;; The dynamic call failed, presumably because the function isn't available.
      ;; So do what _RtlInitializeSListHead@4 (which is what we jump to on uplevel platforms) does,
      ;; which is to set pHead->Alignment to 0. It is a QWORD-sized value, so 32-bit code must
      ;; clear both of the DWORD halves.
   FuncNotSupported:
      mov   edx, DWORD PTR [esp+4]      ; get pHead->Alignment
      xor   eax, eax
      mov   DWORD PTR [edx],   eax      ; pHead->Alignment = 0
      mov   DWORD PTR [edx+4], eax
      ret   4
   DownlevelInitializeSListHead ENDP


   ; C++ translation:
   ;     extern "C" BOOL WINAPI DownlevelGetModuleHandleExW(DWORD dwFlags, LPCTSTR lpModuleName, HMODULE* phModule)
   ;     {
   ;        const HMODULE hmodKernel32 = ::GetModuleHandleW(L"kernel32");
   ;        typedef decltype(GetModuleHandleExW)* pfnGetModuleHandleExW;
   ;        const pfnGetModuleHandleExW pfn = reinterpret_cast<pfnGetModuleHandleExW>(::GetProcAddress(hmodKernel32, "GetModuleHandleExW"));
   ;        if (pfn)
   ;        {
   ;           // call WinAPI function
   ;           return pfn(dwFlags, lpModuleName, phModule);
   ;        }
   ;        else
   ;        {
   ;           // fallback for downlevel: return failure
   ;           return FALSE;
   ;        }
   ;     }
   DownlevelGetModuleHandleExW PROC
      ;; Get a handle to the DLL containing the function of interest.
      push  OFFSET kszKernel32
      call  DWORD PTR _imp__GetModuleHandleW@4  ; Returns the handle to the library in EAX.

       ;; Attempt to obtain a pointer to the function of interest.
      push  OFFSET kszGetModuleHandleExW        ; Push 2nd parameter (string containing function's name).
      push  eax                                 ; Push 1st parameter (handle to the library).
      call  DWORD PTR _imp__GetProcAddress@8    ; Returns the pointer to the function in EAX.

      ;; Test for success, and call the function if we succeeded.
      test  eax, eax                            ; See if we successfully retrieved a pointer to the function.
      je    SHORT FuncNotSupported              ; Jump on failure (ptr == 0), or fall through in the most-likely case.
      jmp   eax                                 ; We succeeded (ptr != 0), so tail-call the function.

      ;; The dynamic call failed, presumably because the function isn't available.
      ;; The basic VS 2015 CRT (used in a simple Win32 app) only calls this function
      ;; in try_cor_exit_process(), as called from common_exit (both in exit.cpp),
      ;; where it uses it to attempt to get a handle to the module mscoree.dll.
      ;; Since we don't care about managed apps, that attempt should rightfully fail.
      ;; If this turns out to be used in other contexts, we'll need to revisit this
      ;; and implement a proper fallback.
  FuncNotSupported:
      xor   eax, eax   ; return failure
      ret   12
   DownlevelGetModuleHandleExW ENDP


   DownlevelSystemFunction036 PROC
      int 3   ; break --- stub unimplemented
      ret 8
   DownlevelSystemFunction036 ENDP

END

Roy在評論中指出, Microsoft提供了MIT許可的SList實現,實現僅需要InterlockedCompareExchange()。 這將使您的工作稍微容易一些,因為您不必像我一樣對任何SList函數進行反向工程。

不用說,您應該不惜一切代價避免使用MFC,ATL和其他源代碼超出您控制范圍的庫。 它們將依賴於較低版本的操作系統上不可用的功能,從而為您帶來更多工作。 您確實需要將自己限制為原始Win32,這意味着您唯一需要擔心的庫是CRT。

ew! 那應該讓您開始。 如果您對此深深着迷,而不是被它吸引住了,那么您幾乎可以肯定與這種黑客毫無關系。 使用較舊版本的編譯器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM