远程线程的注入 PE的修正
https://bbs.pediy.com/thread-222187.htm
从github上下载了ReflectiverLoader认真学习了一下 在代码中得到一些心得和自己的想法,都按步骤写到了代码中,现在分享给大家,如有错,望大家指正
其中需要注入的dll和解析, 内存RVA与 文件RVA的转换代码(汇编与c++的都有)和解析,shellcode的汇编附到最后的链接中
一.这是用到的shellocode
作用:经调试得出他是为了解决x86下运行x64 的问题(windbg可以看到是通过远跳转到x64下执行)
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
|
static BYTE __ExecutexX64[] = "x55x89xE5x56x57x8Bx75x08x8Bx4Dx0CxE8x00x00x00x00" "x58x83xC0x25x83xECx08x89xE2xC7x42x04x33x00x00x00" "x89x02xE8x09x00x00x00x83xC4x14x5Fx5Ex5DxC2x08x00" "x8Bx3Cx24xFFx2Ax48x31xC0x57xFFxD6x5Fx50xC7x44x24" "x04x23x00x00x00x89x3Cx24xFFx2Cx24" ; static BYTE __FunctionX64[] = "xFCx48x89xCEx48x89xE7x48x83xE4xF0xE8xC8x00x00x00" "x41x51x41x50x52x51x56x48x31xD2x65x48x8Bx52x60x48" "x8Bx52x18x48x8Bx52x20x48x8Bx72x50x48x0FxB7x4Ax4A" "x4Dx31xC9x48x31xC0xACx3Cx61x7Cx02x2Cx20x41xC1xC9" "x0Dx41x01xC1xE2xEDx52x41x51x48x8Bx52x20x8Bx42x3C" "x48x01xD0x66x81x78x18x0Bx02x75x72x8Bx80x88x00x00" "x00x48x85xC0x74x67x48x01xD0x50x8Bx48x18x44x8Bx40" "x20x49x01xD0xE3x56x48xFFxC9x41x8Bx34x88x48x01xD6" "x4Dx31xC9x48x31xC0xACx41xC1xC9x0Dx41x01xC1x38xE0" "x75xF1x4Cx03x4Cx24x08x45x39xD1x75xD8x58x44x8Bx40" "x24x49x01xD0x66x41x8Bx0Cx48x44x8Bx40x1Cx49x01xD0" "x41x8Bx04x88x48x01xD0x41x58x41x58x5Ex59x5Ax41x58" "x41x59x41x5Ax48x83xECx20x41x52xFFxE0x58x41x59x5A" "x48x8Bx12xE9x4FxFFxFFxFFx5Dx4Dx31xC9x41x51x48x8D" "x46x18x50xFFx76x10xFFx76x08x41x51x41x51x49xB8x01" "x00x00x00x00x00x00x00x48x31xD2x48x8Bx0Ex41xBAxC8" "x38xA4x40xFFxD5x48x85xC0x74x0Cx48xB8x00x00x00x00" "x00x00x00x00xEBx0Ax48xB8x01x00x00x00x00x00x00x00" "x48x83xC4x50x48x89xFCxC3" ; |
二.用到的结构体 宏定义和哈希值(利用MakeHanValue计算就行,代码中有小注释)
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
|
#define MYFUNCTION_HASH 0x6654bba6 // hash of "MyFunction" enum { UNKNOWN, X86, X64 }; #define DEREFERENCE (Value) *(UINT_PTR *)(Value) #define DEREFERENCE_64(Value) *(DWORD64 *)(Value) #define DEREFERENCE_32(Value) *(DWORD *)(Value) #define DEREFERENCE_16(Value) *(WORD *)(Value) #define DEREFERENCE_8 (Value) *(BYTE *)(Value) typedef BOOL (WINAPI * LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); typedef BOOL (WINAPI * LPFN_FUNCTIONX64)(DWORD ParameterData); typedef DWORD(WINAPI * LPFN_EXECUTEX64)(LPFN_FUNCTIONX64 FunctionX64, DWORD ParameterData); typedef struct _WOW64CONTEXT_ { union { HANDLE ProcessHandle; BYTE Padding[ 8 ]; }u1; union { LPVOID ThreadProcedure; BYTE Padding[ 8 ]; }u2; union { LPVOID ParameterData; BYTE Padding[ 8 ]; }u3; union { HANDLE ThreadHandle; BYTE Padding[ 8 ]; }u4; } WOW64CONTEXT, * LPWOW64CONTEXT; |
三.主函数的解析
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
|
int main() { HANDLE FileHandle = NULL; ULONG FileLength = 0 ; LPVOID FileData = NULL; ULONG ReturnLength = 0 ; HANDLE ProcessHandle = NULL; HANDLE RemoteThreadHandle = NULL; DWORD ExitCode = 0 ; if (EnableSeDebugPrivilege(L "SeDebugPrivilege" , TRUE) = = FALSE) { return 0 ; } DWORD ProcessID = 0 ; printf( "Input ProcessID:
" ); scanf( "%d" , &ProcessID); #ifdef_WIN64 char * DllFullPath = "ReflectiveLoader.dll" ; #else char * DllFullPath = "ReflectiveLoader.dll" ; #endif / / 1. 打开文件 FileHandle = CreateFileA(DllFullPath, GENERIC_READ, 0 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (FileHandle = = INVALID_HANDLE_VALUE) { printf( "CreateFileA() Error
" ); goto Exit; } / / 2. 获得大小 FileLength = GetFileSize(FileHandle, NULL); if (FileLength = = INVALID_FILE_SIZE || FileLength = = 0 ) { printf( "GetFileSize() Error
" ); goto Exit; } / / 3. 申请堆内存 FileData = HeapAlloc(GetProcessHeap(), 0 , FileLength); if (!FileData) { printf( "HeapAlloc() Error
" ); goto Exit; } / / 4. 读内存 if (ReadFile(FileHandle, FileData, FileLength, &ReturnLength, NULL) = = FALSE) { printf( "HeapAlloc() Error
" ); goto Exit; } / / 以下是对目标进行操作 / / 5. 打开目标进程 ProcessHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, ProcessID); if (!ProcessHandle) { printf( "OpenProcess() Error
" ); goto Exit; } / / 6. 加载动态库 RemoteThreadHandle = LoadRemoteLibrary(ProcessHandle, FileData, FileLength, NULL,MYFUNCTION_HASH,(LPVOID) "911" ,strlen( "911" ) + 1 ); if (!RemoteThreadHandle) { printf( "LoadRemoteLibrary() Error
" ); goto Exit; } printf( "LoadRemoteLibrary() Success
" ); / / 7. 远程线程等待注入 WaitForSingleObject(RemoteThreadHandle, INFINITE); if (!GetExitCodeThread(RemoteThreadHandle, &ExitCode)) printf( "Input AnyKey To Exit
" ); getchar(); / / 8. 释放内存 Exit: if (FileData) { HeapFree(GetProcessHeap(), 0 , FileData); } if (FileHandle! = NULL) { CloseHandle(FileHandle); FileHandle = NULL; } if (ProcessHandle) { CloseHandle(ProcessHandle); ProcessHandle = NULL; } return 0 ; } |
四. LoadRemoteLibrary的解读(其中三种获得目标体系结构的方法 我记入了笔记)
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
|
HANDLEWINAPI LoadRemoteLibrary( HANDLEProcessHandle, LPVOIDFileData, / / Dll文件数据 DWORDFileLength, LPVOIDParameterData, DWORDFunctionHash, / / 函数哈希值 LPVOIDUserData, DWORDUserDataLength) { HANDLE RemoteThreadHandle = NULL; DWORD RemoteThreadID = 0 ; DWORD TargetArchitecture = X86; / / 目标体系结构 DWORD DllArchitecture = UNKNOWN; #ifdefined(_WIN64) DWORD CurrentArchitecture = X64; #elifdefined(_WIN32) DWORD CurrentArchitecture = X86 #else #endif __try { do { if (!ProcessHandle || !FileData || !FileLength) { break ; } / / 第一幕 / / 1. 获得目标进程的Architecture 进程通过内核获得体系结构 HMODULE KernelModuleBase = LoadLibraryA( "kernel32.dll" ); if (!KernelModuleBase) break ; __IsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(KernelModuleBase, "IsWow64Process" ); FreeLibrary(KernelModuleBase); if (__IsWow64Process) { BOOL IsOK; if (!__IsWow64Process(ProcessHandle, &IsOK)); { break ; } if (IsOK) { TargetArchitecture = X86; } else { / / 通过系统判断 32 位与 64 位 SYSTEM_INFO SystemInfo = { 0 }; GetNativeSystemInfo(&SystemInfo); if (SystemInfo.wProcessorArchitecture = = PROCESSOR_ARCHITECTURE_AMD64) TargetArchitecture = X64; elseif (SystemInfo.wProcessorArchitecture = = PROCESSOR_ARCHITECTURE_INTEL) TargetArchitecture = X86; else break ; } } / / 2. 通过PE获得获得Dll的Architecture / / MZ头 + e_lfanew = NT头 PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(((PUINT8)FileData) + ((PIMAGE_DOS_HEADER)FileData) - >e_lfanew); if (ImageNtHeaders - >OptionalHeader.Magic = = IMAGE_NT_OPTIONAL_HDR32_MAGIC) / / PE32 DllArchitecture = X86; elseif (ImageNtHeaders - >OptionalHeader.Magic = = IMAGE_NT_OPTIONAL_HDR64_MAGIC) / / PE64 DllArchitecture = X64; / / 3. 判断DLL和目标进程是否是相同的架构?? if (DllArchitecture ! = TargetArchitecture) { printf( "Must Be Same Architecture
" ); break ; } / / 第二幕 / / 1. 再次检查动态库的装入 / / check if the library has a ReflectiveLoader... DWORD ReflectiveLoaderOffset = GetReflectiveLoaderOffset(FileData); if (!ReflectiveLoaderOffset) { printf( "Could Not Get ReflectiveLoader Offset
" ); break ; } DWORD RemoteBufferLength = FileLength + UserDataLength + 64 ; / / shellcode buffer / / 2.alloc memory (RWX) in the host process for the image... LPVOID RemoteBufferData = VirtualAllocEx(ProcessHandle, NULL, RemoteBufferLength, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!RemoteBufferData) { break ; } printf( "VirtualAllocEx() Success
" ); / / 3.1 write the image into the host process...将图像写入主进程。 / / RemoteBufferData 指向写入数据的指定进程中的基地址的指针 if (!WriteProcessMemory(ProcessHandle, RemoteBufferData, FileData, FileLength, NULL)) break ; / / 基地址 + 偏移 ULONG_PTR ReflectiveLoader = (ULONG_PTR)RemoteBufferData + ReflectiveLoaderOffset; / / 3.2 write our userdata blob into the host process ULONG_PTR RemoteUserData = (ULONG_PTR)RemoteBufferData + FileLength; if (!WriteProcessMemory(ProcessHandle, (LPVOID)RemoteUserData, UserData, UserDataLength, NULL)) break ; / / 3.3 写shellcode ULONG_PTR RemoteShellCode = RemoteUserData + UserDataLength; BYTE Bootstrap[ 64 ] = { 0 }; DWORD BootstrapLength = CreateBootstrap( Bootstrap, 64 , TargetArchitecture, (ULONG_PTR)ParameterData, (ULONG_PTR)RemoteBufferData, FunctionHash, RemoteUserData, UserDataLength, ReflectiveLoader); if (BootstrapLength < = 0 ) { break ; } printf( "%p
" , RemoteShellCode); getchar(); if (!WriteProcessMemory(ProcessHandle, (LPVOID)RemoteShellCode, Bootstrap, BootstrapLength, NULL)) break ; printf( "Wrote ShellCode Success
" ); / * 此处的写入图 RemoteBufferData[FileData的基地址] 写入FileData RemoteUserData[UserData的基地址] 写入UserData RemoteShellCode 写入Bootstrap * / / / 确保我们的更改是马上写的 FlushInstructionCache(ProcessHandle, RemoteBufferData, RemoteBufferLength); printf( "%p
" , RemoteShellCode); getchar(); getchar(); / / 第三幕 判断主体与客体的位 并且创建线程执行 / / 目标 64 当前 32 if (CurrentArchitecture = = X86 && TargetArchitecture = = X64) { Wow64CreateRemoteThread(ProcessHandle, (LPVOID)RemoteShellCode, ParameterData, &RemoteThreadHandle); ResumeThread(RemoteThreadHandle); } else { / / 目标 32 当前 32 / / 目标 64 当前 64 / / 目标 32 当前 64 RemoteThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 1024 * 1024 , (LPTHREAD_START_ROUTINE)RemoteShellCode, ParameterData, (DWORD)NULL, &RemoteThreadID); / * lpStartAddress [ in ]指向由线程执行的类型为LPTHREAD_START_ROUTINE的应用程序 定义函数的指针,并表示远程进程中线程的起始地址。该功能必须存在于远程进程中。 lpParameter [ in ] 指向要传递给线程函数的变量的指针。 * / } } while ( 0 ); } __except (EXCEPTION_EXECUTE_HANDLER) { RemoteThreadHandle = NULL; } return RemoteThreadHandle; } |
五. Wow64CreateRemoteThread解读
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
|
DWORD Wow64CreateRemoteThread(HANDLEProcessHandle, LPVOIDThreadProcedure, LPVOIDParameterData, HANDLE * ThreadHandle) { DWORD Result = ERROR_SUCCESS; LPFN_EXECUTEX64 ExecuteX64 = NULL; LPFN_FUNCTIONX64 FunctionX64 = NULL; WOW64CONTEXT * Wow64Context = NULL; OSVERSIONINFO OsVersionInfo = { 0 }; do { / / 第一幕 判断系统是否合适 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&OsVersionInfo)) { printf( "GetVersionEx() Error
" ); break ; } / / filter out Windows 2003 if (OsVersionInfo.dwMajorVersion = = 5 && OsVersionInfo.dwMinorVersion = = 2 ) { printf( "Is 2003 Error
" ); break ; } / / 第二幕 / / 1. 分别为ExecuteX64,FunctionX64申请shellcode大小的内存兵赋值 / * shellcode经过调试得出是通过远跳转到 64 位进程中执行 惭愧 瞎调了一遍还没有掌握调试方法 有点难。。。 * / ExecuteX64 = (LPFN_EXECUTEX64)VirtualAlloc(NULL, sizeof(__ExecutexX64), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!ExecuteX64) { printf( "VirtualAlloc() Error
" ); break ; } FunctionX64 = (LPFN_FUNCTIONX64)VirtualAlloc(NULL, sizeof(__FunctionX64) + sizeof(WOW64CONTEXT), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!FunctionX64) { printf( "VirtualAlloc() Error
" ); break ; } / / copy over the wow64 - >x64 stub memcpy(ExecuteX64, &__ExecutexX64, sizeof(__ExecutexX64)); / / copy over the native x64 function memcpy(FunctionX64, &__FunctionX64, sizeof(__FunctionX64)); / / 2. 设置上下背景文 Wow64Context = (WOW64CONTEXT * )((BYTE * )FunctionX64 + sizeof(__FunctionX64)); Wow64Context - >u1.ProcessHandle = ProcessHandle; / / 目标进程句柄 Wow64Context - >u2.ThreadProcedure = ThreadProcedure; Wow64Context - >u3.ParameterData = ParameterData; Wow64Context - >u4.ThreadHandle = NULL; / / 3. 执行该代码的环境是 32 位 if (!ExecuteX64(FunctionX64, (DWORD)Wow64Context)) { printf( "ExecuteX64() Error
" ); break ; } / / 作为一个标识 if (!Wow64Context - >u4.ThreadHandle) { printf( "ThreadHandle Is NULL
" ); break ; } / / 4. 成功! 从上下文中抓取新的线程句柄 * ThreadHandle = Wow64Context - >u4.ThreadHandle; } while ( 0 ); / / 5. 退出 if (ExecuteX64) { VirtualFree(ExecuteX64, 0 , MEM_RELEASE); ExecuteX64 = NULL; } if (FunctionX64) { VirtualFree(FunctionX64, 0 , MEM_RELEASE); FunctionX64 = NULL; } return Result; } |
========== End