http://bugs.winehq.org/show_bug.cgi?id=28089
Summary: exception handling code touches stack for exceptions handled by the debugger Product: Wine Version: unspecified Platform: x86 OS/Version: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: ntdll AssignedTo: wine-bugs@winehq.org ReportedBy: bernhardloos@googlemail.com
Created an attachment (id=35971) --> (http://bugs.winehq.org/attachment.cgi?id=35971) a hack to work around the problem
Wine places the CONTEXT and EXCEPTION_RECORD structures onto the stack past ESP during the unix signal handler and continues with most of the exception handling code outside of the signal handler. Unfortunately and contrary to windows behavior the debugger gets notified only after this happens. Windows doesn't touch the stack at all, if the exception is handled by the debugger. This makes it very hard to single step trough code which keeps useful data past ESP (securom 8 for example).
it's easy to show with this small test:
void foo() { char *x = 0, *y = 0, *from = 0, *to = 0; char c;
x = &c; y = &c - 500;
while (y != x) *y++ = 0x55;
c = 0x77; /* single step a few times here */ y = &c - 500;
while (y != x) { if (*y != 0x55) if (from) to = y; else from = y; y++; } /* to and from shoudl be NULL */ }
http://bugs.winehq.org/show_bug.cgi?id=28089
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |obfuscation, patch CC| |austinenglish@gmail.com Version|unspecified |1.3.26
http://bugs.winehq.org/show_bug.cgi?id=28089
Pavel Zelinka eimia.company@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |eimia.company@gmail.com
--- Comment #1 from Pavel Zelinka eimia.company@gmail.com 2011-12-04 06:08:06 CST --- itunes nefunguje video
http://bugs.winehq.org/show_bug.cgi?id=28089
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW CC| |focht@gmx.net Ever Confirmed|0 |1
--- Comment #2 from Anastasius Focht focht@gmx.net 2012-03-10 16:49:08 CST --- Hello,
besides bug 25853 (Dead Space 2, SecuROM 8) another example is bug 26541 (Dragon Saga). That game makes excessive use of asm continuations that break when being single stepped under debugger. Wine's exception handling code taints the stack, overwriting continuation EIP in this case.
--- snip --- ... 0158D4B1 68 058A8000 PUSH 00808A05 0158D4B6 8D6424 04 LEA ESP,[ESP+4] 0158D4BA FF6424 FC JMP DWORD PTR SS:[ESP-4] ... --- snip ---
$ wine --version wine-1.4-78-g94953f1
Regards
http://bugs.winehq.org/show_bug.cgi?id=28089
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |download URL| |http://www.ausgamers.com/fi | |les/download/57867/dragonsa | |ga-client-v012920110216
--- Comment #3 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting, still present.
Adding download from bug 26541 as 'real world' example which contains code that breaks when being single stepped (see my comment #2)
$ wine --version wine-1.7.8-248-g8dd9c61
Regards
https://bugs.winehq.org/show_bug.cgi?id=28089
--- Comment #4 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting, still present.
Found another example, making excessive use of this pattern: Gothic II (lots of obfuscated code)
Download: http://www.fileplanet.com/151400/150000/fileinfo/Gothic-II-Demo-
--- snip --- ... 2BC4036C 8B85 52AC5000 MOV EAX,DWORD PTR SS:[EBP+Gothic2.50AC52] 2BC40372 8BA5 62AC5000 MOV ESP,DWORD PTR SS:[EBP+Gothic2.50AC62] 2BC40378 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX 2BC4037C 64:67:8F06 0000 POP DWORD PTR FS:[SMALL 0] 2BC40382 83C4 04 ADD ESP,4 2BC40385 61 POPAD 2BC40386 83C4 08 ADD ESP,8 2BC40389 FF6424 F8 JMP DWORD PTR SS:[ESP-8] ... --- snip ---
$ sha1sum gothic2-demo-setup.exe 3f1ff6d9b1d1ccdd5032caf349e7c0d79c6a9d24 gothic2-demo-setup.exe
$ du -sh gothic2-demo-setup.exe 381M gothic2-demo-setup.exe
$ wine --version wine-1.7.35-108-g512db44
Regards
https://bugs.winehq.org/show_bug.cgi?id=28089
Sebastian Lackner sebastian@fds-team.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |sebastian@fds-team.de
--- Comment #5 from Sebastian Lackner sebastian@fds-team.de --- (In reply to Anastasius Focht from comment #4)
Hello folks,
revisiting, still present.
Found another example, making excessive use of this pattern: Gothic II (lots of obfuscated code)
Download: http://www.fileplanet.com/151400/150000/fileinfo/Gothic-II-Demo-
--- snip --- ... 2BC4036C 8B85 52AC5000 MOV EAX,DWORD PTR SS:[EBP+Gothic2.50AC52] 2BC40372 8BA5 62AC5000 MOV ESP,DWORD PTR SS:[EBP+Gothic2.50AC62] 2BC40378 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX 2BC4037C 64:67:8F06 0000 POP DWORD PTR FS:[SMALL 0] 2BC40382 83C4 04 ADD ESP,4 2BC40385 61 POPAD 2BC40386 83C4 08 ADD ESP,8 2BC40389 FF6424 F8 JMP DWORD PTR SS:[ESP-8] ... --- snip ---
$ sha1sum gothic2-demo-setup.exe 3f1ff6d9b1d1ccdd5032caf349e7c0d79c6a9d24 gothic2-demo-setup.exe
$ du -sh gothic2-demo-setup.exe 381M gothic2-demo-setup.exe
$ wine --version wine-1.7.35-108-g512db44
Regards
Since this issue is basically a conceptual design flaw in Wine it is a bit difficult to fix everywhere. As a temporary solution I was thinking about adding a red zone of 128 byte below esp, similar to x86_64 calling convertions. Do you think this would have any disadvantages? I think it should be sufficient for most apps out there.
https://bugs.winehq.org/show_bug.cgi?id=28089
--- Comment #6 from Anastasius Focht focht@gmx.net --- Hello Sebastian,
--- quote --- As a temporary solution I was thinking about adding a red zone of 128 byte below esp, similar to x86_64 calling conventions. Do you think this would have any disadvantages? I think it should be sufficient for most apps out there. --- quote ---
I'm fine with that.
Bernhard isn't active anymore but I've used his hack a few times in the past. Feel free to add a patch to Wine-Staging (maybe it's possible to get this to upstream, too). I'll test it.
"128 bytes ought to be enough anybody." -- slackner.
Regards
https://bugs.winehq.org/show_bug.cgi?id=28089
--- Comment #7 from Sebastian Lackner sebastian@fds-team.de --- Hm, the idea was good, but it unfortunately doesn't work in practice. The function to restore registers on x86 uses IRET, which means that 12 bytes are always destroyed (eflags / eip / cs). I guess we have to use ptrace, or alternatively really do a rewrite of the whole exception handling logic. :/
https://bugs.winehq.org/show_bug.cgi?id=28089
--- Comment #8 from Anastasius Focht focht@gmx.net --- Hello folks,
revisiting, still present. Encountered while investigating bug 45249
Copy/pasta from my comment https://bugs.winehq.org/show_bug.cgi?id=45249#c5
---
Another debugging tidbit: the app protection stores state data past the current ESP which makes single stepping painful. You have to recognize those sequences and *not* single step nearby -> bug 28089 ("exception handling code touches stack for exceptions handled by the debugger")
Examples:
--- snip --- 0051D033 F0:DB2B LOCK FLD TBYTE PTR DS:[EBX] 0051D036 83EC 04 SUB ESP,4 0051D039 890424 MOV DWORD PTR SS:[ESP],EAX 0051D03C C1F8 00 SAR EAX,0 0051D03F 897424 FC MOV DWORD PTR SS:[ESP-4],ESI ; taint if single stepped 0051D043 83EC 04 SUB ESP,4 0051D046 83EC 04 SUB ESP,4 0051D049 890C24 MOV DWORD PTR SS:[ESP],ECX 0051D04C 894424 FC MOV DWORD PTR SS:[ESP-4],EAX ; taint if single stepped 0051D050 83EC 04 SUB ESP,4 0051D053 60 PUSHAD --- snip ---
--- snip --- 00B1D0F3 5F POP EDI 00B1D0F4 894424 FC MOV DWORD PTR SS:[ESP-4],EAX ; taint if single stepped 00B1D0F8 F3:EB 02 REP JMP SHORT 00B1D0FD 00B1D0FB D15CE9 B1 RCR DWORD PTR DS:[EBP*8+ECX-4F],1 00B1D0FF E4 FF IN AL,0FF 00B1D101 FFC3 INC EBX 00B1D103 E9 02000000 JMP 00B1D10A --- snip ---
$ wine --version wine-3.12-111-g8ae98cfdc3
Regards
https://bugs.winehq.org/show_bug.cgi?id=28089
joaopa jeremielapuree@yahoo.fr changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |jeremielapuree@yahoo.fr
--- Comment #9 from joaopa jeremielapuree@yahoo.fr --- Created attachment 68026 --> https://bugs.winehq.org/attachment.cgi?id=68026 compiled test
Does the bug still occur with wine-5.15? I compiled the test but I do not know what it should do.
https://bugs.winehq.org/show_bug.cgi?id=28089
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |RESOLVED Fixed by SHA1| |3889c374a11d92733f6830473ff | |589f8846a7396 Keywords| |testcase Resolution|--- |FIXED
--- Comment #10 from Anastasius Focht focht@gmx.net --- Hello folks,
this was fixed by commits:
* https://source.winehq.org/git/wine.git/commitdiff/485c8566f103f05dba3c8c31d3... ("ntdll: Build the exception record on the signal stack first.")
* https://source.winehq.org/git/wine.git/commitdiff/3889c374a11d92733f6830473f... ("ntdll: Send debug event before pushing exception data on x86.")
Part of Wine 5.13 release.
Thanks Alexandre.
Disassembly of 'foo' from pre-built testcase (comment #9):
--- snip --- 00401530 PUSH EBP 00401531 MOV EBP,ESP 00401533 AND ESP,FFFFFFF0 00401536 SUB ESP,30 00401539 CALL 004016A0 0040153E MOV DWORD PTR SS:[LOCAL.4],0 00401546 MOV DWORD PTR SS:[LOCAL.1],0 0040154E MOV DWORD PTR SS:[LOCAL.2],0 00401556 MOV DWORD PTR SS:[LOCAL.3],0 0040155E LEA EAX,[LOCAL.5+3] 00401562 MOV DWORD PTR SS:[LOCAL.4],EAX 00401566 LEA EAX,[LOCAL.5+3] 0040156A SUB EAX,1F4 0040156F MOV DWORD PTR SS:[LOCAL.1],EAX 00401573 JMP SHORT 00401583 00401575 MOV EAX,DWORD PTR SS:[LOCAL.1] 00401579 LEA EDX,[EAX+1] 0040157C MOV DWORD PTR SS:[LOCAL.1],EDX 00401580 MOV BYTE PTR DS:[EAX],55 00401583 MOV EAX,DWORD PTR SS:[LOCAL.1] 00401587 CMP EAX,DWORD PTR SS:[LOCAL.4] 0040158B JNE SHORT 00401575 0040158D MOV BYTE PTR SS:[LOCAL.5+3],77 ; bpx here (= cause debugger event) 00401592 LEA EAX,[LOCAL.5+3] 00401596 SUB EAX,1F4 0040159B MOV DWORD PTR SS:[LOCAL.1],EAX 0040159F JMP SHORT 004015CA 004015A1 MOV EAX,DWORD PTR SS:[LOCAL.1] 004015A5 MOVZX EAX,BYTE PTR DS:[EAX] 004015A8 CMP AL,55 004015AA JE SHORT 004015C5 004015AC CMP DWORD PTR SS:[LOCAL.2],0 004015B1 JE SHORT 004015BD 004015B3 MOV EAX,DWORD PTR SS:[LOCAL.1] 004015B7 MOV DWORD PTR SS:[LOCAL.3],EAX 004015BB JMP SHORT 004015C5 004015BD MOV EAX,DWORD PTR SS:[LOCAL.1] 004015C1 MOV DWORD PTR SS:[LOCAL.2],EAX 004015C5 ADD DWORD PTR SS:[LOCAL.1],1 004015CA MOV EAX,DWORD PTR SS:[LOCAL.1] 004015CE CMP EAX,DWORD PTR SS:[LOCAL.4] 004015D2 JNE SHORT 004015A1 004015D4 MOV EAX,DWORD PTR SS:[LOCAL.2] 004015D8 MOV DWORD PTR SS:[LOCAL.10],EAX 004015DC MOV EAX,DWORD PTR SS:[LOCAL.3] 004015E0 MOV DWORD PTR SS:[LOCAL.11],EAX 004015E4 MOV DWORD PTR SS:[LOCAL.12],OFFSET 00404000 ; ASCII "to = %p, ..." 004015EB CALL <JMP.&msvcrt.printf> 004015F0 MOV EAX,0 004015F5 LEAVE 004015F6 RETN -- snip ---
To test this in automated way here is my one-liner which uses winedbg in gdb proxy mode:
Old behaviour:
--- snip --- $ wine --version wine-5.12-260-g485c8566f10
$ WINEDEBUG=+console winedbg --gdb test.exe -q <<< "b *0x0040158D"$'\n'cont$'\n' 2>&1 | grep "to =" 017c:trace:console:WriteConsoleW 0x27 L"to = 0064FDF7, from = 0064FC2B\r\n" 32 0x64fa1c (nil) --- snip ---
Fixed:
--- snip --- $ wine-5.12-264-g3889c374a11
$ WINEDEBUG=+console winedbg --gdb test.exe -q <<< "b *0x0040158D"$'\n'cont$'\n' 2>&1 | grep "to =" 017c:trace:console:WriteConsoleW 0x27 L"to = 00000000, from = 00000000\r\n" 32 0x64fa1c (nil) --- snip ---
The breakpoint triggers an exception event at the right place.
The app is a console app hence +console debug channel is used to capture and filter the output.
Regards
https://bugs.winehq.org/show_bug.cgi?id=28089
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #11 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 6.0-rc1.
https://bugs.winehq.org/show_bug.cgi?id=28089
--- Comment #12 from Anastasius Focht focht@gmx.net --- Hello folks,
adding stable download links from Internet Archive for documentation:
Dragon Saga Client1.0:
https://web.archive.org/web/20201129153406/https://dl.rocketfiles.com/downlo...
$ sha1sum DragonSagaInstaller-0.1.29-20110216.msi 196069ac69dcbefe6940c515b9bdab257885e684 DragonSagaInstaller-0.1.29-20110216.msi
$ du -sh DragonSagaInstaller-0.1.29-20110216.msi 1.9G DragonSagaInstaller-0.1.29-20110216.msi
---
Gothic II demo:
https://web.archive.org/web/20201204220749/http://download.fileplanet.com/ft...
$ sha1sum gothic2-demo-setup.exe 3f1ff6d9b1d1ccdd5032caf349e7c0d79c6a9d24 gothic2-demo-setup.exe
Regards