Results 1 to 12 of 12

Thread: XGETBV trickies

  1. #1
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1

    XGETBV trickies

    Well, started play for some reassembly & meet this XGETBV instruction (AVX related?), which quite puzzled me.
    this instruction is included in CPU detection routines with bunch of CPUIDs. ..and..
    when I ripped these routines, XGETBV does fault in my prog! while not doing in there.. (FFox)
    now I have few assumpts:
    1. instruction activated by specifically compiled mz-pe header?? (tried some flags..) or signed pe-images?
    2. instruction activated by some call to system?
    3. or in registry is granted some keys upon installation? (less likely)

    also, checked inet, where is few info:
    https://www.felixcloutier.com/x86/xgetbv

    here is written about ECX=1. while in FFox ECX=0

    https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xgetbv
    "Currently, only the value '0' is allowed."

    Code:
    Code010001010:
        push ebx
        push edi
        push esi
        pushf
        pop eax
        mov ecx eax
        xor eax 0200000
        push eax
        popf
        pushf
        pop eax
        mov edx 0
        cmp ecx eax | je Code01000102E
        mov edx 01
    Code01000102E:
        test edx edx | je Code0100010F1
        xor eax eax
        cpuid
        test eax eax | je Code0100010F1
        mov esi eax
        xor ecx ecx
        mov eax 01
        cpuid
        mov eax ecx
        shr edx 017
        and al 01
        and dl 01
        mov B$Virtual0100695ED al
        mov eax ecx
        mov B$Virtual0100695EC dl
        shr eax 09
        and al 01
        cmp esi 080000001
        mov B$Virtual0100695EE al
        mov eax 0 | jb Code01000108F
        mov edi ecx
        mov eax 080000001
        xor ecx ecx
        cpuid
        mov eax ecx
        shr al 06
        mov ecx edi
        and al 01
    Code01000108F:
        mov B$Virtual0100695EF al
        mov eax ecx
        mov edx ecx
        shr eax 013
        and edx 01C000000
        and al 01
        mov B$Virtual0100695F0 al
        mov eax ecx
        shr eax 014
        and al 01
        cmp edx 01C000000
        mov B$Virtual0100695F1 al | jne Code01000112D
        mov edi ecx
        xor ecx ecx
        xgetbv
        and eax 06
        xor ebx ebx
        cmp eax 06
        sete B$Virtual0100695F2
        cmp esi 07

  2. #2
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,525
    Blog Entries
    15
    xgetbv is compiled via the intrinsic _xgetbv defined in immintrin.h
    as far as i know only one register is defined XCR0 == 0

    but this intrinsic also takes 1 as its parameter
    and returns result in EAX:EDX (this can probably be used as an anti debugging feature )
    because the results are different inside and outside of debugger (3 no debugger ,7 with debugger afaik)


    Code:
    :\>f:\git\usr\bin\grep -ir xcr --include=*.h *
    immintrin.h:#define _XCR_XFEATURE_ENABLED_MASK 0
    
    :\>f:\git\usr\bin\grep -n -A 6 -B 6 -ir xcr --include=*.h *
    immintrin.h-1082-
    immintrin.h-1083-/* Start of new intrinsics for Dev10 SP1
    immintrin.h-1084- *
    immintrin.h-1085- * The list of extended control registers.
    immintrin.h-1086- * Currently, the list includes only one register.
    immintrin.h-1087- */
    immintrin.h:1088:#define _XCR_XFEATURE_ENABLED_MASK 0
    immintrin.h-1089-
    immintrin.h-1090-/* Returns the content of the specified extended control register */
    immintrin.h-1091-extern unsigned __int64 __cdecl _xgetbv(unsigned int ext_ctrl_reg);
    immintrin.h-1092-
    immintrin.h-1093-/* Writes the value to the specified extended control register */
    immintrin.h-1094-extern void __cdecl _xsetbv(unsigned int ext_ctrl_reg, unsigned __int64 val);
    you can use windbg in kmode to look at xcr0

    Code:
    0: kd> dx @$curprocess.Threads.First().Registers.Kernel
    @$curprocess.Threads.First().Registers.Kernel                
        cr0              : 0x80050033
        cr2              : 0xffffe70634a784c0
        cr3              : 0x45f81002
        cr4              : 0x170678
        cr8              : 0x0
        gdtr             : 0xfffff802531f0fb0
        gdtl             : 0x57
        idtr             : 0xfffff802531ee000
        idtl             : 0xfff
        tr               : 0x40
        ldtr             : 0x0
        kmxcsr           : 0x1f80
        kdr0             : 0x0
        kdr1             : 0x0
        kdr2             : 0x0
        kdr3             : 0x0
        kdr6             : 0xffff0ff0
        kdr7             : 0x400
        xcr0             : 0x1f   <<<<<<

    nothing special needed like registry or whatever it will compile and run correctly without any cpuid if you have a computer that can use that instruction as below

    Code:
    #include <stdio.h>
    #include <windows.h>
    #include <intrin.h>
    #include <excpt.h>
    	unsigned long long foo = 0;
    int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
    {
        if (code == EXCEPTION_ACCESS_VIOLATION)
        {
            printf("Access Violation ");
    		foo = 0;
            return EXCEPTION_EXECUTE_HANDLER;
        }
        else
        {
            puts("didn't catch AV, unexpected.");
            return EXCEPTION_CONTINUE_SEARCH;
        };
    }
    
    void main(void)
    {
    	printf("lets print some xcrs\n");
    
    	for (int i=0;i<0x10;i++){
    		__try {
    		 foo = _xgetbv(i);
    		 printf( "                 %x = %I64X\n" , i,foo);
    		}__except(filter(GetExceptionCode(), GetExceptionInformation()))
    		{
    		printf( "%x = %I64X\n" , i,foo);
    		}
    	}
    }
    will return

    Code:
    :\>sixcr.exe
    lets print some xcrs
                     0 = 1F
                     1 = 3
    Access Violation 2 = 0
    Access Violation 3 = 0
    Access Violation 4 = 0
    Access Violation 5 = 0
    Access Violation 6 = 0
    Access Violation 7 = 0
    Access Violation 8 = 0
    Access Violation 9 = 0
    Access Violation a = 0
    Access Violation b = 0
    Access Violation c = 0
    Access Violation d = 0
    Access Violation e = 0
    Access Violation f = 0

    disassembly of main

    Code:
    0:000> uf .
    sixcr!main:
    00007ff7`45881050 4883ec38        sub     rsp,38h
    00007ff7`45881054 488d0d1dd30400  lea     rcx,[sixcr!__xt_z+0x40 (00007ff7`458ce378)]
    00007ff7`4588105b e8d0000000      call    sixcr!printf (00007ff7`45881130)
    00007ff7`45881060 c744242000000000 mov     dword ptr [rsp+20h],0
    00007ff7`45881068 eb0a            jmp     sixcr!main+0x24 (00007ff7`45881074)  Branch
    
    sixcr!main+0x1a:
    00007ff7`4588106a 8b442420        mov     eax,dword ptr [rsp+20h]
    00007ff7`4588106e ffc0            inc     eax
    00007ff7`45881070 89442420        mov     dword ptr [rsp+20h],eax
    
    sixcr!main+0x24:
    00007ff7`45881074 837c242010      cmp     dword ptr [rsp+20h],10h
    00007ff7`45881079 7d4b            jge     sixcr!main+0x76 (00007ff7`458810c6)  Branch
    
    sixcr!main+0x2b:
    00007ff7`4588107b 8b4c2420        mov     ecx,dword ptr [rsp+20h]
    00007ff7`4588107f 0f01d0          xgetbv
    00007ff7`45881082 48c1e220        shl     rdx,20h
    00007ff7`45881086 480bd0          or      rdx,rax
    00007ff7`45881089 488bc2          mov     rax,rdx
    00007ff7`4588108c 4889053deb0500  mov     qword ptr [sixcr!foo (00007ff7`458dfbd0)],rax
    00007ff7`45881093 4c8b0536eb0500  mov     r8,qword ptr [sixcr!foo (00007ff7`458dfbd0)]
    00007ff7`4588109a 8b542420        mov     edx,dword ptr [rsp+20h]
    00007ff7`4588109e 488d0debd20400  lea     rcx,[sixcr!__xt_z+0x58 (00007ff7`458ce390)]
    00007ff7`458810a5 e886000000      call    sixcr!printf (00007ff7`45881130)
    00007ff7`458810aa eb18            jmp     sixcr!main+0x74 (00007ff7`458810c4)  Branch
    
    sixcr!main+0x74:
    00007ff7`458810c4 eba4            jmp     sixcr!main+0x1a (00007ff7`4588106a)  Branch
    
    sixcr!main+0x76:
    00007ff7`458810c6 33c0            xor     eax,eax
    00007ff7`458810c8 4883c438        add     rsp,38h
    00007ff7`458810cc c3              ret

    different results for ecx =1 inside and outside of debugger


    Code:
    :\>sixcr.exe
    lets print some xcrs
                     0 = 1F
                     1 = 3       <<<<<<<<<<<<< outside debugger
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
    :\>cdb  -c "g;q" sixcr.exe
    
    Microsoft (R) Windows Debugger Version 10.0.17763.132 AMD64
    
    0:000> cdb: Reading initial command 'g;q'
    lets print some xcrs
                     0 = 1F
                     1 = 7     <<<<<<<<<<<< inside debugger 
    (2d5c.2b9c): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    quit:
    Last edited by blabberer; March 10th, 2020 at 09:15.

  3. #3
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    sorry all! I am ashamed ;(
    mistaped 3d byte opcode, while assembling (0D)..
    well, lets remove this thread. or keep?

    well, on 32bit under ollydbg it returns
    ECX=0 > EAX=1F
    ECX=1 > EAX=3
    Last edited by evaluator; March 10th, 2020 at 09:55.

  4. #4
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,147
    Blog Entries
    5
    Is it possible xgetbv isn't emulated in a VM? The test program crashes ("didn't catch AV, unexpected") in VMWare 15 under Win7x64_sp1, compiled with VS2013 (<immintrin.h> required)

    It might be because of Win7 and not the VM, but I also enabled AVX instructions with
    bcdedit /set xsavedisable 0

    But when I copy the same file over to my Win10 desktop it runs just fine. Haven't tested under a debugger yet.
    lets print some xcrs
    0 = 1F
    1 = 3

  5. #5
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    Kayaker, to clarify thingy, code is from Frie.Fox (32bit), thus it's intriguing, if it will not run under VM :!)
    We will report it and +ask them about unblacklist site, as such a good we are

    download.mozilla.org/?product=firefox-latest-ssl&os=win

  6. #6
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    mm, I just tested under W1064 > VirtualBox 6.0.18 > W1032, XGETBV works.
    Difference:
    ECX=0 > EAX=7 << (1F is under W1064 real)
    ECX=1 > EAX=3
    (under OllyDbg)

    strange behavior shows CPUID, like with POP SS.
    (new advanced detection for VM!?)

  7. #7
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    so there is paired instruction XSETBV, so debugger probably sets values in RING0.. tested under Windbg and for ecx=1 > eax=7 ;
    PS: seems, this is per-process flag, as other programs did not got change.
    thiis FrieFox maybe too much tries against anti-debug; can say, it is showcase of this. also it has is strangely generated code, which caused to fail test reassembly to run. while I was sure, reassembly was proper. after debug, I discovered, that in assembly exist RAW Pointers(like in IAT) to strings. and dissam can't handle guess this, as they are not relocated and special code adds base to them;
    then I manually rewrote these and now reassembly works
    in fact these blocks are like "artifical" IAT
    there is also similar RAW-offset chunk, which is for msvcrt fail cases, I ignored these,as they will need for failures only..

    Code:
    [Data044242C: D$ 01, 04274A, 0460A8, 0460D8, 04250C, 0, 0, 0]
    04274A > Data044274A: B$ "USER32.dll", 0
    04250C > Data044250C:  0425A4 ... like IT
    0425A4 > Data04425A4: B$ 0 0 "CloseDesktop", 0
    Last edited by evaluator; May 7th, 2020 at 05:05.

  8. #8
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,147
    Blog Entries
    5
    Just for fun I started grepping system files for XGETBV (0F 01 D0) and XSETBV (0F 01 D1) to see how they were used. I found them in many files, including ntoskrnl.exe, but also in many other non-system files.

    In a lot of cases they're used separately with no real indication of what they do, but I found a pairing of the 2 instructions in the 32 bit file C:\Windows/Boot/PCAT/memtest.exe.

    Here is how they are used, disassembled in IDA 7 free with symbols loaded, in procs _ArchEnableProcessorFeatures and _ArchRestoreProcessorFeatures.

    I just thought this was sort of interesting code. Notice the 'or eax, 7'.

    Code:
    .text:0040A993 _ArchEnableProcessorFeatures@0 proc near
    .text:0040A993                                         ; CODE XREF: ArchInitializeProcessorFeatures():loc_40A98A↑p
    .text:0040A993
    .text:0040A993 var_8           = dword ptr -8
    .text:0040A993 var_4           = dword ptr -4
    .text:0040A993
    .text:0040A993                 mov     edi, edi
    .text:0040A995                 push    ebp
    .text:0040A996                 mov     ebp, esp
    .text:0040A998                 push    ecx
    .text:0040A999                 push    ecx
    .text:0040A99A                 test    byte ptr _BlPlatformFlags, 1
    .text:0040A9A1                 jz      short locret_40A9F0
    .text:0040A9A3                 mov     eax, cr4
    .text:0040A9A6                 mov     ecx, 40000h
    .text:0040A9AB                 test    ecx, eax
    .text:0040A9AD                 jnz     short loc_40A9BA
    .text:0040A9AF                 or      eax, ecx
    .text:0040A9B1                 mov     _ArchCr4BitsToClear, ecx
    .text:0040A9B7                 mov     cr4, eax
    .text:0040A9BA
    .text:0040A9BA loc_40A9BA:                             ; CODE XREF: ArchEnableProcessorFeatures()+1A↑j
    .text:0040A9BA                 xor     ecx, ecx
    .text:0040A9BC                 xgetbv
    .text:0040A9BF                 mov     [ebp+var_8], eax
    .text:0040A9C2                 mov     [ebp+var_4], edx
    .text:0040A9C5                 mov     ecx, [ebp+var_8]
    .text:0040A9C8                 mov     eax, [ebp+var_4]
    .text:0040A9CB                 and     ecx, 4
    .text:0040A9CE                 xor     eax, eax
    .text:0040A9D0                 or      ecx, eax
    .text:0040A9D2                 jnz     short locret_40A9F0
    .text:0040A9D4                 mov     eax, [ebp+var_8]
    .text:0040A9D7                 mov     edx, [ebp+var_4]
    .text:0040A9DA                 or      eax, 7
    .text:0040A9DD                 xsetbv
    .text:0040A9E0                 and     _ArchXCr0BitsToClearLo, ecx
    .text:0040A9E6                 mov     _ArchXCr0BitsToClearHi, 4
    .text:0040A9F0
    .text:0040A9F0 locret_40A9F0:                          ; CODE XREF: ArchEnableProcessorFeatures()+E↑j
    .text:0040A9F0                                         ; ArchEnableProcessorFeatures()+3F↑j
    .text:0040A9F0                 leave
    .text:0040A9F1                 retn
    .text:0040A9F1 _ArchEnableProcessorFeatures@0 endp
    .text:0040A9F1
    Code:
    .text:0040A9F2 _ArchRestoreProcessorFeatures@4 proc near
    .text:0040A9F2                                         ; CODE XREF: BlDestroyLibrary():loc_43410F↓p
    .text:0040A9F2                                         ; InitializeLibrary(x,x):loc_434BA7↓p
    .text:0040A9F2
    .text:0040A9F2 var_8           = dword ptr -8
    .text:0040A9F2 var_4           = dword ptr -4
    .text:0040A9F2
    .text:0040A9F2                 mov     edi, edi
    .text:0040A9F4                 push    ebp
    .text:0040A9F5                 mov     ebp, esp
    .text:0040A9F7                 push    ecx
    .text:0040A9F8                 push    ecx
    .text:0040A9F9                 push    ebx
    .text:0040A9FA                 push    esi
    .text:0040A9FB                 mov     esi, _ArchXCr0BitsToClearHi
    .text:0040AA01                 mov     eax, esi
    .text:0040AA03                 push    edi
    .text:0040AA04                 mov     edi, _ArchXCr0BitsToClearLo
    .text:0040AA0A                 or      eax, edi
    .text:0040AA0C                 push    0
    .text:0040AA0E                 pop     ebx
    .text:0040AA0F                 jz      short loc_40AA39
    .text:0040AA11                 xor     ecx, ecx
    .text:0040AA13                 xgetbv
    .text:0040AA16                 mov     [ebp+var_8], eax
    .text:0040AA19                 not     esi
    .text:0040AA1B                 mov     [ebp+var_4], edx
    .text:0040AA1E                 not     edi
    .text:0040AA20                 mov     eax, [ebp+var_8]
    .text:0040AA23                 mov     edx, [ebp+var_4]
    .text:0040AA26                 and     eax, esi
    .text:0040AA28                 and     edx, edi
    .text:0040AA2A                 xsetbv
    .text:0040AA2D                 mov     _ArchXCr0BitsToClearHi, ebx
    .text:0040AA33                 mov     _ArchXCr0BitsToClearLo, ebx
    .text:0040AA39
    .text:0040AA39 loc_40AA39:                             ; CODE XREF: ArchRestoreProcessorFeatures(x)+1D↑j
    .text:0040AA39                 mov     ecx, _ArchCr4BitsToClear
    .text:0040AA3F                 test    ecx, ecx
    .text:0040AA41                 jz      short loc_40AA53
    .text:0040AA43                 mov     eax, cr4
    .text:0040AA46                 not     ecx
    .text:0040AA48                 mov     _ArchCr4BitsToClear, ebx
    .text:0040AA4E                 and     ecx, eax
    .text:0040AA50                 mov     cr4, ecx
    .text:0040AA53
    .text:0040AA53 loc_40AA53:                             ; CODE XREF: ArchRestoreProcessorFeatures(x)+4F↑j
    .text:0040AA53                 cmp     _ArchDisableNx, 0
    .text:0040AA5A                 jz      short loc_40AA6A
    .text:0040AA5C                 mov     ecx, 0C0000080h
    .text:0040AA61                 rdmsr
    .text:0040AA63                 and     eax, 0FFFFF7FFh
    .text:0040AA68                 wrmsr
    .text:0040AA6A
    .text:0040AA6A loc_40AA6A:                             ; CODE XREF: ArchRestoreProcessorFeatures(x)+68↑j
    .text:0040AA6A                 cmp     _ArchForceNx, 0
    .text:0040AA71                 jz      short loc_40AA81
    .text:0040AA73                 mov     ecx, 1A0h
    .text:0040AA78                 rdmsr
    .text:0040AA7A                 or      eax, ebx
    .text:0040AA7C                 or      edx, 4
    .text:0040AA7F                 wrmsr
    .text:0040AA81
    .text:0040AA81 loc_40AA81:                             ; CODE XREF: ArchRestoreProcessorFeatures(x)+7F↑j
    .text:0040AA81                 pop     edi
    .text:0040AA82                 pop     esi
    .text:0040AA83                 pop     ebx
    .text:0040AA84                 leave
    .text:0040AA85                 retn
    .text:0040AA85 _ArchRestoreProcessorFeatures@4 endp

  9. #9
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    these code shows XGETBV for ecx=0, where it seems for "check the AVX registers restore at context switch".
    look for case ecx=1, which seems about debugging(?), or just WINDBG uses some extended states, so it writes this flag;
    ps. i did not find 0F01D1 in "Windows Kits" folder except for arm folder.
    Last edited by evaluator; May 13th, 2020 at 23:36.

  10. #10
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,147
    Blog Entries
    5
    Not xgetbv but another opcode I hadn't come across before, VPCEXT 7, 0Bh, used to detect the presence of VirtualPC.

    This is just an observation really. I was looking at an app that detected VMWare, using the well known check for VMXh through the I/O port. I then noticed in IDA the opcode 'vpcext 7, 0Bh', a quick google search found that this is also a known check for VirtualPC.

    Both detections are described here
    https://shasaurabh.blogspot.com/2017/07/virtual-machine-detection-techniques.html

    What I found interesting was that IDA was able to decode the instruction while neither Olly or WinDbg could. VirtualPC is made by MS but apparently their debugger chooses not to support disassembling that opcode instruction.

    Code:
    IDA:
    BB 00 00 00 00      mov     ebx, 0
    B8 01 00 00 00      mov     eax, 1
    0F 3F 07 0B         vpcext  7, 0Bh
    85 DB               test    ebx, ebx
    0F 94 45 E4         setz    [ebp+var_1C]
    
    
    WinDbg:
    bb00000000      mov     ebx,0
    b801000000      mov     eax,1
    0f              ???
    3f              aas
    07              pop     es
    0b85db0f9445    or      eax,dword ptr [ebp+45940FDBh]
    I tried to find documentation on the two-byte 0F-3Fh opcode (vpcext) but none was to be found other than the anecdotal mentions of its existence. The secondary opcode map in the AMD64 ArchitectureProgrammerís Manual on page 488 shows that opcode slot as being undefined.

    https://www.amd.com/system/files/TechDocs/24594.pdf

    There is a Wikipedia reference to 0F-3Fh being a backdoor Alternate Instruction Set (AIS) x86 instruction that was used by VIA Technologies. On these VIA C3 processors, the second hidden processor mode is accessed by executing the x86 instruction ALTINST (0F 3F). If AIS mode has been enabled, the processor will perform a JMP EAX and begin executing AIS instructions at the address of the EAX register. Using AIS allows native access to the Centaur Technology-designed RISC core inside the processor.

    So props to IDA for being so good as to recognize that instruction. It crossed my mind that searching for these opcode bytes in malware might point to any general VM detection it uses, though they could just as easily be hidden in self modifying code (SMC).

  11. #11
    Super Moderator
    Join Date
    Dec 2004
    Posts
    1,525
    Blog Entries
    15
    the 0f 3f opcodes were used by virtual pc as some backdoor communication with host (vmsti,vmcli etc (set interrupt , clear interrupt hooks )


    you can find some relevant discussion here

    https://community.osr.com/discussion/146174/windbg-doesnt-display-data-or-how-to-force-windbg-to-display-data
    https://community.osr.com/discussion/145334/disassembly-not-done-for-certain-opcoded-in-windbg

  12. #12
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,518
    Blog Entries
    1
    Kayaker, cmon.. 0F 3F is just illegal intruction, artifically used by software as opcode; sure you heard about such like VBox "opcodes"..
    while blaming Olly, try that "OP" under real PC+Olly :)

    ps, if we can't find xsetbv with ecx=1, then Q will: how is it set?
    Last edited by evaluator; May 16th, 2020 at 22:55.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •