吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2264|回复: 6
上一主题 下一主题
收起左侧

[系统底层] win32笔记七 线程控制

  [复制链接]
跳转到指定楼层
楼主
huchen 发表于 2024-4-22 00:36 回帖奖励
本帖最后由 huchen 于 2024-4-22 00:38 编辑

之前的索引

线程控制

控制一个线程,就要用到其他的API,所以本章就说说那些常用的控制线程的部分API

让自己停下来(本线程):

Sleep

VOID Sleep(
  DWORD dwMilliseconds   // sleep time
);

让线程停止多少毫秒


让别人停下来(其他线程):

SuspendThread

DWORD SuspendThread(
  HANDLE hThread   // handle to thread
);

让线程变成挂起状态,挂起状态的计数器+1


线程恢复

ResumeThread

DWORD ResumeThread(
  HANDLE hThread   // handle to thread
);

让线程恢复执行的状态,挂起状态的计数器-1

代码实验

#include<stdio.h>
#include<Windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(500);
                printf("+++++++++++++++%d\n", i);
        }
        return 0;
}

int main()
{

        HANDLE hThread;
        hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

        Sleep(5000);  //停下5秒
        SuspendThread(hThread);
        Sleep(5000);
        ResumeThread(hThread);

        getchar();                //让控制台显示输出
        CloseHandle(hThread);
        return 0;

}

这里用的在按个线程用的Sleep就停的那个线程,别搞混了

然后继续,每当线程执行完毕,我怎么知道这个线程执行完毕了?

新的API来啦

WaitForSingleObject

DWORD WaitForSingleObject(
  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds   // time-out interval
);

他会阻塞你给的线程,什么时候停止呢?当他判断该线程变更的时候,即线程执行完毕了,就会返回,继续向下执行

这里你可以设置时间,第二个参数就是,超过设定的时间,他也会返回

如果想让他一直等待,给他个宏:INFINITE

实验

#include<stdio.h>
#include<Windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }
        return 0;
}

int main()
{

        HANDLE hThread;
        hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

        WaitForSingleObject(hThread,INFINITE);
        printf("线程执行完毕\n");

        getchar();
        CloseHandle(hThread);
        return 0;
}

会发现会一直等待线程执行完才打印执行完毕

这个函数只能等待某一个内核对象的状态发生变更,如果我有两个线程,我要想让两个线程都做完了,才打印,那么又来啦,新API

WaitForMultipleObjects

DWORD WaitForMultipleObjects(
  DWORD nCount,             // number of handles in array
  CONST HANDLE *lpHandles,  // object-handle array
  BOOL fWaitAll,            // wait option
  DWORD dwMilliseconds      // time-out interval
);
  • 第一个参数:你要等几个内核对象
  • 第二个参数:内核对象的数组
  • 第三个参数:等待模式,可以指定所有的等待对象都发生变更才返回即为TRUE,也可以任意一个对象发生变更就返回即为FALSE
  • 第四个参数:等待时间
实验
#include<stdio.h>
#include<Windows.h>

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }
        return 0;
}

int main()
{
        HANDLE hThread[2];
        hThread[0] = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
        hThread[1] = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);

        WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
        printf("线程执行完毕\n");

        getchar();
        CloseHandle(hThread);
        return 0;
}

也是能成功执行


这次来细嗦CreateThread函数的返回值

这个函数值可以自己设置,比如创建成功返回一个值,失败一个值,那么就可以用下面的API来接收

GetExitCodeThread

BOOL GetExitCodeThread(
  HANDLE hThread,      // handle to the thread
  LPDWORD lpExitCode   // termination status
);

第一个句柄,第二个就是返回值了,是个out参数

代码

#include<stdio.h>
#include<Windows.h>

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }
        return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }
        return 1;
}

int main()
{
        DWORD dwre1;
        DWORD dwre2;
        HANDLE hThread[2];
        hThread[0] = CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
        hThread[1] = CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);

        GetExitCodeThread(hThread[0],&dwre1);
        GetExitCodeThread(hThread[1],&dwre2);

        getchar();
        CloseHandle(hThread[0]);
        CloseHandle(hThread[1]);
        return 0;
}

我们都说如果只有一个核的时候怎么切换线程,那里面的信息怎么保存呢,总不可能不回来吧。

每一个线程都有结构体,当自己被切换的时候,就会把自己运行的信息存储到该结构体

CONTEXT

俗称:线程上下文,点F12,就可以看到是 一堆寄存器

要获取这些信息要先把他挂起

#include<stdio.h>
#include<Windows.h>

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
        /*
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }*/
        return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
        for (int i = 0 ; i < 100; i++)
        {
                Sleep(50);
                printf("+++++++++++++++%d\n", i);
        }
        return 1;
}

int main()
{
        HANDLE hThread[2];
        hThread[0] = CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);
        //hThread[1] = CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);

        SuspendThread(hThread[0]);
        CONTEXT context;
        context.ContextFlags = CONTEXT_INTEGER;
        GetThreadContext(hThread[0],&context);
        printf("%x %x\n",context.Eax,context.Ecx);
        ResumeThread(hThread[0]);

        getchar();
        CloseHandle(hThread[0]);
        CloseHandle(hThread[1]);
        return 0;
}

由于寄存器较多,需要设置一下flag,如图

这里我去调试了一下,发现与调试显示的并不是一样的,请大佬解释一下

获取线程上下文:

GetThreadContext

BOOL GetThreadContext(
  HANDLE hThread,       // handle to thread with context
  LPCONTEXT lpContext   // context structure
);

设置线程上下文

SetThreadContext

BOOL SetThreadContext(
  HANDLE hThread,            // handle to thread
  CONST CONTEXT *lpContext   // context structure
);

总结


各种的API函数的使用

免费评分

参与人数 3吾爱币 +8 热心值 +3 收起 理由
allspark + 1 + 1 用心讨论,共获提升!
Issacclark1 + 1 谢谢@Thanks!
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
MJ_B 发表于 2024-4-22 15:43
本帖最后由 MJ_B 于 2024-4-22 16:22 编辑

是一样的,你不一样有可能是还没执行到自己程序位置,最好加上eip,我的是64,你32改下。
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <Windows.h>

DWORD WINAPI ThreadProc2(LPVOID lpParameter) {
    for (int i = 0; 1; i++) {
    }
    return 1;
}

int main() {
    HANDLE hThread[2];
    hThread[0] = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

    Sleep(1000);
    SuspendThread(hThread[0]);
    CONTEXT context = {0};
    context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
    GetThreadContext(hThread[0], &context);
    printf("%llX\n", &ThreadProc2);
    printf("%llX,%llX,%llX\n", context.Rax, context.Rsp, context.Rip);
    ResumeThread(hThread[0]);

    getchar();
    CloseHandle(hThread[0]);
    return 0;
}

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
zyz1z1 + 1 + 1 感谢!
huchen + 1 + 1 用心讨论,共获提升!

查看全部评分

沙发
b0y 发表于 2024-4-22 07:36
挂起/恢复线程的api微软不是不建议使用了吗,有没有新的api实现
3#
hesqiang 发表于 2024-4-22 09:41
5#
QinHanHan 发表于 2024-4-23 08:39
支持一下
6#
 楼主| huchen 发表于 2024-4-23 11:02 |楼主
MJ_B 发表于 2024-4-22 15:43
是一样的,你不一样有可能是还没执行到自己程序位置,最好加上eip,我的是64,你32改下。
[mw_shl_code=cp ...

我去看了下,确实,我以为的是取当前的值,但是发现只是把堆栈的值赋给寄存器,然后在入栈,然后在打印,并且按照你说把eip给弄上去了,但是eip输出的值却有点奇特,是77A45170,这是啥情况啊
7#
MJ_B 发表于 2024-4-23 11:27
huchen 发表于 2024-4-23 11:02
我去看了下,确实,我以为的是取当前的值,但是发现只是把堆栈的值赋给寄存器,然后在入栈,然后在打印, ...

你threadproc里面有调用其他方法吗?
不要调用其他函数,比如sleep,printf(这个特殊点,会卡),调用其他函数会进入相应的dll地址。
所以我用了死循环。
[C] 纯文本查看 复制代码
DWORD WINAPI ThreadProc2(LPVOID lpParameter) {
    for (int i = 0; 1; i++) {
    }
    return 1;
}
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 16:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表