В общем я использую для перехвата кода дебаговые регистры. На хп сп3 все хорошо и просто. В DLL_PROCESS_ATTACH я делаю AddVectoredExceptionHandler(1,veh) и запускаю поток который ставит дебаг регистры для каждого потока(на всякий случай) хотя все перехваты срабатывают из основного потока. В 7ке происходит следующее: перехваты не срабатывают вообще, но сразу после AddVectoredExceptionHandler(1,veh) при вызове DebugBreak() перехват срабатывает. В чем может быть проблема? Приложение одно и то же, разница только в ос.
основной поток, в котором срабатывают hbps - это основной поток процесса, в который производится инжект? а не пробовали повторить ситуацию в дебаггере? поставить hbp и посмотреть, сработает ли?
да. Вот код который перечисляет все потоки: Код (Text): HANDLE th = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,GetCurrentProcessId()); THREADENTRY32 t = {0}; t.dwSize = sizeof(THREADENTRY32); Thread32First(th,&t); do { if(t.th32OwnerProcessID!=GetCurrentProcessId()) continue; HANDLE h; hookthread(h = OpenThread(THREAD_QUERY_INFORMATION|THREAD_GET_CONTEXT|THREAD_SET_CONTEXT,false,t.th32ThreadID)); CloseHandle(h); } while (Thread32Next(th,&t)); ну естественно в винде 7, в ольке хардварные брейкпойнты работают. Может там есть какая-то особенность при установке? я задействовал 4 слота. в Dr7 вписал следующее: (1<<0)|(1<<2)|(1<<4)|(1<<6)
нет, я конечно попробую, но у меня в принципе 1 раз ловится сразу после AddVectoredExceptionHandler. Проверил отладчиком - никто не перебивает мой VEH.
нашел проблему. Оказалось, что в ХР можно создавать потоки из DllMain, а в 7 нельзя. Это можно как-то обойти?
конечно можно. в inject dll сделайте экспортируемую функцию Start с сигнатурой HRESULT (STDMETHODCALLTYPE *PFNSTART)(DWORD), и повторите трюк аналогичный удалённому запуску LoadLibrary. Авторство функции RemoteGetProcAddress не моё Код (Text): DWORD dwThreadId; HRESULT hr = Common::InjectDll( dwProcessId, lpszDllPath, &dwThreadId, msWait, hTargetProcess.get()); if (FAILED(hr)) return hr; // Get the HMODULE of the injected library std::vector< ::MODULEENTRY32> vModules; hr = Common::ThGetProcessModules(vModules, dwProcessId); if (FAILED(hr)) return hr; std::vector< ::MODULEENTRY32>::const_iterator pme = std::find_if(vModules.begin(), vModules.end(), Common::CIsSameModulePath(lpszDllPath)); if (vModules.end() == pme) { WRITE_MSG(L"Module " << lpszDllPath << L" isn't found"); return E_NOTFOUND; } // Get address of Start function in the injected process's address space // exact signature is: //typedef HRESULT (STDCALLMETHODTYPE *PFNSTART)(DWORD msWait); HMODULE hMod = pme->hModule; PTHREAD_START_ROUTINE pfnStart = reinterpret_cast<PTHREAD_START_ROUTINE>( Common::RemoteGetProcAddress(hTargetProcess.get(), hMod, "Start")); if (!pfnStart) return HRESULT_FROM_WIN32(::GetLastError()); // Remote call Start function HANDLE hrawRemoteThread = ::CreateRemoteThread(hTargetProcess.get(), NULL, 0, pfnStart, &msWait, 0, &dwThreadId); if (!hrawRemoteThread) return HRESULT_FROM_WIN32(::GetLastError()); boost::shared_ptr<void> hRemoteThread(hrawRemoteThread, &::CloseHandle); // Wait for Start execution completion hr =Common::GetWaitErrorCode( ::WaitForSingleObject(hRemoteThread.get(), msWait)); if (FAILED(hr)) return hr; // Get remote thread exit code DWORD dwExitCode; if (! ::GetExitCodeThread(hRemoteThread.get(), &dwExitCode)) return HRESULT_FROM_WIN32( ::GetLastError()); if (STILL_ACTIVE == dwExitCode) return E_UNEXPECTED; return S_OK; // // FUNCTION: void* RemoteGetProcAddress(HANDLE , HMODULE, const char* ) // // PARAMETERS: [IN] hProcess - описатель процесса // [IN] hLib - HMODULE dll в заданном процессе // [IN] name - имя функции // // RETURN VALUE: адрес функции в заданном процессе или NULL // // REVISION: 17.09.2004 Сергей Холодилов // // PURPOSE: Находит нужную функцию в указанной dll в указанном процессе // // COMMENTS: // void *STDMETHODCALLTYPE RemoteGetProcAddress(HANDLE hProcess, HMODULE hLib, const char* name) { // Нам нужен именно адрес загрузки! А результат работы // LoadLibrary бывает иногда неожиданным.. char* baseAddress = reinterpret_cast<char*> (reinterpret_cast<DWORD>(hLib) & 0xFFFF0000); // Смещение секции экспорта int export_offset; HRESULT hr = GetExportSectionRVA(hProcess, baseAddress, &export_offset); if (FAILED(hr)) { // Какие-то проблемы с экспортом return NULL; } // Читаем заголовок секции экспорта IMAGE_EXPORT_DIRECTORY ied; if (!::ReadProcessMemory( hProcess, baseAddress + export_offset, &ied, sizeof(IMAGE_EXPORT_DIRECTORY), 0)) { // Не судьба return NULL; } // Индекс в массиве функций WORD funcIndex = -1; if (reinterpret_cast<DWORD_PTR>(name) > 0x0000ffff) { // Функция экспортируется по имени. Ищем имя int nameIndex; hr = FindName( hProcess, baseAddress, ied.AddressOfNames, ied.NumberOfNames, name, &nameIndex); if (FAILED(hr)) { // Такой функции нет return NULL; } // Читаем индекс (они двухбайтные!!!) if (!::ReadProcessMemory( hProcess, baseAddress + ied.AddressOfNameOrdinals + nameIndex * sizeof(WORD), &funcIndex, sizeof(funcIndex), 0)) { return NULL; } } else { // Функция экспортируется по ординалу WORD funcOrdinal = static_cast<WORD>(reinterpret_cast<DWORD>(name)); if ((funcOrdinal < ied.Base) || (funcOrdinal >= ied.Base + ied.NumberOfFunctions)) { // Такой функции нет return NULL; } funcIndex = static_cast<WORD>(funcOrdinal - ied.Base); } #ifdef __BORLANDC__ #pragma option push -w-8008 #endif // __BORLANDC__ if ((funcIndex < 0) || (funcIndex >= ied.NumberOfFunctions)) #ifdef __BORLANDC__ #pragma option pop #endif // __BORLANDC__ { // Такой функции нет return NULL; } // Читаем адрес DWORD funcRVA; if (!::ReadProcessMemory( hProcess, baseAddress + ied.AddressOfFunctions + funcIndex * sizeof(DWORD), &funcRVA, sizeof(funcRVA), 0)) { return NULL; } // Результат это базовый адрес + RVA return (baseAddress + funcRVA); } // Определяет RVA секции экспорта HRESULT STDMETHODCALLTYPE GetExportSectionRVA(HANDLE hProcess, const char* baseAddress, int *iRVA) { if (!iRVA) return E_POINTER; // Читаем DOS-заголовок IMAGE_DOS_HEADER dos_header; if (!::ReadProcessMemory( hProcess, baseAddress, &dos_header, sizeof(IMAGE_DOS_HEADER), 0)) { return HRESULT_FROM_WIN32(::GetLastError()); } // Читаем PE-заголовок IMAGE_NT_HEADERS pe_header; if (!::ReadProcessMemory( hProcess, baseAddress + dos_header.e_lfanew, &pe_header, sizeof(IMAGE_NT_HEADERS), 0)) { return HRESULT_FROM_WIN32(::GetLastError()); } // Смещение секции экспорта *iRVA = pe_header.OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; return S_OK; } // Перебирает массив имён функций, ищет там заданное имя HRESULT STDMETHODCALLTYPE FindName( HANDLE hProcess, const char* baseAddress, DWORD AddressOfNames, DWORD count, const char* name, int *pnIndex) { if (!pnIndex) return E_POINTER; // Для сравнения имени его нужно прочитать, для этого нужно знать размер int size = lstrlenA(name) + 1; std::auto_ptr<char> candidate(new char[size]); // Перебираем имена в массиве имён функций for (DWORD index = 0; index < count; ++index) { DWORD nameRVA; // Читаем адрес начала строки if (!::ReadProcessMemory( hProcess, baseAddress + AddressOfNames + index * sizeof(DWORD), &nameRVA, sizeof(nameRVA), 0)) { return HRESULT_FROM_WIN32(::GetLastError()); } // Читаем строку if (!::ReadProcessMemory( hProcess, baseAddress + nameRVA, candidate.get(), size, 0)) { return HRESULT_FROM_WIN32(::GetLastError()); } if (strcmp(name, candidate.get()) == 0) { // Она! Сваливаем :) *pnIndex = index; return S_OK; } } // Такой функции нет return E_NOTFOUND; }
Создавать потоки можно откуда угодно. Но вот запустить их откуда попало нельзя. Тред войдёт в загрузчик и будет ждать на LdrpLoaderLock и других кс. Да и вообще стартап контекст не доступен, пока тред находится в загрузчике.
float Зачем костыли. Решение зависит от того, что будет делать ваш поток. Если не дать ему войти в загрузчик, то он будет работать http://kitrap08.blogspot.com/2011/05/apc-dispatchera.html Если какойто тред находится в загрузчике, то стартап контекст лежит в конце SFC: http://www.wasm.ru/forum/viewtopic.php?id=38284 При использовании HWB нужно отслеживать создаваемые треды через какой либо нотификатор или иной механизм.