首页 > 其他分享 >API Hooking revealed part 3 and 4 - Thread Deadlock Detector

API Hooking revealed part 3 and 4 - Thread Deadlock Detector

时间:2022-12-13 15:22:21浏览次数:77  
标签:Hooking Thread thread object API mode deadlock o0

API Hooking revealed part 3 and 4 - Thread Deadlock Detector

 

Image 1

Introduction

This is the third, fourth (and the last) part for building a thread deadlock detector. Please see the first and second articles to understand what is going on, at A (working) implementation of API hooking (Part II).

In fact, I've added a small library called SetThreadName which allows you to set the thread name and to get meaningful names for the synchronization object. The library does nothing in Release build, you don't even need it.

Remarks: This software will work even without this DLL, you don't have to recompile anything, unless you want to have your thread and object named.

The thread naming trick allows the thread name to be supported in Visual debugger (under Debug\Thread menu, real names instead of 0x0000C340), so it is of 100% benefit if you use it, even if you are not using my software. For the automatic object naming, the following algorithm is used :

  • The first is the process clock value, so that a function creating the object will still create different object names.
  • The second is the process ID, so that you can run your application multiple times, it will still have a unique name.
  • The third string is the object type. (Mutex, Event, Semaphore, etc.)
  • The fourth string is the file name where the object was created.
  • The fifth number is the line where the object was created.

Part III : The thread deadlock detector

The background

If you've followed my previous articles, then you should know what is API hooking, and how to use it to spy what is going on in any application (Part I). You should also know what are we interested in for a thread deadlock detector, and what are the tricks to get all the required information (Part II).

The idea

Now that we can get every call to any synchronization and thread function, we face a problem. How can we know when a target application is deadlocked or not? The algorithm I'm using here is quite simple. Here is an example of a deadlock:

 
Let's take 2 threads (A and B), and 2 objects (o0 and o1).
Thread B locks o0, and then locks o1.
In parallel, Thread A locks o1, and then locks o0.

If o0 and o1 are free (ready to be locked), then they are 4 possibles cases:
 1) Thread B is executed, and not interrupted, then thread A is executed.
 2) Thread A is executed, and not interrupted, then thread B is executed.
 3) Thread B is executed, but gets interrupted before locking o1, then thread A 
    is executed, and waits for o0. Thread B is then executed, and waits for o1.
 4) Thread A is executed, but gets interrupted before locking o0, then thread B 
    is executed, locks o0 and waits for o1. Thread A is then executed, 
    and waits for o0.

It is clear that case 1 and 2 are okay. However, when reaching case 3 or 4, the application goes to deadlock. To avoid this, the server (deadlock detector) monitors each object and thread using its CSyncObject and CThread classes. Then, each object keeps a track on who owns it (a thread list). Similarly, each thread has an object waiting list and locked list. Now let's see how the algorithm finds the deadlock:

 
    Case 3:
Time 
  0          Thread B locks o0      (o0 now has Thread B in its list
                                     and Thread B have o0 in its Locked list)
  1          Thread B is interrupted
  2          Thread A locks o1      (o1 now has Thread A in its list
                                     and Thread A have o1 in its Locked list)
  3          Thread A tries to lock o0
               (as o0 is already locked, we look inside it to find who got it.
                we find Thread B, so then we check if thread B is waiting for
                any object current thread (thread A) may have. In that case,
                the waiting list of thread B is empty, so we add o0 to our 
                waiting list)
  4          Thread A is interrupted
  5          Thread B tries to lock o1
               (as o1 is already locked, we look inside it to find who'got it.
                we find Thread A, so then we check if thread A is waiting for
                any object current thread (thread B) may have. Thread A is 
                waiting for o0 but o0 is in our locked list => deadlock)

The algorithm is quite simple but works out of the box.

The implementation

