一.资料检索以及归纳
-
XDBG调试时默认是只运行下断调试的线程 其它线程处于暂停挂起状态属于单线程调试。打开线程窗口可以查看线程挂起计数(+号 -号快捷键可以挂起恢复线程)双击线程可进入选择线程,如果要调试指定线程的话我的理解是应该在线程代码中下断(线程的各种系统 CALL),线程会自己断下。CE调试时是不挂起其它线程的。
-
c当中创建新线程的函数为:CreateThread函数,下面是具体例子
#include <windows.h> #include <stdio.h> // 线程函数 DWORD WINAPI ThreadFunc(LPVOID lpParam) { printf("Hello, World from new thread! "); return 0; } int main() { HANDLE hThread; // 线程句柄 DWORD dwThreadId; // 线程ID // 创建线程 hThread = CreateThread( NULL, // default security attributes 0, // use default stack size ThreadFunc, // thread function name NULL, // argument to thread function 0, // use default creation flags &dwThreadId); // returns the thread identifier if (hThread == NULL) { printf("CreateThread failed, error %d ", GetLastError()); return 1; } // 等待线程结束 WaitForSingleObject(hThread, INFINITE); // 关闭线程句柄 CloseHandle(hThread); return 0; }
-
TEB (Thread Environment Block) 是 Windows 操作系统中的一个数据结构,用于存储线程本地存储的数据。每个线程都有自己的 TEB,包含了该线程所需的所有变量和函数调用的上下文信息。
typedef struct _TEB { PVOID Reserved1[12]; PPEB ProcessEnvironmentBlock;//重点关注该指针的内容 PVOID Reserved2[399]; BYTE Reserved3[1952]; PVOID TlsSlots[64]; BYTE Reserved4[8]; PVOID Reserved5[26]; PVOID ReservedForOle; PVOID Reserved6[4]; PVOID TlsExpansionSlots; } TEB, *PTEB; Reserved1: 保留字段,不能被使用。 ProcessEnvironmentBlock: 指向当前进程的环境块的指针,包含有关进程环境的信息。 Reserved2: 保留字段,不能被使用。 Reserved3: 保留字段,不能被使用。 TlsSlots: 指向线程本地存储(TLS)中的插槽数组的指针,每个插槽用于存储一个特定的变量或数据结构。 Reserved4: 保留字段,不能被使用。 Reserved5: 保留字段,不能被使用。 ReservedForOle: 保留字段,不能被使用。 Reserved6: 保留字段,不能被使用。 TlsExpansionSlots: 指向线程本地存储扩展槽的指针,用于支持扩展属性
-
多线程执行的时候线程的执行顺序是不确定的,这是由操作系统决定,线程的优先级只是决定CPU分配给该线程时间片的多少,不决定执行次序,优先级低的线程可能先执行。
二.思考记录
-
在xdbg当中可以通过查看线程窗口查看有关的线程内容,里面的线程有关信息。
-
找到创建进程的函数调用处,使用F8单步步过,然后过一段时间就可以在线程窗口找到该线程的有关信息。
-
针对多线程可以通过一个信号量实现多线程之间的同步,确保线程之间的执行顺序。
例如:
这里就是典型的通过全局变量dword_409804来判断应该执行哪个线程,当某个线程执行时先判断全局变量是否正确,如果不正确则sleep,等到下次cpu调用该线程时再判断是否相等,如果相等则执行。这个时候多线程就可以看成是一个线程。
//线程1 while ( dword_409804 != 1 ) { Sleep(0x1F4u); sub_4015E0(); } ... dword_409804 = 2; //线程2 while ( dword_409804 != 2 ) Sleep(0x1F4u); dword_409804n = 3;
-
多线程情况下,在创建了一个线程后,该线程会根据操作系统的调度自动执行,所以如果要分析不同线程的代码,那么就应该确定该线程执行的代码块,然后在该代码块处下断点分析,当该线程执行的时候,就可以停下来动态分析,所以最好还是先静态调试分析代码,然后再考虑应该如何动态分析。