Сейчас на форуме: zombi-vadim, zds (+4 невидимых)

 [email protected] —› Программирование —› Вопрос по лоадеру
Посл.ответ Сообщение

Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 13:26 · Поправил: figgler
· Личное сообщение · #1

Уважаемые коллеги,
столкнулся со следующей проблемой, подскажите куда копать и как вообще правильно...

Ниже приведен кусок кода который:
1. Создает процесс в SUSPENDED состоянии
2. Запускает процесс на 20 мсек и потом опять останавливает
3. Делает снимок запущеного модуля
4. Находит адрес таблицы импорта
5. В процедуре POKES происходит поиск нужной функции, ее адреса и замена кода

Проблема:

пункт 2 - в коде коментарий
Это делается для того, чтобы нормально отработала функция снимка модуля - если ее делать сразу после создания процесса, снимок не получается.
Если поставить время выполнения процесса (между запуском и остановкой) меньше - процесс не успевает "развернуться" и снимок не выходит, если поставить больше (например 300) то успевает сработать функция которую я хочу изменить в целевой программе.
Время это разное (как я понял) для разного "железа" - зависит от быстродействия, загруженности и пр.

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

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

Возможно я изначально пошел не по тому пути, идея такова:

1. В целевой программе используется ДЛЛ с функциями которые легко заблокировать заменой точки входа этих функций на РЕТ (изменять саму ДЛЛ нельзя как и основную программу)
2. Можно найти адреса этих функций (вызовы в программе) и загрузчиком их изменить, но захотелось автоматизма.
3. Загрузчик должен сам найти адреса функций (где они размещены после загрузки ДЛЛ) и заменить код.

На текущий момент все реализовано, но хотелось бы гарантированного результата...

Буду рад подсказкам, идеям и вообще...

Code:
  1. invoke CreateProcessA, ADDR exeName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,NULL, ADDR StartupInfo, ADDR ProcessInfo
  2.  
  3. ;//NORMAL_PRIORITY_CLASS
  4. ;//CREATE_SUSPENDED
  5. ;//IDLE_PRIORITY_CLASS
  6.  
  7. .IF eax!=0
  8.  
  9.  
  10. ;//ЗАПУСК ПРОЦЕССА И ОПЯТЬ ОСТАНОВКА
  11.  
  12. invoke ResumeThread, ProcessInfo.hThread
  13. invoke Sleep, 20
  14. invoke SuspendThread, ProcessInfo.hThread
  15.  
  16.  
  17. invoke CreateToolhelp32Snapshot, TH32CS_SNAPMODULE, ProcessInfo.dwProcessId
  18. cmp eax, 0
  19. je someerror
  20. mov hSnapshoot, eax
  21.  
  22. mov me32.dwSize,size MODULEENTRY32
  23. invoke Module32First,  hSnapshoot,addr me32
  24. cmp eax, 0
  25. je someerror
  26.  
  27. ;//me32 содержит данные о нужном модуле
  28.  
  29. mov eax, me32.modBaseAddr
  30. mov baseAddr, eax
  31.  
  32. invoke CloseHandle, hSnapshoot
  33.  
  34. ;baseAddr dd ?
  35. ;ITA dd ?
  36.  
  37. ;//get ITA
  38.  
  39. invoke VirtualAllocEx, ProcessInfo.hProcess, NULL, 10000, MEM_COMMIT, PAGE_READONLY  
  40.  
  41. mov edi, baseAddr
  42. add edi, 180h
  43. invoke ReadProcessMemory, ProcessInfo.hProcess, edi, ADDR szBuff, 4, 0 
  44. mov ebx, OFFSET szBuff 
  45. mov ebx, [ebx]
  46. cmp ebx, 0;// if 0 конец массива
  47. je someerror
  48. add ebx, baseAddr;//ebx содержит ITA (адрес таблицы импорта)
  49. mov ITA, ebx
  50.  
  51. invoke POKES ;//меняем код
  52.  
  53. someerror:
  54. invoke VirtualFreeEx, ProcessInfo.hProcess, NULL, 10000, MEM_DECOMMIT
  55. invoke ResumeThread, ProcessInfo.hThread
  56. invoke ExitProcess, NULL





Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 07 сентября 2013 13:48
· Личное сообщение · #2

