HideProcess

本文最后更新于:1 年前

Dll注入方式:远程线程注入 CreateRemoteThread()
该程序主要核心为InstallInlineHook_x86()和InstallInlineHook_x64()两个函数
同时由于不同操作系统下,两个函数的实现方式不同

x86位系统下,实现流程为:

​ 1)借助ntdll.dll模块句柄获取NtQuerySystemInformation的函数地址OriginalAddress 该函数可以遍历进程信息 属于任务管理器的一大特征函数
​ 2)申请虚拟内存地址 一个跳板地址TrampolineAddress 若VirtualAlloc第一个参数为NULL,分配的内存必以64K的整数倍为内存起始地址,哪怕你只分配一个字节
​ 3)将获取的NtQuerySystemInformation的函数的前五个指令拷贝到shellcode中
​ 4)获取OriginalAddress到TrampolineAddress的偏移值,并将该偏移写入shellcode中E9指令后面,用作跳转
​ 5)将shellcode写入跳板地址处
​ 6)将跳板地址定义为白名单地址
​ 7)计算我们注入DLL中的函数FakeNtQuerySystemInformation到NtQuerySystemInformation的偏移 赋给一片带有E9指令的缓冲区后,用作跳转指令
​ 8)将该跳转指令覆盖源函数的前五个字节

x64位系统下,实现流程为:

​ 1)shellcode中的不使用E9跳转指令 而转用FF 25指令 因为E9指令后跟的偏移为4bytes在64位下,可能放不下 所以用FF 25 + 绝对地址的形式
​ 2)获取模块句柄和函数地址等方法与x86类似
​ 3)主要区别在于shellcode的编写
​ 4)为跳板地址分配内存时,需要注意需要可以容纳一个绝对地址 的PAGE 4k(4096B)
​ 5)将注入Dll的函数的绝对地址写入shellcode

两个项目
1.Dll
2.HideProcess

1.Dll
1)DllMain.h
2)DllMain.cpp

1)DllMain.h

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
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;

#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT_64
#else
#define ENVIRONMENT_32
#endif
#endif

typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation,
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation,
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemNextEventIdInformation,
SystemEventIdsInformation,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemPlugPlayBusInformation,
SystemDockInformation,
SystemProcessorSpeedInformation,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation
} SYSTEM_INFORMATION_CLASS;

#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)


typedef struct UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;

typedef LONG KPRIORITY;

typedef struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER WorkingSetPrivateSize; //VISTA
ULONG HardFaultCount; //WIN7
ULONG NumberOfThreadsHighWatermark; //WIN7
ULONGLONG CycleTime; //WIN7
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
//
// This part corresponds to VM_COUNTERS_EX.
// NOTE: *NOT* THE SAME AS VM_COUNTERS!
//
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;

//
// This part corresponds to IO_COUNTERS
//
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
// SYSTEM_THREAD_INFORMATION TH[1];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;


//定义的函数指针
typedef NTSTATUS(_stdcall *LPFN_NTQUERYSYSTEMINFORMATIONORIGINALDEF)(SYSTEM_INFORMATION_CLASS
SystemInformationClass, PVOID SystemInformation, SIZE_T SystemInformationLength, PSIZE_T ReturnLength);


NTSTATUS _stdcall FakeNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation, SIZE_T SystemInformationLength, PSIZE_T ReturnLength);

PVOID Allocate2GBRange(UINT_PTR VirtualAddress, SIZE_T ViewSize);



#if defined(ENVIRONMENT_32)
void InstallInlineHook_x86();
#endif
#if defined(ENVIRONMENT_64)
void InstallInlineHook_x64();
#endif

2)DllMain.cpp

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
#include "DllMain.h"

LPFN_NTQUERYSYSTEMINFORMATIONORIGINALDEF __WhiteListAddrss; //白名单地址


BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpvReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{

HMODULE ModuleHandle = GetModuleHandle(_T("ntdll.dll"));
LPVOID OriginalAddress = GetProcAddress(ModuleHandle, "NtQuerySystemInformation");
TCHAR BufferData[0x1000] = { 0 };
_stprintf(BufferData, _T("0x%p"), OriginalAddress);

MessageBox(NULL, BufferData, _T("DLL_PROCESS_ATTACH"), NULL);
#if defined(ENVIRONMENT_32)
InstallInlineHook_x86();
#endif
#if defined(ENVIRONMENT_64)
InstallInlineHook_x64();
#endif
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
{

//指令恢复

}
break;

}