We need a server called ThreadDLD (what a wonderful name, isn't it?). Its purpose is to:

  • Launch the debuggee (can be any application with or without source code).
  • Inject the spying DLL in it, and make it infect the debuggee.
  • Receive the thread monitoring function.
  • Receive any API sniffing from the client.
  • Parse the sniff, and display them as log.
  • Analyze the sniff and spot errors (deadlocks).

The debuggee is launched in CMainFrame::OnFileOpen in suspended state. The spying DLL ThreadSpy.DLL is then injected using the usual CreateRemoteThread trick. Then the debuggee is resumed, and the server waits for any message from it. The debuggee then sends the StartMeUp command with the thread monitoring function address, and sends any hooked command to the server (with stack trace and timestamp). The server waits for any CommunicationObject from the debuggee in its CThreadDLDView::ReceivedMessage. The server then parses the message and logs it accordingly. There are four logging modes, from the simple mode to the Analysis mode. Each of them reports the same information but from a different point of view.

  • Log mode

    In this mode the received messages are shown un-factored, and is not intelligent. However, this is the fastest reporting mode, and should be used while reproducing the deadlock in the debuggee.

  • Thread life

    In this mode the received messages are shown from the thread point of view. No deadlock detection is done in this mode. However, this mode is perfect to check each thread behavior.

  • Object life

    In this mode the received messages are shown from the object point of view. No deadlock detection is done in this mode. However, this mode is perfect to check what happens to any object you are monitoring.

  • Analysis

    In this mode the received messages are analyzed and the deadlock detection is performed on the fly. This is the slowest mode. However, this is the only mode that will outline thread deadlocks and errors. The algorithm described above is defined in CThread::CheckLock method. The objects are declared in SyncObject.h.

Part IV : The bonus track

Each CommunicationObject sent between the debuggee and the server contains the stack trace in the debuggee. This stack trace is useful to spot where the deadlock has occurred. The problem with stack traces, is mainly due to their lack of meaning (when an error occurs at 0x00401345, I'm almost sure it doesn't tell you much). The idea, is to use a map file (if available), to map the address from the stack trace to real functions. I've included a MapFileParser to reverse the addresses into undecorated function names. It will not give you the line number, but anyway it is better than nothing. (Map file can be built in Release build too without any risks, as they are separate files). The map file parser finds the function that is just before the given address. This will not work for DLLs, as it is really not possible to know where the DLL will be mapped (except if you specify it by yourself like Google says "Mark Pietrek").

To conclude

I looked around to find such a tool for about a month, and because none of them where available, here is mine. It is obvious that this is not a "professional" software. For example, it cannot detect potential deadlock like tools that cover code statically, it will only detect real deadlock. I'm sure I can add the functionality for the same, because I have all the needed data. This project is made with ATL and WTL, so I would rather encourage you to learn those tools. I've implemented an owner drawn CListViewCtrl as I didn't find any good one around. The implementation is in CThreadDLDView. It is not possible to save the log, or read it. I've kept the print icon, but there is no print code. If you want to upgrade/add functionalities please post a line or two below:

What I would like to see is:

  • function::line number in the map field (it is possible to generate a map file with line numbers too, but then the MapFileParser will be more complex).
  • Reply to the debuggee to prevent it from deadlocking (as we know the situation before it really happens in the debuggee process). This could be done without thread and delay by using shared memory area.

Update

  • April 1st, 2005
    • Added mapping of imported DLL too (so now, you should be able to locate deadlock even a in DLL).
    • You can use the software to see what modules are loaded in a target process.
    • Analyze mode can now detect possible deadlocks (yes, even those that deadlock only in client site).
    • Can pass parameters to the program being analyzed.
    • Can save the analysis to a file (yes, and can be imported in Excel too).
  • Feb - 2005
    • Initial release.

标签:Hooking,Thread,thread,object,API,mode,deadlock,o0
From: https://www.cnblogs.com/qzxff/p/16978927.html

相关文章

  • 通过API操作阿里云ECS(开关机)
    场景:定时开关机ECS,节省模式关机完整代码示例官方链接:https://next.api.aliyun.com/api-tools/sdk/Ecs?version=2014-05-26&language=go-tea关机:https://next.api.aliyun......
  • ThreadLocal(2) - FastThreadLocal
    FastThreadLocal该类位于netty的util包下,netty的线程都使用的是FastThreadLocal而不是jdk的ThreadLocaljdk的ThreadLocal使用Thread类的ThreadLocalMapnetty的Fas......
  • 前端页面Ajax控制后端线程(Thread)运行
    1、后端生成线程JSONObjectredisJson=newJSONObject();Threadth=newThread(()->{...while(){...}.........
  • 非maven项目使用阿里云短信服务API
    不说废话,先上代码单发/***单发短信*@paramphone手机号*@paramcode模板code*@return*@throwsClientException*/......
  • ThreadLocal实现原理和使用场景
    ThreadLocal是线程本地变量,每个线程中都存在副本。实现原理:每个线程中都有一个ThreadLocalMap,而ThreadLocalMap中的key即是ThreadLocal。  内存泄漏:ThreadLocal......
  • vue全局API
    ​​Vue.extend(options)​​参数:​​{Object}options​​用法:使用基础Vue构造器,创建一个“子类”。参数是一个包含组件选项的对象。​​data​​​ 选项是特例,需要注......
  • 对vue的api的研究
    ​​Vue.config​​ 是一个对象,包含Vue的全局配置。可以在启动应用之前修改下列属性:​​silent​​类型:​​boolean​​默认值:​​false​​用法:Vue.config.silent=tru......
  • 给ASP.NET Core WebAPI添加Swagger支持
    ASP.NETCoreWebAPI是开发WebAPI接口的有利武器,且由于拥有.NETCore的基因支持跨平台,是当前.NET中开发接口的有利武器。但一般来说WebAPI接口开发完毕后,在发布前还需要测......
  • 【Java】ThreadLocal 可以在指定线程内存储数据,只有指定线程可以得到存储数据
     一般事务会用到 ThreadLocal可以保障同一个线程用同一个Connection 可以参考 ThreadLocal是线程的内部存储类,可以在指定线程内存储数据。只有指定线程可以得到存储......
  • 优雅的API接口设计
    前言在实际工作中,我们需要经常跟第三方平台打交道,可能会对接第三方平台API接口,或者提供API接口给第三方平台调用。那么问题来了,如果设计一个优雅的API接口,能够满足:安全......