-
честно говоря, такую деталь не помню. Писал давно, да и по сути делал перевод с сишного примера Рихтера на паскаль, а под рукой сейчас исходника нет. Вечером посмотрю, если не забуду :)
-
> сишного примера Рихтера на паскаль
я то же с чьегото сишного примера делал
-
> KygECHuK (03.09.2008 10:34:39) [159]
Есть и на русском и на английском. Четвертое издание.
-
function InjectLibByRemoteThread(dwProcessId: DWORD; lpModName: PChar): Boolean;
var
l_hProcess: THandle;
l_hThread: THandle;
l_ThreadFunc: TFNThreadStartRoutine;
l_ThreadId: DWORD;
l_iLength: Cardinal;
l_pBuffer: PChar;
l_NumberOfBytesWritten: DWORD;
begin
Result := False;
l_hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE, False, dwProcessId);
if l_hProcess = 0 then Exit;
try
l_ThreadFunc := GetProcAddress(GetModuleHandle(kernel32), 'LoadLibraryA');
if not Assigned(l_ThreadFunc) then Exit;
l_iLength := Length(lpModName);
l_pBuffer := VirtualAllocEx(l_hProcess, nil, l_iLength + 1,
MEM_COMMIT, PAGE_READWRITE);
if not Assigned(l_pBuffer) then Exit;
try
if not WriteProcessMemory(l_hProcess, l_pBuffer, lpModName, l_iLength,
l_NumberOfBytesWritten)
then Exit;
l_hThread := CreateRemoteThread(l_hProcess, nil, 0, l_ThreadFunc,
l_pBuffer, 0, l_ThreadId);
Result := l_hThread <> 0;
if Result then begin
WaitForSingleObject(l_hThread, INFINITE);
CloseHandle(l_hThread);
end;
finally
VirtualFreeEx(l_hProcess, l_pBuffer, 0, MEM_RELEASE);
end;
finally
CloseHandle(l_hProcess);
end;
end;
function WithdrawLibByRemoteThread(dwProcessId: DWORD; lpModName: PChar): Boolean;
var
l_hProcess: THandle;
l_hThread: THandle;
l_ThreadFunc: TFNThreadStartRoutine;
l_ToolHelp: TToolHelp;
l_me: TModuleEntry32;
l_ThreadId: DWORD;
begin
Result := False;
l_hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE, False, dwProcessId);
if l_hProcess = 0 then Exit;
try
l_ThreadFunc := GetProcAddress(GetModuleHandle(kernel32), 'FreeLibrary');
if not Assigned(l_ThreadFunc) then Exit;
l_ToolHelp := TToolHelp.Create(TH32CS_SNAPMODULE, dwProcessId);
try
l_me.dwSize := SizeOf(TModuleEntry32);
if not l_ToolHelp.ModuleByNameFind(lpModName, l_me) then Exit;
l_hThread := CreateRemoteThread(l_hProcess, nil, 0, l_ThreadFunc,
Pointer(l_me.hModule), 0, l_ThreadId);
Result := l_hThread <> 0;
if Result then begin
WaitForSingleObject(l_hThread, INFINITE);
CloseHandle(l_hThread);
end;
finally
l_ToolHelp.Free;
end;
finally
CloseHandle(l_hProcess);
end;
end;
-
> Ты её делаешь сразу без условий или с какими то либо задержками > или синхронизацией?
Из кода видно, что выполняется ожидание завершения потока до закрытия хэндла. Или ты под задержкой/синхронизацией имел ввиду что-то другое?
-
> Из кода видно, что выполняется ожидание завершения потока > до закрытия хэндла. Или ты под задержкой/синхронизацией > имел ввиду что-то другое?
Я имел ввиду действия, которые производит библиотека при отключении жертвы от неё.
-
Действия, которые производит библиотека при отключении, выполняются в DLL_PROCESS_DETACH (в АП жертвы). Пока они не выполнятся, поток не завершит свою работу. А сервис (у меня сервис), т.е. процесс, который занимается внедрением/изъятием dll в/из АП жертвы, ждет завершения удаленного потока WaitForSingleObject(l_hThread, INFINITE); Этим и достигается синхронизация.
-
> Этим и достигается синхронизация.
Все это хоршо, я это понял из предыдущего поста. мения интеризуют не конкретно используемые объекты синхронизации Windows, а "синхронизация" потока, исправляющего адреса с другими потоками процесса жертвы
-
аааа.... Ты вот о чем. Идея такова. После того, как случился внедреж :), dll в жертве (далее просто жертва) начинает общаться с сервисом, вариантов реализации этого общения - масса, каждый выбирает, что ему по вкусу, поэтому не буду на этом останавливаться. Жертва запрашивает у сервиса, что приготовлено для данного процесса, какую dll надо загрузить, после чего выполняет LoadLibrary уже штатно. Далее останавливаются все потоки процесса кроме текущего (или это лучше сделать самым первым делом после внедрения), из загруженной dll вытягивается инфа, что должно быть перехвачено, вычисляются адреса и данные, которые должны быть по ним записаны, и все это сообщается сервису, который успешно производит подмены адресов. Сообщение жертве "все готово", та запускает потоки и завершает свой стартовый код DLL_PROCESS_ATTACH. Ну вот типа такого.
-
> evvcom © (05.09.08 12:07) [168]
А грабли как были , так и остались, не смотря на все эти хитромудрые телодвижения)
Ведь выгрузку модуля-перехватчика нельзя делать пор, пока хотя бы в одном из потоков процесса-жертвы исполняется код, принадлежащий АП модуля-перехватчика..
Первое что напрашивается для устранения засады - в ходе деинициализации перехватчика вернуть на место оригинальные IAT/EAT-элементы и в цикле (опасно, но куда деваться ?) проверять, не ссылается ли контекст каждого из существующих потоков жертвы на код в АП перехватчика или не фигурирует ли в стеках потоков адреса возвратов, указывающие на АП перехватчика.
Это отдельный геморрой, но он, видимо, того стОит ..
-
Согласен :) Я не все здесь описал, что задумал. Даже если в настоящий момент код не выполняется, и мы определим это из контекстов, стеков и прочих ухищрений, нет никакой гарантии, что не схватим AV после Resume потоков. Я столкнулся с этим в первой же своей подобной задаче, о чем упомянул в [141]. Гораздо проще, имхо, и надежнее сделать нечто типа MakeObjectInstance, которая конструировала бы в куче что-то типа вызова перехваченной функции или оригинала по условию в зависимости от взведенного флага и соответственно перед выполнением кода "ловушки" inc счетчика, после dec. Естественно все это надежно защитить, например, крит. секцией. Детали я еще не реализовывал, потому по ходу будут грабли, обязательно будут.
-
> нет никакой гарантии, что не схватим AV после Resume потоков
Гарантия есть, потому что тек.контексты и стеки потоков отныне ни прямо ни косвенно не ссылаются ни на один из адресов в АП модуля-перехватчика, что как раз и покажет проверка. И более никогда не будут обращаться к этому АП, потому что оригинальная IAT восстановлена перед началом проверки.
-
Сергей, ты в [141] читал ситуацию? > И более никогда не будут обращаться к этому АП, потому что > оригинальная IAT восстановлена перед началом проверки.
Разве обращаться к функции можно только каждый раз проверяя IAT? Еще раз поясню ситуацию. Процесс загрузил мою dll, dll изменила IAT, процесс считал адрес (это уже адрес в моей dll) и сохранил его в ebx, далее цикл:
push ebx
условие 1:
call ebx
... прочие условия
условие N:
call FreeLibrary
pop ebx
cmp ...
jmp nz, цикл
Вот такая вот реальная ситуация была и происходило это в однопоточном приложении.
-
> evvcom © (05.09.08 14:10) [172]
А, ты вон о чем ..
Ч.г., я не вник в [141], а ты там завел речь о частном случае (довольно редкий он и заведомо не случай автора, потому я и не рассматривал его) ..
Ну что тут сказать ? Для случаев, подобных твоему, метод перехвата путем модификации IAT/EAT не годится, здесь на сцену выходит метод сплайсинга.
-
> здесь на сцену выходит метод сплайсинга.
Что за зверь, где о нём можно раздобыть инфу?
-
-
> Тебе-т он зачем ? Явно же не твой же случай ..
Автор:
Для того, чтобы его понять нужна всего-лишь капля мозгов (не больше).
по минимальным требованиям, вроде подхожу... :) Учиться никогда не поздно, хотя часто бесполезно ....
|