return TRUE;
}


void InstallInlineHook_x86()
{
BYTE v1[10] = { 0, 0, 0, 0, 0, 0xE9, 0, 0, 0, 0 }; //ShellCode
BYTE v2[5] = { 0xE9, 0, 0, 0, 0 }; //覆盖源函数的前5个字节指令
HMODULE ModuleHandle = GetModuleHandle(_T("ntdll.dll"));
LPVOID OriginalAddress = GetProcAddress(ModuleHandle, "NtQuerySystemInformation");

LPVOID TrampolineAddress = VirtualAlloc(NULL, 10, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

memcpy(v1, OriginalAddress, 5);
// Offset = OriginalAddress + 5 - TrampolineAddress + 5 - 5

*(DWORD*)(v1 + 6) = (DWORD)OriginalAddress - (DWORD)TrampolineAddress - 5; //仔细审题

memcpy(TrampolineAddress, v1, 10);

__WhiteListAddrss = (LPFN_NTQUERYSYSTEMINFORMATIONORIGINALDEF)TrampolineAddress;

*(DWORD*)&v2[1] = (DWORD)FakeNtQuerySystemInformation - (DWORD)OriginalAddress - 5;

//将v2中的字节指令覆盖到源函数前5个字节处
BOOL IsOk = WriteProcessMemory(GetCurrentProcess(), OriginalAddress, v2, sizeof(v2), NULL);
}
void InstallInlineHook_x64()
{
//e9 Offset(4Bytes)
//FF 25 0 0 0 0 绝对地址
BYTE v1[14] = { 0xFF, 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //2 + 4 + 8 跳转至Fake函数
BYTE v2[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0xE9, 0, 0, 0, 0 }; //中间有3个零注意 是由于该函数内部存在 特定问题特殊分析
/*

0:023> u ZwQuerySystemInformation
ntdll!ZwQuerySystemInformation:
00007ffb`b29cd770 4c8bd1 mov r10,rcx
00007ffb`b29cd773 b836000000 mov eax,36h //中间有3个零注意
*/
BYTE v3[5] = { 0xE9, 0, 0, 0, 0 };

HMODULE ModuleHandle = GetModuleHandle(_T("ntdll.dll"));
LPVOID OriginalAddress = GetProcAddress(ModuleHandle, "NtQuerySystemInformation");

LPVOID TrampolineAddress = Allocate2GBRange((ULONG_PTR)OriginalAddress, 27); //跳板地址

*(__int64*)&v1[6] = (__int64)FakeNtQuerySystemInformation;
memcpy(TrampolineAddress, v1, 14);
memcpy(v2, OriginalAddress, 5);
//TrampolineAddress + 15 + 5 + 5 + Offset = OriginalAddress + 5

*(DWORD*)(v2 + 9) = (DWORD)OriginalAddress - 15 - (DWORD)TrampolineAddress - 5;
memcpy((LPVOID)((__int64)TrampolineAddress + 15), v2, 13);

__WhiteListAddrss = (LPFN_NTQUERYSYSTEMINFORMATIONORIGINALDEF) ((__int64)TrampolineAddress + (__int64)15);

*(DWORD*)&v3[1] = (DWORD)TrampolineAddress - (DWORD)OriginalAddress - 5;
BOOL IsOk = WriteProcessMemory(GetCurrentProcess(), OriginalAddress, v3, sizeof(v3), NULL);
}
PVOID Allocate2GBRange(UINT_PTR VirtualAddress, SIZE_T ViewSize)
{
static ULONG AllocationGranularity;
if (!AllocationGranularity)
{
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
AllocationGranularity = SystemInfo.dwAllocationGranularity;
}

UINT_PTR Min, Max, v1, v2 = AllocationGranularity - 1, Mask = ~v2;

Min = VirtualAddress >= 0x80000000 ? (VirtualAddress - 0x80000000 + v2) & Mask : 0;
Max = VirtualAddress < (UINTPTR_MAX - 0x80000000) ? (VirtualAddress + 0x80000000) & Mask : UINTPTR_MAX;

MEMORY_BASIC_INFORMATION MemoryBasicInfo;
do
{
if (!VirtualQuery((void*)Min, &MemoryBasicInfo, sizeof(MemoryBasicInfo))) return NULL;

Min = (UINT_PTR)MemoryBasicInfo.BaseAddress + MemoryBasicInfo.RegionSize;

if (MemoryBasicInfo.State == MEM_FREE)
{
v1 = ((UINT_PTR)MemoryBasicInfo.BaseAddress + v2) & Mask;

if (v1 < Min && ViewSize <= (Min - v1))
{
if (v1 = (UINT_PTR)VirtualAlloc((PVOID)v1, ViewSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))
return (PVOID)v1;
}
}
} while (Min < Max);

return NULL;

}

NTSTATUS _stdcall FakeNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, SIZE_T SystemInformationLength, PSIZE_T ReturnLength)
{
NTSTATUS Status;
PSYSTEM_PROCESS_INFORMATION v1 = NULL;
PSYSTEM_PROCESS_INFORMATION v2 = NULL;

//先调用源函数获取枚举信息
Status = __WhiteListAddrss(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);

if (NT_SUCCESS(Status) && SystemInformationClass == SystemProcessInformation) //判读是否是由于枚举进程信息了
{

v1 = (PSYSTEM_PROCESS_INFORMATION)SystemInformation; //枚举到的信息在该成员中
v2 = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)v1 + v1->NextEntryOffset);

while (v2->NextEntryOffset != 0)
{
if (lstrcmpW((&v2->ImageName)->Buffer, L"explorer.exe") == 0)
{
v1->NextEntryOffset += v2->NextEntryOffset;
}
v1 = v2;
v2 = (PSYSTEM_PROCESS_INFORMATION)((PBYTE)v1 + v1->NextEntryOffset);
}
}

//放行数据
return Status;
}

2.HideProcess
1)_tmain.h

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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#pragma once
#include <Windows.h>
#include <tchar.h>
#include <iostream>
#include <tlhelp32.h>
using namespace std;

BOOL SeEnableSeDebugPrivilege(IN const TCHAR* PriviledgeName, BOOL IsEnable);
BOOL SeInjectDll(DWORD ProcessIdentify, LPCTSTR DllPath);
BOOL SeEjectDll(DWORD ProcessIdentify, LPCTSTR DllPath);
BOOL SeGetProcessIdentify(HANDLE* ProcessIdentify,
ULONG_PTR ProcessIdentifyLength, const TCHAR* ImageName, ULONG_PTR ImageNameLength);

2)_tmain.cpp
#include "_tmain.h"


int _tmain(int argc, TCHAR* argv[])
{

SeEnableSeDebugPrivilege(SE_DEBUG_NAME, TRUE);

HANDLE ProcessIdentify = 0;

TCHAR ImageName[MAX_PATH] = { _T("Taskmgr.exe") };

SeGetProcessIdentify((PHANDLE)&ProcessIdentify, sizeof(HANDLE),
ImageName, MAX_PATH * sizeof(TCHAR));

TCHAR DllFullPath[MAX_PATH] = { 0 };
GetCurrentDirectory(MAX_PATH, DllFullPath);

_tcscat_s(DllFullPath, _T("\\Dll.dll"));

SeInjectDll((DWORD)ProcessIdentify, DllFullPath);

_tprintf(_T("Input AnyKey To Exit\r\n"));
_gettchar();
SeEjectDll((DWORD)ProcessIdentify, DllFullPath);

return 0;
}

BOOL SeEnableSeDebugPrivilege(IN const TCHAR* PriviledgeName, BOOL IsEnable)
{
// 打开权限令牌
HANDLE ProcessHandle = GetCurrentProcess();
HANDLE TokenHandle = NULL;
TOKEN_PRIVILEGES TokenPrivileges = { 0 };
if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
return FALSE;
}
LUOID v1;
if (!LookupPrivilegeValue(NULL, PriviledgeName, &v1))
{
CloseHandle(TokenHandle);
TokenHandle = NULL;
return FALSE;
}

TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0;
TokenPrivileges.Privileges[0].Luid = v1;

