News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Retrieving Windows OS Version

Started by bluedevil, June 06, 2017, 01:40:10 AM

Previous topic - Next topic

bluedevil

Hello;
There were several threads opened in the past in MASM forum; these are about retrieving Windows' version:
http://www.masmforum.com/board/index.php?topic=11963.0
http://masm32.com/board/index.php?topic=4653.0
http://www.masmforum.com/board/index.php?PHPSESSID=8d46cd4ecb1688be429ab49694ec53e6&topic=6488.0;wap2
http://masm32.com/board/index.php?topic=3629.0


OK! I have written some code about this issue. I want my code to understand which version of Windows it is running - in the lowest level- and prints as much info as about windows version structure
In this code i used:
APIs:
GetVersion
GetVersionEx
RtlGetVersion
Structures:
OSVERSIONINFO
OSVERSIONINFOEX
RTL_OSVERSIONINFOEXW

I have compiled this by using ML.exe v14 (why? because i have forgot that binary inside the masm/bin directory)
I have tested on win10x64, win7x86, winXpx86, and works. But i have some issues

1.Getting info from PEB is just awesome and fast:
print "Read From Process Environment Block:",13,10
    ASSUME FS:Nothing
    mov edx,fs:[30h] ;PEB.InheritedAddressSpace
    ASSUME  FS:ERROR
    mov     eax,[edx+0A4h] ;eax = Major Version
    push eax
    push    edx
    print   ustr$(eax),'.'
    pop     edx
    push edx
    mov     eax,[edx+0A8h] ;eax = Minor Version
    print   ustr$(eax),'.'
    pop edx
    mov eax,[edx+0ACh] ;eax = build
    and eax,0FFFFh ;because win 7 collapses
    print ustr$(eax),13,10,13,10
pop eax

I can retrieve version(maj,min,build) from PEB. Can i get ServicePack info from here. Here are some documentations.
PEB Structure MSDN
A Good PDF about PEB
Windows Heap Overflows using the Process Environment Block (PEB)
According to these docs PEB structure also provides us

+0x1f0 CSDVersion : _UNICODE_STRING "Service Pack 1"

Which i couldn't managed to retrieve. But also is it possible to get Servicepack maj and min version numbers to retrieve from PEB?

2. I want to make a single executable which can run on all windows versions (i mean at least win xp to win 10 - but from 3.1 to 10 would be awesome :eusa_dance: seriously is that possible?) and checks version. Win XP returns 0 while using GetVersion API. And also Win XPdoenst retrieve Service pack maj min versions. Is it normal?
3.RtlGetVersion doesnt retrieve service pack versions on windows 7 :/ Am i doing wrong?

4. I cant compile RtlGetSuiteMask  I just want to try this NTAPI but masm gave error like not defined even i declared "ntdll.lib". So is this api useless or can i make this NTAPI run? Or is this impossible?

5.Finally; i am just trying to learn stuff. I want to print every element on OSVERSIONINFO, OSVERSIONINFOEX, RTL_OSVERSIONINFOEXW. That is why i am asking here.

Replies are welcome
..Dreams make the future
But the past never lies..
BlueDeviL // SCT
My Code Site:
BlueDeviL Github

aw27

I have just 3 comments:
1) There are new APIs for Windows 7 and above.
2) RtlGetVersion was thought for device drivers, but is obsolete as well for new Windows release.
3) Using the PEB for whatever is subject to changes without notice between Windows releases.
Anyway for Windows 10:
   +0x0a4 OSMajorVersion   : Uint4B
   +0x0a8 OSMinorVersion   : Uint4B
   +0x0ac OSBuildNumber    : Uint2B
   +0x0ae OSCSDVersion     : Uint2B
   +0x0b0 OSPlatformId     : Uint4B
   +0x0b4 ImageSubsystem   : Uint4B
   +0x0b8 ImageSubsystemMajorVersion : Uint4B
   +0x0bc ImageSubsystemMinorVersion : Uint4B

Quote
A Good PDF about PEB
The best documentation is Windbg, but is a pain to learn to work with it  :badgrin:

bluedevil

Quote from: aw27 on June 06, 2017, 02:36:22 AM
The best documentation is Windbg, but is a pain to learn to work with it  :badgrin:
Totally aggree with that!!
..Dreams make the future
But the past never lies..
BlueDeviL // SCT
My Code Site:
BlueDeviL Github

jj2007

include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  Print Str$("This is Windows version %i", MbWinVersion()), Str$(".%i", ecx)
  void MbWinVersion()
  Print Str$(", build %i", dx)
EndOfCode


Output:
This is Windows version 6.1, build 7601

