[Bug 13516] Dynamic HTML Editor 4.2 Demo installs, crashes on startup

wine-bugs at winehq.org wine-bugs at winehq.org
Thu May 27 10:48:41 CDT 2010


http://bugs.winehq.org/show_bug.cgi?id=13516


Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net




--- Comment #10 from Anastasius Focht <focht at gmx.net>  2010-05-27 10:48:39 ---
Hello,

whenever I encounter vb6 apps I despise Microsoft ... I was tortured years ago,
forced to audit/review/reverse various vb apps :-|

That VB6 app in question is protected with tElock 0.981b.
After getting rid of this minor nuisance chances got better analysing/debugging
vb junk code ;-)

The bug in Wine is actually unearthed by some kind of unicode subclass
wrapper/framework for VB6 forms.
Basically junk^H^H^H^Hthunk code gets written and patched in dynamic memory at
runtime to provide subclassing/hooking facility. 

I provide an annotated app code snippet to illustrate the idea how thunks get
written and to understand the Wine traces:

--- snip ---
...
mov edx, 004CB67Ch ; thunk opcode snippet string
"5589E583C4F85731C08945FC8945F8EB0EE8xxxxx01x83F802742185C07424E830000000837DF800750AE838000000E84D0000005F8B45FCC9C21000E826000000EBF168xxxxx02x6AFCFF7508E8xxxxx03xEBE031D24ABFxxxxx04xB9xxxxx05xE82D000000C3FF7514FF7510FF750CFF750868xxxxx06xE8xxxxx07x8945FCC331D2BFxxxxx08xB9xxxxx09xE801000000C3E32F09C978078B450CF2AF75248D4514508D4510508D450C508D4508508D45FC508D45F85052B8xxxxx0Ax508B00FF501CC3"
; "xxxx" will be patched later (jmp/call destinations)
...
call MSVBVM60.DLL.__vbaStrCopy
...
call [004010C4h] ; Len(arg)
mov edi, MSVBVM60.DLL.__vbaStrMove
...
opcode_bstr_loop:

cmp ebx, var_1C ; all opcodes copied?
jnle opcode_bstr_loop_end
...
push 004ADF0Ch ; "&H"
push ecx
push ebx
push edx
call [00401210h] ; Mid$(arg1, arg2, arg3)
mov edx, eax
lea ecx, var_28
call edi
push eax
call [00401118h] ; operator "&"
...
push eax
call [0040150Ch] ; Val(arg)
call MSVBVM60.DLL.__vbaFpUI1
push eax
call MSVBVM60.DLL.rtcBstrFromByte
...
call [00401118h] ; operator "&"
...
jmp opcode_bstr_loop

opcode_bstr_loop_end:
...
push eax
call [00401138h] ; LenB(arg)
mov edi, eax
push 00000040h
push 00003000h
push edi         ; length of opcode snippet (thunk) in bytes
push 00000000h
mov [esi+50h], edi
VirtualAlloc(%x1, %x2, %x3, %x4)
mov var_58, eax
call MSVBVM60.DLL.__vbaSetSystemError
...
call [00401398h] ; VarPtr(arg)
push edi
mov edi, CopyMemory(%x1, %x2, %x3)
mov var_58, eax
push eax
mov eax, [esi+48h]
push eax
call edi ; copy BSTR thunk code snippet to final location
...
--- snip ---

With that annotated code snippet in mind we can now make a meaning of
corresponding Wine traces:

0xC3 (ret) is the last opcode (iteration) from that specific thunk snippet.

+tid,+seh,+relay,+ole,+variant

--- snip ---
0046:Call oleaut32.VarBstrCat(004adf0c L"&H",0016fcb4 L"C3",0032eb20)
ret=733867fd
...
0046:Call oleaut32.VarParseNumFromStr(0016f6ec
L"&HC3",00000409,80000000,0032eadc,0032eabc) ret=73373408 
...
0046:Call oleaut32.VariantChangeType(0032eb0c,0032eb0c,00000000,00000005)
ret=733734a9
0046:trace:variant:VariantChangeTypeEx
(0x32eb0c->(VT_I4),0x32eb0c->(VT_I4),0x00000400,0x0000,VT_R8) 
...
0046:Call oleaut32.SysAllocStringByteLen(0032eb24,00000001) ret=73380bf5
0046:Call ntdll.RtlAllocateHeap(00110000,00000000,00000007) ret=68b29e68
0046:Ret  ntdll.RtlAllocateHeap() retval=0016f6e8 ret=68b29e68
0046:Ret  oleaut32.SysAllocStringByteLen() retval=0016f6ec ret=73380bf5
0046:Call oleaut32.VarBstrCat(0016fce4 L"",0016f6ec L"\00c3",0032eb24)
ret=733867fd
0046:trace:variant:VarBstrCat L"",L"",0x32eb24
0046:Call ntdll.RtlAllocateHeap(00110000,00000000,00000006) ret=68b29f0b
0046:Ret  ntdll.RtlAllocateHeap() retval=0016f700 ret=68b29f0b
0046:trace:variant:VarBstrCat L""
0046:Ret  oleaut32.VarBstrCat() retval=00000000 ret=733867fd
0046:Call oleaut32.SysFreeString(0016fce4 L"") ret=733869b7 
...
--- snip ---

After the binary opcode snippet is stuffed into a BSTR it should get written
out to memory...
Unfortunately the thunk code allocator is called with zero length:

--- snip ---
0046:Call KERNEL32.VirtualAlloc(00000000,00000000,00003000,00000040)
ret=00aa1b04
0046:Ret  KERNEL32.VirtualAlloc() retval=00000000 ret=00aa1b04
0046:Call KERNEL32.GetLastError() ret=7336c0c7
0046:Ret  KERNEL32.GetLastError() retval=00000057 ret=7336c0c7
0046:Call KERNEL32.TlsGetValue(00000005) ret=7336c0d5
0046:Ret  KERNEL32.TlsGetValue() retval=0013d280 ret=7336c0d5
0046:Call ntdll.RtlMoveMemory(00000000,0016f704,00000000) ret=00aa1b2e
0046:Ret  ntdll.RtlMoveMemory() retval=00000000 ret=00aa1b2e 
--- snip ---

When the jmp/call destinations contained in that thunk are to be resolved, the
app crashes:

--- snip ---
...
0046:Call ntdll.RtlMoveMemory(0000004e,0032eb20,00000004) ret=00aa245a
0046:trace:seh:raise_exception code=c0000005 flags=0 addr=0x681f2043
ip=681f2043 tid=0046
0046:trace:seh:raise_exception  info[0]=00000001
0046:trace:seh:raise_exception  info[1]=0000004e
0046:trace:seh:raise_exception  eax=ffcd152e ebx=7bc98440 ecx=00000001
edx=0032eb1c esi=0032eb20 edi=0000004e
0046:trace:seh:raise_exception  ebp=0032ea68 esp=0032ea48 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010202 
--- snip ---

dest ptr = 0x4e is the offset from the thunks block base address (base should
be 0x02220000 in this example but due to previous failure it returned NULL).
Thunk code to be patched:

--- snip ---
02220000    55              PUSH EBP
...
02220043    68 00000002     PUSH 2000000 
02220048    6A FC           PUSH -4
0222004A    FF75 08         PUSH DWORD PTR SS:[EBP+8]
0222004D    E8 00000003     CALL 05220052
...
--- snip ---

The final BSTR containing the opcodes is actually empty, so the previous
concatenations failed.

The culprit in Wine seems to be a misunderstanding what BSTR really are and the
relation to WCHAR*.

This app (mis)uses BSTRs to not only store/move unicode strings but to also
move binary data around (like thunk opcodes).
That means the BSTR _can_ actually contain an odd number of bytes - simple
case: the opcode loop which converts each opcode byte to 1-byte BSTR and
concats them into a binary (byte) array -> BSTR.

Unfortunately Wine code like oleaut32's VarBstrCat() deals with BSTRs as they
were true UNICODE strings.

--- snip dlls/oleaut32/vartype.c ---

HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
{
  unsigned int lenLeft, lenRight;

  TRACE("%s,%s,%p\n",
   debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
   debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);

  if (!pbstrOut)
    return E_INVALIDARG;

  lenLeft = pbstrLeft ? SysStringLen(pbstrLeft) : 0;
  lenRight = pbstrRight ? SysStringLen(pbstrRight) : 0;

  *pbstrOut = SysAllocStringLen(NULL, lenLeft + lenRight);
  if (!*pbstrOut)
    return E_OUTOFMEMORY;

  (*pbstrOut)[0] = '\0';

  if (pbstrLeft)
    memcpy(*pbstrOut, pbstrLeft, lenLeft * sizeof(WCHAR));

  if (pbstrRight)
    memcpy(*pbstrOut + lenLeft, pbstrRight, lenRight * sizeof(WCHAR));

  TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
  return S_OK;
} 

--- snip dlls/oleaut32/vartype.c ---

That means incorrect behaviour if for example "ansi" BSTRs with odd length are
passed (SysStringLen() determines the length in wide-characters).

Make sure the test suite contains such cases and passes to not break other
stuff ;-)

Regards

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
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