Задача в отслеживании стартовых адресов новых потоков. Сейчас у меня для отслеживания новых потоков идет перехват NtContinue. Из переданного в нее контекста, в Eax лежит адрес старта нового потока, это работает на хр сп3 и windows 7/+wow64. Недавно задумался насколько это грамотно или неграмотно, и будет ли это работать на всех остальных NT, если нет то какой способ отслеживания стартовых адресов предпочтительнее? ой... промахнулся разделом извините. Имел в виду WASM.WIN32
Определённо тот, который ваш фаерволл не будет отслеживать. Я бы создавал копии нормальных потоков и получал управление в начале их исполнения(тоесть пока поток гдето в загрузчике например). Такие потоки не вызывают подозрений, да и не могут, так как адреса стартап процедур нормальные(ну определите вы что CONTEXT.rEax = AddressOfEntryPoint, что дальше ?), а отследить куда такой тред перейдёт не получится.
да собственно задача то намного проще у меня. просто я не уверен что на всех версиях винды именно в eax будет адрес старта.
Или еще точнее - нужно получить ETHREAD интересующего тебя потока Там: Код (Text): typedef struct _ETHREAD { KTHREAD Tcb; LARGE_INTEGER CreateTime; union { LARGE_INTEGER ExitTime; LIST_ENTRY KeyedWaitChain; }; union { LONG ExitStatus; PVOID OfsChain; }; union { LIST_ENTRY PostBlockList; struct { PVOID ForwardLinkShadow; [b] PVOID StartAddress;[/b] }; }; union { PTERMINATION_PORT TerminationPort; PETHREAD ReaperLink; PVOID KeyedWaitValue; PVOID Win32StartParameter; }; [skip] } ETHREAD, *PETHREAD;
izl3sa SYSTEM_HANDLE_INFORMATION.Object не ? Код (Text): ; + ; Опредедяет адрес описателя обьекта(KPROCESS, KTIMER etc). ; QueryObject proc uses ebx ObjectHandle:HANDLE, Object:PVOID Local SystemInformation:PVOID, SystemInformationLength:ULONG Local ProcessInformation:PROCESS_BASIC_INFORMATION Local HandleInformation[sizeof(SYSTEM_HANDLE_INFORMATION) + 4]:BYTE invoke ZwQueryInformationProcess, NtCurrentProcess, ProcessBasicInformation, addr ProcessInformation, sizeof(PROCESS_BASIC_INFORMATION), NULL test eax,eax jnz Exit mov SystemInformation,eax invoke ZwQuerySystemInformation, SystemHandleInformation, addr HandleInformation, sizeof(SYSTEM_HANDLE_INFORMATION) + 4, addr SystemInformationLength cmp eax,STATUS_INFO_LENGTH_MISMATCH jne Exit cmp SystemInformationLength,NULL je Exit add SystemInformationLength,50*sizeof(SYSTEM_HANDLE_INFORMATION) invoke ZwAllocateVirtualMemory, NtCurrentProcess, addr SystemInformation, 0, addr SystemInformationLength, MEM_COMMIT, PAGE_READWRITE test eax,eax jnz Exit invoke ZwQuerySystemInformation, SystemHandleInformation, SystemInformation, SystemInformationLength, Eax test eax,eax mov edx,SystemInformation jnz Error mov ebx,ProcessInformation.UniqueProcessId mov ecx,dword ptr [edx] mov eax,ObjectHandle add edx,4 assume edx:PSYSTEM_HANDLE_INFORMATION Next: cmp [edx].ProcessId,ebx jne @f cmp [edx].Handle,ax je Objext @@: add edx,sizeof(SYSTEM_HANDLE_INFORMATION) loop Next mov eax,STATUS_NOT_FOUND jmp Error Objext: mov edx,[edx].Object mov ebx,Object xor eax,eax mov dword ptr [ebx],edx Error: push eax invoke ZwFreeVirtualMemory, NtCurrentProcess, addr SystemInformation, addr SystemInformationLength, MEM_RELEASE pop eax Exit: ret QueryObject endp Только как вы будите дальше читать память ядра %
float Скажите, что вы будите делать дальше с полученной ссылкой ? В шелле(shlwapi.dll) есть функа SHCreateThread(): Код (Text): typedef struct { LPTHREAD_START_ROUTINE pfnMain; LPTHREAD_START_ROUTINE pfnSync; HANDLE hSync; void *pvData; DWORD dwFlags; IUnknown *punkThreadRef; IUnknown *punkProcessRef; } PRIVCREATETHREADDATA; DWORD CALLBACK WrapperThreadProc(void *pv) { // make a copy of the input buffer, this is sitting on the calling threads stack // once we signal him his copy will be invalid PRIVCREATETHREADDATA rgCreate = *((PRIVCREATETHREADDATA *)pv); HRESULT hrInit; if (rgCreate.dwFlags & CTF_COINIT) hrInit = SHCoInitialize(); // call the synchronous ThreadProc while the other thread is waiting on hSync if (rgCreate.pfnSync) rgCreate.pfnSync(rgCreate.pvData); SetEvent(rgCreate.hSync); // release the main thread.. // call the main thread proc DWORD dwRes = rgCreate.pfnMain(rgCreate.pvData); if (rgCreate.punkThreadRef) rgCreate.punkThreadRef->Release(); if (rgCreate.punkProcessRef) rgCreate.punkProcessRef->Release(); if (rgCreate.dwFlags & CTF_COINIT) SHCoUninitialize(hrInit); return dwRes; } // Call if you want to kick off an independent thread and // you don't care about the handle or thread ID. // // If the create fails, call synchronously. // // optionally call a secondary callback when the thread // is created. // returns: // TRUE if the thread was created STDAPI_(BOOL) SHCreateThread( LPTHREAD_START_ROUTINE pfnThreadProc, void *pvData, DWORD dwFlags, // CTF_* LPTHREAD_START_ROUTINE pfnCallback) OPTIONAL { BOOL bRet = FALSE; PRIVCREATETHREADDATA rgCreate = {0}; // can be on the stack since we sync the thread ASSERT(dwFlags & CTF_INSIST ? pfnCallback == NULL : TRUE); // can't have a sync if you insist if (CTF_THREAD_REF & dwFlags) SHGetThreadRef(&rgCreate.punkThreadRef); if (CTF_PROCESS_REF & dwFlags) _SHGetInstanceExplorer(&rgCreate.punkProcessRef); rgCreate.pfnMain = pfnThreadProc; rgCreate.pfnSync = pfnCallback; rgCreate.pvData = pvData; rgCreate.dwFlags = dwFlags; rgCreate.hSync = CreateEvent(NULL, FALSE, FALSE, NULL); if (rgCreate.hSync) { DWORD idThread; HANDLE hThread = CreateThread(NULL, 0, WrapperThreadProc, &rgCreate, 0, &idThread); if (hThread) { // BUGBUG: should this be infinite, or should it be say 20 seconds ? WaitForSingleObject(rgCreate.hSync, INFINITE); CloseHandle(hThread); bRet = TRUE; } CloseHandle(rgCreate.hSync); } if (!bRet) { if (rgCreate.punkThreadRef) rgCreate.punkThreadRef->Release(); if (rgCreate.punkProcessRef) rgCreate.punkProcessRef->Release(); if (dwFlags & CTF_INSIST) { // failed to create another thread... call synchronously ASSERT(pfnCallback == NULL); // can't have a sync if you insist pfnThreadProc(pvData); bRet = TRUE; // what should the return be here? } } return bRet; } Она создаёт тред в текущем процессе. Но стартап процедура системная - WrapperThreadProc(), далее она вызывает колбек, ссылка на который передана аргументом в SHCreateThread(). Получите вы контекст потока, также ссылку на стартап код. Что делать дальше, как определить что тред паразитный и найти реальный стартап код ? Это только частный случай, общая модель таких вызовов - используется шлюз, через который вызывается стартап процедура. Взять любой код, который передаёт управление по произвольной ссылке, например: Код (Text): ZwClose: mov eax,19 mov edx,7FFE0300 call dword ptr ds:[edx] ret 4 Первое что пришло на ум, ссылка на колбек расположена в [Edx]. Формируем её и загружаем в контекст @ZwClose(). Вы определите что стартап процедура расположена в системном модуле. Разумеется это самые простейшие способы, можно использовать весьма сложные механизмы вызова, так что в контексте будет мусор с первого взгляда. Весьма пичально, что во всей малваре используются примитивные механизмы таких вызовов(решение "в лоб"), вызовы апи не безопасны(не скрывается адрес возврата), потоки создаются с стартапом, который пайлод и тп.