int freerdp_client_rdp_file_set_integer_option(rdpFile* file, const char* name, int value) { int index; int length; char* text; rdpFileLine* line; line = freerdp_client_rdp_file_find_line_by_name(file, name); length = _scprintf("%s:i:%d", name, value); text = (char*) malloc(length + 1); sprintf_s(text, length + 1, "%s:i:%d", name, value); text[length] = '\0'; if (line) { line->iValue = value; free(line->text); line->text = text; } else { index = freerdp_client_parse_rdp_file_add_line(file, text, -1); line = freerdp_client_rdp_file_find_line_index(file, index); freerdp_client_rdp_file_set_integer(file, (char*) name, value, index); free(text); } return 0; }
void BrowserFactory::LaunchBrowserUsingIELaunchURL(const std::string& initial_url, PROCESS_INFORMATION* proc_info, std::string* error_message) { LOG(TRACE) << "Entering BrowserFactory::IsIELaunchURLAvailable"; LOG(DEBUG) << "Starting IE using the IELaunchURL API"; std::wstring wide_initial_url = StringUtilities::ToWString(initial_url); HRESULT launch_result = ::IELaunchURL(wide_initial_url.c_str(), proc_info, NULL); if (FAILED(launch_result)) { size_t launch_msg_count = _scprintf(IELAUNCHURL_ERROR_MESSAGE, launch_result, initial_url.c_str()); vector<char> launch_result_msg(launch_msg_count + 1); _snprintf_s(&launch_result_msg[0], launch_result_msg.size(), launch_msg_count + 1, IELAUNCHURL_ERROR_MESSAGE, launch_result, initial_url.c_str()); std::string launch_error = &launch_result_msg[0]; *error_message = launch_error; } }
int freerdp_client_rdp_file_set_string_option(rdpFile* file, const char* name, const char* value) { int index; int length; char* text; rdpFileLine* line; line = freerdp_client_rdp_file_find_line_by_name(file, name); length = _scprintf("%s:s:%s", name, value); text = (char*) malloc(length + 1); sprintf_s(text, length + 1, "%s:s:%s", name, value ? value : ""); text[length] = '\0'; if (line) { free(line->sValue); line->sValue = _strdup(value); free(line->text); line->text = text; } else { index = freerdp_client_parse_rdp_file_add_line(file, text, -1); line = freerdp_client_rdp_file_find_line_index(file, index); freerdp_client_rdp_file_set_string(file, name, value, index); free(text); } return 0; }
char* FGDump::CreateSessionID() { // Format for the session ID is: YYYY-MM-DD-HH-mm-SS // Will be dynamically allocated, caller should free the memory SYSTEMTIME st; char* szIDBuffer = NULL; GetSystemTime(&st); size_t nArgSize = _scprintf("%d-%02d-%02d-%02d-%02d-%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); szIDBuffer = (char*)malloc(nArgSize + 1); memset(szIDBuffer, 0, nArgSize + 1); _snprintf(szIDBuffer, nArgSize, "%d-%02d-%02d-%02d-%02d-%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); return szIDBuffer; }
int HtiStifMsg::CheckResponseCommandCode(struct soap *soap, BYTE commandCode) { int result = SOAP_OK; if( msgBody[0] != commandCode ) { char msg[] = "incorrect response CommandCode (expected 0x%x, got 0x%x)"; int msgLen = _scprintf(msg, commandCode, msgBody[0])+1; // +1 for nul char char *buf = new char[msgLen]; sprintf(buf, msg, commandCode, msgBody[0]); soap->error = soap_receiver_fault(soap, "HtiError", buf); delete buf; result = SOAP_FAULT; } return result; }
AppletParameter::AppletParameter(const char *name, const char *value) : m_isValid(false), m_formattedString(NULL) { _ASSERT(name != NULL); _ASSERT(value != NULL); m_isValid = isStringValid(name) && isStringValid(value); if (isValid()) { const char *format = "<PARAM NAME=\"%s\" VALUE=\"%s\" >\n"; int len = _scprintf(format, name, value) + 1; m_formattedString = new char[len]; sprintf_s(m_formattedString, (size_t)(len), format, name, value); } }
DWORD BrowserFactory::LaunchBrowserProcess(const std::string& initial_url, const bool ignore_protected_mode_settings, std::string* error_message) { LOG(TRACE) << "Entering BrowserFactory::LaunchBrowserProcess"; DWORD process_id = NULL; bool has_valid_protected_mode_settings = false; LOG(DEBUG) << "Ignoring Protected Mode Settings: " << ignore_protected_mode_settings; if (!ignore_protected_mode_settings) { LOG(DEBUG) << "Checking validity of Protected Mode settings."; has_valid_protected_mode_settings = this->ProtectedModeSettingsAreValid(); } LOG(DEBUG) << "Has Valid Protected Mode Settings: " << has_valid_protected_mode_settings; if (ignore_protected_mode_settings || has_valid_protected_mode_settings) { STARTUPINFO start_info; PROCESS_INFORMATION proc_info; ::ZeroMemory(&start_info, sizeof(start_info)); start_info.cb = sizeof(start_info); ::ZeroMemory(&proc_info, sizeof(proc_info)); std::wstring wide_initial_url(CA2W(initial_url.c_str(), CP_UTF8)); FARPROC proc_address = 0; HMODULE library_handle = ::LoadLibrary(IEFRAME_LIBRARY_NAME); if (library_handle != NULL) { proc_address = ::GetProcAddress(library_handle, IELAUNCHURL_FUNCTION_NAME); } std::string launch_api = "The IELaunchURL() API"; std::string launch_error = ""; if (proc_address != 0) { // If we have the IELaunchURL API, expressly use it. This will // guarantee a new session. Simply using CoCreateInstance to // create the browser will merge sessions, making separate cookie // handling impossible. HRESULT launch_result = ::IELaunchURL(wide_initial_url.c_str(), &proc_info, NULL); if (FAILED(launch_result)) { size_t launch_msg_count = _scprintf(IELAUNCHURL_ERROR_MESSAGE, launch_result, initial_url); vector<char> launch_result_msg(launch_msg_count + 1); _snprintf_s(&launch_result_msg[0], sizeof(launch_result_msg), launch_msg_count + 1, IELAUNCHURL_ERROR_MESSAGE, launch_result, initial_url); launch_error = &launch_result_msg[0]; *error_message = launch_error; } } else { launch_api = "The CreateProcess() API"; std::wstring executable_and_url = this->ie_executable_location_ + L" " + wide_initial_url; LPWSTR command_line = new WCHAR[executable_and_url.size() + 1]; wcscpy_s(command_line, executable_and_url.size() + 1, executable_and_url.c_str()); command_line[executable_and_url.size()] = L'\0'; BOOL create_process_result = ::CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info); if (!create_process_result) { int create_proc_msg_count = _scwprintf(CREATEPROCESS_ERROR_MESSAGE, command_line); vector<wchar_t> create_proc_result_msg(create_proc_msg_count + 1); _snwprintf_s(&create_proc_result_msg[0], sizeof(create_proc_result_msg), create_proc_msg_count, CREATEPROCESS_ERROR_MESSAGE, command_line); launch_error = CW2A(&create_proc_result_msg[0], CP_UTF8); *error_message = launch_error; } delete[] command_line; } process_id = proc_info.dwProcessId; if (process_id == NULL) { // If whatever API we are using failed to launch the browser, we should // have a NULL value in the dwProcessId member of the PROCESS_INFORMATION // structure. In that case, we will have already set the approprate error // message. On the off chance that we haven't yet set the appropriate // error message, that means we successfully launched the browser (i.e., // the browser launch API returned a success code), but we still have a // NULL process ID. if (launch_error.size() == 0) { *error_message = launch_api + NULL_PROCESS_ID_ERROR_MESSAGE; } } if (proc_info.hThread != NULL) { ::CloseHandle(proc_info.hThread); } if (proc_info.hProcess != NULL) { ::CloseHandle(proc_info.hProcess); } if (library_handle != NULL) { ::FreeLibrary(library_handle); } } else { *error_message = PROTECTED_MODE_SETTING_ERROR_MESSAGE; } return process_id; }
bool BrowserFactory::AttachToBrowser(ProcessWindowInfo* process_window_info, const int timeout_in_milliseconds, const bool ignore_zoom_setting, std::string* error_message) { LOG(TRACE) << "Entering BrowserFactory::AttachToBrowser"; clock_t end = clock() + (timeout_in_milliseconds / 1000 * CLOCKS_PER_SEC); while (process_window_info->hwndBrowser == NULL) { if (timeout_in_milliseconds > 0 && (clock() > end)) { break; } ::EnumWindows(&BrowserFactory::FindBrowserWindow, reinterpret_cast<LPARAM>(process_window_info)); if (process_window_info->hwndBrowser == NULL) { ::Sleep(250); } } if (process_window_info->hwndBrowser == NULL) { int attach_fail_msg_count = _scprintf(ATTACH_TIMEOUT_ERROR_MESSAGE, process_window_info->dwProcessId, timeout_in_milliseconds); vector<char> attach_fail_msg_buffer(attach_fail_msg_count + 1); _snprintf_s(&attach_fail_msg_buffer[0], attach_fail_msg_buffer.size(), attach_fail_msg_count, ATTACH_TIMEOUT_ERROR_MESSAGE, process_window_info->dwProcessId, timeout_in_milliseconds); std::string attach_fail_msg = &attach_fail_msg_buffer[0]; *error_message = attach_fail_msg; return false; } CComPtr<IHTMLDocument2> document; if (this->GetDocumentFromWindowHandle(process_window_info->hwndBrowser, &document)) { CComPtr<IHTMLWindow2> window; HRESULT hr = document->get_parentWindow(&window); // Test for zoom level = 100% int zoom_level = 100; LOG(DEBUG) << "Ignoring zoom setting: " << ignore_zoom_setting; if (!ignore_zoom_setting) { zoom_level = this->GetZoomLevel(document, window); } if (zoom_level != 100) { vector<char> zoom_level_buffer(10); _itoa_s(zoom_level, &zoom_level_buffer[0], 10, 10); std::string zoom(&zoom_level_buffer[0]); *error_message = "Browser zoom level was set to " + zoom + "%. It should be set to 100%"; return false; } if (SUCCEEDED(hr)) { // http://support.microsoft.com/kb/257717 CComPtr<IServiceProvider> provider; window->QueryInterface<IServiceProvider>(&provider); if (provider) { CComPtr<IServiceProvider> child_provider; hr = provider->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, reinterpret_cast<void**>(&child_provider)); if (SUCCEEDED(hr)) { IWebBrowser2* browser; hr = child_provider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, reinterpret_cast<void**>(&browser)); if (SUCCEEDED(hr)) { process_window_info->pBrowser = browser; return true; } else { LOGHR(WARN, hr) << "IServiceProvider::QueryService for SID_SWebBrowserApp failed"; } } else { LOGHR(WARN, hr) << "IServiceProvider::QueryService for SID_STopLevelBrowser failed"; } } else { LOG(WARN) << "QueryInterface for IServiceProvider failed"; } } else { LOGHR(WARN, hr) << "Call to IHTMLDocument2::get_parentWindow failed"; } } else { *error_message = "Could not get document from window handle"; } return false; }
LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* ptrs) { EXCEPTION_RECORD* rec = ptrs->ExceptionRecord; CONTEXT* ctx = ptrs->ContextRecord; DWORD base = Vars.pModule ? Vars.pModule->dwBaseAddress : (DWORD)Vars.hModule; char path[MAX_PATH+_MAX_FNAME] = ""; sprintf_s(path, sizeof(path), "%s\\D2BS.bin", Vars.szPath); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId()); HANDLE hThread = GetCurrentThread(); CONTEXT context = *ctx; unsigned int i; int len; char* szString; char* dllAddrs; SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_FAIL_CRITICAL_ERRORS|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS); SymInitialize(hProcess, Vars.szPath, TRUE); SymLoadModule64(hProcess, NULL, path, NULL, base, 0); STACKFRAME64 stack; stack.AddrPC.Offset = context.Eip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Esp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Ebp; stack.AddrFrame.Mode = AddrModeFlat; std::string trace; for(i = 0; i < 64; i++) { if(!StackWalk64(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) break; // infinite loop if(stack.AddrReturn.Offset == stack.AddrPC.Offset) break; // jump to 0 if(stack.AddrPC.Offset == 0) break; SYMBOL_INFO* sym = GetSymFromAddr(hProcess, stack.AddrPC.Offset); if(sym) { char msg[1024]; ULONG64 base2 = (sym->Address - sym->ModBase); IMAGEHLP_LINE64* line = GetLineFromAddr(hProcess, stack.AddrPC.Offset); if(line) sprintf_s(msg, 1024, "\t%s+0x%08x, File: %s line %d\n", sym->Name, base2, strrchr(line->FileName, '\\')+1, line->LineNumber); else sprintf_s(msg, 1024, "\t%s+0x%08x\n", sym->Name, base2); trace.append(msg); delete line; } else { char addr[100]; sprintf_s(addr, sizeof(addr), "\t0x%08x\n", stack.AddrFrame.Offset); trace.append(addr); } delete[] (char*)sym; } SYMBOL_INFO* sym = GetSymFromAddr(hProcess, (DWORD64)rec->ExceptionAddress); IMAGEHLP_LINE64* line = GetLineFromAddr(hProcess, (DWORD64)rec->ExceptionAddress); len = _scprintf("EXCEPTION!\n*** 0x%08x at 0x%08x (%s in %s line %d)\n" "D2BS loaded at: 0x%08x\n" "Registers:\n" "\tEIP: 0x%08x, ESP: 0x%08x\n" "\tCS: 0x%04x, DS: 0x%04x, ES: 0x%04x, SS: 0x%04x, FS: 0x%04x, GS: 0x%04x\n" "\tEAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x, EDX: 0x%08x, ESI: 0x%08x, EDI: 0x%08x, EBP: 0x%08x, FLG: 0x%08x\n" "Stack Trace:\n%s\nEnd of stack trace.", rec->ExceptionCode, rec->ExceptionAddress, sym != NULL ? sym->Name : "Unknown", line != NULL ? strrchr(line->FileName, '\\')+1 : "Unknown", line != NULL ? line->LineNumber : 0, base, ctx->Eip, ctx->Esp, ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegSs, ctx->SegFs, ctx->SegGs, ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx, ctx->Esi, ctx->Edi, ctx->Ebp, ctx->EFlags, trace.c_str()); dllAddrs = DllLoadAddrStrs(); szString = new char[len+1]; sprintf_s(szString, len+1, "EXCEPTION!\n*** 0x%08x at 0x%08x (%s in %s line %d)\n" "D2BS loaded at: 0x%08x\n" "Registers:\n" "\tEIP: 0x%08x, ESP: 0x%08x\n" "\tCS: 0x%04x, DS: 0x%04x, ES: 0x%04x, SS: 0x%04x, FS: 0x%04x, GS: 0x%04x\n" "\tEAX: 0x%08x, EBX: 0x%08x, ECX: 0x%08x, EDX: 0x%08x, ESI: 0x%08x, EDI: 0x%08x, EBP: 0x%08x, FLG: 0x%08x\n" "Stack Trace:\n%s\nEnd of stack trace.", rec->ExceptionCode, rec->ExceptionAddress, sym != NULL ? sym->Name : "Unknown", line != NULL ? strrchr(line->FileName, '\\')+1 : "Unknown", line != NULL ? line->LineNumber : 0, base, ctx->Eip, ctx->Esp, ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegSs, ctx->SegFs, ctx->SegGs, ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx, ctx->Esi, ctx->Edi, ctx->Ebp, ctx->EFlags, trace.c_str()); Log("%s\n%s", szString, dllAddrs); free(dllAddrs); delete[] szString; delete[] (char*)sym; delete line; SymCleanup(hProcess); return EXCEPTION_EXECUTE_HANDLER; }
HRESULT CALLBACK KnownStructOutput ( IN ULONG Flag, IN ULONG64 Address, IN PSTR StructName, OUT PSTR Buffer, IN OUT PULONG BufferSize ) { HRESULT hRes=E_FAIL; if(Flag==DEBUG_KNOWN_STRUCT_GET_NAMES) { if ((*BufferSize)<strlen(SYSEXTS_KNOWNSTRUCT_1)+2) { // Not enough buffer available, return S_FALSE (*BufferSize)=strlen(SYSEXTS_KNOWNSTRUCT_1)+2; hRes=S_FALSE; } else { hRes=StringCchPrintfA(Buffer,(*BufferSize)-2,"%s\0",SYSEXTS_KNOWNSTRUCT_1 ); if (FAILED(hRes)) { dprintf ("Failed to copy the data type name into buffer\n"); } } } else if(Flag==DEBUG_KNOWN_STRUCT_GET_SINGLE_LINE_OUTPUT) { ULONG ulData=0; ULONG ulLeft=0; ULONG ulRight=0; if(FAILED(hRes=GetNodeValues(Address, &ulData, &ulLeft, &ulRight))) { return hRes; } DWORD dwLen=_scprintf(SYSEXTS_KNOWNSTRUCT_OUT, ulData, ulLeft, ulRight)+1; if(dwLen>(*BufferSize)) { dprintf("KnownStructOutput unable to fit return data into buffer\n"); hRes=E_FAIL; return hRes; } hRes=StringCchPrintfA(Buffer, dwLen, SYSEXTS_KNOWNSTRUCT_OUT, ulData, ulLeft, ulRight); if(FAILED(hRes)) { dprintf ("KnownStructOutput unable to write data into buffer\n"); } } else if(Flag==DEBUG_KNOWN_STRUCT_SUPPRESS_TYPE_NAME) { return S_OK; } else { dprintf("KnownStructOutput called with invalid flags\n"); } return hRes; }
bool CacheDumpControl::Execute(const char* lpszPSExecPath, const char* lpszDumpPath, char* lpszMachine, bool bIs64Bit, char* lpszPipeName) { char* lpszCmdLineFormat; int nArgSize; char* lpszStopCmdLine; char* lpszParams; bool result = false; if (lpszPipeName == NULL) { // Set the local cachedump path if (!bIs64Bit) lpszCmdLineFormat = "%s\\cachedump.exe"; else lpszCmdLineFormat = "%s\\cachedump64.exe"; nArgSize = _scprintf(lpszCmdLineFormat, lpszDumpPath); lpszStopCmdLine = new char[nArgSize + 1]; memset(lpszStopCmdLine, 0, nArgSize + 1); _snprintf_s(lpszStopCmdLine, nArgSize, strlen(lpszCmdLineFormat)-1+strlen(lpszDumpPath), lpszCmdLineFormat, lpszDumpPath); // Now set the parameters lpszCmdLineFormat = " -v"; lpszParams = new char[nArgSize + 1]; memset(lpszParams, 0, nArgSize + 1); _snprintf_s(lpszParams, nArgSize, strlen(lpszCmdLineFormat)-1, lpszCmdLineFormat); } else { lpszStopCmdLine = new char[strlen(lpszPSExecPath) + 1]; memset(lpszStopCmdLine, 0, strlen(lpszPSExecPath) + 1); strncpy_s(lpszStopCmdLine, strlen(lpszPSExecPath) + 1, lpszPSExecPath, strlen(lpszPSExecPath)); if (!bIs64Bit) lpszCmdLineFormat = " -c -n %s %s \"%s\\cachedump.exe\" -v"; else lpszCmdLineFormat = " -c -n %s %s \"%s\\cachedump64.exe\" -v"; nArgSize = _scprintf(lpszCmdLineFormat, lpszPipeName, lpszMachine, lpszDumpPath); lpszParams = new char[nArgSize + 1]; memset(lpszParams, 0, nArgSize + 1); _snprintf_s(lpszParams, nArgSize, strlen(lpszCmdLineFormat)-3+strlen(lpszPipeName)+strlen(lpszMachine)+strlen(lpszDumpPath), lpszCmdLineFormat, lpszPipeName, lpszMachine, lpszDumpPath); } try { Process p; HANDLE hProcess = p.CreateProcess(lpszStopCmdLine, lpszParams); if (hProcess != 0) { DWORD dwResult = WaitForSingleObject(hProcess, 1200000); // Wait 20 minutes for process to complete if (dwResult != WAIT_OBJECT_0) { Log.CachedReportError(m_nCacheID, CRITICAL, "Warning: cachedump did not complete in a timely manner - exiting"); result = false; } else { // Read from process's output char* szResult; int nSize = 65535; szResult = new char[nSize]; memset(szResult, 0, nSize); p.ReadFromPipe(&szResult, nSize); // Was it successful? if (strstr(szResult, "successfully removed") != NULL) { // Success // Write results to a file size_t nLen = strlen(lpszMachine) + 10; // 10 chars accounts for ".cachedump" extension char* szTempFilename = new char[nLen + 1]; memset(szTempFilename, 0, nLen + 1); _snprintf_s(szTempFilename, nLen, strlen(lpszMachine)+10, "%s.cachedump", lpszMachine); std::ofstream outputFile(szTempFilename, std::ios::out | std::ios::trunc); outputFile.write((const char*)szResult, (DWORD)strlen(szResult)); outputFile.close(); delete [] szTempFilename; Log.CachedReportError(m_nCacheID, CRITICAL, "Cache dumped successfully\n", lpszMachine); result = true; } else { // Failed Log.CachedReportError(m_nCacheID, CRITICAL, "Failed to dump cache (the text returned follows):\n%s", szResult); result = false; } delete [] szResult; } } else result = false; } catch(...) { result = false; } delete [] lpszStopCmdLine; delete [] lpszParams; return result; }
int Inject(HANDLE hProcess, const char *dll_dir, const char *dll_fn, const char *func_name, const void *param, const size_t param_size) { // String constants const char *injectError1Format = "Could not inject %s.\n" "\n" "If you're running Windows Vista or 7, make sure that you have installed the KB2533623 update:\n" "\n" "\thttp://support.microsoft.com/kb/2533623/"; const char *injectError2Format = "Could not load the function: %s"; //------------------------------------------// // Function variables. // //------------------------------------------// // Main DLL we will need to load HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); // Main functions we will need to import. // If [dll_fn] is absolute, LoadLibraryEx() with the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR // flag is used to guarantee that the injected DLL and its dependencies really // are only loaded from the given directory. Otherwise, LoadLibrary() may load // a possible other DLL with the same name from the directory of [hProcess]. FARPROC getcurrentdirectory = GetProcAddress(kernel32, "GetCurrentDirectoryW"); FARPROC setcurrentdirectory = GetProcAddress(kernel32, "SetCurrentDirectoryW"); FARPROC loadlibrary = GetProcAddress(kernel32, "LoadLibraryW"); FARPROC loadlibraryex = GetProcAddress(kernel32, "LoadLibraryExW"); FARPROC getprocaddress = GetProcAddress(kernel32, "GetProcAddress"); FARPROC exitthread = GetProcAddress(kernel32, "ExitThread"); FARPROC freelibraryandexitthread = GetProcAddress(kernel32, "FreeLibraryAndExitThread"); int have_kb2269637 = GetProcAddress(kernel32, "SetDefaultDllDirectories") != 0; // The workspace we will build the codecave on locally. // workspaceSize gets incremented with the final length of the error strings. size_t workspaceSize = 2048; LPBYTE workspace = NULL; LPBYTE p = NULL; // The memory in the process we write to LPBYTE codecaveAddress = NULL; // Strings we have to write into the process size_t injectError1_len = _scprintf(injectError1Format, dll_fn) + 1; size_t injectError2_len = _scprintf(injectError2Format, func_name) + 1; char *injectError0 = "Error"; VLA(char, injectError1, injectError1_len); VLA(char, injectError2, injectError2_len); char *user32Name = "user32.dll"; char *msgboxName = "MessageBoxW"; // Placeholder addresses to use the strings LPBYTE user32NameAddr = 0; LPBYTE user32Addr = 0; LPBYTE msgboxNameAddr = 0; LPBYTE msgboxAddr = 0; LPBYTE dllAddr = 0; LPBYTE dllDirAddr = 0; LPBYTE dllNameAddr = 0; LPBYTE funcNameAddr = 0; LPBYTE funcParamAddr = 0; LPBYTE error0Addr = 0; LPBYTE error1Addr = 0; LPBYTE error2Addr = 0; // Where the codecave execution should begin at LPTHREAD_START_ROUTINE codecaveExecAddr = 0; // Handle to the thread we create in the process HANDLE hThread = NULL; // Old protection on page we are writing to in the process and the bytes written DWORD oldProtect = 0; DWORD byte_ret = 0; // Return code of injection function DWORD injRet; //------------------------------------------// // Variable initialization. // //------------------------------------------// // This section will cause compiler warnings on VS8, // you can upgrade the functions or ignore them // Build error messages sprintf(injectError1, injectError1Format, dll_fn); sprintf(injectError2, injectError2Format, func_name); workspaceSize += ( strlen(dll_dir) + 1 + strlen(dll_fn) + 1 + strlen(func_name) + 1 + param_size + strlen(injectError1) + 1 + strlen(injectError2) + 1 ) * sizeof(wchar_t); // Create the workspace workspace = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, workspaceSize); p = workspace; // Allocate space for the codecave in the process codecaveAddress = (LPBYTE)VirtualAllocEx(hProcess, 0, workspaceSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Note there is no error checking done above for any functions that return a pointer/handle. // I could have added them, but it'd just add more messiness to the code and not provide any real // benefit. It's up to you though in your final code if you want it there or not. //------------------------------------------// // Data and string writing. // //------------------------------------------// // Reserve space for the user32 dll address, the MessageBox address, // and the address of the injected DLL's module. user32Addr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); msgboxAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); dllAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); // User32 Dll Name user32NameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, user32Name); // MessageBox name msgboxNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, msgboxName, strlen(msgboxName) + 1); // Directory name if(dll_dir) { dllDirAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_dir); } // Dll Name dllNameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_fn); // Function Name funcNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, func_name, strlen(func_name) + 1); // Function Parameter funcParamAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, param, param_size); // Error Message 1 error0Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError0); // Error Message 2 error1Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError1); // Error Message 3 error2Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError2); // Pad a few INT3s after string data is written for seperation *p++ = 0xCC; *p++ = 0xCC; *p++ = 0xCC; // Store where the codecave execution should begin codecaveExecAddr = (LPTHREAD_START_ROUTINE)((p - workspace) + codecaveAddress); // For debugging - infinite loop, attach onto process and step over //*p++ = 0xEB; //*p++ = 0xFE; //------------------------------------------// // User32.dll loading. // //------------------------------------------// // User32 DLL Loading // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibrary *p++ = 0x68; p = ptrcpy_advance_dst(p, user32NameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibrary into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibrary); // CALL EAX - Call LoadLibrary *p++ = 0xFF; *p++ = 0xD0; // MessageBox Loading // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, msgboxNameAddr); // Push EAX, module to use in GetProcAddress *p++ = 0x50; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0xA3; p = ptrcpy_advance_dst(p, msgboxAddr); //------------------------------------------// // Injected dll loading. // //------------------------------------------// /* // This is the way the following assembly code would look like in C/C++ // In case the injected DLL depends on other DLLs, // we need to change the current directory to the one given as parameter if(dll_dir) { size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1; VLA(wchar_t, cur_dir, cur_dir_len); GetCurrentDirectory(cur_dir, cur_dir_len); SetCurrentDirectory(dll_dir); } // Load the injected DLL into this process HMODULE h = LoadLibraryEx(dll_fn, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); if(!h) { MessageBox(0, injectError1, "Error", MB_ICONERROR); ExitThread(1); } if(dll_dir) { SetCurrentDirectory(cur_dir); } // Get the address of the export function FARPROC p = GetProcAddress(h, func_name); if(!p) { MessageBox(0, injectError2, "Error", MB_ICONERROR); FreeLibraryAndExitThread(h, 2); } // So we do not need a function pointer interface __asm call p // Exit the thread so the loader continues ExitThread(0); */ // DLL Loading if(dllDirAddr) { // Registers: // ebp: Base stack frame // esi: GetCurrentDirectory / SetCurrentDirectory // ebx: Current directory of process (on stack) // ecx: byte length of string at ebx // mov ebp, esp - Save stack frame *p++ = 0x89; *p++ = 0xe5; // Get length for current directory // push 0 // push 0 *p++ = 0x6a; *p++ = 0x00; *p++ = 0x6a; *p++ = 0x00; // mov esi, GetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, getcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; /// Calculate byte size of directory buffer. /// Also do some poor man's DWORD boundary alignment /// in order to not f**k up the stack // mov ecx, eax // shl ecx, 1 // and ecx, fffffff8 // add ecx, 4 *p++ = 0x89; *p++ = 0xc1; *p++ = 0xd1; *p++ = 0xe1; *p++ = 0x83; *p++ = 0xe1; *p++ = 0xf8; *p++ = 0x83; *p++ = 0xc1; *p++ = 0x04; /// "Allocate" ecx bytes on stack and store buffer pointer to ebx // sub esp, ecx // mov ebx, esp *p++ = 0x29; *p++ = 0xcc; *p++ = 0x89; *p++ = 0xe3; /// Call GetCurrentDirectory // push ebx // push eax // call esi *p++ = 0x53; *p++ = 0x50; *p++ = 0xff; *p++ = 0xd6; /// PUSH 0x00000000 - Push the address of our directory *p++ = 0x68; p = ptrcpy_advance_dst(p, dllDirAddr); // mov esi, SetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, setcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; } if(PathIsRelativeA(dll_fn) || !have_kb2269637) { // PUSH 0x00 (dwFlags = 0) *p++ = 0x6a; *p++ = 0x00; } else { // PUSH 0x00000900 (dwFlags = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32) *p++ = 0x68; *p++ = 0x00; *p++ = 0x09; *p++ = 0x00; *p++ = 0x00; } // PUSH 0x00 (hFile = NULL) *p++ = 0x6a; *p++ = 0x00; // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibraryEx *p++ = 0x68; p = ptrcpy_advance_dst(p, dllNameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibraryEx into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibraryex); // CALL EAX - Call LoadLibraryEx *p++ = 0xFF; *p++ = 0xD0; // mov edi, eax - Save return value *p++ = 0x89; *p++ = 0xc7; if(dllDirAddr) { /// Reset directory to the original one of the process // push ebx // call esi *p++ = 0x53; *p++ = 0xFF; *p++ = 0xD6; /// Reset stack frame // mov esp, ebp *p++ = 0x89; *p++ = 0xec; } // Error Checking // CMP EDI, 0 *p++ = 0x83; *p++ = 0xFF; *p++ = 0x00; // JNZ EIP + 0x1E to skip over eror code *p++ = 0x75; *p++ = 0x1E; // Error Code 1 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error1Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, [ADDRESS] - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxW *p++ = 0xFF; *p++ = 0xD0; // ExitThread // PUSH 1 *p++ = 0x6A; *p++ = 0x01; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; // Now we have the address of the injected DLL, so save the handle // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0x89; *p++ = 0x3D; p = ptrcpy_advance_dst(p, dllAddr); // Load the initilize function from it // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, funcNameAddr); // Push EDI - module to use in GetProcAddress *p++ = 0x57; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // Error Checking // CMP EAX, 0 *p++ = 0x83; *p++ = 0xF8; *p++ = 0x00; // JNZ EIP + 0x23 to skip eror code *p++ = 0x75; *p++ = 0x23; // Error Code 2 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error2Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxA *p++ = 0xFF; *p++ = 0xD0; // FreeLibraryAndExitThread // PUSH 2 *p++ = 0x6A; *p++ = 0x02; // PUSH 0x000000 - Push the injected DLL's module handle *p++ = 0x68; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call ExitThread function *p++ = 0xFF; *p++ = 0xD0; // PUSH 0x000000 - Push the address of the function parameter *p++ = 0x68; p = ptrcpy_advance_dst(p, funcParamAddr); // CALL EAX - Call [func_name] *p++ = 0xFF; *p++ = 0xD0; // If we get here, [func_name] has been called, // so it's time to close this thread and optionally unload the DLL. //------------------------------------------// // Exiting from the injected dll. // //------------------------------------------// // Call ExitThread to leave the DLL loaded #if 1 // PUSH 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; #endif // Call FreeLibraryAndExitThread to unload DLL #if 0 // Push 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // PUSH [0x000000] - Push the address of the DLL module to unload *p++ = 0xFF; *p++ = 0x35; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call FreeLibraryAndExitThread *p++ = 0xFF; *p++ = 0xD0; #endif //------------------------------------------// // Code injection and cleanup. // //------------------------------------------// // Change page protection so we can write executable code VirtualProtectEx(hProcess, codecaveAddress, p - workspace, PAGE_EXECUTE_READWRITE, &oldProtect); // Write out the patch WriteProcessMemory(hProcess, codecaveAddress, workspace, p - workspace, &byte_ret); // Restore page protection VirtualProtectEx(hProcess, codecaveAddress, p - workspace, oldProtect, &oldProtect); // Make sure our changes are written right away FlushInstructionCache(hProcess, codecaveAddress, p - workspace); // Free the workspace memory HeapFree(GetProcessHeap(), 0, workspace); // Execute the thread now and wait for it to exit, note we execute where the code starts, and not the codecave start // (since we wrote strings at the start of the codecave) hThread = CreateRemoteThread(hProcess, NULL, 0, codecaveExecAddr, 0, 0, NULL); WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &injRet); CloseHandle(hThread); // Free the memory in the process that we allocated VirtualFreeEx(hProcess, codecaveAddress, 0, MEM_RELEASE); VLA_FREE(injectError1); VLA_FREE(injectError2); return injRet; }