Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.08.01;
Скачать: CL | DM;

Вниз

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 вся ветка

Текущий архив: 2004.08.01;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.061 c
6-1086254122
t100
2004-06-03 13:15
2004.08.01
Прием почты.


8-1084513139
Push
2004-05-14 09:38
2004.08.01
Installer


3-1089442246
Kaginava
2004-07-10 10:50
2004.08.01
работа с БД из отдельного потока


8-1084647905
Agent[007]
2004-05-15 23:05
2004.08.01
MP3 в API


1-1089878900
Yurko
2004-07-15 12:08
2004.08.01
Обработка нажатия