[Bug 44817] Some software protection schemes need ntdll.NtSetLdtEntries implementation

WineHQ Bugzilla wine-bugs at winehq.org
Sun Jan 9 11:48:07 CST 2022


https://bugs.winehq.org/show_bug.cgi?id=44817

--- Comment #1 from Anastasius Focht <focht at gmx.net> ---
Created attachment 71582
  --> https://bugs.winehq.org/attachment.cgi?id=71582
VMWare detection test app 'vmgpftest-x86.exe' with source

Hello folks,

revisiting. I've found some real-world code snippet that mimics the sequence
described by Michael. It's probably used in application virtualization /
sand-boxing schemes and malware that employ virtualization detection.

https://web.archive.org/web/20070108201905/https://eeyeresearch.typepad.com/blog/2006/09/another_vmware_.html

--- quote ---
September 19, 2006
Another VMWare Detection

Derek Soeder, uber researcher and code ninja extraordinaire posted this over at
Rootkit.Com without the code so we thought we would add it here.

We stumbled on another way of detecting VMware in emulation mode while writing
that PiXiE network boot virus, not very elegant but it works...

Basically, VMware emulates near execution transfers outside the CS: limit
incorrectly, in that it completes the transfer (changes EIP and modifies the
stack when applicable) before raising the General Protection Fault. Physical
processors raise the fault before actually doing anything.

To test this in Windows user-mode, create a < 4GB code segment
(ZwSetLdtEntries), then transfer into it (change CS), and with an exception
handler in place, try doing e.g. a near RET out of it (like PUSH -1 / RET). If
you're running natively (or in accelerated mode in VMware), then EIP will still
be within the CS: limits and ESP will remain unchanged; if you're running in
emulation mode (ring-0 or with acceleration disabled), EIP will be above the
CS: limit and the return address will have been popped.

(Far execution transfers are emulated faithfully, so that's why you want to do
the near transfer from within the short code segment. Trying to do a CALL FAR
seg:ofs to outside the short segment, from within the default flat ring-3 code
segment, would raise a GPF with CS:EIP and ESP unmodified, the same between
native execution and emulation.)

If you use a technique like this in combination with Joanna's SIDT trick, that
should give you comprehensive detection. BTW haven't tested this on anything
except VMware.

We ran into this quirk because we were trying to make OSLOADER raise a GPF, so
yeah, it's not just a feature, it's a bug =] I wonder if it would interfere
with any of the execution protection software that relies upon a short CS and a
high-addressed stack?

This trick only works if VMware's running in emulation mode, which is the case
if the code is running privileged, or if acceleration is disabled (VM ->
Settings -> Options, Advanced: Disable acceleration). Joanna's SIDT technique
only works if VMware is not running in emulation mode, so if you combine these
two, you should get "comprehensive" VMware detection.

I figure that VMware would consider any form of unfaithful emulation as a
"bug", so this might be fixed in some current or future version of VMware.
--- quote ---

Another copy of it which includes more checks:

https://web.archive.org/web/20220109171838/https://www.aldeid.com/wiki/ScoopyNG

The attached tarball contains the original source code with the following
modifications:

(1) replaced the code to retrieve the highest user mode address with a constant
since Wine doesn't set KSHARED_USER_DATA+0x2B4

--- snip ---
#define EndUserModeAddress (*(UINT_PTR*)0x7FFE02B4)
--- snip ---

(2) handled native API failure

(3) improved diagnostic output (print addresses)

The tarball also contains a prebuilt 32-bit x86 executable for testing. Built
with debug info under Wine using:

https://github.com/mstorsjo/msvc-wine

--- snip ---
$ tar tvf vmgpftest-bug44817.tar

drwxrwxr-x focht/focht       0 2022-01-09 18:35 vmgpftest-bug44817/
-rw-rw-r-- focht/focht    1636 2022-01-09 18:35 vmgpftest-bug44817/vmgpftest.c
-rwxrwxr-x focht/focht   24576 2022-01-09 18:35
vmgpftest-bug44817/vmgpftest-x86.exe
-rw-rw-r-- focht/focht  708608 2022-01-09 18:35
vmgpftest-bug44817/vmgpftest-x86.pdb
--- snip ---

$ sha1sum vmgpftest-x86.exe 
cd0b3bfd15075462ea90d9ebbf341af8df7c506a  vmgpftest-x86.exe

Some Virus scanners detect the executable as malware which is kinda expected
because of the unusual occurrence of native API 'ntdll.NtSetLdtEntries':

https://www.virustotal.com/gui/file/7d3abb621177f6d905cc9931dad012c48137b784e850736e27647fc7992cdf6c

You can always rebuild from source if you are scared ;-)

With current Wine:

--- snip ---
$ wine ./vmgpftest-x86.exe 
ZwSetLdtEntries() failed: c000011a
--- snip ---

With Wine-Staging patch(es):

--- snip ---
$ WINEDEBUG=+seh,+relay wine ./vmgpftest-x86.exe >>log.txt 2>&1
...
0024:Call KERNEL32.GetProcAddress(7bc00000,0040602c "ZwSetLdtEntries")
ret=00401491
0024:Ret  KERNEL32.GetProcAddress() retval=7bc09a10 ret=00401491
0024:Call ntdll.ZwSetLdtEntries(0000000f,c7fa000000ffef,00000000,000000000)
ret=004014d2
0024:Ret  ntdll.ZwSetLdtEntries() retval=00000000 ret=004014d2
0024:trace:seh:dispatch_exception code=c0000005 flags=0 addr=00401502
ip=00401502 tid=0024
0024:trace:seh:dispatch_exception  info[0]=00000000
0024:trace:seh:dispatch_exception  info[1]=ffffffff
0024:warn:seh:dispatch_exception EXCEPTION_ACCESS_VIOLATION exception
(code=c0000005) raised
0024:trace:seh:dispatch_exception  eax=ffffffff ebx=7ffd1000 ecx=00000004
edx=00000000 esi=0041aa50 edi=004297f0
0024:trace:seh:dispatch_exception  ebp=0032fec0 esp=0032fe88 cs=000f ss=002b
ds=002b es=002b fs=0063 gs=006b flags=00010286
0024:trace:seh:call_stack_handlers calling handler at 00401649 code=c0000005
flags=0
0024:Call
ucrtbase._except_handler4_common(00406080,004010b4,0032fce8,0032feb0,0032fa04,0032f9cc)
ret=00401672
0024:trace:seh:_except_handler4_common exception c0000005 flags=0 at 00401502
handler=00401649 0032FA04 0032F9CC cookie=2f7ee785 scope table=00405618
cookies=-2/0,-56/0
0024:trace:seh:_except_handler4_common level 0 prev -2 filter 0040150D
0024:trace:seh:_except_handler4_common filter returned EXECUTE_HANDLER
0024:trace:seh:__DestructExceptionObject (0032FCE8)
0024:trace:seh:_global_unwind2 (0032FEB0)
0024:trace:seh:__regs_RtlUnwind code=c0000027 flags=2
0024:trace:seh:__regs_RtlUnwind eax=00000000 ebx=0032feb0 ecx=7bc0be1c
edx=0000002a esi=0032feb0 edi=00000000
0024:trace:seh:__regs_RtlUnwind ebp=0032f740 esp=0032f73c eip=00371b23 cs=0023
ds=002b fs=0063 gs=006b flags=00000206
0024:trace:seh:__regs_RtlUnwind calling handler at 7BC48370 code=c0000027
flags=2
0024:trace:seh:__regs_RtlUnwind handler at 7BC48370 returned 1
0024:trace:seh:msvcrt_local_unwind4 (0032FEB0,0,0)
0024:trace:seh:msvcrt_local_unwind4 unwound OK
0024:trace:seh:_except_handler4_common __finally block 0040151A
0024:Call KERNEL32.GetModuleHandleW(00000000) ret=00402159
0024:Ret  KERNEL32.GetModuleHandleW() retval=00400000 ret=00402159
0024:Call ucrtbase.exit(00000000) ret=004018fd
...
--- snip ---

$ wine --version
wine-7.0-rc5

Regards

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list