Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2004
- 131 participants
- 823 messages
Re: WINEDLLOVERRIDES for all dlls?
by James Hawkins
On Wed, 29 Sep 2004 09:28:46 -0400, James Hawkins <truiken(a)gmail.com> wrote:
> > Yes I know that isn't what I said before. I suck :)
>
> It's ok don't worry about it... thanks for the tip Mike.
>
>
>
>
> On Wed, 29 Sep 2004 09:37:49 +0100, Mike Hearn
> <m.hearn(a)signal.qinetiq.com> wrote:
> > > I used WINEDLLOVERRIDES="advapi32=b" WINEDEBUG=+loaddll, and it still
> > > shows the downloaded native advapi32.dll being loaded.
> >
> > You need WINEDLLOVERRIDES="*advapi32=b"
> >
> > Yes I know that isn't what I said before. I suck :)
> >
>
>
> --
> James Hawkins
>
I used WINEDLLOVERRIDES="*advapi32=b" and the installer got a little
further. Not perfect, but better.
Back when I used no dll overrides (because I thought advapi32=b would
work for all instances of an advapi32.dll) I got this error:
err:vxd:VMM_VxDCall Using the native Win95 advapi32.dll is no longer supported.
err:vxd:VMM_VxDCall Please configure advapi32 to builtin.
If we don't want any user using a native advapi32.dll no matter what
the circumstances, shouldn't the default override for advapi32 be
*advapi32=b (no matter whether it's in a config file or the registry
or whatever)? If the user is not using a config file, where are the
default overrides stored btw?
--
James Hawkins
Sept. 29, 2004
Re: ez-cdda sleep
by James Hawkins
On Wed, 29 Sep 2004 12:38:32 -0400, James Hawkins <truiken(a)gmail.com> wrote:
> > Let's engage on a little log analysis shall we? This is something that
> > just comes with practice ...
>
> Wow...very impressive.
>
> > Here's an idea. Hack the Sleep() call like this:
> >
> > if (delay == 64) delay = 3000;
>
> ok I will try this out and get back to you on what happens.
>
>
>
>
> On Wed, 29 Sep 2004 16:51:23 +0100, Mike Hearn
> <m.hearn(a)signal.qinetiq.com> wrote:
> > I think Marcus is right, this looks like copy protection.
> >
> > Let's engage on a little log analysis shall we? This is something that
> > just comes with practice ...
> >
> > Just after the program starts, it does a CreateProcess:
> >
> > > 0023:Call kernel32.CreateProcessA(406cd2f0 "C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe",403810d8 "ezcddax.exe",00000000,00000000,00000001,00000004,00000000,00000000,406cd2ac,406cd61c) ret=00750ec9
> >
> > ezcddax is the real program and what you launched is just a stub.
> >
> > Note the 6th parameter: it's 4, which is CREATE_SUSPENDED. So, the new
> > process isn't supposed to start.
> >
> > [ snip lots of traces from CreateProcess ]
> >
> > > 0023:Ret kernel32.CreateProcessA() retval=00000001 ret=00750ec9
> >
> > Here we are at the end.
> >
> > > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750fdb
> > > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750fdb
> > > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750ffe
> > > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750ffe
> > > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00751012
> > > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00751012
> >
> > Interesting. GetModuleHandle(NULL) returns the HMODULE of the current
> > process. An HMODULE is simply a pointer to the base of the file which is
> > mapped in: in the case of an EXE it'll be the headers.
> >
> > So, it looks like this program is walking its own headers in memory -
> > probably inspecting them for signs of tampering. More and more likely
> > that this is copy protection.
> >
> > > 0023:Call kernel32.ReadProcessMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=007556bd
> >
> > It then reads the memory of the newly created process, 2 bytes from
> > 0x761060. I wonder what is at that address?
> >
> > Grep the log for it and bingo!
> >
> > > 0025:Starting process L"C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe" (entryproc=0x761060)
> >
> > So it's reading the first two bytes of the entry point. Checking for a
> > breakpoint perhaps?
> >
> > > 0023:Call ntdll.NtReadVirtualMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=404fab7a
> > > 0023:Ret ntdll.NtReadVirtualMemory() retval=00000000 ret=404fab7a
> > > 0023:Ret kernel32.ReadProcessMemory() retval=00000001 ret=007556bd
> > > 0023:Call kernel32.WriteProcessMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=00755723
> >
> > Then it writes back 2 bytes to the same address. Maybe this is the bit
> > that lets ezcddax know it was started by the launcher program and not
> > directly by the user. I suspect if you suppress this WPM call, the
> > program will pop up an error asking you to run the launcher app
> > directly. It's probably writing a jump opcode.
> >
> > > 0023:Call ntdll.NtWriteVirtualMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=404fabea
> > > 0023:Ret ntdll.NtWriteVirtualMemory() retval=00000000 ret=404fabea
> > > 0023:Ret kernel32.WriteProcessMemory() retval=00000001 ret=00755723
> > > 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
> >
> > Now it goes into a loop, attempting to get the exit code of the process.
> >
> > > 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> > > 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> > > 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
> >
> > It's trying to find out what the exit code of the process was.
> > Unfortunately, we don't know what the answer is because the return code
> > is a success/failure bool, not the actual exit code. You'd have to whack
> > an ERR in here or something to find out.
> >
> > > 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> > > 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> > > 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> > > 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> > > 0023:Call kernel32.Sleep(00000064) ret=007557cd
> >
> > Then it tries to wake it up (remember, the remote process was started
> > suspended) and sleeps for a moment.
> >
> > > 0023:Call ntdll.NtDelayExecution(00000000,406cb888) ret=40507cff
> > > trace:relay:RELAY_InitDebugLists RelayExclude = L"RtlEnterCriticalSection;RtlLeaveCriticalSection;_EnterSysLevel;_LeaveSysLevel;LOCAL_Lock;LOCAL_Unlock;TlsGetValue;kernel32.GetLastError;kernel32.SetLastError"
> > > 0025:Call PE DLL (proc=0x401d3bb4,module=0x401c0000 L"ntdll.dll",reason=PROCESS_ATTACH,res=0x1)
> >
> > At this point the kernel does a context switch into the new process, and
> > it begins initializing. Note that CREATE_SUSPENDED doesn't mean nothing
> > runs in the new process. It still gets the ATTACH notifications (at
> > least, it does in Wine ... maybe not in real windows). So there's a lot
> > of stuff we can ignore here generated by the startup sequence.
> >
> > Let's find out what the first process is doing:
> >
> > > 0025:Ret ntdll.RtlAllocateHeap() retval=40393550 ret=4083acae
> > > 0023:Ret ntdll.NtDelayExecution() retval=00000000 ret=40507cff
> > > 0023:Ret kernel32.Sleep() retval=00000000 ret=007557cd
> > > 0023:Call kernel32.SuspendThread(0000005c) ret=007557da
> > > 0023:Call ntdll.NtSuspendThread(0000005c,406cb8a0) ret=4050e80e
> > > 0023:Ret ntdll.NtSuspendThread() retval=00000000 ret=4050e80e
> > > 0023:Ret kernel32.SuspendThread() retval=00000000 ret=007557da
> > > 0023:Call kernel32.GetThreadContext(0000005c,406cb948) ret=0075580e
> > > 0023:Call ntdll.NtGetContextThread(0000005c,406cb948) ret=4050e7ae
> > > 0023:Ret ntdll.NtGetContextThread() retval=00000000 ret=4050e7ae
> > > 0023:Ret kernel32.GetThreadContext() retval=00000001 ret=0075580e
> >
> > Context switch after the first line, and it awakens from its sleep.
> >
> > It then suspends the thread, and grabs its context. Why does it suspend?
> > Reading MSDN reveals that the target thread has to be suspended for
> > GetThreadContext to work. The CONTEXT structure holds the register state
> > of the thread. I wonder what it's looking for in this structure?
> >
> > > 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
> > > 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> > > 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> > > 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
> > > 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> > > 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> > > 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> > > 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> > > 0023:Call kernel32.Sleep(00000064) ret=007557cd
> >
> > OK, and we go back into a loop. In fact, this is an infinite loop.
> >
> > Probably it looks like this:
> >
> > while (1)
> > {
> > int code;
> > CONTEXT86 context;
> >
> > GetExitCodeProcess(process, &code);
> >
> > if (code == ???) do something;
> >
> > ResumeThread(thread);
> >
> > Sleep(64);
> >
> > SuspendThread(thread);
> > GetThreadContext(thread, &context);
> >
> > // do something with context here
> > if (context.???) break ???
> > }
> >
> > So the question is, what condition will make it break out of the loop,
> > and why isn't it getting it in Wine?
> >
> > It looks like it's waiting for some condition to become true in the
> > remote process. This will never happen because ResumeThread here doesn't
> > seem to be waking it up! We just loop over and over, resuming it,
> > sleeping for a while, grabbing its context to check something which
> > never changes, and starting over.
> >
> > So, I guess the problem is that ResumeThread isn't actually waking up
> > the suspended process. Question is, why not?
> >
> > Here's an idea. Hack the Sleep() call like this:
> >
> > if (delay == 64) delay = 3000;
> >
> > Ie, rule out the possibility that the delay between resume and suspend
> > is so short Wine can't react in time. Then continue your investigation
> > from there.
> >
> > Good luck!
> >
> > thanks -mike
> >
>
>
> --
> James Hawkins
>
> > Ie, rule out the possibility that the delay between resume and suspend
> > is so short Wine can't react in time. Then continue your investigation
> > from there.
I modified Sleep to do an ERR("USING MODIFIED SLEEP!\n") and then
added the check for timeout==64, set it to 3000, but it still calls
sleep over and over again without any progress. I even took out the
check for timeout==64 and just timeout to 3000 for the second test,
but I get the same results.
--
James Hawkins
Sept. 29, 2004
Re: ez-cdda sleep
by James Hawkins
> Let's engage on a little log analysis shall we? This is something that
> just comes with practice ...
Wow...very impressive.
> Here's an idea. Hack the Sleep() call like this:
>
> if (delay == 64) delay = 3000;
ok I will try this out and get back to you on what happens.
On Wed, 29 Sep 2004 16:51:23 +0100, Mike Hearn
<m.hearn(a)signal.qinetiq.com> wrote:
> I think Marcus is right, this looks like copy protection.
>
> Let's engage on a little log analysis shall we? This is something that
> just comes with practice ...
>
> Just after the program starts, it does a CreateProcess:
>
> > 0023:Call kernel32.CreateProcessA(406cd2f0 "C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe",403810d8 "ezcddax.exe",00000000,00000000,00000001,00000004,00000000,00000000,406cd2ac,406cd61c) ret=00750ec9
>
> ezcddax is the real program and what you launched is just a stub.
>
> Note the 6th parameter: it's 4, which is CREATE_SUSPENDED. So, the new
> process isn't supposed to start.
>
> [ snip lots of traces from CreateProcess ]
>
> > 0023:Ret kernel32.CreateProcessA() retval=00000001 ret=00750ec9
>
> Here we are at the end.
>
> > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750fdb
> > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750fdb
> > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750ffe
> > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750ffe
> > 0023:Call kernel32.GetModuleHandleA(00000000) ret=00751012
> > 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00751012
>
> Interesting. GetModuleHandle(NULL) returns the HMODULE of the current
> process. An HMODULE is simply a pointer to the base of the file which is
> mapped in: in the case of an EXE it'll be the headers.
>
> So, it looks like this program is walking its own headers in memory -
> probably inspecting them for signs of tampering. More and more likely
> that this is copy protection.
>
> > 0023:Call kernel32.ReadProcessMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=007556bd
>
> It then reads the memory of the newly created process, 2 bytes from
> 0x761060. I wonder what is at that address?
>
> Grep the log for it and bingo!
>
> > 0025:Starting process L"C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe" (entryproc=0x761060)
>
> So it's reading the first two bytes of the entry point. Checking for a
> breakpoint perhaps?
>
> > 0023:Call ntdll.NtReadVirtualMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=404fab7a
> > 0023:Ret ntdll.NtReadVirtualMemory() retval=00000000 ret=404fab7a
> > 0023:Ret kernel32.ReadProcessMemory() retval=00000001 ret=007556bd
> > 0023:Call kernel32.WriteProcessMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=00755723
>
> Then it writes back 2 bytes to the same address. Maybe this is the bit
> that lets ezcddax know it was started by the launcher program and not
> directly by the user. I suspect if you suppress this WPM call, the
> program will pop up an error asking you to run the launcher app
> directly. It's probably writing a jump opcode.
>
> > 0023:Call ntdll.NtWriteVirtualMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=404fabea
> > 0023:Ret ntdll.NtWriteVirtualMemory() retval=00000000 ret=404fabea
> > 0023:Ret kernel32.WriteProcessMemory() retval=00000001 ret=00755723
> > 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
>
> Now it goes into a loop, attempting to get the exit code of the process.
>
> > 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> > 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> > 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
>
> It's trying to find out what the exit code of the process was.
> Unfortunately, we don't know what the answer is because the return code
> is a success/failure bool, not the actual exit code. You'd have to whack
> an ERR in here or something to find out.
>
> > 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> > 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> > 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> > 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> > 0023:Call kernel32.Sleep(00000064) ret=007557cd
>
> Then it tries to wake it up (remember, the remote process was started
> suspended) and sleeps for a moment.
>
> > 0023:Call ntdll.NtDelayExecution(00000000,406cb888) ret=40507cff
> > trace:relay:RELAY_InitDebugLists RelayExclude = L"RtlEnterCriticalSection;RtlLeaveCriticalSection;_EnterSysLevel;_LeaveSysLevel;LOCAL_Lock;LOCAL_Unlock;TlsGetValue;kernel32.GetLastError;kernel32.SetLastError"
> > 0025:Call PE DLL (proc=0x401d3bb4,module=0x401c0000 L"ntdll.dll",reason=PROCESS_ATTACH,res=0x1)
>
> At this point the kernel does a context switch into the new process, and
> it begins initializing. Note that CREATE_SUSPENDED doesn't mean nothing
> runs in the new process. It still gets the ATTACH notifications (at
> least, it does in Wine ... maybe not in real windows). So there's a lot
> of stuff we can ignore here generated by the startup sequence.
>
> Let's find out what the first process is doing:
>
> > 0025:Ret ntdll.RtlAllocateHeap() retval=40393550 ret=4083acae
> > 0023:Ret ntdll.NtDelayExecution() retval=00000000 ret=40507cff
> > 0023:Ret kernel32.Sleep() retval=00000000 ret=007557cd
> > 0023:Call kernel32.SuspendThread(0000005c) ret=007557da
> > 0023:Call ntdll.NtSuspendThread(0000005c,406cb8a0) ret=4050e80e
> > 0023:Ret ntdll.NtSuspendThread() retval=00000000 ret=4050e80e
> > 0023:Ret kernel32.SuspendThread() retval=00000000 ret=007557da
> > 0023:Call kernel32.GetThreadContext(0000005c,406cb948) ret=0075580e
> > 0023:Call ntdll.NtGetContextThread(0000005c,406cb948) ret=4050e7ae
> > 0023:Ret ntdll.NtGetContextThread() retval=00000000 ret=4050e7ae
> > 0023:Ret kernel32.GetThreadContext() retval=00000001 ret=0075580e
>
> Context switch after the first line, and it awakens from its sleep.
>
> It then suspends the thread, and grabs its context. Why does it suspend?
> Reading MSDN reveals that the target thread has to be suspended for
> GetThreadContext to work. The CONTEXT structure holds the register state
> of the thread. I wonder what it's looking for in this structure?
>
> > 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
> > 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> > 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> > 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
> > 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> > 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> > 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> > 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> > 0023:Call kernel32.Sleep(00000064) ret=007557cd
>
> OK, and we go back into a loop. In fact, this is an infinite loop.
>
> Probably it looks like this:
>
> while (1)
> {
> int code;
> CONTEXT86 context;
>
> GetExitCodeProcess(process, &code);
>
> if (code == ???) do something;
>
> ResumeThread(thread);
>
> Sleep(64);
>
> SuspendThread(thread);
> GetThreadContext(thread, &context);
>
> // do something with context here
> if (context.???) break ???
> }
>
> So the question is, what condition will make it break out of the loop,
> and why isn't it getting it in Wine?
>
> It looks like it's waiting for some condition to become true in the
> remote process. This will never happen because ResumeThread here doesn't
> seem to be waking it up! We just loop over and over, resuming it,
> sleeping for a while, grabbing its context to check something which
> never changes, and starting over.
>
> So, I guess the problem is that ResumeThread isn't actually waking up
> the suspended process. Question is, why not?
>
> Here's an idea. Hack the Sleep() call like this:
>
> if (delay == 64) delay = 3000;
>
> Ie, rule out the possibility that the delay between resume and suspend
> is so short Wine can't react in time. Then continue your investigation
> from there.
>
> Good luck!
>
> thanks -mike
>
--
James Hawkins
Sept. 29, 2004
Re: ez-cdda sleep
by Mike Hearn
I think Marcus is right, this looks like copy protection.
Let's engage on a little log analysis shall we? This is something that
just comes with practice ...
Just after the program starts, it does a CreateProcess:
> 0023:Call kernel32.CreateProcessA(406cd2f0 "C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe",403810d8 "ezcddax.exe",00000000,00000000,00000001,00000004,00000000,00000000,406cd2ac,406cd61c) ret=00750ec9
ezcddax is the real program and what you launched is just a stub.
Note the 6th parameter: it's 4, which is CREATE_SUSPENDED. So, the new
process isn't supposed to start.
[ snip lots of traces from CreateProcess ]
> 0023:Ret kernel32.CreateProcessA() retval=00000001 ret=00750ec9
Here we are at the end.
> 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750fdb
> 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750fdb
> 0023:Call kernel32.GetModuleHandleA(00000000) ret=00750ffe
> 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00750ffe
> 0023:Call kernel32.GetModuleHandleA(00000000) ret=00751012
> 0023:Ret kernel32.GetModuleHandleA() retval=00400000 ret=00751012
Interesting. GetModuleHandle(NULL) returns the HMODULE of the current
process. An HMODULE is simply a pointer to the base of the file which is
mapped in: in the case of an EXE it'll be the headers.
So, it looks like this program is walking its own headers in memory -
probably inspecting them for signs of tampering. More and more likely
that this is copy protection.
> 0023:Call kernel32.ReadProcessMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=007556bd
It then reads the memory of the newly created process, 2 bytes from
0x761060. I wonder what is at that address?
Grep the log for it and bingo!
> 0025:Starting process L"C:\\Program Files\\Easy CD-DA Extractor 7\\ezcddax.exe" (entryproc=0x761060)
So it's reading the first two bytes of the entry point. Checking for a
breakpoint perhaps?
> 0023:Call ntdll.NtReadVirtualMemory(00000058,00761060,0078c96c,00000002,406cbc0c) ret=404fab7a
> 0023:Ret ntdll.NtReadVirtualMemory() retval=00000000 ret=404fab7a
> 0023:Ret kernel32.ReadProcessMemory() retval=00000001 ret=007556bd
> 0023:Call kernel32.WriteProcessMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=00755723
Then it writes back 2 bytes to the same address. Maybe this is the bit
that lets ezcddax know it was started by the launcher program and not
directly by the user. I suspect if you suppress this WPM call, the
program will pop up an error asking you to run the launcher app
directly. It's probably writing a jump opcode.
> 0023:Call ntdll.NtWriteVirtualMemory(00000058,00761060,406cbc08,00000002,406cbc0c) ret=404fabea
> 0023:Ret ntdll.NtWriteVirtualMemory() retval=00000000 ret=404fabea
> 0023:Ret kernel32.WriteProcessMemory() retval=00000001 ret=00755723
> 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
Now it goes into a loop, attempting to get the exit code of the process.
> 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
It's trying to find out what the exit code of the process was.
Unfortunately, we don't know what the answer is because the return code
is a success/failure bool, not the actual exit code. You'd have to whack
an ERR in here or something to find out.
> 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> 0023:Call kernel32.Sleep(00000064) ret=007557cd
Then it tries to wake it up (remember, the remote process was started
suspended) and sleeps for a moment.
> 0023:Call ntdll.NtDelayExecution(00000000,406cb888) ret=40507cff
> trace:relay:RELAY_InitDebugLists RelayExclude = L"RtlEnterCriticalSection;RtlLeaveCriticalSection;_EnterSysLevel;_LeaveSysLevel;LOCAL_Lock;LOCAL_Unlock;TlsGetValue;kernel32.GetLastError;kernel32.SetLastError"
> 0025:Call PE DLL (proc=0x401d3bb4,module=0x401c0000 L"ntdll.dll",reason=PROCESS_ATTACH,res=0x1)
At this point the kernel does a context switch into the new process, and
it begins initializing. Note that CREATE_SUSPENDED doesn't mean nothing
runs in the new process. It still gets the ATTACH notifications (at
least, it does in Wine ... maybe not in real windows). So there's a lot
of stuff we can ignore here generated by the startup sequence.
Let's find out what the first process is doing:
> 0025:Ret ntdll.RtlAllocateHeap() retval=40393550 ret=4083acae
> 0023:Ret ntdll.NtDelayExecution() retval=00000000 ret=40507cff
> 0023:Ret kernel32.Sleep() retval=00000000 ret=007557cd
> 0023:Call kernel32.SuspendThread(0000005c) ret=007557da
> 0023:Call ntdll.NtSuspendThread(0000005c,406cb8a0) ret=4050e80e
> 0023:Ret ntdll.NtSuspendThread() retval=00000000 ret=4050e80e
> 0023:Ret kernel32.SuspendThread() retval=00000000 ret=007557da
> 0023:Call kernel32.GetThreadContext(0000005c,406cb948) ret=0075580e
> 0023:Call ntdll.NtGetContextThread(0000005c,406cb948) ret=4050e7ae
> 0023:Ret ntdll.NtGetContextThread() retval=00000000 ret=4050e7ae
> 0023:Ret kernel32.GetThreadContext() retval=00000001 ret=0075580e
Context switch after the first line, and it awakens from its sleep.
It then suspends the thread, and grabs its context. Why does it suspend?
Reading MSDN reveals that the target thread has to be suspended for
GetThreadContext to work. The CONTEXT structure holds the register state
of the thread. I wonder what it's looking for in this structure?
> 0023:Call kernel32.GetExitCodeProcess(00000058,0078ca58) ret=0074f235
> 0023:Call ntdll.NtQueryInformationProcess(00000058,00000000,406cb86c,00000018,00000000) ret=404f5dfa
> 0023:Ret ntdll.NtQueryInformationProcess() retval=00000000 ret=404f5dfa
> 0023:Ret kernel32.GetExitCodeProcess() retval=00000001 ret=0074f235
> 0023:Call kernel32.ResumeThread(0000005c) ret=007557c5
> 0023:Call ntdll.NtResumeThread(0000005c,406cb8a0) ret=4050e85e
> 0023:Ret ntdll.NtResumeThread() retval=00000000 ret=4050e85e
> 0023:Ret kernel32.ResumeThread() retval=00000001 ret=007557c5
> 0023:Call kernel32.Sleep(00000064) ret=007557cd
OK, and we go back into a loop. In fact, this is an infinite loop.
Probably it looks like this:
while (1)
{
int code;
CONTEXT86 context;
GetExitCodeProcess(process, &code);
if (code == ???) do something;
ResumeThread(thread);
Sleep(64);
SuspendThread(thread);
GetThreadContext(thread, &context);
// do something with context here
if (context.???) break ???
}
So the question is, what condition will make it break out of the loop,
and why isn't it getting it in Wine?
It looks like it's waiting for some condition to become true in the
remote process. This will never happen because ResumeThread here doesn't
seem to be waking it up! We just loop over and over, resuming it,
sleeping for a while, grabbing its context to check something which
never changes, and starting over.
So, I guess the problem is that ResumeThread isn't actually waking up
the suspended process. Question is, why not?
Here's an idea. Hack the Sleep() call like this:
if (delay == 64) delay = 3000;
Ie, rule out the possibility that the delay between resume and suspend
is so short Wine can't react in time. Then continue your investigation
from there.
Good luck!
thanks -mike
Sept. 29, 2004
Re: Problems installing IE6
by James Courtier-Dutton
Joaquín Fernández wrote:
> Stefan Leichter wrote:
>
>> Am Montag, 27. September 2004 20:03 schrieb Joaquín Fernández:
>>
>> Hello,
>>
>> try
>> WINEDLLOVERRIDES="advapi32=builtin"
>>
>> (see http://www.winehq.org/hypermail/wine-devel/2004/08/0640.html)
>>
>> Bye Stefan
>>
>>
>>
>
> Thanks Stefan, i tried but i can't install IE, the installer stay in
> endless loop at the end of process. I tried with other WINEDLLOVERRIDES
> but i was not able to install IE.
>
> Regards
>
> Joaquín
>
>
Is WINEDLLOVERRIDES pronounced "Wined Lover Rides" ? ;-)
Sept. 29, 2004
Re: Progress Bar: Fix Class Style & Repainting (resend2)
by Alexandre Julliard
"Dmitry Timoshkov" <dmitry(a)baikal.ru> writes:
> The problem with Rob's patch is that it causes entire background of
> the progress bar to be repainted. Some time ago (3 years or like that)
> I wrote tests for progress bar and found that it invalidates background
> only when (oldPos < newPos) and it really has a separate WM_ERASEBKGND
> handler. Since then my code has been removed and rewritten (by you
> Alexandre) for no obvious reason IMO.
The reason was precisely to avoid flicker in certain cases (I believe
it was during the MS Office install).
--
Alexandre Julliard
julliard(a)winehq.org
Sept. 29, 2004
Re: Upgrade management
by Mike Hearn
[CCd wine-devel as I think you meant it to go there originally]
Holly Bostick wrote:
> Seems to me that whether or not 99% of users will forget is not your
> responsibility as developers. Other than making very sure that users
> know there is something to remember, further programming against the
> possibility that they will forget what you told them not to is more work
> for you, simply in order to absolve them of responsibility for their own
> system and make things "look good" at all times to those who want
> everything "click and run".
>
> Look at the problems that attitude (and the compensatory measures to
> resolve it) has caused Microsoft. I would think that you all have better
> things to do with your valuable development time-- namely developing the
> actual application, not babysitting me (the user with the mind like a
> sieve).
Well, there are a couple of good reasons why automatic upgrades are good
for us developers:
1) If we don't, we'll just get bug reports due to people not having full
upgrades: we already get plenty of bizarre bug reports due to broken
packaging, last thing we need is for people to fill bugzilla with
even more. And yes some developers do tech support :)
2) We already do a ton of stuff automatically, and nobody ever
notices. This strongly implies that automatic setup and configuration
does benefit people: I can assure you they noticed when we didn't
set up the wine config upstream! We want Wine to have a good
reputation for reliability, but currently it doesn't - people run
random Foo app, it crashes and burns maybe due to incorrect
configuration and they walk away saying "Oh well, Wine is crap,
what did I expect?". This happens quite a bit. Ensuring the user
is cleanly and transparently upgraded makes things Just Work to
a greater extent, which is good for everybody.
I'm still not hugely convinced about the backup thing: if you want to
back up your configuration before upgrading Wine it's very easy:
cp -rv ~/.wine ~/.wine.old
... we could even do that as part of the upgrade process.
Possibly we should back up the registry, but not the virtual drive C.
The C drive is going to change a lot less than the registry will: a Wine
upgrade typically means new DLLs and maybe new registry contents. It
rarely means changes to the drive layout.
thanks -mike
Sept. 29, 2004
How to deal with C++ APIs in wine spec file
by Jia L Wu
Hi,
I have to write a spec file so that a winelib application can use a third
party dll. The problem is that APIs in third party dll are written in C++.
As c++ names and parameters are mangled, how can i call them in spec file?
For example, how can I call a class constructor (which is built form
another class) in spec file? Can anyone provide me an example? Thanks.
Wu
Sept. 29, 2004
Re: WINEDLLOVERRIDES for all dlls?
by James Hawkins
> Yes I know that isn't what I said before. I suck :)
It's ok don't worry about it... thanks for the tip Mike.
On Wed, 29 Sep 2004 09:37:49 +0100, Mike Hearn
<m.hearn(a)signal.qinetiq.com> wrote:
> > I used WINEDLLOVERRIDES="advapi32=b" WINEDEBUG=+loaddll, and it still
> > shows the downloaded native advapi32.dll being loaded.
>
> You need WINEDLLOVERRIDES="*advapi32=b"
>
> Yes I know that isn't what I said before. I suck :)
>
--
James Hawkins
Sept. 29, 2004
Re: Moved some local variables from StartServiceCtrlDispatcherA/W to service environment block
by Alexander Yaworsky
Hello
> I don't think you want to pass ASCII strings across processes, there's
> no guarantee that both processes are using the same codepage.
> Inter-process communication should always be done in Unicode.
I was not going to use those variables for interprocess communications.
But incidentally you've just kept me off the wrong way. There are
some wrong things in these functions if we take SERVICE_WIN32_SHARE_PROCESS
into account. Generally, they should not handle service arguments like
they do now and should not try to find service entry. The _running_
service control dispatcher should do these things.
So, more restructurization of StartServiceCtrlDispatcherA/W is required.
In fact, their code should be completely merged into common dispatcher
function like in my original huge patch (that was also wrong) but since
I tried to avoid this for some reason.
Thanks.
Sept. 29, 2004