Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
|
[Pascal] CreateRemoteThread подводные камни. Что делать? Help, please ;-((( 27.10.02 01:58 Число просмотров: 1639
Автор: :-) <:-)> Статус: Elderman
|
> Итак, как можно видеть, открывается дескриптор процесса > RegEdit. В нём выделяется память под поток. Копируется в > эту память исполняемый код потока. Запускается поток на > выполнение. Работает допущение, что базовый адрес, куда > загружен Kernel32 в чужом процессе и в моём одинаковые. > Вопросы: > 1) Существует ли более-менее "человеческий" способ > определения размера исполняемого кода — или заходить в > дебуггер и вручную его считать.
void F1() {}
void F2() {}
int SizeOfF1 = (int)F2 - (int)F1;
> 2) В этом простейшем случае инструкции в потоке идут одна > за другой. Надо думать, что с появлением ветвлений, циклов > и т.п., компилятор Delphi, "думая", что компилит для > "родного" процесса, будет ставить > абсолютные адреса переходов для > ветвлений. Можно ли как-нибудь исхитриться и задать > относительные? И вообще, возможно ли такое без применения > in-line ассемблера?
А по-моему, для ветвлений, циклов и т.п большинство компиляторов (VC и Delphi в том числе) генерят относительные переходы...
> 3) Почему компилятор генерит такой код возврата из функции, > помеченной как Stdcall: RET $0004. Я на всякий случай > поставил просто RET. Как более правильно, поскольку что > так, что эдак работает ;-)
Должно быть retn 4. Раз ф-я stdcall и принимает 1 параметр, она по возвращении сама должна снять со стека 4 байта. Мне вообще не понятно, зачем нужен этот код (и без него должно работать):
ASM // Correct return throm tread
POP EBP
RET
END;
К тому же этот код зависит от конкретного компилятора: компилятор может и не положить в стек EBP (или наоборот, кроме EBP в стеке может оказаться еще что-нибудь).
> И вообще, может я делаю что-то через задницу? ;-)) Что > лучше всего использовать для создания кода, который будет > исполняться в другом процессе? > Всем спасибо, жду ответов.
Посмотри в книге Рихтера - он с помощью CreateRemoteThread загружает в чужой процесс свою DLL. Вызывая CreateRemoteThread, ей качестве threadfunc передает адрес LoadLibrary (раз Kernel32 в другом процессе загружен по тому же адресу), а в качестве параметра - адрес строки "c:\mydll.dll" (перед этим ее надо поместить в адресное пространство чужого процесса).
|
<programming>
|
[Pascal] CreateRemoteThread подводные камни. Что делать? Help, please ;-((( 26.10.02 23:06
Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 26.10.02 23:16 Количество правок: 1
|
Ну вот, доигрался. Не хватает мне возможностей моего любимого компилера. Что делать? Ума не преложу. Неужели на Asm писать весь код?
Итак, проблема. Нужно кое-что поделать в адресном пространстве запущенного приложения — к примеру, RegEdit.
Вот код примера, а конкретные вопросы смотрите после ;-)
implementation
{$R *.DFM}
Type TBeepProc = Function(dwFreq, dwDuration: DWORD): BOOL; StdCall;
Function rThread(aValue: Pointer): DWORD; StdCall;
Begin
TBeepProc(aValue)(5000, 10);
Result := 777;
ASM // Correct return throm tread
POP EBP
RET
END;
End;
procedure TForm1.Button1Click(Sender: TObject);
Function GetProcessIDByTopmostWindowClass(aClass: String): DWORD;
Var wHndl: THandle;
begin
wHndl := FindWindow(PChar(aClass), Nil);
Win32Check(wHndl <> 0);
GetWindowThreadProcessID(wHndl, @Result);
End;
Function GetProcAddrFromKernel(aProcName: String): Pointer;
Var hMod: THandle;
Begin
hMod := GetModuleHandle(Kernel32);
Win32Check(hMod <> 0);
Result := GetProcAddress(hMod, PChar(aProcName));
Win32Check(Result <> Nil);
End;
Const pMemSize = 32;
Var
pID, pHndl, tHndl, tID: THandle;
rMem: Pointer;
S: DWORD;
begin
pID := GetProcessIDByTopmostWindowClass('RegEdit_RegEdit');
Win32Check(pID <> 0);
pHndl := OpenProcess(PROCESS_ALL_ACCESS, False, pID);
Win32Check(pHndl <> 0);
Try
rMem := VirtualAllocEx(pHndl, Nil, 1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Win32Check(rMem <> Nil);
Try
Win32Check(WriteProcessMemory(pHndl, rMem, @rThread, pMemSize, S));
Win32Check(S = pMemSize);
Win32Check(VirtualProtectEx(pHndl, rMem, pMemSize, PAGE_EXECUTE_READ, S));
tHndl := CreateRemoteThread(pHndl, Nil, 0, rMem, GetProcAddrFromKernel('Beep'), CREATE_SUSPENDED, tID);
Win32Check(tHndl <> 0);
Try
ResumeThread(tHndl);
WaitForSingleObject(tHndl, INFINITE);
Win32Check(GetExitCodeThread(tHndl, S));
Caption := IntToStr(S);
Finally
CloseHandle(tHndl);
End;
Finally
Win32Check(VirtualFreeEx(pHndl, rMem, 0, MEM_RELEASE) <> Nil);
End;
Finally
CloseHandle(pHndl);
End
end;
---
Итак, как можно видеть, открывается дескриптор процесса RegEdit. В нём выделяется память под поток. Копируется в эту память исполняемый код потока. Запускается поток на выполнение. Работает допущение, что базовый адрес, куда загружен Kernel32 в чужом процессе и в моём одинаковые.
Вопросы:
1) Существует ли более-менее "человеческий" способ определения размера исполняемого кода — или заходить в дебуггер и вручную его считать.
2) В этом простейшем случае инструкции в потоке идут одна за другой. Надо думать, что с появлением ветвлений, циклов и т.п., компилятор Delphi, "думая", что компилит для "родного" процесса, будет ставить абсолютные адреса переходов для ветвлений. Можно ли как-нибудь исхитриться и задать относительные? И вообще, возможно ли такое без применения in-line ассемблера?
3) Почему компилятор генерит такой код возврата из функции, помеченной как Stdcall: RET $0004. Я на всякий случай поставил просто RET. Как более правильно, поскольку что так, что эдак работает ;-)
И вообще, может я делаю что-то через задницу? ;-)) Что лучше всего использовать для создания кода, который будет исполняться в другом процессе?
Всем спасибо, жду ответов.
|
|
[Pascal] CreateRemoteThread подводные камни. Что делать? Help, please ;-((( 27.10.02 01:58
Автор: :-) <:-)> Статус: Elderman
|
> Итак, как можно видеть, открывается дескриптор процесса > RegEdit. В нём выделяется память под поток. Копируется в > эту память исполняемый код потока. Запускается поток на > выполнение. Работает допущение, что базовый адрес, куда > загружен Kernel32 в чужом процессе и в моём одинаковые. > Вопросы: > 1) Существует ли более-менее "человеческий" способ > определения размера исполняемого кода — или заходить в > дебуггер и вручную его считать.
void F1() {}
void F2() {}
int SizeOfF1 = (int)F2 - (int)F1;
> 2) В этом простейшем случае инструкции в потоке идут одна > за другой. Надо думать, что с появлением ветвлений, циклов > и т.п., компилятор Delphi, "думая", что компилит для > "родного" процесса, будет ставить > абсолютные адреса переходов для > ветвлений. Можно ли как-нибудь исхитриться и задать > относительные? И вообще, возможно ли такое без применения > in-line ассемблера?
А по-моему, для ветвлений, циклов и т.п большинство компиляторов (VC и Delphi в том числе) генерят относительные переходы...
> 3) Почему компилятор генерит такой код возврата из функции, > помеченной как Stdcall: RET $0004. Я на всякий случай > поставил просто RET. Как более правильно, поскольку что > так, что эдак работает ;-)
Должно быть retn 4. Раз ф-я stdcall и принимает 1 параметр, она по возвращении сама должна снять со стека 4 байта. Мне вообще не понятно, зачем нужен этот код (и без него должно работать):
ASM // Correct return throm tread
POP EBP
RET
END;
К тому же этот код зависит от конкретного компилятора: компилятор может и не положить в стек EBP (или наоборот, кроме EBP в стеке может оказаться еще что-нибудь).
> И вообще, может я делаю что-то через задницу? ;-)) Что > лучше всего использовать для создания кода, который будет > исполняться в другом процессе? > Всем спасибо, жду ответов.
Посмотри в книге Рихтера - он с помощью CreateRemoteThread загружает в чужой процесс свою DLL. Вызывая CreateRemoteThread, ей качестве threadfunc передает адрес LoadLibrary (раз Kernel32 в другом процессе загружен по тому же адресу), а в качестве параметра - адрес строки "c:\mydll.dll" (перед этим ее надо поместить в адресное пространство чужого процесса).
|
| |
Понятно, спасибо. Про DLL я понимаю что будет клёво работать, просто мне была интересна идея работы "впрыскивания кода" в чужой процесс. "Чисто впрыснутый" поток трудно отследить ;-) 27.10.02 19:17
Автор: HandleX <Александр М.> Статус: The Elderman
|
|
|
|