A look under the hood with Olly:
RtlGetNtVersion Ú$  8BFF                         mov edi, edi                           ; ntdll.RtlGetNtVersionNumbers
77B0B35F        ³.  55                           push ebp
77B0B360        ³.  8BEC                         mov ebp, esp
77B0B362        ³.  8B45 08                      mov eax, [ebp+8]
77B0B365        ³.  85C0                         test eax, eax
77B0B367        ³. 74 06                        jz short 77B0B36F
77B0B369        ³.  C700 06000000                mov dword ptr [eax], 6                 ; major version
77B0B36F        ³>  8B45 0C                      mov eax, [ebp+0C]
77B0B372        ³.  85C0                         test eax, eax
77B0B374        ³. 74 06                        jz short 77B0B37C
77B0B376        ³.  C700 01000000                mov dword ptr [eax], 1                 ; minor version
77B0B37C        ³>  8B45 10                      mov eax, [ebp+10]
77B0B37F        ³.  85C0                         test eax, eax
77B0B381        ³. 0F85 3F4D0300                jnz 77B400C6                           ; get build # and come back here
77B0B387        ³>  5D                           pop ebp
77B0B388        À.  C2 0C00                      retn 0C
...
77B400C6        Ú> ÀC700 B11D00F0                mov dword ptr [eax], F0001DB1          ; $1DB1=7601
77B400CC        À. E9 B6B2FCFF                  jmp 77B0B387


Note the sophisticated method used by the OS to return 6.1 and the build number 8)

Raistlin

Could'nt Test  ::)- as per normal - virus scanner went nuts - Symantec Endpoint ...
Seems you have the same problems as me - Version Info Block and Manifest.
I used the following longer code blocks in my enumerator ExtremeID - re:
GetVersion, GetVersionEx, OSVERSIONINFO ,OSVERSIONINFOEX  etc. - which
seems to work well. There is also a couple of tricks to enumerate all intermediate
SKU's (Microsoft stock keeping units) operating systems - but I do find your
method intriguing (shorter & thus faster) and will investigate feasibility.
Are you pondering what I'm pondering? It's time to take over the world ! - let's use ASSEMBLY...

bluedevil

Quote from: Raistlin on June 06, 2017, 03:25:50 PM
but I do find your
method intriguing (shorter & thus faster) and will investigate feasibility.
Thank you 8)

Quote from: jj2007 on June 06, 2017, 09:58:26 AM
include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  Print Str$("This is Windows version %i", MbWinVersion()), Str$(".%i", ecx)
  void MbWinVersion()
  Print Str$(", build %i", dx)
EndOfCode


Output:
This is Windows version 6.1, build 7601

A look under the hood with Olly:
RtlGetNtVersion Ú$  8BFF                         mov edi, edi                           ; ntdll.RtlGetNtVersionNumbers
77B0B35F        ³.  55                           push ebp
77B0B360        ³.  8BEC                         mov ebp, esp
77B0B362        ³.  8B45 08                      mov eax, [ebp+8]
77B0B365        ³.  85C0                         test eax, eax
77B0B367        ³. 74 06                        jz short 77B0B36F
77B0B369        ³.  C700 06000000                mov dword ptr [eax], 6                 ; major version
77B0B36F        ³>  8B45 0C                      mov eax, [ebp+0C]
77B0B372        ³.  85C0                         test eax, eax
77B0B374        ³. 74 06                        jz short 77B0B37C
77B0B376        ³.  C700 01000000                mov dword ptr [eax], 1                 ; minor version
77B0B37C        ³>  8B45 10                      mov eax, [ebp+10]
77B0B37F        ³.  85C0                         test eax, eax
77B0B381        ³. 0F85 3F4D0300                jnz 77B400C6                           ; get build # and come back here
77B0B387        ³>  5D                           pop ebp
77B0B388        À.  C2 0C00                      retn 0C
...
77B400C6        Ú> ÀC700 B11D00F0                mov dword ptr [eax], F0001DB1          ; $1DB1=7601
77B400CC        À. E9 B6B2FCFF                  jmp 77B0B387


Note the sophisticated method used by the OS to return 6.1 and the build number 8)

Your code works like charm on Win10x64 (i have masmbasic). And i saw the trick comes from RtlGetNtVersionNumbers. But according to these links:
https://source.winehq.org/WineAPI/RtlGetNtVersionNumbers.html
http://man.docs.sk/3w/rtlgetntversionnumbers.html
We can get only major minor and build. How can you get ServicePack info jj2007 ?
..Dreams make the future
But the past never lies..
BlueDeviL // SCT
My Code Site:
BlueDeviL Github

jj2007

This relates to a post by adeyblue. The problem here is really the lack of documentation by M$. Wine has it, though.

