Jump to content
mvanrijnen

TMethodImplementationIntercept/__dbk_fcall_wrapper called infinite and high cpu

Recommended Posts

We have one application which since a few months gives problems on most of the workstation here. 

(not all, ofcourse not on the dev machines 🙂 )

 

The application goes into high cpu constantly without doing anything (wanted).

We noticed that this was causes by a thread which uses/started because TMethodImplementationIntercept

so we fixed thats this method was not exported, then the troubles moved to __dbk_fcall_wrapper.

 

It's only in one of the many applications we have here that this problem occurs, anyone any idea or direction we should search in?

 

Share this post


Link to post
On 8/10/2023 at 6:16 PM, mvanrijnen said:

We noticed that this was causes by a thread which uses/started because TMethodImplementationIntercept

so we fixed thats this method was not exported, then the troubles moved to __dbk_fcall_wrapper.

I think screenshot would helped earlier, so others here could spot the problem for you, look at these

image.thumb.png.fb1523e01bc83bb9e4faecb76f47aa7b.png

image.thumb.png.e71ad35287be9a532160e60b3397f3b7.png

 

is that what do you see ?

The first one is an new project while the second has this

Quote

procedure TForm10.FormCreate(Sender: TObject);
begin
  while True do
end;

 

So i think you are following the wrong thing, as many tools are build for Windows binaries with PDB debug information, in this case it could find a suitable address (previous with an export or known from the debug info) so it grabbed the closest before the address and resolved it as entry point.

Find the culprit address by calculating the address of TMethodImplementationIntercept +xxxxxx then follow it in you debugger, or attach a debugger or... may be try Andres PDB debug info tool see if that works with your watching tool, or find another tool that does show an address instead of a relative address ...

 

Hope that helps, and good luck.

Share this post


Link to post

Yes, indeed thats what we see, difference is that there are more threads which also take cpu. 

gonna take a look into your tip of finding the real method/thread you mentioned.

 

quick question, the Displayed ThreadID should always be correct ?

 

Edited by mvanrijnen

Share this post


Link to post
50 minutes ago, mvanrijnen said:

Displayed ThreadID should always be correct ?

Yes.

 

Using remote Delphi debugger or using different debugger to get these addresses will be way more accurate and easier.

This one is the best out there 

https://x64dbg.com/

Share this post


Link to post

@mvanrijnen Did you find an effective way to debug this? My application started to do the same, with a similar call stack in the offending thread:

 

image.png.04890ac24a1139537895fd8c112b4826.png

 

It's important to note that this thread is not a worker of mine, I don't know what or when it was created. It also safely can be killed and won't cause any (noticable) disturbances.

I also couldn't find a way to reproduce the issue, one time it just thinks it's time and then it locks up.

Share this post


Link to post
15 hours ago, aehimself said:

image.png.04890ac24a1139537895fd8c112b4826.png

 

It's important to note that this thread is not a worker of mine, I don't know what or when it was created. It also safely can be killed and won't cause any (noticable) disturbances.

Evidently it is from Delphi code and started with CreateThread , see the UserThreadStart ? that is it.

 

So this thread in particular is create from library you are using, it could be VCL or RTL or 3rd party or some unit you included, but without any doubt it is started from CreateThread there is high chance to be from TThread somewhere, but this is an encapsulation after all.

 

There is also a chance it is from a DLL your code is calling, but again this thread is created from user space code not the kernel, also from the stack itself it is deep nested with 7 levels in your EXE, so it should be easy to identify.

Share this post


Link to post
1 hour ago, Kas Ob. said:

without any doubt it is started from CreateThread there is high chance to be from TThread somewhere, but this is an encapsulation after all.

There are other ways for a thread to get started, but ignoring that and assuming it was created with CreateThread, one could simply place a breakpoint on the CreateThread import in Winapi.Windows and investigate the call stack as the threads gets crated.

  • Like 1

Share this post


Link to post
11 minutes ago, Anders Melander said:

There are other ways for a thread to get started,

Yes there is, but in this case the RtlUserThreadStart from the kernel user mode (ntdll) is the one supplied with ThreadProc from CreateThread from this running process.

Share this post


Link to post
32 minutes ago, Kas Ob. said:

Yes there is, but in this case the RtlUserThreadStart from the kernel user mode (ntdll) is the one supplied with ThreadProc from CreateThread from this running process.

How can you tell?

Share this post


Link to post

@aehimself use ApiMonitor to find these not-yours threads http://www.rohitab.com/apimonitor

 

image.thumb.png.669e016f38a532fe00b0f66b8d64ff00.png

 

NT Native -> Process and Threads -> Ntdll.dll for lower level functions

and

Process and Threads -> Thread -> Kernel32.dll for higher level function (your usual user mode functions aka RTL)

 

Share this post


Link to post
Just now, Anders Melander said:

How can you tell?

Hours and hours digging into Windows kernel, also the name of that first in the stack function is very specific and very familiar RtlUserThreadStart, as example, CreateRemoteThread doesn't invoke this one.

Lastly from old readings, i can't find many resources but have a look here http://www.nynaeve.net/?p=200

Share this post


Link to post
2 minutes ago, Kas Ob. said:

Hours and hours digging into Windows kernel, also the name of that first in the stack function is very specific and very familiar RtlUserThreadStart, as example, CreateRemoteThread doesn't invoke this one.

