Сейчас на форуме: bezumchik, tyns777, Lohmaty (+7 невидимых)

 eXeL@B —› Вопросы новичков —› Не возвращается управление отладчику
Посл.ответ Сообщение

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

Создано: 04 мая 2019 22:35
· Личное сообщение · #1

Привет! При изучении программы заметил, что есть call, после которого управление отладчику не передается, а в этом call'e еще такой же и так далее. Что это такое и как исследовать с этим программу?




Ранг: 622.6 (!), 521thx
Активность: 0.330.89
Статус: Участник
_Вечный_Студент_

Создано: 04 мая 2019 22:51 · Поправил: plutos
· Личное сообщение · #2

Flari пишет:
что есть call


Какой именно call, если не секрет? и какой отладчик?

Flari пишет:
а в этом call'e еще такой же и так далее


Может это recursion?

-----
Give me a HANDLE and I will move the Earth.




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

Создано: 04 мая 2019 22:55
· Личное сообщение · #3

x64dbg, call - переход, типо jmp. Может это виртуализация какая-то?




Ранг: 271.2 (наставник), 331thx
Активность: 0.321.49
Статус: Участник

Создано: 04 мая 2019 22:56 · Поправил: f13nd
· Личное сообщение · #4

Управление может не возвращаться в принципе, потому что так задумано. Ольга этим часто болеет при step over через SendMessageW например.

-----
2 оттенка серого


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


Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 05 мая 2019 04:29
· Личное сообщение · #5

Flari пишет:
При изучении программы заметил, что есть call, после которого управление отладчику не передается, а в этом call'e еще такой же и так далее


При Step Over не передаётся?

В первом случае в функции, которая вызывается инструкцией call, может прога уже запускается, может бесконечная рекурсия, может на какой-то рекурсии бесконечный цикл, а может быть реализован один или несколько приёмов антиотладки. Попробуй, например, поставить бряк на NtSetInformationThread, перед эти дойдя до этого колла. Остановится там прога? Если да - смотри, что в аргументах. Если во втором 0x11 - прога прячет себя от отладчика, переставь eip на ret.

-----
IZ.RU




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

Создано: 05 мая 2019 12:38
· Личное сообщение · #6

Да, не передается при Step Over. Забыл упомянуть, изучаю программу с защитой VMP.
Заходить в каждый call не очень хочется.




Ранг: 331.1 (мудрец), 561thx
Активность: 0.190.06
Статус: Участник

Создано: 05 мая 2019 13:11
· Личное сообщение · #7

Заходить в каждый call не очень хочется.
Ну-ну, в реализации вмп нет call, все они трактуются как push any; jmp addr; и возврата из них в принципе быть не может.

-----
Everything is relative...


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

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

Создано: 05 мая 2019 13:31
· Личное сообщение · #8

А, понял. А есть какие-то способы облегчить себе работу в изучении такой реализации?




Ранг: 331.1 (мудрец), 561thx
Активность: 0.190.06
Статус: Участник

Создано: 05 мая 2019 13:43
· Личное сообщение · #9

Flari
Читайте --> тут <--, практически всё что нужно знать про вмп здесь можно найти.

-----
Everything is relative...





Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 05 мая 2019 14:27 · Поправил: difexacaw
· Личное сообщение · #10

Flari

Call часто используется для загрузки констант. Тоесть Call/Value. Разумеется управление назад не передаётся, так как там не код, а данные. Что удивительно такая конструкция была в некоторых системных стабах(переходниках).

-----
vx





Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 05 мая 2019 21:51 · Поправил: DenCoder
· Личное сообщение · #11

Flari пишет:
А есть какие-то способы облегчить себе работу в изучении такой реализации?


Во-первых, тебе не нужно заходить в каждый call! И тем более не нужно ждать, что из него будет выход. Для вмп это смешно. Во-вторых, для вмп нужен статико-динамический анализ - дизасм + дебаггер/эмулятор.

