Ok, since you're doing funky stuff how about a funky idea? No idea if this will help with the problem, it's just a hack-and-see thought at the moment.
PEB / PEB_LDR_DATA doesn't get fully initialized until ntdll!LdrpInitializeProcess is called.
http://www.openrce.org/forums/posts/594
LdrpInitializeProcess is called as an APC, which from all accounts won't happen until ResumeThread is called.
http://www.woodmann.com/forum/showthread.php?t=11154
There is a function called Nt/ZwAlertResumeThread, which maps to nt!_KeAlertResumeThread.
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/NtAlertResumeThread.html
Code:
NtAlertResumeThread(
IN HANDLE ThreadHandle,
OUT PULONG SuspendCount
);
ThreadHandle
Handle to thread object.
SuspendCount
Returns number of suspend request for thread ThreadHandle
before call NtAlertResumeThread.
If this number is 0, thread will continue execution.
Difference between AlertResumeThread and ResumeThread:
the first one sets Thread Object to alerted state
(so before thread will continue execution, all APC will be executed).
The idea here is to execute the outstanding APC which will call LdrpInitializeProcess, without actually resuming the process.
So find the starting thread valid handle of the suspended process, EPROCESS.ThreadListHead might work.
Increase the suspend count (so you don't actually resume the thread if it drops to 0) in KTHREAD.SuspendCount.
Call NtAlertResumeThread and see what happens.
Check that the SuspendCount is reduced back to the original after you call NtAlertResumeThread.
Hopefully when the original ResumeThread is called, the fact that the LdrpInitializeProcess APC has already been run won't matter to the process starting normally. In the meantime, you've had the opportunity to do whatever it is you want to do re the Olly attach.
btw, your [fs:18h + 0F24h] is probably TEB.DbgSsReserved and is part of the DbgUiConnectToDbg function. Do a "dt _TEB" in WinDbg/LiveKd to check the offset for your OS.
Kayaker