Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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.58 MB
Время: 0.034 c
6-1085758756
kalishenko
2004-05-28 19:39
2004.08.01
Неблокирующий режим в сокетах


3-1089189160
reticon
2004-07-07 12:32
2004.08.01
Подключение к PostgreSQL


1-1090212946
Valeri
2004-07-19 08:55
2004.08.01
Image


1-1089925831
AlexR
2004-07-16 01:10
2004.08.01
Отследить нажатие га доп. клавиатуре


1-1090354319
Kotka
2004-07-21 00:11
2004.08.01
Неуловимый exception





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский