[Bug 15301] Biliardo 2 installer terminates on launch (32-bit Ghost-based installer uses year 2045 file date for decrypting database, triggering y2038 problem)

wine-bugs at winehq.org wine-bugs at winehq.org
Fri Nov 20 17:05:45 CST 2015


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

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |obfuscation
                 CC|                            |focht at gmx.net
          Component|-unknown                    |ntdll
            Summary|Biliardo 2 installer        |Biliardo 2 installer
                   |terminates on launch        |terminates on launch
                   |                            |(32-bit Ghost-based
                   |                            |installer uses year 2045
                   |                            |file date for decrypting
                   |                            |database, triggering y2038
                   |                            |problem)

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

confirming.

The message box is shown in blink of an eye but it's clearly present in trace
log ;-)

--- snip ---
$ WINEDEBUG=+tid,+seh,+relay wine ./setup.exe >>log.txt 2>&1
...
0009:Call KERNEL32.CreateFileA(00451ab0
"C:\\users\\fred\\Temp\\0FJ5E783\\setup\\db.pdb",80000000,00000001,00000000,00000003,00000080,00000000)
ret=00406a3f
0009:Ret  KERNEL32.CreateFileA() retval=00000044 ret=00406a3f
0009:Call KERNEL32.GetFileSize(00000044,00000000) ret=00414d53
0009:Ret  KERNEL32.GetFileSize() retval=00000e16 ret=00414d53
0009:Call KERNEL32.VirtualAlloc(00458000,00004000,00001000,00000004)
ret=00401646
0009:Ret  KERNEL32.VirtualAlloc() retval=00458000 ret=00401646
0009:Call KERNEL32.ReadFile(00000044,00457668,00000e16,0032fd04,00000000)
ret=00406a81
0009:Ret  KERNEL32.ReadFile() retval=00000001 ret=00406a81
0009:Call KERNEL32.CloseHandle(00000044) ret=00406ad2
0009:Ret  KERNEL32.CloseHandle() retval=00000001 ret=00406ad2
0009:Call user32.LoadStringA(00400000,0000ff90,0032f8ec,00000400) ret=00404a7d
0009:Ret  user32.LoadStringA() retval=00000022 ret=00404a7d
0009:Call KERNEL32.RaiseException(0eedfade,00000001,00000007,0032fce4)
ret=004169f4
0009:trace:seh:raise_exception code=eedfade flags=1 addr=0x7b8383c3 ip=7b8383c3
tid=0009
0009:trace:seh:raise_exception  info[0]=004169f4
0009:trace:seh:raise_exception  info[1]=004592a8
0009:trace:seh:raise_exception  info[4]=00000000
0009:trace:seh:raise_exception  info[5]=0032fd60
0009:trace:seh:raise_exception  info[6]=0032fd00
0009:trace:seh:raise_exception  eax=7b82569d ebx=7b88fff4 ecx=0032fd00
edx=0032fc20 esi=0032fce4 edi=0032fc60
0009:trace:seh:raise_exception  ebp=0032fc48 esp=0032fbe4 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00000283
0009:trace:seh:call_vectored_handlers calling handler at 0x7e33d144
code=eedfade flags=1
0009:trace:seh:call_vectored_handlers handler at 0x7e33d144 returned 0 
...
0009:Call user32.SetWindowsHookExA(00000005,00414ea8,00000000,00000009)
ret=00414f39
0009:Ret  user32.SetWindowsHookExA() retval=00020064 ret=00414f39
0009:Call user32.MessageBoxA(00010064,004592f0 "Invalid character in the tag
name. Line 1, position 102.",00459338 "Error",00012010) ret=00414f75
0009:Ret  user32.MessageBoxA() retval=ffffffff ret=00414f75
--- snip ---

ProtectionID scan reveals it's wrapped with an old version of 'Ghost Installer'
(http://www.ethalone.com/download.html)

--- snip ---
-=[ ProtectionID v0.6.6.7 DECEMBER]=-
(c) 2003-2015 CDKiLLER & TippeX
Build 24/12/14-22:48:13
Ready...
Scanning -> Z:\home\focht\Downloads\setup.exe
File Type : 32-Bit Exe (Subsystem : Win GUI / 2), Size : 894386 (0DA5B2h)
Byte(s)
Compilation TimeStamp : 0x2A425E19 -> Fri 19th Jun 1992 22:22:17 (GMT)
[TimeStamp] 0x2A425E19 -> Fri 19th Jun 1992 22:22:17 (GMT) | PE Header | - |
Offset: 0x00000108 | VA: 0x00400108 | -
-> File has 786354 (0BFFB2h) bytes of appended data starting at offset 01A600h
[File Heuristics] -> Flag #1 : 00000000000000001100001000100111 (0x0000C227)
[Entrypoint Section Entropy] : 7.90 (section #1) "UPX1    " | Size : 0x18600
(99840) byte(s)
[DllCharacteristics] -> Flag : (0x0000) -> NONE
[SectionCount] 3 (0x3) | ImageSize 0x48000 (294912) byte(s)
[-= Installer =-] Ghost Installer Module !
[!] UPX 1.20 compressed !
upx internal version : 012 / compression method : 02 (M_NRV2B_LE32) - Level :
010
decompressed adler32 : 0x28F0F142 / compressed adler32 : 0x354761E5
uncompressed size : 0x00043F54 (0278356) / compressed size : 0x000183D0
(099280)
original file size : 0x0003BC00 (0244736) / filter : 0x026 / ct0 0x0E /
linkchecksum : 0x02F
[CompilerDetect] -> Borland Delphi (unknown version) - 80% probability
- Scan Took : 0.336 Second(s) [000000150h (336) tick(s)] [558 of 573 scan(s)
done]
--- snip ---

Tidbit: The error message is also mentioned in release notes of the 'Ghost
Installer' vendor site:

http://www.ethalone.com/download/gi/WhatsNew.txt

--- quote ---
...

=== Version 3.1 (from 07/15/2002) ==============================
 [+] The rollback function has been greatly improved. Now it completely returns
system to the state before installation process.
 [+] Now installation process can be resumed automatically after the reboot (if
reboot was necessary for replacing in-use files, or if reboot has been
initiated by some application launched by <runapp> tag).
 [+] New events: EV_CALCFUNCTION, EV_QUERYREBOOT. New control messages:
CM_CALCEXPRESSION, CM_CALCBOOLEXPRESSION, CM_REGISTERFUNCTION, CM_ALLOCMEM,
CM_FREEMEM.
 [+] New variable - InstallPlatform.
 [+] The Romanian, Slovenian translations has been added.
 [-] Sometimes (very rare) installer displayed "Invalid character in the tag
name" error message on start setup.
 [-] The DotNetInstalled function didn't worked during installing files.
 [-] If there was an environment variable on the destination computer, it was
used instead of variable defined in project.
 [-] Ini file parameters didn't removed on install/uninstall.
 [-] Sometimes installer displayed "Invalid package size!" error message when
another Ghost Installer package was included into setup.
 [-] Some small bugfixes.
...
--- quote ---

-> " [-] Sometimes (very rare) installer displayed "Invalid character in the
tag name" error message on start setup."

The 'Ghost installer' version the app is wrapped with is older and Wine
triggers the error every time.

Spent some hours of debugging...
The installer decrypts a database 'db.pdb' using a builtin key.
Part of the key is derived at runtime from the file date/time of the encrypted
database file (which is constant).
The actual key incorrect (re)creation can't be seen in trace log (-> debugger).

The file date/time is set here:

--- snip ---
...
002c:Call KERNEL32.CreateFileA(100095e8
"C:\\users\\focht\\Temp\\2325J0M5\\setup\\db.pdb",c0000000,00000001,00000000,00000003,00000080,00000000)
ret=10001797
002c:Ret  KERNEL32.CreateFileA() retval=0000006c ret=10001797
002c:Call KERNEL32.DosDateTimeToFileTime(00008305,00000000,0033fc68)
ret=100017b5
002c:Ret  KERNEL32.DosDateTimeToFileTime() retval=00000001 ret=100017b5
002c:Call KERNEL32.LocalFileTimeToFileTime(0033fc68,0033fc60) ret=100017c7
002c:Ret  KERNEL32.LocalFileTimeToFileTime() retval=00000001 ret=100017c7
002c:Call KERNEL32.SetFileTime(0000006c,0033fc60,00000000,0033fc60)
ret=100017de
002c:Ret  KERNEL32.SetFileTime() retval=00000001 ret=100017de
002c:Call KERNEL32.CloseHandle(0000006c) ret=100017e6
002c:Ret  KERNEL32.CloseHandle() retval=00000001 ret=100017e6
...
--- snip ---

Before setting the file date/time on the database:

--- snip ---
$ pwd
/home/focht/.wine/drive_c/users/focht/Temp

$ ll */*/*
-rw-rw-r--. 1 focht focht  3606 Nov 20 21:51 2327FO2C/setup/db.pdb
...
--- snip ---

--- snip ---
Wine-dbg>bt

Backtrace:
=>0 0x7b88a171 DosDateTimeToFileTime+0x21(fatdate=0x8305, fattime=0,
ft=<couldn't compute location>)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/time.c:1040] in kernel32
(0x0033fc38)
  1 0x100017b5 in unpack (+0x17b4) (0x0033fc7c)

Wine-dbg>p newtm
{tm_sec=0, tm_min=0, tm_hour=0, tm_mday=0x5, tm_mon=0x7, tm_year=0x91,
tm_wday=0x7ffd8c00, tm_yday=0x33fc3c, tm_isdst=0xffffffff, tm_gmtoff=0x33fc7c,
tm_zone="..."}

...

Wine-dbg>info locals
0x7bca922c RtlSecondsSince1970ToTime+0x39: (0033fbe8)
    DWORD Seconds=0xffffffff (parameter [EBP+8])
    LARGE_INTEGER* Time=0x33fc68 (parameter [EBP+12])

Wine-dbg>p *Time
{u={LowPart=0xd4a5e980, HighPart=0x236485e}, ={LowPart=0xd4a5e980,
HighPart=0x236485e}, QuadPart=0x236485ed4a5e980}

...
Wine-dbg>bt
Backtrace:
=>0 0x7b889d89 LocalFileTimeToFileTime(localft=0x33fc68, utcft=0x33fc60)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/time.c:854] in kernel32
(0x0033fc7c)

Wine-dbg>p *localft
{dwLowDateTime=0xd4a5e980, dwHighDateTime=0x236485e}

...
860        if (!(status = RtlLocalTimeToSystemTime( &local, &utc )))
Wine-dbg>n
862            utcft->dwLowDateTime = utc.u.LowPart;
Wine-dbg>n
863            utcft->dwHighDateTime = utc.u.HighPart;
Wine-dbg>n
867        return !status;

Wine-dbg>p utc
{u={LowPart=0x72e18180, HighPart=0x2364856}, ={LowPart=0x72e18180,
HighPart=0x2364856}, QuadPart=0x236485672e18180}

...
Wine-dbg>bt
Backtrace:
=>0 0x7b84a4c6 SetFileTime(hFile=0x64, ctime=0x33fc60, atime=(nil),
mtime=0x33fc60)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/file.c:1256] in kernel32
(0x0033fc7c)

Wine-dbg>p *ctime
{dwLowDateTime=0x72e18180, dwHighDateTime=0x2364856}
...
Wine-dbg>n
1278        status = NtSetInformationFile( hFile, &io, &info, sizeof(info),
FileBasicInformation );

Wine-dbg>bt

Backtrace:
=>0 0x7bc5a34b set_file_times(fd=0xd, mtime=0x33fc10, atime=0x33fc08)
[/home/focht/projects/wine/wine.repo/src/dlls/ntdll/file.c:2000] in ntdll
(0x0033fbb8)
  1 0x7b84a562 SetFileTime+0x9b(hFile=<couldn't compute location>,
ctime=<couldn't compute location>, atime=<couldn't compute location>,
mtime=<couldn't compute location>)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/file.c:1278] in kernel32
(0x0033fc38)
  2 0x100017de in unpack (+0x17dd) (0x0033fc7c)

Wine-dbg>p *mtime
{u={LowPart=0x72e18180, HighPart=0x2364856}, ={LowPart=0x72e18180,
HighPart=0x2364856}, QuadPart=0x236485672e18180}

Wine-dbg>n
2015            tv[1].tv_sec = mtime->QuadPart / 10000000 - SECS_1601_TO_1970;
Wine-dbg>n
2016            tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
Wine-dbg>n
2018        if (futimens( fd, tv ) == -1) status = FILE_GetNtStatus();

Wine-dbg>p tv[1]
{tv_sec=0xfffff1ef, tv_nsec=0}

--- snip ---

After setting the file date/time:

--- snip ---
$ pwd
/home/focht/.wine/drive_c/users/focht/Temp

$ ll */*/*
-rw-rw-r--. 1 focht focht  3606 Dec 31  1969 2327FO2C/setup/db.pdb
...
--- snip ---

MSDN:
https://msdn.microsoft.com/de-de/library/windows/desktop/ms724247%28v=vs.85%29.aspx

--- quote ---
wFatDate [in]

    The MS-DOS date. The date is a packed value with the following format.
    Bits    Description
    0-4    Day of the month (1–31)
    5-8    Month (1 = January, 2 = February, and so on)
    9-15    Year offset from 1980 (add 1980 to get actual year)
--- quote ---

fatdate = 0x8305 -> 2045-08-05

The DOS date is hard-coded, triggering timespec y2038 problem on 32-bit Linux
userspace ;-)

Although one could stop right here, the retrieval of file date/time to generate
parts of the decryption key from (which shows another roll-over problem):

--- snip ---
...
002c:Call KERNEL32.FindFirstFileA(00457080
"C:\\users\\focht\\Temp\\2325J0M5\\setup\\db.pdb",0033fb8c) ret=00406af4
002c:Ret  KERNEL32.FindFirstFileA() retval=0014c100 ret=00406af4
002c:Call KERNEL32.FindClose(0014c100) ret=00406aff
002c:Ret  KERNEL32.FindClose() retval=00000001 ret=00406aff
002c:Call KERNEL32.FileTimeToLocalFileTime(0033fba0,0033fccc) ret=00406b18
002c:Ret  KERNEL32.FileTimeToLocalFileTime() retval=00000001 ret=00406b18
002c:Call KERNEL32.FileTimeToDosDateTime(0033fccc,0033fcd6,0033fcd4)
ret=00406b29
002c:Ret  KERNEL32.FileTimeToDosDateTime() retval=00000001 ret=00406b29 
...
--- snip ---

--- snip ---
Wine-dbg>bt
Backtrace:
=>0 0x7b84cdd5
FindFirstFileA(lpFileName="C:\users\focht\Temp\2326M678\setup\db.pdb",
lpFindData=0x33fb8c)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/file.c:2299] in kernel32
(0x0033fcd8)
  1 0x00413a21 in setup (+0x13a20) (0x0033fcf0)
  2 0x00413a59 in setup (+0x13a58) (0x0033fd04)
  3 0x0042c40d in setup (+0x2c40c) (0x0033fd30)
  4 0x0042c4de in setup (+0x2c4dd) (0x0033fd64)
  5 0x0042cc88 in setup (+0x2cc87) (0x0033fdd4)
  6 0x0042da9c in setup (+0x2da9b) (0x0033fe10)
  7 0x0042dd1b in setup (+0x2dd1a) (0x0033fe30)
  8 0x7b86ea34 call_process_entry+0xb() in kernel32 (0x0033fe48)

Wine-dbg>n
2318        handle = FindFirstFileExW(nameW, fInfoLevelId, &dataW, fSearchOp,
lpSearchFilter, dwAdditionalFlags);
...
Wine-dbg>p dataW
{dwFileAttributes=0x20, ftCreationTime={dwLowDateTime=0x72e18180,
dwHighDateTime=0x2364856}, ftLastAccessTime={dwLowDateTime=0x7c667729,
dwHighDateTime=0x1d123c1}, ftLastWriteTime={dwLowDateTime=0x72e18180,
dwHighDateTime=0x2364856}, nFileSizeHigh=0, nFileSizeLow=0xe16, dwReserved0=0,
dwReserved1=0, cFileName={...}}

...

Wine-dbg>bt
Backtrace:
=>0 0x7b889e0f FileTimeToLocalFileTime(utcft=0x33fba0, localft=0x33fccc)
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/time.c:874] in kernel32
(0x0033fcd8)
  1 0x00413a21 in setup (+0x13a20) (0x0033fcf0)
  2 0x00413a59 in setup (+0x13a58) (0x0033fd04)
  3 0x0042c40d in setup (+0x2c40c) (0x0033fd30)
  4 0x0042c4de in setup (+0x2c4dd) (0x0033fd64)
  5 0x0042cc88 in setup (+0x2cc87) (0x0033fdd4)
  6 0x0042da9c in setup (+0x2da9b) (0x0033fe10)
  7 0x0042dd1b in setup (+0x2dd1a) (0x0033fe30)
  8 0x7b86ea34 call_process_entry+0xb() in kernel32 (0x0033fe48)

Wine-dbg>p *utcft 
{dwLowDateTime=0x72e18180, dwHighDateTime=0x2364856}

Wine-dbg>n
880        if (!(status = RtlSystemTimeToLocalTime( &utc, &local )))
...
Wine-dbg>p local
{u={LowPart=0xd4a5e980, HighPart=0x236485e}, ={LowPart=0xd4a5e980,
HighPart=0x236485e}, QuadPart=0x236485ed4a5e980}

Wine-dbg>bt
Backtrace:
=>0 0x7b88a200 FileTimeToDosDateTime(ft=0x33fccc, fatdate="", fattime="8")
[/home/focht/projects/wine/wine.repo/src/dlls/kernel32/time.c:1064] in kernel32
(0x0033fcd8)
  1 0x00413a21 in setup (+0x13a20) (0x0033fcf0)
  2 0x00413a59 in setup (+0x13a58) (0x0033fd04)
  3 0x0042c40d in setup (+0x2c40c) (0x0033fd30)
  4 0x0042c4de in setup (+0x2c4dd) (0x0033fd64)
  5 0x0042cc88 in setup (+0x2cc87) (0x0033fdd4)
  6 0x0042da9c in setup (+0x2da9b) (0x0033fe10)
  7 0x0042dd1b in setup (+0x2dd1a) (0x0033fe30)
  8 0x7b86ea34 call_process_entry+0xb() in kernel32 (0x0033fe48)

Wine-dbg>p *ft
{dwLowDateTime=0xd4a5e980, dwHighDateTime=0x236485e}

Wine-dbg>n
1075        li.u.LowPart = ft->dwLowDateTime;
Wine-dbg>n
1076        li.u.HighPart = ft->dwHighDateTime;
Wine-dbg>n
1077        if (!RtlTimeToSecondsSince1970( &li, &t ))
Wine-dbg>n

...
Wine-dbg>si
0x7bca9161 RtlTimeToSecondsSince1970+0x28
[/home/focht/projects/wine/wine.repo/src/dlls/ntdll/time.c:353] in ntdll: call 
  0x7bcb52a0 __divdi3 in ntdll
353        ULONGLONG tmp = Time->QuadPart / TICKSPERSEC - SECS_1601_TO_1970;

Wine-dbg>info reg
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:7bca9161 ESP:0033fb00 EBP:0033fb28 EFLAGS:00000206(   - --  I   - -P- )
 EAX:d4a5e980 EBX:0033fb7c ECX:0033fb7c EDX:0236485e
 ESI:0033fd54 EDI:f750d000

Wine-dbg>x/4x $esp
0x0033fb00:  d4a5e980 0236485e 00989680 00000000

; 0236485e|d4a5e980 = Time->QuadPart
; 00000000|00989680 = TICKSPERSEC = 10000000

; awk 'BEGIN { printf "%x\n", 0x236485ED4A5E980/0x989680 }'
; 3b61090ff

Wine-dbg>ni
0x7bca9166 RtlTimeToSecondsSince1970+0x2d
[/home/focht/projects/wine/wine.repo/src/dlls/ntdll/time.c:353] in ntdll: addl 
  $1240428288,%eax
353        ULONGLONG tmp = Time->QuadPart / TICKSPERSEC - SECS_1601_TO_1970;

Wine-dbg>info reg
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:7bca9166 ESP:0033fb00 EBP:0033fb28 EFLAGS:00000202(   - --  I   - - - )
 EAX:b61090ff EBX:0033fb7c ECX:00000000 EDX:00000003
 ESI:0033fd54 EDI:f750d000

$ p SECS_1601_TO_1970
0x2b6109100

Wine-dbg>ni

0x7bca916b RtlTimeToSecondsSince1970+0x32
[/home/focht/projects/wine/wine.repo/src/dlls/ntdll/time.c:353] in ntdll: adcl 
  $-3,%edx
353        ULONGLONG tmp = Time->QuadPart / TICKSPERSEC - SECS_1601_TO_1970;
...

Wine-dbg>info reg
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:7bca916e ESP:0033fb00 EBP:0033fb28 EFLAGS:00000257(   - --  I  Z-A-P-C)
 EAX:ffffffff EBX:0033fb7c ECX:00000000 EDX:00000000
 ESI:0033fd54 EDI:f750d000

; awk 'BEGIN { printf "%x\n", 0x3b61090ff-0x2b6109100 }'
; ffffffff

...
1082        unixtime = t;

Wine-dbg>p li
{u={LowPart=0xd4a5e980, HighPart=0x236485e}, ={LowPart=0xd4a5e980,
HighPart=0x236485e}, QuadPart=0x236485ed4a5e980}

Wine-dbg>p t
0xffffffff
Wine-dbg>n  
1083        tm = gmtime( &unixtime );
Wine-dbg>p unixtime
0xffffffff

--- snip ---

Malice or stupidity using that hard-coded date which triggers y2038 problem...
who knows.

$ sha1sum setup.exe 
5e3e780718019f5b859226b4dfb2de274625afd9  setup.exe

$ du -sh setup.exe 
876K    setup.exe

$ wine --version
wine-1.8-rc1

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