Hmm. Okay, I'll defer to your expertise then 🙂 - but I can't tell, from looking at the call stack, if the thread was created from Delphi code or from something injected into the process from the outside. I was hoping there was some obvious clue that I had missed.

 

5 minutes ago, Kas Ob. said:

Lastly from old readings, i can't find many resources but have a look here http://www.nynaeve.net/?p=200

Quote

RtlUserThreadStart is used on Windows Vista and Windows Server 2008 (and later OS’s) to form the initial entrypoint context for a thread started with NtCreateThreadEx (this is a marked departure from the approach taken by NtCreateThread, wherein the user mode caller supplies the initial thread context).

More hmmm. Doesn't really tell me much with regard to the source of the thread.

Share this post


Link to post
8 minutes ago, Anders Melander said:

Nice! I didn't know that one.

What to say, i have pasted the link and mentioned many times 😎

For more powerful tool i use, different but more invasive/intrusive i use CheatEngine 

https://www.cheatengine.org/

https://github.com/cheat-engine/cheat-engine

 

Written mostly in FreePascal, and it is for games, yet it is so much powerful with its monitoring and even capturing low level event like executing a specific assembly code or passing though (executing) specific address or even accessing a block of memory (read or write), also there is LUA scripting...

In short it is really useful to master and use.

Share this post


Link to post

 

So the process of finding these is not that easy but not that hard either, I'll put it here so future visitors don't have to research / experiment.

- Download @Anders Melander's Map2pdb, compile it and run it against your applications .map file. You'll get a .pdb file.

- Download WinDbg and install it. Once done, go to File -> Settings -> Debugging settings and add the folder where your .pdb file is to the Symbol path list

- Launch your application and when it's in the state you want to examine, go to File -> Attach to process and select your application.

- In the lower-right pane select the "Threads" tab and double-click the offending one (TID = ThreadID in HEX)

- Now go to the Stack tab and if everything is good, you get readable stack traces

 

In my case @Stefan Glienke was absolutely right:

 

image.thumb.png.4c18204b065d4f95d0a01cc68b090c9b.png

 

As I am not using thread pools, I need to find out what does... and get rid of it, somehow...

 

  • Thanks 1

Share this post


Link to post
11 minutes ago, Anders Melander said:

Too bad about the XP skin though 🙂

Turns out there's good explanation for that 😕

image.png.d5e8ef370f1154e3836550f1b2b8184b.png

 

But at least the UI has a "Windows 7" skin.

 

Share this post


Link to post
3 minutes ago, Anders Melander said:

if the thread was created from Delphi code or from something injected into the process from the outside.

Good point, but remember invoking/calling CreateThread from local thread doesn't require specific privileges but while injecting (almost always ) with CreateRemoteThreads does require security privileges.

 

This is interesting https://github.com/stephenfewer/ReflectiveDLLInjection/pull/17

Quote

Firefox on Windows hooks kernel32!BaseThreadInitThunk which prevents the remote thread to start in the target, see https://dxr.mozilla.org/mozilla-central/source/mozglue/build/WindowsDllBlocklist.cpp#821:

FireFox indeed tries (tried in the past i don't know the current code) to protect itself from remote injection by hooking the BaseThreadInitThunk not the RtlUserThreadStart, for the same reason that RtlUserThreadStart is not always the start point.

 

 

16 minutes ago, Anders Melander said:
Quote

RtlUserThreadStart is used on Windows Vista and Windows Server 2008 (and later OS’s) to form the initial entrypoint context for a thread started with NtCreateThreadEx (this is a marked departure from the approach taken by NtCreateThread, wherein the user mode caller supplies the initial thread context).

More hmmm. Doesn't really tell me much with regard to the source of the thread.

Well you are diving deeper into OS kernel, so to make sure we are on the same page first let clear the separation of the functions in the OS as whole Kernel part and kernel user part.

 

In Windows there is 3 levels of functions, and they are named little differently, sometimes the difference is only with Nt or Zw against nothing, or completely different name encapsulating multi functionality.

eg CreateThread is for RTL user mode, this will internally call NtCreateThread we still in the kernel but in the user part which is lower than user process but higher than the kernel itself (the hidden and protected one), then comes ZwCreateThread which reside in the kernel and this one is system call not system function, meaning the execution is not done by simple assembly branching instruction like JMP or CALL, no this is done by SYSCALL and SYSENTER 

https://www.felixcloutier.com/x86/syscall

https://www.felixcloutier.com/x86/sysenter

 

This page https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-nt-and-zw-versions-of-the-native-system-services-routines explain the difference but still hard to grasp or understand it from one reading, hence i am trying (or failing) to make clearer a little.

With each level different checks are performed for security, errors, ... Zw calls are essentially to be called directly and exclusively form drivers and the kernel, Nt calls are less strict yet these Nt call are the ones that will check for privileges to perform/acces from User more process, while Zw are the ultimate to decide as there is many of them will simply refuse to execute because the calling thread is not kernel one, Nt will refuse to execute if you don't have user mode privileges.

 

Take as example CloseHandle, this function does close almost everything yet it called CloseHandle, there is NtCloseHandle, but there is no ZwCloseHandle, there is ZwClose that perform all the closing in the kernel.

 

Now i drifted far form the question and your comment (but for IMO good reason), NtCreateThreadEx is the real function behind CreateThread (which in fact is calling NtCreateThread) from the User Mode and will perform the same functionality but it does have the last check for privileges and context to execute or invoke a new thread.

 

Not sure if this was clear, i just hope.

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×