Note this is a can of worms, as even Microsoft admits:
QuoteWe have made some significant changes in how the GetVersion(Ex) APIs work in Windows 8.1 due to undesirable customer behaviors resulting from how the GetVersion(Ex) APIs have been used in the past.

In previous versions of Windows, calling the GetVersion(Ex) APIs would return the actual version of the operating system (OS), unless the process had been mitigated by an app compat shim to give it a different version. This was done on a provisional basis and was relatively incomplete in terms of the number of processes that Microsoft could reasonably shim in a release. Many applications fell through the cracks because they didn't get shimmed due to poorly designed version checks.

The number one reason to do a version check is to show some message of OS supportability for the application. However due to the poor checks, the message would often show that the app needed to be run on XP or later, which of course the newest OS is. More often than not, the newest OS would run the application without any issues if not for these checks.

If there was a Pulitzer prize for software documentation, the author would be a hot candidate :P

Another real jewel from the same MSDN page:#include <VersionHelpers.h>
...
    if (!IsWindows8OrGreater())
    {
       MessageBox(NULL, "You need at least Windows 8", "Version Not Supported", MB_OK);
    }


There are a few more:See also

IsWindowsXPSP1OrGreater
IsWindowsXPSP2OrGreater
IsWindowsXPSP3OrGreater
IsWindowsVistaOrGreater
IsWindowsVistaSP1OrGreater
IsWindowsVistaSP2OrGreater
IsWindows7OrGreater
IsWindows7SP1OrGreater
IsWindows8OrGreater
IsWindows8Point1OrGreater
IsWindowsServer


The main purpose of these "helper" functions is evidently to help kick Windows XP out of the software market, because programs written with these new "helpers" will probably not run on XP 8)

bluedevil

@jj2007 i am totally aggre with you!

1. I have seen these functions while searching, but as you say these apis wont work on a xp machine?
See also

IsWindowsXPSP1OrGreater
IsWindowsXPSP2OrGreater
IsWindowsXPSP3OrGreater
IsWindowsVistaOrGreater
IsWindowsVistaSP1OrGreater
IsWindowsVistaSP2OrGreater
IsWindows7OrGreater
IsWindows7SP1OrGreater
IsWindows8OrGreater
IsWindows8Point1OrGreater
IsWindowsServer

But i will make an example with these 8)

BTW i am reading fresh new "Windows Internals 7" right at the moment, and it says on page 55:
QuoteWith so many different editions of Windows and each having the same kernel image, how does the system know which edition is booted? By querying the registry values "ProductType" and "ProductSuite" under the HKLM\SYSTEM\CurrentControlSet\Control\ProductOptions key. "ProductType" is used to distinguish whether the system is a client system or a server system (of any flavor). These values are loaded into the registry based on the licensing policyfile described earlier. The valid values are listed in Table 2-3. This can be queried from the user-mode "VerifyVersionInfo" function or from a device deriver using the kernel-mode support function "RtlVerifyVersion" and "RtlVerifyVersionInfo", both documented in the Windows Driver Kit  (WDK).

And with this info i checked "VerifyVersionInfo" function:
QuoteThe VerifyVersionInfo function retrieves version information about the currently running operating system and compares it to the valid members of the lpVersionInfo structure. This enables you to easily determine the presence of a required set of operating system version conditions. It is preferable to use VerifyVersionInfo rather than calling the GetVersionEx function to perform your own comparisons.

I will implement this function in my very first free time :t Because according to MSDN VerifyVersionInfo needs Win2000 and above.
..Dreams make the future
But the past never lies..
BlueDeviL // SCT
My Code Site:
BlueDeviL Github

jj2007

Quote from: blue_devil on June 06, 2017, 09:33:17 PM
@jj2007 i am totally aggre with you!

1. I have seen these functions while searching, but as you say these apis wont work on a xp machine?
...
according to MSDN VerifyVersionInfo needs Win2000 and above.

You already gave the answer :biggrin:

Yes, they will probably work (XP>2000), all you have to do is download and install a few gigabytes of "appcompat shi*" SDK or similar to get the VersionHelper.h and its macros.

Btw I am shocked that so far nobody has tested RtlVerifyVersionInfo here, another magic answer to the old "hey, which Windows are you??" question :shock:

Here is one more for the fans of Douglas Adams:include \masm32\MasmBasic\MasmBasic.inc
WhichWindowsAreYou? MACRO
  EXITM Chr$("This is Windows 42")
ENDM
  Init
  Inkey WhichWindowsAreYou?()
EndOfCode


In the end, I picked RtlGetNtVersionNumbers for MbWinVersion() because it's hard-coded into ntdll. No chance for any tricks, this is the real thing. But of course, undocumented, use at your own risk bla bla, and don't forget to put some bets on the possibility that one day in the near future (2100?) Micros**t may remove that function (used e.g. in C:\Windows\System32\msvcrt.dll) from ntdll 8)

TWell

Verifying the System Version
Quote[ Use of the VerifyVersionInfo function to verify the currently running operating system is not recommended. Instead, use the Version Helper APIs]
QuoteThe Version Helper functions use the VerifyVersionInfo function, so the behavior IsWindows8Point1OrGreater and IsWindows10OrGreater are similarly affected by the presence and content of the manifest.
QuoteVerifyVersionInfo function
Compares a set of operating system version requirements to the corresponding values for the currently running version of the system. This function is subject to manifest-based behavior. For more information, see the Remarks section.
link
:P

hutch--

Its easy to write software for XP, use the old API functions in Win32.hlp. For later stuff up to XP, look for one of the older (pre Vista) SDK's where you got offline help files. If you try and use the later stuff you will run into M$ dirty work excluding XP by design.

nidud

#11
deleted

bluedevil

Quote from: nidud on June 07, 2017, 03:22:54 AM
Maybe the LINK version in the dll header could give a clue about "version trickery".

ver32.exe:

include stdio.inc
include tchar.inc
include winbase.inc

    .code

main proc
    .if LoadLibrary("ntdll.dll")
mov edi,eax
mov ebx,[edi+0x3C]
movzx eax,[edi+ebx].IMAGE_NT_HEADERS.OptionalHeader.MajorLinkerVersion
movzx edx,[edi+ebx].IMAGE_NT_HEADERS.OptionalHeader.MinorLinkerVersion
printf("Link:    %d.%d\n", eax, edx)
movzx eax,[edi+ebx].IMAGE_NT_HEADERS.OptionalHeader.MajorOperatingSystemVersion
movzx edx,[edi+ebx].IMAGE_NT_HEADERS.OptionalHeader.MinorOperatingSystemVersion
printf("Windows: %d.%d\n", eax, edx)
FreeLibrary(edi)
    .else
printf("NTDLL not found..\n")
    .endif
    xor eax,eax
    ret
main endp

    end _tstart


ver64.exe:

include stdio.inc
include tchar.inc
include winbase.inc

    .code

main proc
    .if LoadLibrary("ntdll.dll")
mov rdi,rax
mov ebx,[rdi+0x3C]
movzx eax,[rdi+rbx].IMAGE_NT_HEADERS.OptionalHeader.MajorLinkerVersion
movzx edx,[rdi+rbx].IMAGE_NT_HEADERS.OptionalHeader.MinorLinkerVersion
printf("Link:    %d.%d\n",rax,rdx)
movzx eax,[rdi+rbx].IMAGE_NT_HEADERS.OptionalHeader.MajorOperatingSystemVersion
movzx edx,[rdi+rbx].IMAGE_NT_HEADERS.OptionalHeader.MinorOperatingSystemVersion
printf("Windows: %d.%d\n",rax,rdx)
FreeLibrary(rdi)
    .else
printf("NTDLL not found..\n")
    .endif
    xor eax,eax
    ret
main endp

    end _tstart


Win7-64

ver32:
Link: 9.0
Windows: 6.1

ver64:
Link: 9.0
Windows: 6.1

Thanks for your reply. nidud. I want to ask smth to you.
1.Where did you compile these sources? Under MASM32 or another assembler?
2.Those include files => stdio.inc, tchar.inc, winbase.inc. Where did you find them. I mean i use masm32 v11 and under the include directory there is no files like that.


And generally i want to ask a question. We find several instances of version information. But service pack information is still obscure. I wonder did microsoft put an integer like -version info- to specify the service pack? Or did they (or 3rd parties) retrieves this information from "build" numbers. Like:
Quote6.1.7600.16385    4A5BDADB (14th July 2009)    1,286,144    Windows 7
6.1.7601.17514    4CE7B96E (20th November 2010)    1,288,488    Windows 7 SP1
Look above, maybe microsoft or other people retrieve build numbers and compares with hardcoded numbers and says this is service pack 1?

For example Win10 has no service pack right at the moment. Maybe it will 4 years later ok? So can we code a example that could gives us win10's sp info? Is it that much hidden  :badgrin:
..Dreams make the future
But the past never lies..
BlueDeviL // SCT
My Code Site:
BlueDeviL Github

aw27

RtlGetVersion has the Service pack in the returned structure. Unlike others this one still works for Windows 10 although Microsoft is trying to pull away from it.

It is also in the PEB as shown above:
+0x0ae OSCSDVersion (32-bit only)
for Windows 64 bit is at:
+0x122 OSCSDVersion
The current values should be 0


nidud

#14
deleted