Форум: "WinAPI";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];
ВнизCreateRemoteThread Найти похожие ветки
← →
Тимохов © (2004-06-18 11:08) [0]Когда читал Рихтера пропустил эту функцию. Но тут любопытство заело - не ужто можно в любом процессе создать поток. Во-первых, я понял, что не в любом - есть ограничения (правда не совсем понял какие). Во-вторых, почитав того же Рихтера понял, что в качестве потоковой функции он передает LoadLibrary, в функции инициализации которой он и делает нужные действия в другом процессе.
Насколько я понимаю точка входа в LoadLabriary определается в исходном процессе. Считается, что точка входа LoadLabriary в remote процессе будет таже, т.к. Kernel32.dll будет якобы загружена по тому же базовому адресу. Но как я понимаю никаких гарантий этого нет (Рихтер и сам говорит, что по опыту это так и не более).
Поэтому возникло желание внедрить не LoadLibrary, а свою функцию в качестве потоковой.
Ясно, что она должна быть в адресном пространстве другого процесса. Т.е. нужно:
1. Зарезервировать и выделить памятиь в помощью VirtualAllocEx в remote процессе.
2. С помощью WriteProcessMemory в выделенной памяти сохранить функцию.
3. Вызвать CreateRemoteThread.
В связи в пунктом 2 и вопрос: как переписать функцию? Допустим, можно в текущем процессе описать функцию и затем ее скопировать в remote процесс. Но тогда поползут все адреса. К тому же непонятно как определять конец функции, т.е. сколько копировать.
:))Все, что после жирного - мои домыслы, предназначенные показать, что я сам над этим тоже думал :)) Скорее всего они абсолютно лажовые.
← →
panov © (2004-06-18 11:43) [1]Так LoadLibrary для того и используется, чтобы в другом процессе загрузить функцию из библиотеки во внедренном в процесс потоке.
http://bugtraq.ru/library/programming/invisible.html
← →
Тимохов © (2004-06-18 12:02) [2]
> panov © (18.06.04 11:43) [1]
спасибо за ссылку - почитаю.
Но, как я сказал выше, мы предполагаем, что loadlibrary загружен по тому же адресу. Но это же не гарантировано...
← →
Игорь Шевченко © (2004-06-18 12:06) [3]
> Считается, что точка входа LoadLabriary в remote процессе
> будет таже, т.к. Kernel32.dll будет якобы загружена по тому
> же базовому адресу.
kernel32.dll НЕ МОЖЕТ БЫТЬ ЗАГРУЖЕН ПО ДРУГОМУ БАЗОВУМУ АДРЕСУ!!!
← →
Игорь Шевченко © (2004-06-18 12:09) [4]
> В связи в пунктом 2 и вопрос: как переписать функцию? Допустим,
> можно в текущем процессе описать функцию и затем ее скопировать
> в remote процесс. Но тогда поползут все адреса. К тому же
> непонятно как определять конец функции, т.е. сколько копировать
А почему они (адреса) поползут, если писать функцию в позиционно-независимом коде (обычно на языке ассемблера) ? "Конец функции", точнее, ее размер, определяется одним из доступных способов, например, по MAP-файлу или по разнице адресов между нужной фукнцией и следующей за ней.
← →
Тимохов © (2004-06-18 12:18) [5]
> Игорь Шевченко © (18.06.04 12:06) [3]
Рихтер, 4изд, 22 глава, если не ошибаюсь 549-551 стр. Вот Жефри такого не утверждает однозначно - он говорит по опыту. Вы думаете он не прав? Почему не может быть по другому адресу? Есть документальное подтверждение?
Теперь вопрос по поводу:
> А почему они (адреса) поползут, если писать функцию в позиционно-независимом
> коде (обычно на языке ассемблера) ? "Конец функции", точнее,
> ее размер, определяется одним из доступных способов, например,
> по MAP-файлу или по разнице адресов между нужной фукнцией
> и следующей за ней.
Т.е. на дельфи не выйдет?
Вы делали такое сами?
← →
Игорь Шевченко © (2004-06-18 12:36) [6]Тимохов © (18.06.04 12:18)
Для обоснования могу предложить попробовать провести следующий эксперимент: напиши программу на Delphi, укажи у нее базовый адрес в опциях линкера чуть меньше базового адреса kernel32.dll, запусти и посмотри, что тебе скажет система.
> Т.е. на дельфи не выйдет?
>
> Вы делали такое сами?
Выйдет. Делал.
← →
Тимохов © (2004-06-18 12:39) [7]
> Игорь Шевченко © (18.06.04 12:36) [6]
В дельфи разве позиционно независимый код?
← →
Игорь Шевченко © (2004-06-18 12:49) [8]Тимохов © (18.06.04 12:39)
> В дельфи разве позиционно независимый код?
Как написать
← →
Тимохов © (2004-06-18 12:56) [9]И как же надо писать, чтобы был позиционно независим?
Вот например такой кодprocedure TForm1.Button6Click(Sender: TObject);
var
s: string;
begin
s := "Dima";
end;
имеет в себе такой асм фрагмент на строке s := "Dima"00452833 8D45FC lea eax,[ebp-$04]
00452836 BA68284500 mov edx,$00452868
0045283B E88C1AFBFF call @LStrLAsg
Т.е. это позиционно зависимый код. И как быть.
← →
Игорь Шевченко © (2004-06-18 12:58) [10]
> Т.е. это позиционно зависимый код. И как быть.
Не писать такого кода, например. Тщательно изучать сгенерированный компилятором код.
← →
Тимохов © (2004-06-18 13:07) [11]
> Игорь Шевченко © (18.06.04 12:58) [10]
> Не писать такого кода, например. Тщательно изучать сгенерированный
> компилятором код.
Я так понимаю, что вы имеете в виду следующий цикл операций для получения позиционно независимого кода в дельфи:
1. Написать код в дельфи.
2. Посмотреть асм.
3. Если есть абсолютные ссылки, переписать.
4. Повторить шаг 1.
Так?
Как кстати в данном примере можно заполнить s строкой "dima"?
Cуммирую полученные сведения:
1. Нужно написать функцию, которая будет позиционна НЕзависима (пока не понял, как это делать на дельфи, а не на asm).
2. Далее посползоваться VirtualAllocEx, WriteProcessMemorty, CreateRemoteThread.
И результат готов.
← →
Игорь Шевченко © (2004-06-18 13:35) [12]
> Так?
Так, вроде.
> Как кстати в данном примере можно заполнить s строкой "dima"?
Например, объявить переменную из 5-и символов и каждый символ заполнить вручную, последний - нулем.
← →
Тимохов © (2004-06-18 14:34) [13]
> Игорь Шевченко © (18.06.04 13:35) [12]
Я вот, что подумал - в remote процессе не будет же никакого дельфового манагера памяти! Т.е. там не будет никаких длинный строк!
И еще в коде0045283B E88C1AFBFF call @LStrLAsg
@LStrLAsg является абсолютной ссылкой (или нет?). Т.е. я вообще в другом процессе не смогу вызывать никакие знакомые мне функции.
А как же быть то ? :)))
← →
VMcL © (2004-06-18 14:42) [14]>>Тимохов © (18.06.04 14:34) [13]
А вот так и быть. Или руцями писать. Или вызывать только те функции, которые импортируются программой-жертвой из DLL. Если она импортирует LoadLibrary() & GetProcAddress(), то уже немного легче.
← →
Тимохов © (2004-06-18 14:45) [15]
> VMcL © (18.06.04 14:42) [14]
Функции oadLibrary() & GetProcAddress() она вроде должна (вернее вероятно) ипмортирует.
Понятно, что можно подргузить dll.
А раз так, то зачем вообще нужно делать это (т.е. свою потоковую функцию) - можно воспользоваться методом Рихтера из 22 главы 4-го издания - т.е. к качестве потоковой функции использовать LoadLibrary
← →
panov © (2004-06-18 15:37) [16]>Тимохов © (18.06.04 14:45) [15]
А раз так, то зачем вообще нужно делать это (т.е. свою потоковую функцию)
Представь, что тебе надо создать отдельный поток в некотороом процессе.
Функция отока у тебя также импортируется из библиотеки.
И тут возникает проблема.
Если ты хочешь, чтобы поток продолжал работать, но DLL-ку ты хочешь выгрузить, то при попытке это сделать процесс-жертва успешно молча исчезнет(терминируется).
Вот для этого и можно бы вручную записать код для выполнения.
← →
Тимохов © (2004-06-18 15:45) [17]
> Вот для этого и можно бы вручную записать код для выполнения.
предасталяю какие это муки сделать на дельфи - вдруг случайно используешь функцию, которой нет в remote процессе.
Думаю, что реально сделать только знатокам асма :)
Вопрос знатокам delphi+asm
в данном коде @LStrLAsg является абсолютной ссылкой?0045283B E88C1AFBFF call @LStrLAsg
Мне как бы нужно понять можно ли в экспортируемой функции потока допускать наличие таких конструкций или нет.
← →
Игорь Шевченко © (2004-06-18 16:09) [18]
> в данном коде @LStrLAsg является абсолютной ссылкой?
А какая разница ? В целевом процессе функции @LStrLAsg нет и быть не может (тем более, по нужному адресу).
Используй LoadLibrary, как советует Рихтер, и не мучайся
← →
Тимохов © (2004-06-18 16:13) [19]
> Игорь Шевченко © (18.06.04 16:09) [18]
Я тоже так думал, но вот Panov мне сказал, что не всегда это хорошо.
Да и интересно же. Вы же в [6] сказали что делали без LoadLibrary. Вот и мне интересно как это.
← →
Игорь Шевченко © (2004-06-18 16:19) [20]Тимохов © (18.06.04 16:13)
> Вы же в [6] сказали что делали без LoadLibrary. Вот и мне
> интересно как это.
В [6] я, насколько мне помнится, сказал, что делал позиционно-независимый код, а не CreateRemoteThread без LoadLibrary
← →
Тимохов © (2004-06-18 16:28) [21]
> Игорь Шевченко © (18.06.04 16:19) [20]
> В [6] я, насколько мне помнится, сказал, что делал позиционно-независимый
> код, а не CreateRemoteThread без LoadLibrary
ну в общем да, другого вы и не говорили.
значит я вас не так понял или вопрос не так задал.
Тогда поставлю вопрос более корректно (ну чтобы разночтений не было)
А все-таки без LoadLibrary со своей позиционнонезависимой поточной функцией делали CreateRemoteThread?
← →
Тимохов © (2004-06-18 16:29) [22]виноват "Вы" забыл в вопросе :)
← →
Игорь Шевченко © (2004-06-18 16:42) [23]Тимохов © (18.06.04 16:29)
Не делал. А зачем, когда можно сделать LoadLibrary ? В процессы, которые функции из kernel32.dll не экспортируют, я не пытался внедряться, вроде незачем.
← →
Тимохов © (2004-06-18 16:50) [24]
> В процессы, которые функции из kernel32.dll не экспортируют,
Вы этот факт как то проверяли перед внедрением?
Т.о. еще раз суммирую полученные знания:
1. Все кто пользовался CreateRemoteThread делали это так, как написано у Рихтера, т.е. через LoadLibrary.
2. Явных указаний, что кто-то все-таки делал свою функцию я не увидел.
← →
Burmistroff (2004-06-18 18:16) [25]Пример со "своими" функциями. Правда довольно корявый. когда он писался, знания асма были близки к нулю ;)
(см. "DoRemoteJob")
http://www.maxcomputing.narod.ru/ahijack2.html
← →
Тимохов © (2004-06-18 18:23) [26]
> Burmistroff (18.06.04 18:16) [25]
спасибо.
← →
Игорь Шевченко © (2004-06-18 21:48) [27]
> Вы этот факт как то проверяли перед внедрением?
Вообще-то кроме SMSS.EXE все процессы импортируют KERNEL32.DLL (по крайней мере, я не встречал другого Native-процесса)
← →
Тимохов © (2004-06-21 11:19) [28]
> Игорь Шевченко © (18.06.04 21:48) [27]
т.е. проверять не надо, надо верить!
Так?
Все ж таки про базовый адрес kernel32.dll.
Посидел в выходные не нашел документального подтверждения тому, что он во всех процессах обязательно будет одинаковым.
← →
VMcL © (2004-06-21 11:33) [29]>>Тимохов © (21.06.04 11:19) [28]
>Все ж таки про базовый адрес kernel32.dll
см. [6] Я уже попробовал. Очень интересное окошко вылазит.
← →
Игорь Шевченко © (2004-06-21 11:41) [30]
> Посидел в выходные не нашел документального подтверждения
> тому, что он во всех процессах обязательно будет одинаковым
У Рихтера написано. В главе DLL и следующей за ней.
← →
Тимохов © (2004-06-21 11:57) [31]
> VMcL © (21.06.04 11:33) [29]
тоже хочу попробовать.
Какой базовый адрес у kernel32?
← →
Тимохов © (2004-06-21 12:34) [32]
> тоже хочу попробовать.
НАшел.
ПРоверил. Действительно ругается.
> Игорь Шевченко © (21.06.04 11:41) [30]
Не подумайте, что придираюсь, просто ищу правду.
Но вот это:
Рихтер 4 изд, глава 22.
"Вызов CreateRemoteThread предполагает, что Kerne32.dll спроецирована в локальном процессе на ту же область памяти, что и в удаленном. Kernel32.dll используется всеми приложениями, и, как показывает опыт, система проецирует эту DLL в каждом процессе по одному и тому же адресу."
Промотрел начиная с 19 главы. Не вижу, что Kernel32.dll проецируется по одному адресу.
Все ж таки интересно, как эту информацию обрабатывать...
← →
Игорь Шевченко © (2004-06-21 12:38) [33]
> Промотрел начиная с 19 главы. Не вижу, что Kernel32.dll
> проецируется по одному адресу.
> ПРоверил. Действительно ругается.
Насколько я помню, это было написано, где говорилось про bound import (Хотя, может, и ошибаюсь, Рихтера под рукой нет)
← →
Тимохов © (2004-06-21 12:45) [34]Спасибо всем за обсуждение.
Я склонен постановить, что тема для меня раскрыта в полном объеме. Данный вопрос является скорее всего теоретическим.
← →
Burmistroff (2004-06-22 00:04) [35]Кстати, по поводу размещений в памяти системных DLL. как-то раз вылезло забавное окошко:
http://mc.webm.ru/5/reloc.gif
← →
Burmistroff (2004-06-22 00:06) [36]Ага, полагаю такое же что и у [29]
;)
← →
Тимохов © (2004-06-22 11:02) [37]
> Burmistroff (22.06.04 00:04) [35]
оно у меня тоже вылезало (только про другую библиотеку) при попытке расположиться по адресу kernel32.
← →
diMAN (2004-06-23 11:43) [38]Вот, взял кусочек из своего кода, только для примера. Надеюсь тут всё будет понятно, хотя есть конечно свои тонкости.
type
// Данные, которые необходимы для работы в remote thread
TRData = packed record
MessageBox : pointer;
end;
PRData = ^TRData;
// Собственно сам код, который будет работать в remote thread
function ThreadProc(RData: PRData): DWORD; stdcall;
asm
call @Where
@Where:
pop esi
sub esi, offset @Where
mov edi, RData
// Это эквивалент MessageBox(...)
push dword ptr MB_SYSTEMMODAL or MB_OK
lea ecx, [esi][@Caption]
push ecx
lea ecx, [esi][@Text]
push ecx
push dword ptr $00
call [edi + TRData.MessageBox]
jmp @Exit
@Caption: db "From ThreadProc", 0
@Text: db "Ну надо же, работает!", 0
@Exit:
mov Result, 0
end;
// Для вычисления размера ThreadProc
procedure EndThreadProc;
begin
end;
var
hProcess : THANDLE = 0;
hThread : THANDLE = 0;
RemoteFuncAddr : pointer = nil;
FuncSize : integer = 0;
lpNumberOfBytesWritten : Cardinal = 0;
RData : TRData;
procedure TForm1.btnRunClick(Sender: TObject);
var PID: DWORD;
begin
FillChar(RData, SizeOf(RData), #0);
PID := LoadLibrary("user32.dll");
with RData do
begin
MessageBox := GetProcAddress(PID, "MessageBoxA");
end;
// Получаем PID процесса в котором мы собираемся запустить remote thread
if edtPID.Text <> ""
then PID := StrToInt( edtPID.Text )
else PID := GetCurrentProcessId;
// Открываем этот процесс
hProcess := OpenProcess(
PROCESS_CREATE_THREAD or // For CreateRemoteThread
PROCESS_QUERY_INFORMATION or // Required by Alpha
PROCESS_VM_OPERATION or // For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE or // For WriteProcessMemory
PROCESS_VM_READ, // For ReadProcessMemory
FALSE, PID);
if (hProcess = 0) then
begin
memLog.Lines.Add("Error OpenProcess: " + SysErrorMessage(GetLastError));
Abort;
end;
// Вычисляем размер ThreadProc
asm
push eax
mov eax, offset EndThreadProc
sub eax, offset ThreadProc
mov FuncSize, eax
pop eax
end;
// Выделяем память для кода и данных
RemoteFuncAddr :=
VirtualAllocEx(hProcess, nil, FuncSize + SizeOf(TRData), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (RemoteFuncAddr = nil)
then begin
memLog.Lines.Add("Error VirtualAllocEx: " + SysErrorMessage(GetLastError));
Abort;
end;
// Копируем код
if not WriteProcessMemory(hProcess, RemoteFuncAddr,
@ThreadProc, FuncSize, lpNumberOfBytesWritten)
then begin
memLog.Lines.Add("Error WriteProcessMemory RemoteControl: " + SysErrorMessage(GetLastError));
Abort;
end;
// Копируем данные
if not WriteProcessMemory(hProcess, Pointer(Integer(RemoteFuncAddr) + FuncSize),
@RData, SizeOf(TRData), lpNumberOfBytesWritten)
then begin
memLog.Lines.Add("Error WriteProcessMemory RData: " + SysErrorMessage(GetLastError));
Abort;
end;
// ... и в путь :)
hThread := CreateRemoteThread(hProcess, nil, 4096,
RemoteFuncAddr, Pointer(Integer(RemoteFuncAddr) + FuncSize), 0, hThread);
if (hThread = 0)
then begin
memLog.Lines.Add("Error CreateRemoteThread: " + IntToHex(GetLastError, 8) + " " + SysErrorMessage(GetLastError));
Abort;
end;
end;
← →
Тимохов © (2004-06-23 11:51) [39]
> diMAN (23.06.04 11:43) [38]
Спасибо.
Очень интересно.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.036 c