Для статики вот тебе скрипт для иды на питоне. Не доработан, правда, даже до 90%, я там учитывал всё по мере столкновения, но всё же он мне помог:
Code:
  1. from idaapi import *
  2. from idautils import *
  3. from idc import *
  4.  
  5. def makeTail(fea, ea, notAdd = []):
  6.          pfn = get_func(fea)
  7.          if not pfn: return
  8.          
  9.          if func_contains(pfn, ea): return
  10.          
  11.          begin = ea
  12.          stop = False
  13.          toMake = []
  14.          while not stop:
  15.                  xrefs = [xref for xref in XrefsFrom(ea)]
  16.                  if len(xrefs) == 0:
  17.                         if not isCode(getFlags(ea)):
  18.                               setFlags(ea, getFlags(ea) | FF_CODE)
  19.                         elif Byte(ea) & 0xfe != 0xc2:
  20.                               next_ea = ea + decode_insn(ea)
  21.                               if not isCode(getFlags(next_ea)):
  22.                                    setFlags(next_ea, getFlags(next_ea) | FF_CODE)
  23.                         xrefs = [xref for xref in XrefsFrom(ea)]
  24.  
  25.                  if len(xrefs) == 0: stop = True
  26.                  elif Byte(ea) == 0xe8:
  27.                         stop = True
  28.                         if len(xrefs) == 2:
  29.                               DelCodeXref(ea, xrefs[0].to, 0)
  30.                               del xrefs[0]
  31.                         AddCodeXref(ea, xrefs[0].to, XREF_USER | fl_JN)
  32.                         if xrefs[0].to not in notAdd: #vm1_Entry
  33.                               toMake += [xrefs[0].to]
  34.                  elif xrefs[0].type == fl_JN:
  35.                         if xrefs[0].to not in notAdd: #vm1_Entry
  36.                               toMake += [xrefs[0].to]
  37.                         stop = True
  38.                  elif len(xrefs) == 2 and (xrefs[1].type & 0x1f) >= 0x10:
  39.                         if xrefs[1].to not in notAdd: toMake += [xrefs[1].to]
  40.                         if func_contains(pfn, xrefs[0].to): stop = True
  41.                  elif xrefs[0].to in notAdd: #vm1_Entry
  42.                         stop = True
  43.  
  44.                  if stop:
  45.                         end = ea + decode_insn(ea)
  46.                         break
  47.                         
  48.                  ea = xrefs[0].to
  49.          print("Appending tail %x to func %x" %(begin, fea))
  50.          append_func_tail(pfn, begin, end)
  51.          for ch in toMake:
  52.                  print("Handling tail %x to append func %x" %(ch, fea))
  53.                  makeTail(fea, ch, notAdd)
  54.  
  55. def getLastInstruction(ea):
  56.          begin = ea
  57.          stop = False
  58.          while not stop:
  59.                  #print "getLastInstruction(): ", ea
  60.                  xrefs = [xref for xref in XrefsFrom(ea)]
  61.                  if len(xrefs) == 0: stop = True
  62.                  elif Byte(ea) == 0xe8:
  63.                         stop = True
  64.                         if len(xrefs) == 2:
  65.                               DelCodeXref(ea, xrefs[0].to, 0)
  66.                               AddCodeXref(ea, xrefs[1].to, XREF_USER | fl_JN)
  67.                               del xrefs[0]
  68.                  elif xrefs[0].type == fl_JN:
  69.                         stop = True
  70.  
  71.                  if stop:
  72.                         end = ea
  73.                         break
  74.                         
  75.                  ea = xrefs[0].to
  76.          return end
  77.  
  78. def getBlock(ea):
  79.          begin = ea
  80.          stop = False
  81.          while not stop:
  82.                  xrefs = [xref for xref in XrefsFrom(ea)]
  83.                  if len(xrefs) == 0: stop = True
  84.                  elif Byte(ea) == 0xe8:
  85.                         stop = True
  86.                         if len(xrefs) == 2:
  87.                               DelCodeXref(ea, xrefs[0].to, 0)
  88.                               AddCodeXref(ea, xrefs[1].to, XREF_USER | fl_JN)
  89.                               del xrefs[0]
  90.                  elif xrefs[0].type == fl_JN:
  91.                         stop = True
  92.  
  93.                  if stop:
  94.                         end = ea + decode_insn(ea)
  95.                         break
  96.                         
  97.                  ea = xrefs[0].to
  98.          return (begin, end)
  99.  
  100. def makeFunc(ea, notAdd = []):
  101.          if not not get_func(ea): del_func(ea)
  102.  
  103.          fea = begin = ea
  104.          toMake = []
  105.          stop = False
  106.          while not stop:
  107.                  xrefs = [xref for xref in XrefsFrom(ea)]
  108.                  if len(xrefs) == 0:
  109.                         if not isCode(getFlags(ea)):
  110.                               setFlags(ea, getFlags(ea) | FF_CODE)
  111.                         elif Byte(ea) & 0xfe != 0xc2:
  112.                               next_ea = ea + decode_insn(ea)
  113.                               if not isCode(getFlags(next_ea)):
  114.                                    setFlags(next_ea, getFlags(next_ea) | FF_CODE)
  115.                         xrefs = [xref for xref in XrefsFrom(ea)]
  116.  
  117.                  if len(xrefs) == 0: stop = True
  118.                  elif Byte(ea) == 0xe8:
  119.                         stop = True
  120.                         if len(xrefs) == 2:
  121.                               DelCodeXref(ea, xrefs[0].to, 0)
  122.                               del xrefs[0]
  123.                         AddCodeXref(ea, xrefs[0].to, XREF_USER | fl_JN)
  124.                         if xrefs[0].to not in notAdd: #vm1_Entry
  125.                               toMake += [xrefs[0].to]
  126.                  elif xrefs[0].type == fl_JN:
  127.                         if xrefs[0].to not in notAdd: #vm1_Entry
  128.                               toMake += [xrefs[0].to]
  129.                         stop = True
  130.                  elif len(xrefs) == 2 and (xrefs[1].type & 0x1f) >= 0x10 and xrefs[1].to not in notAdd:
  131.                         toMake += [xrefs[1].to]
  132.                  elif xrefs[0].to in notAdd: #vm1_Entry
  133.                         stop = True
  134.  
  135.                  if stop:
  136.                         end = ea + decode_insn(ea)
  137.                         break
  138.                         
  139.                  ea = xrefs[0].to
  140.          
  141.          add_func(begin, end)
  142.          
  143.          for ch in toMake:
  144.                  print("Handling tail %x to append func %x" %(ch, fea))
  145.                  makeTail(fea, ch, notAdd)
  146.  
  147.          calcSpd(fea)
  148.  
  149. def calcSpd(fea):
  150.          pfn = get_func(fea)
  151.          enspdar = []
  152.          nspdar = []
  153.          spdiffar = []
  154.          chs = [ch for ch in Chunks(fea)]
  155.          chsaddr = []
  156.          for ch in chs:
  157.                  cb = ch[0]
  158.                  addr = cb
  159.                  while True:
  160.                         print("tail %x" %addr)
  161.                         chsaddr += [addr]
  162.                         ce = getLastInstruction(addr)
  163.                         insn = DecodeInstruction(ce)
  164.  
  165.                         if Byte(ce) == 0xe8: analyze_area(addr, ce)
  166.                         else: analyze_area(addr, ce + insn.size)
  167.  
  168.                         enspd = GetSpd(ce) - GetSpd(addr)
  169.                         if Byte(ce) == 0xe8: enspd -= 4
  170.                         enspdar += [enspd]
  171.                         if len(nspdar) == 0:
  172.                               nspdar = [0]
  173.                               spdiffar = [0]
  174.                         else:
  175.                               nspdar += [-1]
  176.                               spdiffar += [-1]
  177.                         
  178.                         if ce + insn.size == ch[1]:
  179.                               break
  180.                               
  181.                         addr = ce + insn.size
  182.  
  183.          print "enspdar: ", enspdar
  184.  
  185.          if len(chsaddr) > 1:
  186.                  spdiff = 0
  187.                  spdReset = False
  188.                  chunksLesser = chsaddr[1] < fea
  189.                  for i in range(1, len(chsaddr)):
  190.                         if chunksLesser and chsaddr[i] > fea and not spdReset:
  191.                               spdReset = True
  192.                               spdiff = 0
  193.  
  194.                         print("chsaddr[%x] = %x" %(i, chsaddr[i]))
  195.                         if nspdar[i] == -1:
  196.                               print("call calcSpdByBackRefs(): chsaddr[%d] = %x" %(i, chsaddr[i]))
  197.                               calcSpdByBackRefs(chsaddr, nspdar, enspdar, i, chsaddr[i])
  198.  
  199.                         spdiffar[i] = nspdar[i] - GetSpd(chsaddr[i])
  200.                         spdiff += spdiffar[i]
  201.                         SetSpDiff(chsaddr[i], GetSpDiff(chsaddr[i]) + spdiffar[i])
  202.  
  203.                  print "nspdar: ", nspdar
  204.                  print "spdiffar: ", spdiffar
  205.  
  206. def calcSpdByBackRefs(chsaddr, nspdar, enspdar, i, addr):
  207.          pfn = get_func(addr)
  208.          xrefs = [xref for xref in XrefsTo(addr, 1)]
  209.          for xref in xrefs:
  210.                  if func_contains(pfn, xref.frm) and xref.type in [fl_JN, fl_F]:
  211.                         frmchbeg = func_tail_iterator_t(pfn, xref.frm).chunk().startEA
  212.                         frmi = chsaddr.index(frmchbeg)
  213.                         while frmi + 1 < len(chsaddr) and chsaddr[frmi + 1] > chsaddr[frmi] and chsaddr[frmi + 1] <= xref.frm: frmi += 1
  214.                         
  215.                         if nspdar[frmi] == -1:
  216.                               print("call calcSpdByBackRefs(): chsaddr[%d] = %x" %(frmi, chsaddr[frmi]))
  217.                               calcSpdByBackRefs(chsaddr, nspdar, enspdar, frmi, chsaddr[frmi])
  218.  
  219.                         print "calcSpd: xref = ", hex(xref.frm), ", nspdar[", frmi, "] = ", nspdar[frmi]
  220.                         if xref.frm != getLastInstruction(chsaddr[frmi]):
  221.                               nspdar[i] = nspdar[frmi] + GetSpd(xref.frm) - GetSpd(chsaddr[frmi])
  222.                         else: nspdar[i] = nspdar[frmi] + enspdar[frmi]
  223.                         break
  224.  
  225. for f in Functions(): del_func(f)
  226.  
  227. makeFunc(0x4a5642, []) #Entry point
  228. = 0
  229. funcs = []
  230. for addr in range(0x4a68d5, 0x4a6cd5, 4):#Handler table
  231.          ea = Dword(addr) - 1
  232.          if ea not in funcs:
  233.                  makeFunc(ea, [0x4a3195, 0x4a341c, 0x4a3184, 0x4a001d]) #vm1_init, vm1_startVmTrace, vm1_entry, vm1_verStack
  234.                  funcs += [ea]
  235.          i += 1


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

Адреса находишь свои.
vm1_init - точка входа в вм с новым адресом ленты
vm1_startVmTrace - инициализация указателя ленты вм
vm1_entry - начало выборки следующего примитива
vm1_verStack - адрес кода проверки вм-стека

Извините за названия точек, но я не сильно заморачивался.

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

Это из старых разработок. Можно в статике распаковать и девиртуализировать

-----
IZ.RU




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

Создано: 06 мая 2019 10:21
· Личное сообщение · #12

^ можно скрипт в нормальной форме запостить, а то форум пожувал




Ранг: 324.3 (мудрец), 222thx
Активность: 0.480.37
Статус: Участник

Создано: 06 мая 2019 11:16 · Поправил: DenCoder
· Личное сообщение · #13

Можно. Выкладываю в сыром виде, как есть

9274_06.05.2019_EXELAB.rU.tgz - defTail.py

Скрипт под иду 6.8. Для 7.0 надо менять

-----
IZ.RU



 eXeL@B —› Вопросы новичков —› Не возвращается управление отладчику
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати