首页
社区
课程
招聘
11
[原创]CreateRemoteThread和CreateThread 流程逆向分析从R3到R0
发表于: 2022-2-3 22:15 18795

[原创]CreateRemoteThread和CreateThread 流程逆向分析从R3到R0

2022-2-3 22:15
18795

目录

分析目标:

  1、分析Win10 64位CreateRemoteThread具体流程。
  2、分析为什么无法直接在系统进程中创建远程线程。


一、函数调用流程概述

通过分析整个函数调用流程可以得到这么几个结果:
  1、创建远程线程和普通线程没有本质的区别,其调用的函数都是相同的,唯一的区别就是在进程句柄上,进程句柄为-1是创建普通线程。调用的函数根据这个区别就可以对两种线程分别处理了。
  2、在用户模式下执行的代码主要还是为了在进入内核模式前准备所需的各种信息参数。在内核模式中的代码最为重要,是完成线程创建的关键代码。
  3、在CreateRemoteThead调用的整个流程中没有对系统进程进行权限的检查,所以可以认为权限检查的关键代码在OpenProcess中。如果需要在系统进程中创建远程线程就必须在获取进程句柄前进行提权处理。提权方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//在OpenProcess前调用即可
BOOL KtSetDebugPrivilege(HANDLE ProcessHandle, BOOL IsEnable)
{
    DWORD  LastError = 0;
    HANDLE TokenHandle = 0;
 
    if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
    {
        LastError = GetLastError();
        if (TokenHandle)
        {
            CloseHandle(TokenHandle);
        }
        return LastError;
    }
    TOKEN_PRIVILEGES TokenPrivileges;
    memset(&TokenPrivileges, 0, sizeof(TOKEN_PRIVILEGES));
    LUID v1;//权限类型,本地独有标识
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &v1))
    {
        LastError = GetLastError();
        CloseHandle(TokenHandle);
        return LastError;
    }
    TokenPrivileges.PrivilegeCount = 1;
    TokenPrivileges.Privileges[0].Luid = v1;
    if (IsEnable)
    {
        TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    }
    else
    {
        TokenPrivileges.Privileges[0].Attributes = 0;
    }
    AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
    LastError = GetLastError();
    CloseHandle(TokenHandle);
    return LastError;
}


 

二、函数分析详细报告:

1、用户模式Ring3:

函数调用流程分析:

  通过WinDbg查看函数CreateRemoteThead在用户模式下的调用流程,观察这个调用情况可以确定在用户模式下,这个函数涉及到了三个dll模块(KERNEL32、KERNELBASE、ntdll)。而CreateRemoteThead这个API在KERNEL32模块中真正的函数名是CreateRemoteThreadStub,通过这个KERNEL32中的CreateRemoteThreadStubAPI将参数转发到KERNELBASE模块中的CreateRemoteThreadEx中,然后在KERNELBASE中调用ntdll模块中的NtCreateThreadExAPI,进入内核。待内核处理结束后获取返回值,进行返回值的处理并返回结果。

 

流程图1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
0:000> wt
Tracing KERNEL32!CreateRemoteThreadStub to return address 00007ff7`3f741220
   11     0 0] KERNEL32!CreateRemoteThreadStub
   32     0 1]   KERNELBASE!CreateRemoteThreadEx
   25     0 2]     KERNELBASE!BaseFormatObjectAttributes
   67    25 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     ntdll!NtDuplicateObject
>> More than one level popped 1 -> 1
   77    31 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     ntdll!NtQueryInformationProcess
>> More than one level popped 1 -> 1
   94    37 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     ntdll!NtQueryInformationProcess
>> More than one level popped 1 -> 1
  139    43 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     ntdll!NtCreateThreadEx
>> More than one level popped 1 -> 1
  158    49 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     ntdll!NtClose
>> More than one level popped 1 -> 1
  167    55 1]   KERNELBASE!CreateRemoteThreadEx
    6     0 2]     KERNELBASE!_security_check_cookie
  174    61 1]   KERNELBASE!CreateRemoteThreadEx
   14   235 0] KERNEL32!CreateRemoteThreadStub
 
249 instructions were executed in 248 events (0 from other threads)
 
Function Name                               Invocations MinInst MaxInst AvgInst
KERNEL32!CreateRemoteThreadStub                       1      14      14      14
KERNELBASE!BaseFormatObjectAttributes                 1      25      25      25
KERNELBASE!CreateRemoteThreadEx                       1     174     174     174
KERNELBASE!_security_check_cookie                     1       6       6       6
ntdll!NtClose                                         1       6       6       6
ntdll!NtCreateThreadEx                                1       6       6       6
ntdll!NtDuplicateObject                               1       6       6       6
ntdll!NtQueryInformationProcess                       2       6       6       6
 
5 system calls were executed
 
Calls  System Call
    1  ntdll!NtClose
    1  ntdll!NtCreateThreadEx
    1  ntdll!NtDuplicateObject
    2  ntdll!NtQueryInformationProcess


KERNEL32模块分析:

  用户调用CreateRemoteThreadAPI后,会进入KERNEL32模块中的CreateRemoteThreadStub,参数相同,而CreateRemoteThreadStub则会对CreateRemoteThread的参数进行一些处理,由原来的7个参数扩展到了8个参数,并且对dwCreationFlags参数进行了一些安全处理,规避了系统规定参数外的无效参数。然后将参数转发到KERNELBASE模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.text:000000018003AB20 ; HANDLE __stdcall CreateRemoteThreadStub(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
.text:000000018003AB20                 public CreateRemoteThreadStub
.text:000000018003AB20 CreateRemoteThreadStub proc near        ; DATA XREF: .rdata:0000000180085477↓o
.text:000000018003AB20                                         ; .rdata:off_18009A208↓o ...
.text:000000018003AB20
.text:000000018003AB20 lpParameter     = qword ptr  28h
.text:000000018003AB20 dwCreationFlags = dword ptr  30h
.text:000000018003AB20 lpThreadId      = qword ptr  38h
.text:000000018003AB20
.text:000000018003AB20                 mov     r11, rsp            ; r11存储原来的rsp用来传参
.text:000000018003AB23                 sub     rsp, 48h            ; 栈抬高,用来存储参数
.text:000000018003AB27                 mov     r10d, [rsp+48h+dwCreationFlags]   
.text:000000018003AB2C                 mov     rax, [rsp+48h+lpThreadId]
.text:000000018003AB34                 and     r10d, 10004h   
.text:000000018003AB3B                 mov     [r11-10h], rax            ;    参数8 = lpThreadId
.text:000000018003AB3F                 and     qword ptr [r11-18h], 0    ;    参数7(扩展参数) = 0
.text:000000018003AB44                 mov     rax, [rsp+48h+lpParameter]
.text:000000018003AB49                 mov     [r11-20h], r10d            ;    参数6 = dwCreationFlags & 0x10004h
.text:000000018003AB4D                 mov     [r11-28h], rax            ;    参数5 = lpParameter
.text:000000018003AB51                 call    cs:__imp_CreateRemoteThreadEx
.text:000000018003AB58                 nop     dword ptr [rax+rax+00h]
.text:000000018003AB5D                 add     rsp, 48h
.text:000000018003AB61                 retn
.text:000000018003AB61 ; ---------------------------------------------------------------------------
.text:000000018003AB62                 db 0CCh
.text:000000018003AB62 CreateRemoteThreadStub endp


KERNELBASE模块分析:

  这个API主要是为了给内核模式准备所需的参数的,所以这是执行CreateRemoteThread在用户模式下的最后一个API,然后就会调用ntdll模块中的NtCreateThreadEx进入内核模式执行内核代码,待内核代码执行完成后,将执行结果返回给用户模式,CreateRemoteThread就会获取执行结果,并将结果处理完毕后一层一层的返回给调用者。

函数流程图:

流程图3

函数分析:


[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

上传的附件:
收藏
免费 11
支持
分享
赞赏记录
参与人
雪币
留言
时间
心游尘世外
感谢你的贡献,论坛因你而更加精彩!
2024-11-5 04:24
伟叔叔
为你点赞~
2023-3-18 04:12
户大
为你点赞~
2022-10-10 20:22
mb_dgsueauw
为你点赞~
2022-9-14 16:29
PLEBFE
为你点赞~
2022-7-27 23:49
0x指纹
为你点赞~
2022-3-24 14:46
龙隐王台
为你点赞~
2022-2-9 23:31
mb_rvtoawdm
为你点赞~
2022-2-7 23:30
风中小筑V
为你点赞~
2022-2-6 15:49
旺仔_小可爱
为你点赞~
2022-2-5 14:52
youxiaxy
为你点赞~
2022-2-4 18:05
最新回复 (8)
雪    币: 2054
活跃值: (1881)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

虽然搞有些小游戏的辅助的时候经常createremoteThread(-1,xxxxxx)不过还真没细究过内部的实现。涨知识了。感谢分享

最后于 2022-2-4 18:05 被youxiaxy编辑 ,原因:
2022-2-4 18:04
1
雪    币: 4164
活跃值: (1545)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
-1是一个预定义的伪句柄,代表当前进程的句柄,常用宏函数NtCurrentProcess()和win32 api函数GetCurrentProcess()来引用它。类似的还有GetCurrentThread()等
2022-2-6 02:09
1
雪    币: 53
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
问一下,是科锐的线下班吗?
2022-2-25 10:27
0
雪    币: 129
活跃值: (333)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xed
5
不错,。标记一下~~~
2022-3-22 20:17
0
雪    币: 1989
活跃值: (4245)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好,mark
2022-3-22 21:00
0
雪    币: 2262
活跃值: (5431)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
感谢po主,不过有些错误,有少量误导人的注释
2022-9-5 15:06
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
可以关注下 CR3 的变化 线程在哪使用主要取决于CR3 看看 线程创建的时候用的是 当前进程的CR3 还是 目标进程的CR3 
2022-10-8 13:44
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
创建线程的精髓就在PspCreateThread里面,你却一笔带过了
2022-11-28 16:17
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册