SetThreadContext, ResumeThread - загнался

Тема в разделе "WASM.BEGINNERS", создана пользователем HuXTUS, 4 ноя 2007.

  1. HuXTUS

    HuXTUS New Member

    Публикаций:
    0
    Регистрация:
    8 янв 2007
    Сообщения:
    240
    здравствуйте!
    Развлекался тут с этими функциями и решил сделать простенькую программку, которая создает второй поток, выставляет флаг, после чего засыпает(SuspendThread), а этот второй поток должен всего-навсего изменить у основного потока eip и сделать основному ResumeThread.

    Смысл изменения eip в том, чтобы перепрыгнуть некий участок кода.

    Проблема: не могу понять где у меня ошибка. Прога сначала перепрыгивает ненужный участок кода, но потом все-равно его исполняет. Откуда в стеке берется код возврата я и не могу понять.

    вот программа:

    Код (Text):
    1. .586
    2. .model flat, stdcall
    3. option casemap :none
    4.  
    5. include windows.inc
    6. include kernel32.inc
    7. include user32.inc
    8.  
    9. includelib kernel32.lib
    10. includelib user32.lib
    11.  
    12. .data
    13. flag    dd  ?
    14. hThread dd  ?
    15. context     CONTEXT <>
    16.  
    17. msg1    db  'это сообщение не должно появиться',0
    18. msg2    db  'должно появиться',0
    19.  
    20. .code
    21.  
    22. ThProc  proc   ;наш следяший поток
    23. @@:
    24. invoke Sleep, 100
    25. cmp flag, 1
    26. jnz @b   ;ждем, пока главный поток не заснет
    27.  
    28. mov context.ContextFlags, CONTEXT_FULL
    29. invoke GetThreadContext, hThread, offset context
    30. mov context.regEip, @msg   ;перепрыгиваем ненужный участок
    31. invoke SetThreadContext, hThread, offset context
    32. invoke ResumeThread, hThread   ;отпускаем
    33.  
    34. invoke ExitThread, 0
    35. ret
    36.  
    37. ThProc endp
    38.  
    39. start:
    40. invoke CreateThread, 0, 0, offset ThProc, 0, 0, 0   ;создаем следящий поток
    41.  
    42. invoke GetCurrentThread
    43. mov ebx, eax
    44. invoke GetCurrentProcess
    45. invoke DuplicateHandle, eax, ebx, eax, offset hThread, 0, FALSE, DUPLICATE_SAME_ACCESS
    46.  
    47. inc flag                   ;даем второму потоку разрешение действовать
    48.  
    49. invoke GetCurrentThread    ;
    50. invoke SuspendThread, eax  ;замораживаемся
    51.  
    52. invoke MessageBox, 0, offset msg1, offset msg1, MB_OK   ;сюда нам не надо по идее
    53. invoke ExitProcess, 0
    54.  
    55. @msg:
    56. invoke MessageBox, 0, offset msg2, offset msg2, MB_OK   ;сюда мы должны попасть
    57.  
    58. ret
    59.  
    60. end start
    извиняйте, если вопрос тупой)
     
  2. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    HuXTUS
    Я не очень разбираюсь, но попробую ответить.
    ИМХО у Вас плохое согласование потоков. Может получиться так, что "следящий поток" выставит контекст основного потока еще до того, как произойдет возврат из SuspendThread например. Отсюда и адрес возврата в стэке.
     
  3. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    А почему она не должна его исполнять, если ты потом запускаешь поток? (ResumeThread)
     
  4. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Aspire
    Думаю, что вот поэтому:
    Код (Text):
    1. mov context.regEip, @msg
    2. invoke SetThreadContext, hThread, offset context
     
  5. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    l_inc
    плохое согласование потоков ... еще до того, как произойдет возврат из SuspendThread
    Imho дело не в согласовании, поставь хоть invoke Sleep, 100000 после jnz @b ;ждем, пока главный поток не заснет все равно "Прога сначала перепрыгивает ненужный участок кода, но потом все-равно его исполняет". Дело в том, что первый поток усыпляет себя сам, в этом случае eip всегда будет внутри SuspendThread.
     
  6. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    q_q
    Ну да. :)
    Ну я же сказал, что плохо разбираюсь.
     
  7. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    l_inc
    Это я конкретно тормознул )) Может, просто тогда, после второго мессажебокса exiprocess воткнуть вместо ret'a ?
    [add]
    Нафига основному потоку рет?
     
  8. HuXTUS

    HuXTUS New Member

    Публикаций:
    0
    Регистрация:
    8 янв 2007
    Сообщения:
    240
    Aspire
    это уже затычка будет. Но она не отвечает на вопрос "почему?" )

    Хм...я обычно так программу завершаю. ExitProcess - больше в памяти занимает и печатать дольше)

    l_inc
    главный подвох плохого согласования потоков в том, что эти ошибки редко проявляются(а по сему труднее отлаживаются), но тут фигня происходит всякий раз, поэтому не в синхронизации дело.

    В тот момент, когда основной поток засыпает, его eip 'указывает' куда-то внутрь ntdll на инструкцию ret (у меня это адрес 7C90EB94).

    Вообщем я разобрался, спасибо всем ответившим!
    Чтобы починить прогу надо после
    Код (Text):
    1. mov context.regEip, @msg   ;перепрыгиваем ненужный участок
    добавить:
    Код (Text):
    1. add context.regEsp, 28
    Чтобы на стеке лежал нужный адрес возврата.
     
  9. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    HuXTUS
    Как будто q_q не об этом сказал.
     
  10. HuXTUS

    HuXTUS New Member

    Публикаций:
    0
    Регистрация:
    8 янв 2007
    Сообщения:
    240
    l_inc
    куку сказал, что eip будет внутри SuspendThread. но это не так.
     
  11. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    HuXTUS
    С чего Вы взяли? Уверен, что именно там он и будет (особенно раз q_q сказал). А если Вас смущает, что модуль - не kernel32.dll ... ну тогда я отказываюсь от дальнейших комментариев.
     
  12. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    HuXTUS
    куку сказал, что eip будет внутри SuspendThread. но это не так
    Внутри - это значит, что возврата из SuspendThread в вызвавший ее поток не будет. Imho и ежу понятно, что на NT платформе 90% кода kernel32.dll – это переходники в ntdll.dll