[Bug 42716] 64-bit MetaTrader5 refuses to start, reports ' A debugger has been found running in your system' (Denuvo Anti-Tamper x64)

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Jul 9 12:21:29 CDT 2017


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

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net
            Summary|MetaTrader5 64-bit refuses  |64-bit MetaTrader5 refuses
                   |to start when               |to start, reports 'A
                   |IsDebuggerPresent returns   |debugger has been found
                   |true                        |running in your system'
                   |                            |(Denuvo Anti-Tamper x64)
                URL|                            |https://download.mql5.com/c
                   |                            |dn/web/metaquotes.software.
                   |                            |corp/mt5/mt5setup.exe?utm_c
                   |                            |ampaign=www.metaquotes.net
             Status|UNCONFIRMED                 |NEW
           Keywords|                            |download, obfuscation
     Ever confirmed|0                           |1
          Component|kernel32                    |-unknown

--- Comment #9 from Anastasius Focht <focht at gmx.net> ---
Hello folks,

the conclusion is wrong, correcting summary.

The app is wrapped with Denuvo "Anti-Tamper" x64 software protection.

ProtectionID scan:

--- snip --- 
-=[ ProtectionID v0.6.8.5 DECEMBER]=-
(c) 2003-2017 CDKiLLER & TippeX
Build 24/12/16-13:09:21
Ready...
Scanning -> Z:\home\focht\Downloads\MetaTrader 5\terminal64.exe
File Type : 64-Bit Exe (Subsystem : Win GUI / 2), Size : 16390320 (0FA18B0h)
Byte(s) | Machine: 0x8664 (AMD64)
[!] Warning -> File needs higher OS (Current OS : 05.01, Requires OS: 06.00)
[!] Warning : File is 64 Bit, this os is NOT
Compilation TimeStamp : 0x00F30400 -> Sat 04th Jul 1970 07:57:52 (GMT)
[TimeStamp] 0x00F30400 -> Sat 04th Jul 1970 07:57:52 (GMT) | PE Header | - |
Offset: 0x00000000:00000150 | VA: 0x00000001:40000150 | -
[TimeStamp] 0x59009228 -> Wed 26th Apr 2017 12:27:20 (GMT) | DebugDirectory | -
| Offset: 0x00000000:00CCA664 | VA: 0x00000001:41F49E64 | -
[TimeStamp] 0x59009228 -> Wed 26th Apr 2017 12:27:20 (GMT) | DebugDirectory | -
| Offset: 0x00000000:00CCA680 | VA: 0x00000001:41F49E80 | -
[TimeStamp] 0x59009228 -> Wed 26th Apr 2017 12:27:20 (GMT) | DebugDirectory | -
| Offset: 0x00000000:00CCA69C | VA: 0x00000001:41F49E9C | -
-> File Appears to be Digitally Signed @ Offset 0F9FFA8h, size : 01908h / 06408
byte(s)
-> File has 457640 (06FBA8h) bytes of appended data starting at offset 0F30400h
[!] Executable uses TLS callbacks (3 total... 0 invalid addresses)
[File Heuristics] -> Flag #1 : 00000100000001001101001000000101 (0x0404D205)
[Entrypoint Section Entropy] : 7.99 (section #8) ".cod1   " | Size : 0xD3142C
(13833260) byte(s)
[DllCharacteristics] -> Flag : (0x8160) -> HEVA | ASLR | DEP | TSA
[SectionCount] 11 (0xB) | ImageSize 0x2E15000 (48320512) byte(s)
[VersionInfo] Company Name : MetaQuotes Software Corp.
[VersionInfo] Product Name : MetaTrader 5 Client Terminal
[VersionInfo] Product Version : 5.0.0.1596
[VersionInfo] File Description : MetaTrader 5 Client Terminal
[VersionInfo] File Version : 5.0.0.1596
[VersionInfo] Original FileName : terminal.exe
[VersionInfo] Internal Name : terminal.exe
[VersionInfo] Version Comments : http://www.metaquotes.net
[VersionInfo] Legal Trademarks : MetaTrader
[VersionInfo] Legal Copyrights : © 2001-2017. MetaQuotes Software Corp.
[ModuleReport] [IAT] Modules -> CRYPT32.dll | WINMM.dll | VERSION.dll |
NETAPI32.dll | WINHTTP.dll | gdiplus.dll | UxTheme.dll | KERNEL32.dll |
USER32.dll | GDI32.dll | MSIMG32.dll | WINSPOOL.DRV | ADVAPI32.dll |
SHELL32.dll | COMCTL32.dll | SHLWAPI.dll | ole32.dll | OLEAUT32.dll |
oledlg.dll | urlmon.dll | IPHLPAPI.DLL | dbghelp.dll | WS2_32.dll | Secur32.dll
| OLEACC.dll | IMM32.dll | WTSAPI32.dll | KERNEL32.dll | USER32.dll |
ADVAPI32.dll | KERNEL32.dll | ADVAPI32.dll
[Debug Info] (record 1 of 3) (file offset 0xCCA660)
Characteristics : 0x0 | TimeDateStamp : 0x59009228 (Wed 26th Apr 2017 12:27:20
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 2 (0x2) -> CodeView | Size : 0x5B (91)
AddressOfRawData : 0x1F499C0 | PointerToRawData : 0xCCA1C0
CvSig : 0x53445352 | SigGuid 5D5F75E6-83B5-4F0F-B56BB8527C4A0449
Age : 0x1 (1) | Pdb :
E:\MetaTrader5\Client\MetaTrader5Terminal\Release64\terminal64.pdb
[Debug Info] (record 2 of 3) (file offset 0xCCA67C)
Characteristics : 0x0 | TimeDateStamp : 0x59009228 (Wed 26th Apr 2017 12:27:20
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 12 (0xC) -> Undocumented | Size : 0x14 (20)
AddressOfRawData : 0x1F49A20 | PointerToRawData : 0xCCA220
[Debug Info] (record 3 of 3) (file offset 0xCCA698)
Characteristics : 0x0 | TimeDateStamp : 0x59009228 (Wed 26th Apr 2017 12:27:20
(GMT)) | MajorVer : 0 / MinorVer : 0 -> (0.0)
Type : 13 (0xD) -> Undocumented | Size : 0x418 (1048)
AddressOfRawData : 0x1F49A40 | PointerToRawData : 0xCCA240
[?] Possibly Denuvo "Anti-Tamper" x64
[CompilerDetect] -> Borland Delphi (unknown version) - 20% probability
- Scan Took : 2.322 Second(s) [000000A76h (2678) tick(s)] [234 of 580 scan(s)
done]
--- snip --- 

Some info:

https://steamcommunity.com/app/379720/discussions/0/357286119113278148/

https://www.reddit.com/r/CrackStatus/comments/43dgej/how_denuvo_works_and_why_its_so_hard_to_crack/

Relevant trace log:

--- snip ---
$ WINEDEBUG=+tid,+seh,+relay wine64 ./terminal64.exe >>log.txt 2>&1
...
0037:Call TLS callback
(proc=0x1416b3b84,module=0x140000000,reason=PROCESS_ATTACH,reserved=0)
...
0037:Call KERNEL32.GetModuleHandleA(0023f430 "kernel32.dll") ret=1416629fb
0037:Ret  KERNEL32.GetModuleHandleA() retval=7b460000 ret=1416629fb
0037:Call KERNEL32.GetModuleHandleA(0023f430 "ntdll.dll") ret=1416629fb
0037:Ret  KERNEL32.GetModuleHandleA() retval=7bc80000 ret=1416629fb
0037:Call KERNEL32.IsDebuggerPresent() ret=1416b988d
0037:Ret  KERNEL32.IsDebuggerPresent() retval=00000000 ret=1416b988d
0037:Call KERNEL32.CheckRemoteDebuggerPresent(ffffffffffffffff,0023f68c)
ret=1416b988d
0037:Ret  KERNEL32.CheckRemoteDebuggerPresent() retval=00000001 ret=1416b988d
0037:Call
ntdll.NtQueryInformationProcess(ffffffffffffffff,0000001e,0023f7f0,00000008,00000000)
ret=1416b988d
0037:Ret  ntdll.NtQueryInformationProcess() retval=c0000353 ret=1416b988d
0037:Call
ntdll.NtSetInformationThread(fffffffffffffffe,00000011,00000000,00000000)
ret=1416b988d
0037:Ret  ntdll.NtSetInformationThread() retval=00000000 ret=1416b988d
0037:Call ntdll.NtQuerySystemInformation(00000023,0023fb20,00000002,00000000)
ret=1416b988d
0037:Ret  ntdll.NtQuerySystemInformation() retval=00000000 ret=1416b988d
0037:Call ntdll.NtQuerySystemInformation(0000000b,0023f5f8,00000000,0023fb38)
ret=1416b988d
0037:Ret  ntdll.NtQuerySystemInformation() retval=c0000004 ret=1416b988d
0037:Call KERNEL32.LocalAlloc(00000000,00005348) ret=1416b988d
0037:Ret  KERNEL32.LocalAlloc() retval=00072080 ret=1416b988d
0037:Call ntdll.NtQuerySystemInformation(0000000b,00072080,00005348,00000000)
ret=1416b988d
0037:Ret  ntdll.NtQuerySystemInformation() retval=00000000 ret=1416b988d
0037:Call KERNEL32.LocalFree(00072080) ret=1416b988d
0037:Ret  KERNEL32.LocalFree() retval=00000000 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140c7d000,0060201c,00000040,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(1408b6000,0026ce26,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140001000,008b4744,00000040,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140bfb000,00063b70,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140c5f000,0001bcb8,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140c7b000,00000010,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(140cae000,00005c58,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d
0037:Call KERNEL32.VirtualProtect(141fb3000,00e61674,00000004,0023f670)
ret=1416b988d
0037:Ret  KERNEL32.VirtualProtect() retval=00000001 ret=1416b988d 
...
0037:Call KERNEL32.CloseHandle(deadc0de) ret=1416b988d
0037:Ret  KERNEL32.CloseHandle() retval=00000000 ret=1416b988d
0037:trace:seh:raise_exception code=80000004 flags=0 addr=0x141f49833
ip=141f49833 tid=0037
0037:trace:seh:raise_exception  rax=00000000e9b2b85c rbx=0000000141685350
rcx=00000000deadc0de rdx=00000000000055d1
0037:trace:seh:raise_exception  rsi=0000000000000000 rdi=aaaaaaaaaaaaaaab
rbp=000000000023f5a0 rsp=000000000023f550
0037:trace:seh:raise_exception   r8=0000000000267148  r9=000000000000a388
r10=00000000c5fb301a r11=0000000000000038
0037:trace:seh:raise_exception  r12=0000000141669385 r13=0000000000000048
r14=0000000000000004 r15=000000014166898c
0037:trace:seh:RtlVirtualUnwind type 1 rip 141f49833 rsp 23f550
0037:trace:seh:dump_unwind_info **** func 1f49767-1f498fa
0037:trace:seh:dump_unwind_info unwind info at 0x14164c650 flags 1 prolog 0x19
bytes function 0x141f49767-0x141f498fa
...
0037:trace:seh:call_handler calling handler 0x140c97ee0 (rec=0x23f410,
frame=0x23f550 context=0x23e790, dispatch=0x23ec60) 
...
0037:trace:seh:RtlRestoreContext returning to 141f4983e stack 23f550
0037:Call KERNEL32.GetModuleFileNameW(140000000,0023eb00,00000104)
ret=141f496ef
0037:Ret  KERNEL32.GetModuleFileNameW() retval=00000033 ret=141f496ef
0037:Call advapi32.OpenSCManagerW(00000000,00000000,00000004) ret=1416b988d 
...
0037:Ret  advapi32.OpenSCManagerW() retval=000725c0 ret=1416b988d
0037:Call
advapi32.EnumServicesStatusExW(000725c0,00000000,00000030,00000001,00000000,00000000,0023f568,0023eae0,0023eae4,00000000)
ret=141f496f9 
...
0037:Ret  advapi32.EnumServicesStatusExW() retval=00000000 ret=141f496f9
0037:Call KERNEL32.GetLastError() ret=1416b988d
0037:Ret  KERNEL32.GetLastError() retval=000000ea ret=1416b988d
0037:Call KERNEL32.LocalAlloc(00000000,0000021c) ret=1416b988d
0037:Ret  KERNEL32.LocalAlloc() retval=00072740 ret=1416b988d
0037:Call
advapi32.EnumServicesStatusExW(000725c0,00000000,00000030,00000001,00072740,0000021c,0023f568,0023eae0,0023eae4,00000000)
ret=141f49703 
...
0037:Ret  advapi32.EnumServicesStatusExW() retval=00000001 ret=141f49703
...
0037:Call advapi32.CloseServiceHandle(000725c0) ret=1416b988d
...
0037:Ret  advapi32.CloseServiceHandle() retval=00000001 ret=1416b988d
0037:Call KERNEL32.LoadLibraryA(0023e970 "user32.dll") ret=141653449
0037:Ret  KERNEL32.LoadLibraryA() retval=7fccac340000 ret=141653449
0037:Call user32.MessageBoxW(00000000,0023ed10 L"A debugger has been found
running in your system.\nPlease, unload it from memory and restart your
program.",0023eb4a L"terminal64.exe",00000010) ret=1416b988d 
...
--- snip ---

Those anti-debugging tricks as seen from trace log seem to work fine with
64-bit:

* IsDebuggerPresent
* CheckRemoteDebuggerPresent
* NtQueryInformationProcess( ProcessDebugObjectHandle)
* NtSetInformationThread( ThreadHideFromDebugger)
* NtQuerySystemInformation( SystemKernelDebuggerInformation)
* NtQuerySystemInformation( SystemModuleInformation)
* CloseHandle( invalid handle/EXCEPTION_INVALID_HANDLE)

There is a lot of 64-bit virtual machine code which makes this kinda hard to
debug/analyse.

The single step trap from trace log looks suspicious though.

--- snip ---
0037:trace:seh:raise_exception code=80000004 flags=0 addr=0x141f49833
ip=141f49833 tid=0037
--- snip ---

--- snip ---
...
0x0000000141f49802: call    0x000000014128b557
0x0000000141f49807: pushq    $0xd92eb714
0x0000000141f4980c: call    0x000000014128b557
0x0000000141f49811: pushq    $0x18ff4951
0x0000000141f49816: call    0x000000014128b557
0x0000000141f4981b: pushq    $0xd8d940e7
0x0000000141f49820: call    0x000000014128b557
0x0000000141f49825: testb    %ch,0xffffffffffffffae(%rax)
0x0000000141f49828: aad    $0xd8
0x0000000141f4982a: popq    %rax
0x0000000141f4982b: call    0x000000014128b557
0x0000000141f49830: popfl
0x0000000141f49831: rdtsc
0x0000000141f49833: nop
0x0000000141f49834: pushq    $0x592872dc
0x0000000141f49839: call    0x000000014128b557
0x0000000141f4983e: pushq    $0x58d88e4f
0x0000000141f49843: call    0x000000014128b557
0x0000000141f49848: popfl
0x0000000141f49849: rdtsc
0x0000000141f4984b: nop
0x0000000141f4984c: pushq    $0x98d8fed4
0x0000000141f49851: call    0x000000014128b557 
...

Wine-dbg>b *0x0000000141f49830
Breakpoint 1 at 0x0000000141f49830
Wine-dbg>b *0x0000000141f49831
Breakpoint 2 at 0x0000000141f49831
Wine-dbg>c
Stopped on breakpoint 1 at 0x0000000141f49830

Wine-dbg>info reg
Register dump:
 rip:0000000141f49830 rsp:000000000023f538 rbp:000000000023f590 eflags:00000246
(   - --  I  Z- -P- )
 rax:0000000000000346 rbx:0000000141685350 rcx:00000000deadc0de
rdx:00000000000787c0
 rsi:0000000000000000 rdi:aaaaaaaaaaaaaaab  r8:0000000000267148 
r9:000000000000a400 r10:00000000c5fb2fee
 r11:0000000000000038 r12:0000000141669385 r13:0000000000000048
r14:0000000000000004 r15:000000014166898c

 Wine-dbg>si
 Stopped on breakpoint 2 at 0x0000000141f49831
 0x0000000141f49831: rdtsc

 Wine-dbg>info reg
 Register dump:
  rip:0000000141f49831 rsp:000000000023f540 rbp:000000000023f590
eflags:00000346 (   - --  IT Z- -P- )
  rax:0000000000000346 rbx:0000000141685350 rcx:00000000deadc0de
rdx:00000000000787c0
  rsi:0000000000000000 rdi:aaaaaaaaaaaaaaab  r8:0000000000267148 
r9:000000000000a400 r10:00000000c5fb2fee
  r11:0000000000000038 r12:0000000141669385 r13:0000000000000048
r14:0000000000000004 r15:000000014166898c 
--- snip ---

Normally 'rdtsc' sequences are used for timing analysis, that is VM/emulation
detection, single stepping detection under debugger etc.
I'm not sure why Denuvo sets the trap flag (TF) before execution (popfl ->
eflags), if the trap sequence is intended at all.
Maybe the exception handler has some state machine/logic for timing analysis.
I didn't look very hard though.

The remaining sequence, that is querying the SCM for services state is always
done when something bad happened. You can simulate it by having one of the
anti-debug checks intentionally fail.

$ sha1sum mt5setup.exe 
fe34784ab570f051ed81c6409d07becdae12aafd  mt5setup.exe

$ du -sh mt5setup.exe 
640K    mt5setup.exe

$ wine --version
wine-2.12

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