简体   繁体   中英

Find the reason why a thread starts

I have an application for which I can see threads starting and terminating all over again. I'm now wondering where those threads come from, because IMHO they shouldn't be there (or at least the overhead of creating a thread is not worth it).

This is the first time I use sxe ct to be notified about new threads being started. I can inspect the new thread using k , but it's not giving much information at this point:

0:010> k
 # Child-SP          RetAddr               Call Site
00 000000c7`de1ff898 00000000`00000000     ntdll!RtlUserThreadStart

I then used ~*k and had a look for CreateThread() or similar. Sometimes, I can find such a call

   6  Id: 5264.4d68 Suspend: 1 Teb: 000000c7`dd6cb000 Unfrozen  
 # Child-SP          RetAddr               Call Site
00 000000c7`dd58ea68 00007ffb`77f3baa2     ntdll!NtCreateThreadEx+0x14
[...]

But in many cases, I don't find such a call. I'm aware that threads could also be injected into the process, like the debugger injects the breakpoint thread.

How do I find out what the origin/reason for a newly created thread is?

Clarifications:

The application is written in .NET, but may have loaded unmanaged DLLs, which in worst case might load other stuff written in interpreted languages. I am not looking for an answer that describes the various reasons a .NET application could create a thread. I am looking for an answer where I have already identified a particular thread (with sxe ct ) and I want to know where that thread comes from.

The Break for Sxe ct happens when the system calls the LPTHREADROUTINE function
At this point you do not have the information about who Created the thread in first place.

for example you can run for (i=0;i<x;i++) {CreateThread(....,ThreadRoutine,...);}
and sxe ct wont break until the loop has run x times

You May Need to Set a Breakpoint on one of Create Functions
and look at the Disassembly at the Return Address to know who is Creating the Thread.

a sample code for demo below

the main() creates 10 threads and if you run the binary in windbg with sxe ct
the break will happen only after the printf(...) and before WaitForMultipleObject(...)

#include <stdio.h>
#include <windows.h>
#define THNO 10
CRITICAL_SECTION mycritty;
int counter = 0;
DWORD WINAPI tproc( LPVOID  ) 
{
    EnterCriticalSection(&mycritty);
    counter++;
    printf("%d\n",counter);
    Sleep(10000);
    LeaveCriticalSection(&mycritty);
    return 0;
}

int main(void)
{
    ULONG htid[THNO] = {0};
    HANDLE hth[THNO] = {NULL};
    InitializeCriticalSection( &mycritty );
    for(int i = 0; i < THNO; i++) 
    {
        hth[i] = CreateThread(NULL,0,&tproc,NULL,0,&htid[0]);//Line Number 23
    }
    printf("\n\nAll Threads Created Wait Below  Yields cpu for Scheduling\n");
    printf("tproc() %p will be executed only now\n\n\n", &tproc);
    WaitForMultipleObjects(THNO, hth, TRUE, INFINITE);
    return getchar();    
}

executing with sxe -c "r @eax" ct in cdb.exe
you can notice the printf() in main has executed prior to sxe break
so you either need an utility in kernel doing PsCreateThreadNotifyRoutine() Callback
or you may need to set a break in Say ntdll.NtCreateThreadEx() function and look at callstack for the Module that Does the Thread Creation.

:\>cdb -c ".prompt_allow -reg -sym;sxe -c \"r @eax\" ct;g" critter.exe

Microsoft (R) Windows Debugger Version 10.0.18362.1 X86

ntdll!LdrpDoDebuggerBreak+0x2c:
778c05a6 cc              int     3
0:000> cdb: Reading initial command '.prompt_allow -reg -sym;sxe -c "r @eax" ct;g'


All Threads Created Wait Below  Yields cpu for Scheduling
tproc() 012D1000 will be executed only now


eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0167fccc=00000000
0:001> g
1
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0253f9f4=00000000
0:002> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0235fbec=00000000
0:003> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0211fe68=00000000
0:004> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01f7fbe4=00000000
0:005> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01e1fbdc=00000000
0:006> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01ccfb78=00000000
0:007> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01b9f9cc=00000000
0:008> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01a6fa38=00000000
0:009> g
eax=012d1000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0187fa60=00000000
0:010> g
2
3
4
5
6
7
8
9
10
g
778670f4 c3              ret
0:000>
0:000> q
quit:

**
now with a break and sxe ct
notice the Conditional Bp prints the src line number of LPTHREADROUTINE
**

:\>cdb -c ".lines;.prompt_allow -reg -sym;bp ntdll!NtCreateThreadEx \".frame 3;k1;? poi(@esp+14);gc\";sxe -c \"r @eax\" ct;g" critter.exe

Microsoft (R) Windows Debugger Version 10.0.18362.1 X86

0:000> cdb: Reading initial command '.lines;.prompt_allow -reg -sym;bp ntdll!NtCreateThreadEx ".frame 3;k1;? poi(@esp+14);gc";sxe -c "r @eax" ct;g'

03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000
03 002ef9fc 00091384 critter!main+0x93 [xxx\critter.cpp @ 23]
ChildEBP RetAddr
002ef6ac 75b1b9da ntdll!ZwCreateThreadEx
Evaluate expression: 593920 = 00091000


All Threads Created Wait Below  Yields cpu for Scheduling
tproc() 00091000 will be executed only now


eax=00091000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0160fda4=00000000
0:001> g
1
eax=00091000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:023ef820=00000000
0:002> g
eax=00091000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:0217fea4=00000000
0:003> g
eax=00091000
778670d8 89442404        mov     dword ptr [esp+4],eax ss:0023:01e8fdd0=00000000
0:004>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM