Пишу GUI прогу-оболочку, которая запускает процес-жертву, внедряет в него длл, перехватывает нужные функции, общается с родительским процесом. В общем тулза для исследования алгоритма работы неизвестных прог. Все достаточно банально: - запуск жертвы через CreateProcess( .. CREATE_SUSPENDED .. ) - внедрение длл через CreateRemoteThread - ResumeThread Столкнулся в с проблемой. Некоректное внедрение в некоторые процесы. Например, калькулятор не отображается, а просто висит в памяти ( длл загружается, удаленный поток завершается нормально, ResumeThread - ok ), в notepad длл даже не загружается. В то же время консольные приложения нормально отрабатывают ( хотя GUI, созданное визардом VC, тоже работает ). З.Ы. поиск уже перерыл..
запуск Код (Text): char drv[ MAX_PATH ]; char dir[ MAX_PATH ]; _splitpath( AppPath, drv, dir, 0, 0 ); lstrcat( drv, dir ); CreateProcess( 0, AppPath, 0, 0, 0, CREATE_SUSPENDED, 0, drv, &si, &pi ); InjectDll( pi.dwProcessId ); ResumeThread( pi.hThread ); внедрение Код (Text): BOOL InjectDll( DWORD pid, char*ModulePath ) { BYTE* Memory; DWORD ThreadId; HANDLE hThread; HANDLE hProcess; hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); DWORD Written; Memory = ( BYTE* )VirtualAllocEx( hProcess, 0, sizeof( Inject ), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); if( !Memory ) { return( 0 ); } //инициализация внедряемого кода: Inject inject( Memory, ModulePath ); //записать машинный код по зарезервированному адресу WriteProcessMemory( hProcess, Memory, &inject, sizeof( Inject ), &Written ); //выполнить машинный код hThread = CreateRemoteThread( hProcess, 0, 0, ( LPTHREAD_START_ROUTINE )Memory, 0, 0, &ThreadId ); if( !hThread ) { return( 0 ); } WaitForSingleObject( hThread, INFINITE ); return( 1 ); }
psu Навскидку: ты копируешь указатель на ModulePath в процесс, а не саму строку. Если только Inject - не хитрый класс, перегружающий operator&
n0name Да, может, если в Inject статический массив. А вот перегрузка оператора не поможет, т.к. размер задаётся через sizeof.
Код (Text): struct Inject { BYTE PushCommand; //push BYTE* PushArgument; //LibraryName WORD CallCommand; //call BYTE* LoadLibraryCallAddr; //loadlibrary BYTE PushExitThread; //push BYTE* ExitThreadArg; //0 WORD CallExitThread; //call BYTE* ExitThreadAddr; //exitthread FARPROC AddrLoadLibrary ; //kernel32.LoadLibraryA FARPROC AddrExitThread; //kernel32.ExitThread char LibraryName[MAX_PATH]; //----------------------------------------------------------------- Inject( BYTE* Memory, char* ModulePath ) { HMODULE hKernel32 = GetModuleHandle( "kernel32.dll" ); PushCommand = 0x68; PushArgument = Memory + 30; CallCommand = 0x15FF; LoadLibraryCallAddr = Memory + 22; PushExitThread = 0x68; ExitThreadArg = 0; CallExitThread = 0x15FF; ExitThreadAddr = Memory + 26; AddrLoadLibrary = GetProcAddress( hKernel32, "LoadLibraryA" ); AddrExitThread = GetProcAddress( hKernel32, "ExitThread" ); lstrcpy( LibraryName, ModulePath ); } //----------------------------------------------------------------- }; Выравнивание побайтовое
Да, да, угадал, маладэц! Други, может все-таки кто-нибуть подскажет куда смотреть? Поделюсь исходниками, если надо
подскажу такой код невалиден: CreateProcess( ... CREATE_SUSPENDED ... ) VirtualAllocEx() WriteProcessMemory() CreateRemoteThread( обычно на LoadLibraryA ) WaitForSingleObject() ResumeThread( ProcInfo.hProcess ) иногда (зависит от набора ДЛЛ) при этом ломается список модулей процесса глюки самые невероятные см: http://forum.sources.ru/index.php?showtopic=177691&view=showall http://wasm.ru/forum/viewtopic.php?pid=168358 https://www.rootkit.com/newsread.php?newsid=715 правильно имеено так как на рутките, вместо CreateRemoteThread -> QueueUserAPC меньше рихтеру доверяйте!
Инжекть APC а не Thread, наблюдаются глюки со многими прогами (к примеру Total Commander)... Я скоро планирую написать небольшую статейку, а то инжект от ms-rem'а (вроде как его) немного... гм... страннен... и не полный, в любом случае
psu Попробуй ключ в реестре: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\APPINIT_DLLS. Он содержит имена библиотек подгружаемых ко всем новым процессам (если у тебя ключа нет - создай).
Спасибо, очень помогли! upd: Под XP работает. Под win98 QueueUserAPC() возвращает "успех" , но внедрённый код почему-то не запускается. Сразу запускается threadproc. Это происходит даже если пытаешься внедрить в свой собственный процесс. Но зато под win98 я не заметил проблем с запуском гуишных программ через _CreateRemoteThread() из RemoteLib.
Натолкнулся на очередной глюк. процесс А: - запуск жертвы через CreateProcess( .. CREATE_SUSPENDED .. ) - внедрение куска кода через QueueUserAPC() - ResumeThread - Жду, пока тред сам себя остановит процесс Б: в этом куске запускается и сохр. результат LoadLibraryW, потом GetLastError, потом подмена retAddr и jmp в SuspendThread процесс А: ReadProcessMemory VirtualFreeEx ResumeThread Глюк вот в чем: Запускаю проги типа calc, notepad из Total Commander. Если найти соотв. exe файл и запустить его кликом, то внедрение проходит успешно. Если ввести путь к exe в командной строке Total Commander, то LoadLibraryW() возвращает NULL , а GetLastError() ERROR_NOACCESS Оказалось, что где-то в внутри ntdll:LdrLoadDll() происходит нарушение доступа, причём даже LoadLibrary("kernel32.dll") возвращает эту ошибку. Не знаю, совпадение или нет, но есть ещё глюк с буфером обмена, который проявляется всесте с ошибкой LoadLibrary(). Если запустить Total Commander под дебагом, но без перехватов API, поставить точку останова на CreateProcessW, запустить что угодно из командной строки Total Commander, и в любой другой программе попытаться скопировать текст в буфер, та программа подвисает на несколько секунд. Всё это под WinXP sp3
Не юзать гуан. > Суспендим все потоки. > Создаём стек для каждого потока. > Сохраняем контекст всех потоков. > Загружаем в контекст всех потоков Esp и Ss на новый стек. > Выводим потоки из спящего состояния. > Управление получает наш код. > Восстанавливаем сохранённый контекст потоков.
похоже на внедрение в уже работающий процесс. Мне же надо, загрузить длл в новый процесс до его инициализации. Похоже, что придётся использовать DetourCreateProcessWithDll() , хотя я и не хотел, потому что она меняет таблицу импортов, и такая длл становится невыгружаемой. Хотя можно применить последнее средство - найти и поменять в новом процессе точку входа. Тогда наш код вызовется уже после всей инициализации, и работать это будет даже под "девятками".
Тоесть тебе нужно подгрузить модуль пока загрузчик не инициализирован ? Или до нотификации модулей ? Или пока поток не начал исполнять главную точку входа модуля ?