здравствуйте! Развлекался тут с этими функциями и решил сделать простенькую программку, которая создает второй поток, выставляет флаг, после чего засыпает(SuspendThread), а этот второй поток должен всего-навсего изменить у основного потока eip и сделать основному ResumeThread. Смысл изменения eip в том, чтобы перепрыгнуть некий участок кода. Проблема: не могу понять где у меня ошибка. Прога сначала перепрыгивает ненужный участок кода, но потом все-равно его исполняет. Откуда в стеке берется код возврата я и не могу понять. вот программа: Код (Text): .586 .model flat, stdcall option casemap :none include windows.inc include kernel32.inc include user32.inc includelib kernel32.lib includelib user32.lib .data flag dd ? hThread dd ? context CONTEXT <> msg1 db 'это сообщение не должно появиться',0 msg2 db 'должно появиться',0 .code ThProc proc ;наш следяший поток @@: invoke Sleep, 100 cmp flag, 1 jnz @b ;ждем, пока главный поток не заснет mov context.ContextFlags, CONTEXT_FULL invoke GetThreadContext, hThread, offset context mov context.regEip, @msg ;перепрыгиваем ненужный участок invoke SetThreadContext, hThread, offset context invoke ResumeThread, hThread ;отпускаем invoke ExitThread, 0 ret ThProc endp start: invoke CreateThread, 0, 0, offset ThProc, 0, 0, 0 ;создаем следящий поток invoke GetCurrentThread mov ebx, eax invoke GetCurrentProcess invoke DuplicateHandle, eax, ebx, eax, offset hThread, 0, FALSE, DUPLICATE_SAME_ACCESS inc flag ;даем второму потоку разрешение действовать invoke GetCurrentThread ; invoke SuspendThread, eax ;замораживаемся invoke MessageBox, 0, offset msg1, offset msg1, MB_OK ;сюда нам не надо по идее invoke ExitProcess, 0 @msg: invoke MessageBox, 0, offset msg2, offset msg2, MB_OK ;сюда мы должны попасть ret end start извиняйте, если вопрос тупой)
HuXTUS Я не очень разбираюсь, но попробую ответить. ИМХО у Вас плохое согласование потоков. Может получиться так, что "следящий поток" выставит контекст основного потока еще до того, как произойдет возврат из SuspendThread например. Отсюда и адрес возврата в стэке.
Aspire Думаю, что вот поэтому: Код (Text): mov context.regEip, @msg invoke SetThreadContext, hThread, offset context
l_inc плохое согласование потоков ... еще до того, как произойдет возврат из SuspendThread Imho дело не в согласовании, поставь хоть invoke Sleep, 100000 после jnz @b ;ждем, пока главный поток не заснет все равно "Прога сначала перепрыгивает ненужный участок кода, но потом все-равно его исполняет". Дело в том, что первый поток усыпляет себя сам, в этом случае eip всегда будет внутри SuspendThread.
l_inc Это я конкретно тормознул )) Может, просто тогда, после второго мессажебокса exiprocess воткнуть вместо ret'a ? [add] Нафига основному потоку рет?
Aspire это уже затычка будет. Но она не отвечает на вопрос "почему?" ) Хм...я обычно так программу завершаю. ExitProcess - больше в памяти занимает и печатать дольше) l_inc главный подвох плохого согласования потоков в том, что эти ошибки редко проявляются(а по сему труднее отлаживаются), но тут фигня происходит всякий раз, поэтому не в синхронизации дело. В тот момент, когда основной поток засыпает, его eip 'указывает' куда-то внутрь ntdll на инструкцию ret (у меня это адрес 7C90EB94). Вообщем я разобрался, спасибо всем ответившим! Чтобы починить прогу надо после Код (Text): mov context.regEip, @msg ;перепрыгиваем ненужный участок добавить: Код (Text): add context.regEsp, 28 Чтобы на стеке лежал нужный адрес возврата.
HuXTUS С чего Вы взяли? Уверен, что именно там он и будет (особенно раз q_q сказал). А если Вас смущает, что модуль - не kernel32.dll ... ну тогда я отказываюсь от дальнейших комментариев.
HuXTUS куку сказал, что eip будет внутри SuspendThread. но это не так Внутри - это значит, что возврата из SuspendThread в вызвавший ее поток не будет. Imho и ежу понятно, что на NT платформе 90% кода kernel32.dll – это переходники в ntdll.dll