figgler, как вариант запустить под отладкой, поставить бряку на EP, поймать её как отладочное событие и далее делать, что вам нужно.
Иначе ваш Sleep - это костыль.

-----
the Power of Reversing team




Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 07 сентября 2013 13:54
· Личное сообщение · #3

попробуй создавать нормальный процесс
Code:
  1. .....
  2. .IF eax!=0
  3. invoke WaitForInputIdle, dword ptr [ProcessInfo.hProcess], -1
  4. invoke SuspendThread, ProcessInfo.hThread
  5. .....

А вообще проще дописать чуток кода и стопориться на ОЕП.

| Сообщение посчитали полезным: figgler


Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 07 сентября 2013 14:11
· Личное сообщение · #4

Vovan666
MSDN >> WaitForInputIdle >> the parent process can use the WaitForInputIdle function to determine when the child's initialization has been completed. For example, the parent process should use the WaitForInputIdle function before trying to find a window associated with the child process
...иначе говоря, вы получаете управление после того, как целевая программа войдёт в цикл ожидания сообщений (если она вообще должна в него войти), а это уже может быть далеко от EP.

-----
the Power of Reversing team




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 14:45 · Поправил: figgler
· Личное сообщение · #5

DillerInc
Я понимаю что Слип это костыль - поэтому и интересуюсь - явно есть способы сделать это правильно...

Vovan666 По поводу стопориться на ОЕП - можно поподробнее алгоритм (если код - вообще прекрасно) - или просто какие апи функции(я), я разберусь...

Да, как вариант я пробовал менять в точке входа JMP на себя, но опять же чтобы узнать точку входа нужно узнать базовый адрес...




Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 07 сентября 2013 14:58
· Личное сообщение · #6

figgler, так я вам предложил один из способов - использовать отладочный цикл.
->Например<-
Всё зависит от ваших конкретных условий. Если у вас программа палит отладчик, то такой подход само собой неприемлем.

Чую, что сейчас Вован вам предложит писать с помощью WriteProcessMemory два байта на EP - 0xfeeb - и в таком состоянии отпускать поток. Да, вы застопоритесь на EP, но получите ещё один костыль - очередной Sleep на неопределённое время, чтобы init процесса полностью выполнился.

-----
the Power of Reversing team




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 15:33 · Поправил: figgler
· Личное сообщение · #7

DillerInc Да, программа "палит отладчик", поэтому и просил Vovan666 больше инфы...
Насчет "EP - 0xfeeb" - я так и делал, но опять же вопрос - как узнать нужный адрес ЕР за приемлемое время?



Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 07 сентября 2013 15:46
· Личное сообщение · #8

код не мой но частенько пользуюсь

Code:
  1. .const
  2. hookbytes                 dw 0FEEBh
  3.  
  4. FullHook proc hookaddr:DWORD
  5. LOCAL threadcontext:CONTEXT
  6. LOCAL backup:DWORD
  7. LOCAL backupb:WORD
  8. mov eax,hookaddr
  9. mov backup,eax
  10. invoke ReadProcessMemory,pinfo.hProcess,hookaddr,addr backupb,2h,0
  11. invoke WriteProcessMemory,pinfo.hProcess,hookaddr,offset hookbytes,2h,0
  12. invoke RtlZeroMemory,addr threadcontext,sizeof threadcontext
  13. invoke ResumeThread,pinfo.hThread
  14. invoke Sleep,100
  15. mov threadcontext.ContextFlags,CONTEXT_FULL
  16. @@:
  17. invoke GetThreadContext,pinfo.hThread,addr threadcontext
  18. mov eax,hookaddr
  19. cmp eax,threadcontext.regEip
  20. jnz @B
  21. invoke SuspendThread,pinfo.hThread
  22. invoke WriteProcessMemory,pinfo.hProcess,backup,addr backupb,2h,0
  23. ret
  24. FullHook endp


