使用NtCreateThreadEx将Dll注入目标进程

第一遍学习这个注入方法时候,只知道NtCreateThreadEx是未公开的nt函数,当时要定义一个函数指针出来,好像在看雪上找到的这个函数的声明,,太久远了,记不清了。
在Windows2000的源码和Reactos中都无法找到NtCreateThreadEx的函数声明和实现,所以试了下用IDA看看ntdll的导出表,哇,好开心找到了,但是,,好像什么都没有,只有一个系统调用号,没有任何参数的信息。
在这里插入图片描述
我最后在https://securityxploded.com/ntcreatethreadex.php找到了有关这个函数的声明,它是未文档化的。。难顶
废话不多说,对于注入来说,NtCreateThreadEx也是经常用的一种方法,只是这个函数没有被微软文档化,这点比较d疼。接下来说说实现思路,基本和CreateRemoteThread差不多:

  1. 从控制台得到想要实施注入的目标进程名字
  2. 得到当前进程所在的目录,并保存
  3. 得到当前进程的位数
  4. 根据进程名字得到当前进程的Id
  5. 根据进程Id得到当前进程的完整路径
  6. 通过进程完整路径对PE文件解析得到目标进程位数
  7. 目标与当前进程的位数进行匹配,决定加载哪一个dll
  8. 根据当前进程目录,得到dll完整路径
  9. 通过GetModuleHandle得ntdll和kernel32模块得句柄
  10. 通过GetProcAddress分别从ntdll和kernel32中得到NtCreateThreadEx和LoadLibraryA
  11. 通过目标进程Id,打开目标进程,获得进程句柄
  12. 在目标进程中申请内存
  13. 在申请好的内存中写入Dll完整路径
  14. 利用NtCreateThreadEx启动远程线程执行加载Dll,完成注入

以下是代码框架:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//.h
#pragma once
#include<Windows.h>
#include<iostream>
#include<tchar.h>


using namespace std;


//https://securityxploded.com/ntcreatethreadex.php
//Here is the prototype of NtCreateThreadEx function [undocumented]
typedef NTSTATUS(WINAPI* LPFN_NTCREATETHREADEX)(
    OUT PHANDLE ThreadHandle,
    IN ACCESS_MASK DesiredAccess,
    IN LPVOID ObjectAttributes,
    IN HANDLE ProcessHandle,
    IN LPTHREAD_START_ROUTINE ThreadProcedure,
    IN LPVOID ParameterData,
    IN BOOL CreateSuspended,
    IN SIZE_T StackZeroBits,
    IN SIZE_T SizeOfStackCommit,
    IN SIZE_T SizeOfStackReserve,
    OUT LPVOID BytesBuffer);




typedef HMODULE(WINAPI * LPFN_LOADLIBRARYW)(LPCWSTR lpLibFileName);
typedef HMODULE(WINAPI * LPFN_LOADLIBRARYA)(LPCSTR lpLibFileName);


//.cpp
#include"NtCreateThreadEx.h"
#include"Helper.h"




#ifdef UNICODE
LPFN_LOADLIBRARYW __LoadLibrary = NULL;
#else
LPFN_LOADLIBRARYA __LoadLibrary = NULL;
#endif

LPFN_NTCREATETHREADEX __NtCreateThreadEx = NULL;

int _tmain(int argc, TCHAR* argv[], TCHAR *envp[])
{
    //控制台识别中文
    setlocale(LC_ALL, "Chinese-simplified");

    TCHAR ProcessImageName[MAX_PATH] = { 0 };//保存进程名字

    TCHAR CurrentFullPath[MAX_PATH] = { 0 }; //当前进程的完整路径

    TCHAR TargetProcessFullPath[MAX_PATH] = { 0 };//目标进程的完整路径
    ULONG_PTR TargetProcessPathLength = MAX_PATH;

    ULONG ProcessId = 0;//目标进程Id


    HANDLE ProcessHandle = INVALID_HANDLE_VALUE;//进程句柄
    LPVOID VirtualAddress = NULL;

    SIZE_T ReturnLength = 0;

    BOOL  IsOk = FALSE;

    //注入的启动程序和目标程序的位数
    BOOL  SourceIsWow64 = FALSE;
    BOOL  TargetIsWow64 = FALSE;


    _tprintf(_T("输入一个进程ImageName\r\n"));


    TCHAR RcceiveChar = _gettchar();//接受字符串
    int i = 0;//用来偏移ProcessName字符数组
    while (RcceiveChar != '\n')
    {
        ProcessImageName[i++] = RcceiveChar;
        RcceiveChar = _gettchar();

    }
    //ProcessImageName = 0x00000056f16ff2b0 "Taskmgr.exe"

    GetCurrentDirectory(MAX_PATH, CurrentFullPath);//保存当前进程的完整路径

    IsWow64Process(GetCurrentProcess(), &SourceIsWow64);//得到当前进程位数
   
    ProcessId = KtGetProcessIdentify(ProcessImageName);//通过进程名得到进程Id

    if (ProcessId == 0)
    {
        return 0;
    }
    IsOk = KtGetProcessFullPath(TargetProcessFullPath,
        &TargetProcessPathLength, ProcessId, FALSE);
   
    if (IsOk == FALSE)
    {
        return 0;
    }
    //判断目标进程位数
    KtIsWow64Process(TargetProcessFullPath, &TargetIsWow64);
    if (SourceIsWow64 == TRUE && TargetIsWow64 == TRUE)
    {
        _tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
    }
    else if (SourceIsWow64 == FALSE && TargetIsWow64 == FALSE)
    {
        _tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
    }
    //CurrentFullPath = 0x00000056f16ff3e0 "Z:\\Ring3层代码\\[2]Ring3注入\\NtCreateThreadEx\\NtCreateThreadEx\\Dll.dll"

    HMODULE  NtdllModuleBase = NULL;
    HMODULE  Kernel32ModuleBase = NULL;
    NtdllModuleBase = GetModuleHandle(_T("NTDLL.DLL"));
    Kernel32ModuleBase = GetModuleHandle(_T("KERNEL32.DLL"));
    if (NtdllModuleBase == NULL || Kernel32ModuleBase == NULL) {

        KtCloseHandle(ProcessHandle);
        return 0;
    }
    //当前exe模块中没有该函数导入
    __NtCreateThreadEx = (LPFN_NTCREATETHREADEX)GetProcAddress(NtdllModuleBase,
        "NtCreateThreadEx");
    //__NtCreateThreadEx = ntdll.dll!0x00007ffb6580c0e0 (加载符号以获取其他信息)

    if (__NtCreateThreadEx == NULL)
    {
        KtCloseHandle(ProcessHandle);
        return 0;
    }
#ifdef UNICODE
    __LoadLibrary = (LPFN_LOADLIBRARYW)GetProcAddress(Kernel32ModuleBase, "LoadLibraryW");
#else
    __LoadLibrary = (LPFN_LOADLIBRARYA)GetProcAddress(Kernel32ModuleBase, "LoadLibraryA");
#endif
    //__LoadLibrary = kernel32.dll!0x00007ffb63c7e710 (加载符号以获取其他信息)
    if (__LoadLibrary == NULL) {

        KtCloseHandle(ProcessHandle);
        return 0;
    }
    ProcessHandle = KtOpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
    ULONG BufferLength = 0;
    //在目标进程空间中申请内存
    BufferLength = (_tcslen(CurrentFullPath) + 1) * sizeof(TCHAR);
    //目标进程空间中申请内存
    VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE);
    //VirtualAddress = 0x0000021819010000
    if (VirtualAddress == NULL)
    {
        KtCloseHandle(ProcessHandle);
        return 0;
    }
    //目标进程空间中写入数据
    if (KtProcessMemoryWriteSafe(ProcessHandle, VirtualAddress, CurrentFullPath, BufferLength, &ReturnLength) == FALSE)
    {
        KtCloseHandle(ProcessHandle);
        return 0;
    }
    //再目标进程中启动一个线程
    HANDLE ThreadHandle = INVALID_HANDLE_VALUE;
    IsOk = __NtCreateThreadEx(&ThreadHandle,
        THREAD_ALL_ACCESS, NULL, ProcessHandle, (LPTHREAD_START_ROUTINE)__LoadLibrary, VirtualAddress,
        FALSE, NULL, NULL, NULL, NULL);
    if (IsOk < 0)
    {


        VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
        KtCloseHandle(ProcessHandle);
        return 0;
    }

    else
    {
        WaitForSingleObject(ThreadHandle, INFINITE);
        VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
        KtCloseHandle(ProcessHandle);
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//.dllmain
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <tchar.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        MessageBox(NULL, _T("NtCreateThreadEx"), _T("NtCreateThreadEx"), NULL);
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

Win7(32)注入Explorer和Win10注入Taskmgr.exe(64)两个都测试通过,32和64都没问题
在这里插入图片描述
在这里插入图片描述
今日份头秃:为什么我的Win7(32)调用系统函数IsWow64Process返回的当前程序位数是64位???我醉了。。。。
今日份古诗分享:
“蓬头稚子学垂纶,侧坐莓苔草映身。”
这小孩真挺可爱的,蓬头稚子,哈哈哈哈。。