https://bugs.winehq.org/show_bug.cgi?id=49221
Bug ID: 49221 Summary: Denuvo Anti-Cheat 'denuvo-anti-cheat.sys' needs instruction emulation for querying VMX capabilities via MSR 0x480..0x490 Product: Wine Version: 5.8 Hardware: x86-64 OS: Linux Status: NEW Severity: normal Priority: P2 Component: ntoskrnl Assignee: wine-bugs@winehq.org Reporter: focht@gmx.net Distribution: ---
Hello folks,
continuation of bug 49219 (split out from bug 49194).
--- snip --- $ WINEDEBUG=+seh,+relay,+int,+ntoskrnl,+ntdll wine net start "Denuvo Anti-Cheat" >>log.txt 2>&1 ... 00d0:Call driver init 0000000000C81184 (obj=000000000078EE10,str=L"\Registry\Machine\System\CurrentControlSet\Services\Denuvo Anti-Cheat") ... 00d0:Call ntoskrnl.exe.KeQueryActiveProcessorCountEx(0000ffff) ret=00c83d3a 00d0:fixme:ntoskrnl:KeQueryActiveProcessorCountEx GroupNumber 65535 semi-stub. 00d0:Call KERNEL32.GetSystemInfo(00b5f2f0) ret=00232926 00d0:Call ntdll.NtQuerySystemInformation(00000000,00b5f200,00000040,00000000) ret=7b02c721 00d0:trace:ntdll:NtQuerySystemInformation (0x00000000,0xb5f200,0x00000040,(nil)) 00d0:Ret ntdll.NtQuerySystemInformation() retval=00000000 ret=7b02c721 00d0:Call ntdll.NtQuerySystemInformation(00000001,00b5f1f0,0000000c,00000000) ret=7b02c751 00d0:trace:ntdll:NtQuerySystemInformation (0x00000001,0xb5f1f0,0x0000000c,(nil)) 00d0:Ret ntdll.NtQuerySystemInformation() retval=00000000 ret=7b02c751 00d0:Ret KERNEL32.GetSystemInfo() retval=00000006 ret=00232926 00d0:Ret ntoskrnl.exe.KeQueryActiveProcessorCountEx() retval=00000008 ret=00c83d3a 00d0:Call ntoskrnl.exe.KeSetSystemAffinityThreadEx(ffffffffffffffff) ret=00c83d56 00d0:fixme:ntoskrnl:KeSetSystemAffinityThreadEx (0xffffffff) semi-stub 00d0:Call ntdll.NtQueryInformationThread(fffffffffffffffe,0000001e,00b5f300,00000010,00000000) ret=00232aa8 00d0:Ret ntdll.NtQueryInformationThread() retval=00000000 ret=00232aa8 00d0:Call ntdll.NtSetInformationThread(fffffffffffffffe,0000001e,00b5f310,00000010) ret=00232b00 00d0:Ret ntdll.NtSetInformationThread() retval=c000000d ret=00232b00 00d0:fixme:ntoskrnl:KeSetSystemAffinityThreadEx Set affinity, status 0xc000000d. 00d0:fixme:ntoskrnl:KeSetSystemAffinityThreadEx old.Group 0, old.Mask 0xff. 00d0:Ret ntoskrnl.exe.KeSetSystemAffinityThreadEx() retval=000000ff ret=00c83d56 00d0:Call ntoskrnl.exe.KeSetSystemAffinityThreadEx(00000001) ret=00c83d86 00d0:fixme:ntoskrnl:KeSetSystemAffinityThreadEx (0x1) semi-stub 00d0:Call ntdll.NtQueryInformationThread(fffffffffffffffe,0000001e,00b5f300,00000010,00000000) ret=00232aa8 00d0:Ret ntdll.NtQueryInformationThread() retval=00000000 ret=00232aa8 00d0:Call ntdll.NtSetInformationThread(fffffffffffffffe,0000001e,00b5f310,00000010) ret=00232b00 00d0:Ret ntdll.NtSetInformationThread() retval=00000000 ret=00232b00 00d0:fixme:ntoskrnl:KeSetSystemAffinityThreadEx old.Group 0, old.Mask 0xff. 00d0:Ret ntoskrnl.exe.KeSetSystemAffinityThreadEx() retval=000000ff ret=00c83d86 00d0:trace:seh:raise_exception code=c0000096 flags=0 addr=0xc88ac3 ip=c88ac3 tid=00d0 00d0:trace:seh:raise_exception rax=0000000000000000 rbx=0000000000000000 rcx=00000000008e0370 rdx=000000009c000400 00d0:trace:seh:raise_exception rsi=00000000008e1f70 rdi=00000000008e0370 rbp=0000000000b5f370 rsp=0000000000b5f2f8 00d0:trace:seh:raise_exception r8=000000000027efb1 r9=00000000008e0370 r10=0000000000000000 r11=0000000000000000 00d0:trace:seh:raise_exception r12=0000000000000000 r13=00007fffffea4000 r14=0000000000000000 r15=0000000080000008 00d0:trace:seh:call_vectored_handlers calling handler at 0x22cfa0 code=c0000096 flags=0 00d0:trace:int:emulate_instruction mov cr4,rax at c88ac3 00d0:trace:int:vectored_handler next instruction rip=c88ac6 00d0:trace:int:vectored_handler rax=0000000000000000 rbx=0000000000000000 rcx=00000000008e0370 rdx=000000009c000400 00d0:trace:int:vectored_handler rsi=00000000008e1f70 rdi=00000000008e0370 rbp=0000000000b5f370 rsp=0000000000b5f2f8 00d0:trace:int:vectored_handler r8=000000000027efb1 r9=00000000008e0370 r10=0000000000000000 r11=0000000000000000 00d0:trace:int:vectored_handler r12=0000000000000000 r13=00000000ffea4000 r14=0000000000000000 r15=0000000080000008 00d0:trace:seh:call_vectored_handlers handler at 0x22cfa0 returned ffffffff 00d0:trace:seh:raise_exception code=c0000005 flags=0 addr=0xc88ad4 ip=c88ad4 tid=00d0 00d0:trace:seh:raise_exception info[0]=0000000000000000 00d0:trace:seh:raise_exception info[1]=ffffffffffffffff 00d0:trace:seh:raise_exception rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000480 rdx=000000009c000400 00d0:trace:seh:raise_exception rsi=00000000008e1f70 rdi=00000000008e0370 rbp=0000000000b5f370 rsp=0000000000b5f2f8 00d0:trace:seh:raise_exception r8=000000000027efb1 r9=00000000008e0370 r10=0000000000000000 r11=0000000000000000 00d0:trace:seh:raise_exception r12=0000000000000000 r13=00007fffffea4000 r14=0000000000000000 r15=0000000080000008 00d0:trace:seh:call_vectored_handlers calling handler at 0x22cfa0 code=c0000005 flags=0 00d0:trace:int:emulate_instruction rdmsr CR 0x00000480 00d0:trace:seh:call_vectored_handlers handler at 0x22cfa0 returned 0 00d0:warn:seh:virtual_unwind exception data not found in L"denuvo-anti-cheat.sys" --- snip ---
Relevant disassembly snippet of driver:
--- snip --- 0000000140008AC0 | 4C:8BC9 | mov r9,rcx | 0000000140008AC3 | 0F20E0 | mov rax,cr4 | 0000000140008AC6 | 48:C1E8 0D | shr rax,D | 0000000140008ACA | 24 01 | and al,1 | 0000000140008ACC | 8841 51 | mov byte ptr ds:[rcx+51],al | --- snip ---
CR4 -> bit 13 set -> VMXE
--- snip --- 0000000140008ACF | B9 80040000 | mov ecx,480 | 0000000140008AD4 | 0F32 | rdmsr | 0000000140008AD6 | 48:C1E2 20 | shl rdx,20 | 0000000140008ADA | B9 81040000 | mov ecx,481 | 0000000140008ADF | 48:0BC2 | or rax,rdx | 0000000140008AE2 | 49:8941 58 | mov qword ptr ds:[r9+58],rax | 0000000140008AE6 | 0F32 | rdmsr | 0000000140008AE8 | 48:C1E2 20 | shl rdx,20 | 0000000140008AEC | B9 82040000 | mov ecx,482 | 0000000140008AF1 | 48:0BC2 | or rax,rdx | 0000000140008AF4 | 49:8941 60 | mov qword ptr ds:[r9+60],rax | 0000000140008AF8 | 0F32 | rdmsr | 0000000140008AFA | 48:C1E2 20 | shl rdx,20 | 0000000140008AFE | B9 83040000 | mov ecx,483 | 0000000140008B03 | 48:0BC2 | or rax,rdx | 0000000140008B06 | 4C:8BC0 | mov r8,rax | 0000000140008B09 | 49:8941 68 | mov qword ptr ds:[r9+68],rax | 0000000140008B0D | 0F32 | rdmsr | 0000000140008B0F | 48:C1E2 20 | shl rdx,20 | 0000000140008B13 | B9 84040000 | mov ecx,484 | 0000000140008B18 | 48:0BC2 | or rax,rdx | 0000000140008B1B | 49:8941 70 | mov qword ptr ds:[r9+70],rax | 0000000140008B1F | 0F32 | rdmsr | 0000000140008B21 | 48:C1E2 20 | shl rdx,20 | 0000000140008B25 | B9 85040000 | mov ecx,485 | 0000000140008B2A | 48:0BC2 | or rax,rdx | 0000000140008B2D | 49:8941 78 | mov qword ptr ds:[r9+78],rax | 0000000140008B31 | 0F32 | rdmsr | 0000000140008B33 | 48:C1E2 20 | shl rdx,20 | 0000000140008B37 | B9 86040000 | mov ecx,486 | 0000000140008B3C | 48:0BC2 | or rax,rdx | 0000000140008B3F | 49:8981 80000000 | mov qword ptr ds:[r9+80],rax | 0000000140008B46 | 0F32 | rdmsr | 0000000140008B48 | 48:C1E2 20 | shl rdx,20 | 0000000140008B4C | B9 87040000 | mov ecx,487 | 0000000140008B51 | 48:0BC2 | or rax,rdx | 0000000140008B54 | 49:8981 88000000 | mov qword ptr ds:[r9+88],rax | 0000000140008B5B | 0F32 | rdmsr | 0000000140008B5D | 48:C1E2 20 | shl rdx,20 | 0000000140008B61 | B9 88040000 | mov ecx,488 | 0000000140008B66 | 48:0BC2 | or rax,rdx | 0000000140008B69 | 49:8981 90000000 | mov qword ptr ds:[r9+90],rax | 0000000140008B70 | 0F32 | rdmsr | 0000000140008B72 | 48:C1E2 20 | shl rdx,20 | 0000000140008B76 | B9 89040000 | mov ecx,489 | 0000000140008B7B | 48:0BC2 | or rax,rdx | 0000000140008B7E | 49:8981 98000000 | mov qword ptr ds:[r9+98],rax | 0000000140008B85 | 0F32 | rdmsr | 0000000140008B87 | 48:C1E2 20 | shl rdx,20 | 0000000140008B8B | B9 8A040000 | mov ecx,48A | 0000000140008B90 | 48:0BC2 | or rax,rdx | 0000000140008B93 | 49:8981 A0000000 | mov qword ptr ds:[r9+A0],rax | 0000000140008B9A | 0F32 | rdmsr | 0000000140008B9C | 48:C1E2 20 | shl rdx,20 | 0000000140008BA0 | 45:33D2 | xor r10d,r10d | 0000000140008BA3 | 48:0BC2 | or rax,rdx | 0000000140008BA6 | 49:8981 A8000000 | mov qword ptr ds:[r9+A8],rax | 0000000140008BAD | 4D:85C0 | test r8,r8 | 0000000140008BB0 | 79 3B | jns denuvo-anti-cheat.140008BED | 0000000140008BB2 | B9 8B040000 | mov ecx,48B | 0000000140008BB7 | 0F32 | rdmsr | 0000000140008BB9 | 48:C1E2 20 | shl rdx,20 | 0000000140008BBD | 48:B9 0000000022000000 | mov rcx,2200000000 | 0000000140008BC7 | 48:0BC2 | or rax,rdx | 0000000140008BCA | 49:8981 B0000000 | mov qword ptr ds:[r9+B0],rax | 0000000140008BD1 | 48:85C1 | test rcx,rax | 0000000140008BD4 | 74 1E | je denuvo-anti-cheat.140008BF4 | 0000000140008BD6 | B9 8C040000 | mov ecx,48C | 0000000140008BDB | 0F32 | rdmsr | 0000000140008BDD | 48:C1E2 20 | shl rdx,20 | 0000000140008BE1 | 48:0BC2 | or rax,rdx | 0000000140008BE4 | 49:8981 B8000000 | mov qword ptr ds:[r9+B8],rax | 0000000140008BEB | EB 0E | jmp denuvo-anti-cheat.140008BFB | 0000000140008BED | 4D:8991 B0000000 | mov qword ptr ds:[r9+B0],r10 | 0000000140008BF4 | 4D:8991 B8000000 | mov qword ptr ds:[r9+B8],r10 | 0000000140008BFB | 48:B9 0000000000008000 | mov rcx,80000000000000 | 0000000140008C05 | 49:8549 58 | test qword ptr ds:[r9+58],rcx | 0000000140008C09 | 74 5D | je denuvo-anti-cheat.140008C68 | 0000000140008C0B | B9 8D040000 | mov ecx,48D | 0000000140008C10 | 0F32 | rdmsr | 0000000140008C12 | 48:C1E2 20 | shl rdx,20 | 0000000140008C16 | B9 8E040000 | mov ecx,48E | 0000000140008C1B | 48:0BC2 | or rax,rdx | 0000000140008C1E | 49:8981 C0000000 | mov qword ptr ds:[r9+C0],rax | 0000000140008C25 | 0F32 | rdmsr | 0000000140008C27 | 48:C1E2 20 | shl rdx,20 | 0000000140008C2B | B9 8F040000 | mov ecx,48F | 0000000140008C30 | 48:0BC2 | or rax,rdx | 0000000140008C33 | 49:8981 C8000000 | mov qword ptr ds:[r9+C8],rax | 0000000140008C3A | 0F32 | rdmsr | 0000000140008C3C | 48:C1E2 20 | shl rdx,20 | 0000000140008C40 | B9 90040000 | mov ecx,490 | 0000000140008C45 | 48:0BC2 | or rax,rdx | 0000000140008C48 | 49:8981 D0000000 | mov qword ptr ds:[r9+D0],rax | 0000000140008C4F | 0F32 | rdmsr | 0000000140008C51 | 48:C1E2 20 | shl rdx,20 | 0000000140008C55 | 48:0BC2 | or rax,rdx | 0000000140008C58 | 49:8981 D8000000 | mov qword ptr ds:[r9+D8],rax | 0000000140008C5F | 41:C741 54 11000000 | mov dword ptr ds:[r9+54],11 | 0000000140008C67 | C3 | ret | 0000000140008C68 | 4D:8991 D8000000 | mov qword ptr ds:[r9+D8],r10 | 0000000140008C6F | 4D:8991 D0000000 | mov qword ptr ds:[r9+D0],r10 | 0000000140008C76 | 4D:8991 C8000000 | mov qword ptr ds:[r9+C8],r10 | 0000000140008C7D | 4D:8991 C0000000 | mov qword ptr ds:[r9+C0],r10 | 0000000140008C84 | 41:C741 54 11000000 | mov dword ptr ds:[r9+54],11 | 0000000140008C8C | C3 | ret | --- snip ---
The patch (hack) from https://bugs.winehq.org/show_bug.cgi?id=49194#c1 returns zero rax and rdx for any MSR which isn't recognized in 'emulate_instruction()'
Wine source:
https://source.winehq.org/git/wine.git/blob/b65ca133052ed9053e48c571155a764d...
--- snip --- 769 case 0x32: /* rdmsr */ 770 { 771 ULONG reg = context->Rcx; 772 TRACE("rdmsr CR 0x%08x\n", reg); 773 switch (reg) 774 { 775 case MSR_LSTAR: 776 { 777 ULONG_PTR syscall_address = (ULONG_PTR)fake_syscall_function; 778 context->Rdx = (ULONG)(syscall_address >> 32); 779 context->Rax = (ULONG)syscall_address; 780 break; 781 } 782 default: return ExceptionContinueSearch; 783 } 784 context->Rip += prefixlen + 2; 785 return ExceptionContinueExecution; 786 } --- snip ---
Since the VMX MSR range is well known there could be a default handler for these regs, returning fake (0) values.
---
Tidbits:
Python app to dump VMX capabilities from userspace:
https://github.com/qemu/qemu/blob/master/scripts/kvm/vmxcap
--- snip --- $ sudo ./vmxcap.py
Basic VMX Information Hex: 0xda040000000012 Revision 18 VMCS size 1024 VMCS restricted to 32 bit addresses no Dual-monitor support yes VMCS memory type 6 INS/OUTS instruction information yes IA32_VMX_TRUE_*_CTLS support yes pin-based controls External interrupt exiting yes NMI exiting yes Virtual NMIs yes Activate VMX-preemption timer yes Process posted interrupts no primary processor-based controls Interrupt window exiting yes Use TSC offsetting yes HLT exiting yes INVLPG exiting yes MWAIT exiting yes RDPMC exiting yes RDTSC exiting yes CR3-load exiting default CR3-store exiting default CR8-load exiting yes CR8-store exiting yes Use TPR shadow yes NMI-window exiting yes MOV-DR exiting yes Unconditional I/O exiting yes Use I/O bitmaps yes Monitor trap flag yes Use MSR bitmaps yes MONITOR exiting yes PAUSE exiting yes Activate secondary control yes secondary processor-based controls Virtualize APIC accesses yes Enable EPT yes Descriptor-table exiting yes Enable RDTSCP yes Virtualize x2APIC mode yes Enable VPID yes WBINVD exiting yes Unrestricted guest yes APIC register emulation no Virtual interrupt delivery no PAUSE-loop exiting yes RDRAND exiting yes Enable INVPCID yes Enable VM functions yes VMCS shadowing no Enable ENCLS exiting no RDSEED exiting no Enable PML no EPT-violation #VE no Conceal non-root operation from PT no Enable XSAVES/XRSTORS no Mode-based execute control (XS/XU) no Sub-page write permissions no GPA translation for PT no TSC scaling no User wait and pause no ENCLV exiting no VM-Exit controls Save debug controls default Host address-space size yes Load IA32_PERF_GLOBAL_CTRL yes Acknowledge interrupt on exit yes Save IA32_PAT yes Load IA32_PAT yes Save IA32_EFER yes Load IA32_EFER yes Save VMX-preemption timer value yes Clear IA32_BNDCFGS no Conceal VM exits from PT no Clear IA32_RTIT_CTL no VM-Entry controls Load debug controls default IA-32e mode guest yes Entry to SMM yes Deactivate dual-monitor treatment yes Load IA32_PERF_GLOBAL_CTRL yes Load IA32_PAT yes Load IA32_EFER yes Load IA32_BNDCFGS no Conceal VM entries from PT no Load IA32_RTIT_CTL no Miscellaneous data Hex: 0x300481e5 VMX-preemption timer scale (log2) 5 Store EFER.LMA into IA-32e mode guest control yes HLT activity state yes Shutdown activity state yes Wait-for-SIPI activity state yes PT in VMX operation no IA32_SMBASE support yes Number of CR3-target values 4 MSR-load/store count recommendation 0 IA32_SMM_MONITOR_CTL[2] can be set to 1 yes VMWRITE to VM-exit information fields yes Inject event with insn length=0 no MSEG revision identifier 0 VPID and EPT capabilities Hex: 0xf0106334141 Execute-only EPT translations yes Page-walk length 4 yes Paging-structure memory type UC yes Paging-structure memory type WB yes 2MB EPT pages yes 1GB EPT pages yes INVEPT supported yes EPT accessed and dirty flags yes Advanced VM-exit information for EPT violations no Single-context INVEPT yes All-context INVEPT yes INVVPID supported yes Individual-address INVVPID yes Single-context INVVPID yes All-context INVVPID yes Single-context-retaining-globals INVVPID yes VM Functions Hex: 0x1 EPTP Switching yes --- snip ---
Poor man's version (msr-tools):
--- snip --- $ for i in `seq 0x480 0x490` ; do sudo rdmsr -x $i ; done
da040000000012 7f00000016 fff9fffe0401e172 7fffff00036dff ffff000011ff 300481e5 80000021 ffffffff 2000 1727ff 2a 3cff00000000 f0106334141 7f00000016 fff9fffe04006172 7fffff00036dfb ffff000011fb --- snip ---
$ wine --version wine-5.8-321-gf0a8061663
Regards