if the Thread is Created Suspended and Resume thread is called for the first time ollydbg will not show the thread in its thread window
nor will the stack trace for the thread be available in stack window (ALT+K)->Right Click->Thread ->Checkmark
in such cases you can set a breakpoint on the following apis
follow through is based on xp sp3 layout (you may need a bit of tweking in newer os )
1) ntdll!NtContinue / ZwContinue (can be found without symbol )
2) ntdll!ZwRegisterThreadTerminateport (can find this too without symbol)
3) CsrNewThread (needs symbol)
4) BaseThreadStartThunk ditto
5) BaseThreadStart ditto
Resume thread will break on either of these apis
if it is broken on Zw/Nt Continue follow the context->eip
from the stack [[esp+4] + 0xb8] and set a breakpoint on the eip found (this address normally will be BaseThreadStartThunk which is directly identifiable if you have public symbols loaded
) and hit go once you are on BaseThreadStartThunk single step f8 few times until you get to an indirect call call dword ptr ds:[R32 + CONST]
this is your ThreadProc
if it is broken on ZwRegisterTerminatePort you need to just single step (you will return to csrNewThread which you can find if symbols are available) and keep f8ing until you get to the indirect call stated above to land on ThreadProc
the other apis are included in the above and can reduce the number of single step
ntdll!ZwRegisterThreadTerminatePort is the closest break prior to ThreadProc
needs one ctrl+f9 (execute until return) and 3 f8 (single step)
if windbg / livekd is an option this script can retrieve the eip when broken on ResumeThread call be it Firsttime Resume or subsequent resumes
.foreach /ps 8 /pS 0n19 (place { !process 0 4 ${$arg1} } ) {.printf "ETHREAD = %x\n", place ; r? $t0 = (((nt!_ETHREAD *) @@masm( place ))->Tcb) ; r? $t1 = @$t0.StackLimit;r? $t2 = @$t0.InitialStack;.foreach (vlace {s -[1]d @$t1 @$t2 0x23 0x23 } ) {dt nt!_KTRAP_FRAME DbgEip Eip @@masm(${vlace}-34) }}