Welcome to the new Woodmann RCE Messageboards Regroupment
Please be patient while the rest of the site is restored.

To all Members of the old RCE Forums:
In order to log in, it will be necessary to reset your forum login password ("I forgot my password") using the original email address you registered with. You will be sent an email with a link to reset your password for that member account.

The old vBulletin forum was converted to phpBB format, requiring the passwords to be reset. If this is a problem for some because of a forgotten email address, please feel free to re-register with a new username. We are happy to welcome old and new members back to the forums! Thanks.

All new accounts are manually activated before you can post. Any questions can be PM'ed to Kayaker.

XGETBV trickies

All-in-one reversing related discussions
Post Reply
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

XGETBV trickies

Post by evaluator »

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:

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

https://software.intel.com/en-us/cpp-co ... nce-xgetbv
"Currently, only the value '0' is allowed."

Code: Select all

    push ebx
    push edi
    push esi
    pop eax
    mov ecx eax
    xor eax 0200000
    push eax
    pop eax
    mov edx 0
    cmp ecx eax | je Code01000102E
    mov edx 01
    test edx edx | je Code0100010F1
    xor eax eax
    test eax eax | je Code0100010F1
    mov esi eax
    xor ecx ecx
    mov eax 01
    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
    mov eax ecx
    shr al 06
    mov ecx edi
    and al 01
    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
    and eax 06
    xor ebx ebx
    cmp eax 06
    sete B$Virtual0100695F2
    cmp esi 07
Senior Member
Posts: 1535
Joined: Wed Dec 08, 2004 11:12 am

Post by blabberer »

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: Select all

:\>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-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-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-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: Select all

0: kd> dx @$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: Select all

#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)
        printf("Access Violation ");
		foo = 0;
        puts("didn't catch AV, unexpected.");

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: Select all

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: Select all

0:000> uf .
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

00007ff7`4588106a 8b442420        mov     eax,dword ptr [rsp+20h]
00007ff7`4588106e ffc0            inc     eax
00007ff7`45881070 89442420        mov     dword ptr [rsp+20h],eax

00007ff7`45881074 837c242010      cmp     dword ptr [rsp+20h],10h
00007ff7`45881079 7d4b            jge     sixcr!main+0x76 (00007ff7`458810c6)  Branch

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

00007ff7`458810c4 eba4            jmp     sixcr!main+0x1a (00007ff7`4588106a)  Branch

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: Select all

lets print some xcrs
                 0 = 1F
                 1 = 3       <<<<<<<<<<<<< outside debugger

:\>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.
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

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
User avatar
Posts: 4169
Joined: Thu Oct 26, 2000 11:00 am

Post by Kayaker »

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
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

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

User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

mm, I just tested under W1064 > VirtualBox 6.0.18 > W1032, XGETBV works.
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!?)
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

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: Select all

[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
User avatar
Posts: 4169
Joined: Thu Oct 26, 2000 11:00 am

Post by Kayaker »

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: Select all

.text:0040A993 [email protected] proc near
.text:0040A993                                         ; CODE XREF: ArchInitializeProcessorFeatures():loc_40A98A↑p
.text:0040A993 var_8           = dword ptr -8
.text:0040A993 var_4           = dword ptr -4
.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 loc_40A9BA:                             ; CODE XREF: ArchEnableProcessorFeatures()+1A↑j
.text:0040A9BA                 xor     ecx, ecx
.text:0040A9BC                 [B]xgetbv[/B]
.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                 [B]or      eax, 7[/B]
.text:0040A9DD                 [B]xsetbv[/B]
.text:0040A9E0                 and     [B]_ArchXCr0BitsToClearLo[/B], ecx
.text:0040A9E6                 mov     [B]_ArchXCr0BitsToClearHi[/B], 4
.text:0040A9F0 locret_40A9F0:                          ; CODE XREF: ArchEnableProcessorFeatures()+E↑j
.text:0040A9F0                                         ; ArchEnableProcessorFeatures()+3F↑j
.text:0040A9F0                 leave
.text:0040A9F1                 retn
.text:0040A9F1 [email protected] endp

Code: Select all

.text:0040A9F2 [email protected] proc near
.text:0040A9F2                                         ; CODE XREF: BlDestroyLibrary():loc_43410F↓p
.text:0040A9F2                                         ; InitializeLibrary(x,x):loc_434BA7↓p
.text:0040A9F2 var_8           = dword ptr -8
.text:0040A9F2 var_4           = dword ptr -4
.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, [B]_ArchXCr0BitsToClearHi[/B]
.text:0040AA01                 mov     eax, esi
.text:0040AA03                 push    edi
.text:0040AA04                 mov     edi, [B]_ArchXCr0BitsToClearLo[/B]
.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                 [B]xgetbv[/B]
.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                 [B]xsetbv[/B]
.text:0040AA2D                 mov     [B]_ArchXCr0BitsToClearHi[/B], ebx
.text:0040AA33                 mov     [B]_ArchXCr0BitsToClearLo[/B], ebx
.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 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 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 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 [email protected] endp
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

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.
User avatar
Posts: 4169
Joined: Thu Oct 26, 2000 11:00 am

Post by Kayaker »

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 ... iques.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: Select all

BB 00 00 00 00      mov     ebx, 0
B8 01 00 00 00      mov     eax, 1
[B]0F 3F 07 0B         vpcext  7, 0Bh[/B]
85 DB               test    ebx, ebx
0F 94 45 E4         setz    [ebp+var_1C]

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.


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).
Senior Member
Posts: 1535
Joined: Wed Dec 08, 2004 11:12 am

Post by blabberer »

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/14 ... splay-data
https://community.osr.com/discussion/14 ... -in-windbg
User avatar
Posts: 1538
Joined: Tue Sep 18, 2001 2:00 pm

Post by evaluator »

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?
Post Reply