if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges,
sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
_tprintf(_T("LastError:%d\r\n"), GetLastError());
CloseHandle(TokenHandle);
TokenHandle = NULL;
return FALSE;
}
CloseHandle(TokenHandle);
TokenHandle = NULL;
return TRUE;

}
BOOL SeInjectDll(DWORD ProcessIdentify, LPCTSTR DllPath)
{
HANDLE ProcessHandle, ThreadHandle;
LPVOID VirtualAddress;
DWORD ViewSize = (DWORD)(_tcslen(DllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE ThreadStartRoutine = NULL;

if (!(ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessIdentify)))
{
DWORD LastError = GetLastError();
return FALSE;
}

VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, ViewSize, MEM_COMMIT, PAGE_READWRITE);

WriteProcessMemory(ProcessHandle, VirtualAddress, (LPVOID)DllPath, ViewSize, NULL);

ThreadStartRoutine = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryW");

ThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 0, ThreadStartRoutine, VirtualAddress, 0, NULL);

WaitForSingleObject(ThreadHandle, INFINITE);

CloseHandle(ThreadHandle);

CloseHandle(ProcessHandle);

return TRUE;
}
BOOL SeEjectDll(DWORD ProcessIdentify, LPCTSTR DllPath)
{
BOOL IsOk = FALSE, IsFound = FALSE;
HANDLE SnapshotHandle, ProcessHandle, ThreadHandle;
MODULEENTRY32 ModuleEntry32 = { sizeof(ModuleEntry32) };
LPTHREAD_START_ROUTINE ThreadStartRoutine = NULL;

if (INVALID_HANDLE_VALUE == (SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessIdentify)))
return FALSE;

IsOk = Module32First(SnapshotHandle, &ModuleEntry32);
for (; IsOk; IsOk = Module32Next(SnapshotHandle, &ModuleEntry32))
{
if (!_tcsicmp(ModuleEntry32.szModule, DllPath) || !_tcsicmp(ModuleEntry32.szExePath, DllPath))
{
IsFound = TRUE;
break;
}
}

if (!IsFound)
{
CloseHandle(SnapshotHandle);
return FALSE;
}

if (!(ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessIdentify)))
{
CloseHandle(SnapshotHandle);
return FALSE;
}

ThreadStartRoutine = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibrary");

ThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 0, ThreadStartRoutine, ModuleEntry32.modBaseAddr, 0, NULL);

WaitForSingleObject(ThreadHandle, INFINITE);

CloseHandle(ThreadHandle);
CloseHandle(ProcessHandle);
CloseHandle(SnapshotHandle);

return TRUE;

}
BOOL SeGetProcessIdentify(HANDLE* ProcessIdentify,
ULONG_PTR ProcessIdentifyLength, const TCHAR* ImageName, ULONG_PTR ImageNameLength)
{
BOOL IsOk = FALSE;
HANDLE SnapshotHandle = INVALID_HANDLE_VALUE;
PROCESSENTRY32 ProcessEntry32;
ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);
int LastError = 0;
if (IsBadWritePtr(ProcessIdentify, ProcessIdentifyLength) ||
IsBadReadPtr(ImageName, ImageNameLength))
{

LastError = ERROR_INVALID_PARAMETER;
goto Exit;
}
SnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (SnapshotHandle == INVALID_HANDLE_VALUE)
{
LastError = GetLastError();
return FALSE;
}

if (!Process32First(SnapshotHandle, &ProcessEntry32))
{

LastError = GetLastError();
goto Exit;
}

do
{

if (_tcsicmp(ProcessEntry32.szExeFile, ImageName) == 0)
{

*ProcessIdentify = (HANDLE)ProcessEntry32.th32ProcessID;
IsOk = TRUE;
goto Exit;
}

} while (Process32Next(SnapshotHandle, &ProcessEntry32));



LastError = ERROR_MOD_NOT_FOUND;

Exit:

if (SnapshotHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(SnapshotHandle);
}
SnapshotHandle = INVALID_HANDLE_VALUE;
SetLastError(LastError);
return IsOk;
}

HideProcess
https://wlpswmt.github.io/2023/01/26/HideProcess/
作者
Sivan Zhang
发布于
2023年1月26日
许可协议