Как можно получить PID, если есть hProcess? Ситуация такова: стартует приложение через ShellExecuteEx. Что это за приложение — заранее неизвестно, так как в ShellExecuteEx я передаю путь к файлу, который требуется открыть.
Далее необходимо послать сообщение окну того приложения, которое запустилось для открытия этого файла. После запуска процесса я делаю EnumWindows, а в функции EnumWindowsProc получаю PID процесса, в котором каждое окошко создано — GetWindowThreadProcessId. Один из этих PID — тот, который запустила ShellExecuteEx. По идее, их надо бы сравнить, но у меня на выходе ShellExecuteEx есть hProcess, а не пид. Как быть? Единственный способ узнать пид запущенного процесса, как я понял — вызвать CreateProcess и пид будет возвращен в структуре PROCESS_INFORMATION.
Кто поможет?
--------------------
PS.
Мной были испробован такой способ: (не смеяться!)
Моя прога:
1. Перед запуском процесса через ШелЕкзек я регистрю переменную окружения, допустим RunnerInvoked=1.
2. Создаю именованные объекты — событие и FileMapping.
3. Рождаю процесс через ЩелЕкзек, регистрю хук WH_GETMESSAGE.
4. Ожидаю поднятия события.
Теперь перенесемся в другой процесс :
5. Хук обрабатывается в DLL в которой сидит функция-обработчик хука WH_GETMESSAGE. Кроме того, при загрузке в процесс эта DLL проверяет переменную окружения RunnerInvoked и таким образом определяет, тот ли это процесс, который родился из под ShellExec. Ибо в остальные процессы эта длл тоже будет загружена. Переменная окружения от родителя наследуется только в тот процесс, который мне нужен .
6. Далее, если есть такая переменная, открываю именованный FileMapping и вписываю туда GetCurrentProcessId. Подымаю евент. Все.
А тут просыпается первоначальная прога, так как евент был поднят при загрузке длл в процесс, рожденный из под шел екзек:
7. Вычитываем из FileMapping значение пида.
Теперь я имею пид запущенного процесса, через такую вот задницу .
Верю, что есть способы получше (передавать PID через реестр с использованием выше описанной технологии не предлагать).
Здравствуйте, LeonV, Вы писали:
LV>Как можно получить PID, если есть hProcess? Ситуация такова: стартует приложение через ShellExecuteEx. Что это за приложение — заранее неизвестно, так как в ShellExecuteEx я передаю путь к файлу, который требуется открыть.
Предлагаю свой изощренный способ (навеяно статьей в RSDN о перехвате API):
type
TInjectCode = packed record
instr_call_getpid : WORD; // call []
adr_from_call_getpid: DWORD; // @GetCurrentProcessID
instr_mov_ax: BYTE; // mov,
instr_mov_opcode: BYTE; // ax,
adr_to_move : DWORD; // [target]
instr_push_exitthread_arg: BYTE; // push
exitthread_arg : DWORD; // 0
instr_call_exitthread : WORD; // call
adr_from_call_exitthread: DWORD; // @ExitThread
addr_getpid : DWORD; // Address of GetCurrentProcessID
addr_exitthread: DWORD; // Address of ExitThread
addr_ret_val: DWORD; // Here the pid will be writtenend;
function GetPIDByHandle(AProcessHandle: THandle): DWORD;
var
LInjectCode: TInjectCode;
LThread: THandle;
LThreadID: Cardinal;
P: Pointer;
N: Cardinal;
begin// Allocate memory for further writing and execution of machine instructions
P := VirtualAllocEx(AProcessHandle, nil, SizeOf(LInjectCode),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Fill the region with machine instructions
// call GetCurrentProcessID
// mov [adr_to_move], eax
// push 0
// call ExitThreadwith LInjectCode do
begin// Call GetCurrentProcessID in the context of target process
instr_call_getpid := $15ff; // call
adr_from_call_getpid := DWORD(P) + DWORD(@LInjectCode.addr_getpid) - DWORD(@LInjectCode); // GetCurrentProcessID
// Store the result for future fetching
instr_mov_ax := $89; // mov [target_address], eax
instr_mov_opcode := $05; //
adr_to_move := DWORD(P) + DWORD(@LInjectCode.addr_ret_val) - DWORD(@LInjectCode); // [target]
// Call ExitThread
instr_push_exitthread_arg := $68;
exitthread_arg := 0;
instr_call_exitthread := $15ff;
adr_from_call_exitthread := DWORD(P) + DWORD(@LInjectCode.addr_exitthread) - DWORD(@LInjectCode);
addr_getpid := DWORD(GetProcAddress(GetModuleHandle('kernel32.dll'), 'GetCurrentProcessId'));
addr_exitthread := DWORD(GetProcAddress(GetModuleHandle('kernel32.dll'), 'ExitThread'));
end;
WriteProcessMemory(AProcessHandle, P, @LInjectCode, SizeOf(LInjectCode), N);
// Create remote thread in the target process
LThread := CreateRemoteThread(AProcessHandle, nil, 0, P,
nil, 0, LThreadID);
WaitForSingleObject(LThread, INFINITE);
// Read back PID and free memory
ReadProcessMemory(AProcessHandle, P, @LInjectCode, SizeOf(LInjectCode), N);
VirtualFreeEx(AProcessHandle, P, SizeOf(LInjectCode), MEM_RELEASE);
Result := LInjectCode.addr_ret_val;
end;
Думается, это слишком сложно. В 9х, как утверждает MATT PIETREK, все гораздо проще. Первое, что надо помнить — процесс ID в 9х — это всего лишь некоторое обратимое преобразование указателя на PDB процесса (xor with "Obsfucator" DWORD). Т.к. PDB находятся в shared memory, то pid гарантированно уникальны. Второе — то, что PDB текущего процесса можно получить некоторым образом (см. пример к главе 3 — у меня в электронной книге, к сожалению, эта часть отсутствует). Получая PDB, мы можем определить таблицу хендлов, по таблице хандлов можем получить указатель на PDB нужного нам процесса, а из него, используя пресловутое преобразование (1) получить искомый PID процесса.
Вот, примерно так.
ST>>Предлагаю свой изощренный способ (навеяно статьей в RSDN о перехвате API):
БП>Точно! В Win9x можно сделать xCreateRemoteThread(GetCurrentProcessId()). БП>Павел.
Здравствуйте, EM, Вы писали:
БП>>Точно! В Win9x можно сделать xCreateRemoteThread(GetCurrentProcessId()).
EM>Как раз в Win9x — то и нельзя — CreateRemoteThread() есть только в NT/2000/XP
xCreateRemoteThread() это функция из библиотеки elirt (см google).
Работает замечательно и в 9.x и в NT3.1
DWORD TId = GetCurrentThreadId(); // Get ID of current thread
DWORD Unobsfucator = 0;
__asm
{
mov eax, fs:[0x18] // pTIB = FS:[18h] pointer to the thread information block
sub eax, 0x10 // pointer for the Thread Database 10h bytes upper
xor eax,[TId] // This is unobsfucator variable
mov [Unobsfucator], eax
}
Соответственнно, получить текущий PDB процесса можно: GetCurrentProcessId() ^ Unobsfucator.
Это для 95-х. Впрочем, должно работать и для других 9х систем. Возможно, с небольшими изменениями.
AS>Думается, это слишком сложно. В 9х, как утверждает MATT PIETREK, все гораздо проще. Первое, что надо помнить — процесс ID в 9х — это всего лишь некоторое обратимое преобразование указателя на PDB процесса (xor with "Obsfucator" DWORD). Т.к. PDB находятся в shared memory, то pid гарантированно уникальны. Второе — то, что PDB текущего процесса можно получить некоторым образом (см. пример к главе 3 — у меня в электронной книге, к сожалению, эта часть отсутствует). Получая PDB, мы можем определить таблицу хендлов, по таблице хандлов можем получить указатель на PDB нужного нам процесса, а из него, используя пресловутое преобразование (1) получить искомый PID процесса. AS>Вот, примерно так.
Здравствуйте, Sergey Ten, Вы писали:
ST>Здравствуйте, LeonV, Вы писали:
LV>>Как можно получить PID, если есть hProcess? Ситуация такова: стартует приложение через ShellExecuteEx. Что это за приложение — заранее неизвестно, так как в ShellExecuteEx я передаю путь к файлу, который требуется открыть.
ST>Предлагаю свой изощренный способ (навеяно статьей в RSDN о перехвате API):
// то, что должно выступать в качестве функции треда:
DWORD WINAPI ThreadProc(
LPVOID lpParameter // thread data
);
// То, что мы ему передаем.
DWORD WINAPI GetCurrentProcessId(VOID);
Соглашение о передаче параметров winapi предусматривает то, что вызываемая функция очищает стек параметров. Таким образом, мы получаем на выходе из функции неправильный стек. Что будет дальше? Неизвестно. Скорее всего, никто ничего не заметит. На данной системе с данным процессом. Но если случится (а это обязательно случится) большой бах — то он случится даже не в вашем, а чужом процессе.
И в любом случае — этот метод не решает проблемы с 9х системами.В общем, лучше, правильнее и быстрее использовать в случае winnt (Nt/Zw)QueryInformationProcess.
Точно, оно.
AS>Итак, посмотрим определение функций
AS>
AS>// то, что должно выступать в качестве функции треда:
AS>DWORD WINAPI ThreadProc(
AS> LPVOID lpParameter // thread data
AS>);
AS>// То, что мы ему передаем.
AS>DWORD WINAPI GetCurrentProcessId(VOID);
AS>
При вызове функций, описанных прототипами реализуется вариант неявного
преобразования типов. По-настоящему важным является лишь физический размер
возвращаемого результата. К нашей радости(?) функции Win32 API в основном
возвращают (да и принимают четырехбайтовые) значения.
Вопрос же их интерпретации — целиком на совести использующего.
AS>Соглашение о передаче параметров winapi предусматривает то, что вызываемая функция очищает стек параметров. Таким образом, мы получаем на выходе из функции неправильный стек.
А чем оно отличается от вызыва твоей ThreadFunc, которой также передается
параметр — адрес структуры InjectInfo?
Да и чего ему портиться, если послетовательность CRT и GCPI имеют одно
и тоже соглашение о вызове.
Ну, а верность этих теоретических воззрений легко опровергнуть отладчиком.
IMHO, действительной проблемой является подобный вызов в случае, когда
параметров более одного.
Тогда, действительно есть нужда в ручном формировании стека и копировании
тела функции в чужой процесс по методу Джефа Рихтера, или с помощью
более прозрачной техники by Prasad Dubak, описанной ранее тобой.
AS>И в любом случае — этот метод не решает проблемы с 9х системами.В общем, лучше, правильнее и быстрее использовать в случае winnt (Nt/Zw)QueryInformationProcess.
Это временная проблема, бо 9х системы обречены на скорое вымирание
Ну, и в любом случае, Nt/ZwQueryInformationProcess не смогут ее решить
1. Я не описывал никаких приемов формирования стека функции. Вы меня с кем-то путаете
2. По поводу 9х — смотрите ветку, решение там приведено.
3. По поводу NT тоже. И оно правильное, в отличие от этого.
4. Последнее, и самое главное — см. ниже:
AS>>Итак, посмотрим определение функций
AS>>
AS>>// то, что должно выступать в качестве функции треда:
AS>>DWORD WINAPI ThreadProc(
AS>> LPVOID lpParameter // thread data
AS>>);
AS>>// То, что мы ему передаем.
AS>>DWORD WINAPI GetCurrentProcessId(VOID);
AS>>
LT> При вызове функций, описанных прототипами реализуется вариант неявного LT> преобразования типов. По-настоящему важным является лишь физический размер LT> возвращаемого результата. К нашей радости(?) функции Win32 API в основном LT> возвращают (да и принимают четырехбайтовые) значения. LT> Вопрос же их интерпретации — целиком на совести использующего.
LT> А чем оно отличается от вызыва твоей ThreadFunc, которой также передается параметр — адрес структуры InjectInfo?
При вызове функций главным является соглашение о вызове (в данном случае обе winapi) и количество параметров, которые они в себя принимают. ThreadProc принимает 1 параметр (eq 4 байта на стеке), GetCurrentProcessId принимает 0 параметров. Итак, что происходит. Caller делает перед вызовом ThreadProc push lpParameter, ожидая, что по возвращению, ThreadProc вернет результат в eax и очистит стек (например, ret 2). Однако, GetCurrentProcessId этого не делает (просто ret), хотя и возвращает результат в eax. Итого — внешне все ОК, хотя на самом деле далеко не так — портится caller's стек.
И теперь — самое главное. MSDN:
process can obtain the return value of the ThreadProc of a thread it created with CreateThread by calling the GetExitCodeThread function. A process cannot obtain the return value from the ThreadProc of a thread it created with CreateRemoteThread.
Здравствуйте, LeonV, Вы писали:
LV>Как можно получить PID, если есть hProcess? Ситуация такова: стартует приложение через ShellExecuteEx. Что это за приложение — заранее неизвестно, так как в ShellExecuteEx я передаю путь к файлу, который требуется открыть.
LV>Далее необходимо послать сообщение окну того приложения, которое запустилось для открытия этого файла. После запуска процесса я делаю EnumWindows, а в функции EnumWindowsProc получаю PID процесса, в котором каждое окошко создано — GetWindowThreadProcessId. Один из этих PID — тот, который запустила ShellExecuteEx. По идее, их надо бы сравнить, но у меня на выходе ShellExecuteEx есть hProcess, а не пид. Как быть? Единственный способ узнать пид запущенного процесса, как я понял — вызвать CreateProcess и пид будет возвращен в структуре PROCESS_INFORMATION.
LV>Кто поможет?
<поскипано>
Чего то я не понял. Почему OpenProcess не заюзать?
Передаешь туда PID и сравниваешь хэндлы.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, LeonV, Вы писали:
LV>>Как можно получить PID, если есть hProcess?
А>Чего то я не понял. Почему OpenProcess не заюзать? А>Передаешь туда PID и сравниваешь хэндлы.
OpenProcess вернет другой хэндл каждый раз про открытии того же самого процесса:
#include <windows.h>
main()
{
int i;
for (i = 0; i < 10; i++)
printf("process handle: %d\n",
OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId()));
}
process handle: 2024
process handle: 2036
process handle: 2012
process handle: 2008
process handle: 2004
process handle: 2000
process handle: 1996
process handle: 1992
process handle: 1988
process handle: 1984
Re[3]: Получить ProcessID, имея hProcess?
От:
Аноним
Дата:
03.09.03 04:19
Оценка:
Здравствуйте, Sergey Ten, Вы писали:
ST>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, LeonV, Вы писали:
LV>>>Как можно получить PID, если есть hProcess?
А>>Чего то я не понял. Почему OpenProcess не заюзать? А>>Передаешь туда PID и сравниваешь хэндлы.
ST>OpenProcess вернет другой хэндл каждый раз про открытии того же самого процесса:
А если так:
#include <windows.h>
main()
{
int i;
HANDLE h;
for (i = 0; i < 10; i++)
{
h = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
CloseHandle(h);
}
}
Здравствуйте, Аноним, Вы писали:
А>>>Чего то я не понял. Почему OpenProcess не заюзать? А>>>Передаешь туда PID и сравниваешь хэндлы. А>А если так:
А хоть как.
OpenProcess создает НОВЫЙ хэндл.
А хэндлы по своей природе не сравниваются друг с другом.
Аналогия — утверждение навернства 2-х дверей, если у этих дверей одинаковые ручки.
К тому же, если первый хэндл был валиден в Вашем ВАП, то OpenProcess НИКОГДА не вернет аналогичную величину, потка тот хэндл не будет закрыт, так как нумерация хэндлов для одного процесса сквозная независимо от их типа (процесс, поток, файл, событие и т.д.).
Здравствуйте, vasketsov, Вы писали:
V>Здравствуйте, Аноним, Вы писали:
А>>>>Чего то я не понял. Почему OpenProcess не заюзать? А>>>>Передаешь туда PID и сравниваешь хэндлы. А>>А если так: V>А хоть как. V>OpenProcess создает НОВЫЙ хэндл. V>А хэндлы по своей природе не сравниваются друг с другом. V>Аналогия — утверждение навернства 2-х дверей, если у этих дверей одинаковые ручки. V>К тому же, если первый хэндл был валиден в Вашем ВАП, то OpenProcess НИКОГДА не вернет аналогичную величину, потка тот хэндл не будет закрыт, так как нумерация хэндлов для одного процесса сквозная независимо от их типа (процесс, поток, файл, событие и т.д.).
AS>1. Я не описывал никаких приемов формирования стека функции. Вы меня с кем-то путаете
Я никого ни с кем не путал, IMHO.
Исторически первой была техника Джефа, а Прасад, как раз, предложил вариант, описанный тобой. Именно поэтому они в таком порядке и были упомянуты.
Во всяком случае, я считал, что это нужно знать каждому, кто заинтересовался этим вопросом.
LT>> А чем оно отличается от вызыва твоей ThreadFunc, которой также передается параметр — адрес структуры InjectInfo?
AS>При вызове функций главным является соглашение о вызове (в данном случае обе winapi) и количество параметров, которые они в себя принимают. ThreadProc принимает 1 параметр (eq 4 байта на стеке), GetCurrentProcessId принимает 0 параметров. Итак, что происходит. Caller делает перед вызовом ThreadProc push lpParameter, ожидая, что по возвращению, ThreadProc вернет результат в eax и очистит стек (например, ret 2). Однако, GetCurrentProcessId этого не делает (просто ret), хотя и возвращает результат в eax. Итого — внешне все ОК, хотя на самом деле далеко не так — портится caller's стек.
Какой-какой caller? Речь идет о стеке того самого потока.
Если бы было так, как ты описываешь, то удаленному потоку никогда и не удалось
воспользоваться полученным параметром. По-крайней мере, поток вызывал бы
AV по выходу из функции.
AS>И теперь — самое главное. MSDN: AS>
AS>process can obtain the return value of the ThreadProc of a thread it created with CreateThread by calling the GetExitCodeThread function. A process cannot obtain the return value from the ThreadProc of a thread it created with CreateRemoteThread.
Это надо воспринимать несколько критически, иначе бы мы и не могли пользоваться
ExitCode возвращаемым CreateThread, бо реализация его построена на CRT.