EP читаешь из файла
типа так
Code:
  1. mov d [pMem],InputFile("имя файла")
  2.       mov edx,[pMem]
  3.       add edx,[edx.IMAGE_DOS_HEADER.e_lfanew]
  4.       mov eax,[edx.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint]
  5.       mov ep,eax


ImageBase лучше брать из уже запущенного процесса чтоб на 7 проблем небыло.
после создания засуспенженного процесса прочитать EBX+8



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 15:48
· Личное сообщение · #9

Благодарю, буду пробовать...



Ранг: 226.0 (наставник), 67thx
Активность: 0.160
Статус: Участник

Создано: 07 сентября 2013 21:10
· Личное сообщение · #10

может вместо sleep поствить хук на какой-нибудь api ?



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 22:34
· Личное сообщение · #11

Vovan666 пишет:
ImageBase лучше брать из уже запущенного процесса чтоб на 7 проблем небыло.после создания засуспенженного процесса прочитать EBX+8


Что то тут не то, после создания засуспенженного процесса в EBX - 0 и как ни крути, а прочитать не выходит...



Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 07 сентября 2013 22:43
· Личное сообщение · #12

А должен быть указатель на PEB.
Надеюсь ты ResumeThread и прочие гадости перед получением GetThreadContext не делаешь?



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 23:03
· Личное сообщение · #13

Vovan666 если я правильно понял, то порядок должен быть такой

CreateProcess
GetThreadContext
ebx+8 - BaseAddress



Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 07 сентября 2013 23:07
· Личное сообщение · #14

если я правильно понял, то нет.
CreateProcess
GetThreadContext
mov eax,threadcontext.regEbx
add eax,8
ReadProcessMemory (eax - lpBaseAddress)



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 07 сентября 2013 23:10
· Личное сообщение · #15

Ok, спасибо... буду копать дальше..




Ранг: 72.3 (постоянный), 133thx
Активность: 0.380
Статус: Участник

Создано: 08 сентября 2013 02:06
· Личное сообщение · #16

Извращенья.

Быть может заинфектить свой кодес и не париться ?



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 09 сентября 2013 11:56 · Поправил: figgler
· Личное сообщение · #17

Vovan666 еще вопрос, пож-ста, по предложенному алгоритму, если не сложно - где я в коде допустил ошибку?

Code:
  1. invoke CreateProcessA, ADDR exeName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,NULL, ADDR StartupInfo, ADDR ProcessInfo
  2. invoke GetThreadContext,ProcessInfo.hThread,addr threadcontext
  3. mov eax,threadcontext.regEbx
  4. add eax,8
  5.  
  6. invoke ReadProcessMemory, ProcessInfo.hProcess, eax, ADDR szBuff, 4, 0


На выходе szBuff должен содержать базовый адрес запущеного процесса, но там 0 (если читать память как в приведенном коде)

Просто заинтересовал способ быстрого получения базового адреса.

А так подошел способ с
Code:
  1. invoke WaitForInputIdle, dword ptr [ProcessInfo.hProcess], -1
  2. invoke SuspendThread, ProcessInfo.hThread

теперь все нормально...

Спасибо.



Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 09 сентября 2013 12:30
· Личное сообщение · #18

Code:
  1. mov threadcontext.ContextFlags,CONTEXT_FULL
  2. invoke GetThreadContext,ProcessInfo.hThread,addr threadcontext




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 09 сентября 2013 12:33
· Личное сообщение · #19

Это
Code:
  1. :mov threadcontext.ContextFlags,CONTEXT_FULL
есть в коде раньше, на этапе
Code:
  1. .IF eax==WM_CREATE
  2.          invoke  SetTimer, hWnd, MAINTIMERID, 20, NULL
  3.          invoke RtlZeroMemory,addr threadcontext,sizeof threadcontext
  4.          mov threadcontext.ContextFlags,CONTEXT_FULL


а таймер уже запускает создание процесса...



Ранг: 617.3 (!), 677thx
Активность: 0.540
Статус: Участник

Создано: 09 сентября 2013 13:10
· Личное сообщение · #20

Запусти "жертву" в ольке поставив в настройках System breakpoint, это аналог CREATE_SUSPENDED, и посмотри равен ли EBX там и после GetThreadContext.
Либо скинь в пм свои исходники и жертву, посмотрю где косячишь.




Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 09 сентября 2013 14:32
· Личное сообщение · #21

System breakpoint-это не CREATE_SUSPENDED. Это первый бряк отладчика. И он далеко не равен изначальному CREATE_SUSPENDED.



Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 10 сентября 2013 11:01
· Личное сообщение · #22

Vovan666 спасибо за помощь...

почистил код для проверки этого способа (убрал вообще все лишнее) - действительно работает...

Code:
  1. start:
  2.  
  3.          invoke CreateProcessA, ADDR exeName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,NULL, ADDR StartupInfo, ADDR ProcessInfo
  4.  
  5.          .IF eax!=0
  6.  
  7.          mov threadcontext.ContextFlags,CONTEXT_FULL
  8.          invoke GetThreadContext,ProcessInfo.hThread,addr threadcontext
  9.          mov eax,threadcontext.regEbx
  10.          add eax,8
  11.          invoke ReadProcessMemory, ProcessInfo.hProcess, eax, ADDR szBuff, 4, 0
  12.          mov ebx, offset [szBuff]
  13.          mov ebx, [ebx] ;//base addr here
  14.          
  15.          invoke TerminateProcess, ProcessInfo.hProcess, NULL
  16.  
  17.          .ENDIF
  18. exit:
  19.     invoke        ExitProcess, eax
  20.     
  21. end start





Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 10 сентября 2013 18:46
· Личное сообщение · #23

figgler, у тебя поди szBuff глобальная, нет?

-----
the Power of Reversing team




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 10 сентября 2013 22:39
· Личное сообщение · #24

Да, и что ?




Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 11 сентября 2013 00:02
· Личное сообщение · #25

Сделай переменную szBuff локальной и посмотри, как у тебя отвалится вызов:
invoke ReadProcessMemory, ProcessInfo.hProcess, eax, ADDR szBuff, 4, 0

-----
the Power of Reversing team




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 12 сентября 2013 19:46 · Поправил: figgler
· Личное сообщение · #26

DillerInc Если речь о ошибке выдаваемой компилятором (с локальным буфером) то да - не компилирует..
Code:
  1. testloader.asm(78) : error A2133: register value overwritten by INVOKE

В чем фишка?




Ранг: 136.0 (ветеран), 360thx
Активность: 0.270.14
Статус: Участник
Qt Developer

Создано: 12 сентября 2013 20:03 · Поправил: hors
· Личное сообщение · #27

figgler пишет:
В чем фишка?


ADDR в Invoke использует eax. Если используются локальные переменные.

-----
http://ntinfo.biz





Ранг: 283.6 (наставник), 56thx
Активность: 0.130
Статус: Участник
Author of GeTaOEP

Создано: 12 сентября 2013 20:27
· Личное сообщение · #28

figgler,

# имеем #
ADDR my_var ; my_var локальная
# получаем #
lea eax, my_var
push eax

# имеем #
ADDR my_var ; my_var глобальная
# получаем #
push offset my_var ; актуально для x86

У тебя один из параметров передаётся через eax, который затрётся предыдущим ADDR my_var, если my_var локальная.

-----
the Power of Reversing team




Ранг: 11.2 (новичок), 1thx
Активность: 0.010
Статус: Участник

Создано: 12 сентября 2013 20:36
· Личное сообщение · #29

Мда, ну что тут скажешь... учиться, учитья, учиться...

Всем спасибо за внимание и информацию...


 [email protected] —› Программирование —› Вопрос по лоадеру
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати