Сейчас на форуме: (+5 невидимых)

 eXeL@B —› Дневники и блоги —› Блог DenCoder'а
<< . 1 . 2 . 3 .
Посл.ответ Сообщение


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

Создано: 05 июля 2015 15:23 · Поправил: DenCoder
· Личное сообщение · #1

Всем привет! Всем здоровья, достатка, удачи, успехов... всех благ! )

Вот и нашлось немножко времени, чтобы завести блог. Давно хотел, но время для меня на вес золота...

С вашего позволения здесь буду описывать процессы обхода/взлома/разбора защит, с которыми приходилось сталкиваться. Кому-то может пригодиться, кому-то - нет... Но за время работы немного узнал, что есть такая защита, перед которой некоторые коллеги пасуют - VMProtect. Может, в общем и есть такие страшные версии вмпрота, на которые терять кучу времени бессмысленно - не знаю, я с такими не сталкивался. Но скажу, что очень часто снимать вмпрот или разбирать то, что им накрыто, просто нет необходимости!

Вмпроты, которые мне попались в мае (сразу 2 подряд) - не такие страшные. Первым из них была накрыта lockpdfu.dll - компонент DRM защиты pdf-ок. Подробнее --> здесь <--.
Человек 2 или 3 года ждал, когда же, наконец, найдётся кто-нибудь, кто даст возможность свободно пользоваться pdf-документами на любом компе и редактировать. И находился некто с других сайтов, кто чуть не кинул... Попробую объяснить морально-идеологический аспект в двух словах прежде всего:

Человек - учитель, ему необходим учебный материал без ограничений использования с возможностью редактировать. Одна из купленных тетрадей, на файле которой я помогал решить задачу, стоила что-то вроде 70 гривен, использовать можно только на 2х компах и никак нельзя что-то пометить, что-то исправить. Чтобы, например, поделиться с учениками, сколько-то нужно дополнительно проплачивать... мда... куда катится мир, одни то ли бизнесмены, то ли барыги...

Ставим задачу: перехватить расшифровку запротекченной тетради, записать в отдельную папку оригинальный pdf.

Из совета Vovan666 запротектил пдф-ку персональной версией, после чего без проблем из памяти AcroRd32 достал чистую pdf-ку. честно говоря, не понял про протект персональной версией, но проверил можно ли что-то из памяти выцепить: даже и обычные pdf-ки в первозданном виде в памяти не хранятся, сигнатур %pdf-1.4 .. %pdf-1.7 нет. То, что находится с такой сигной - какая-то полоска для самого ридера )

Я пошёл своим путём. Раз нельзя выцепить из памяти - незаметно (для защиты) встанем на место после декрипта и незаметно сольём поток в файл. Звучит просто, но пришлось немного попотеть...

CreateFile, SetFilePointer, CloseHandle удалось хукнуть джампом без проблем. А вот ветка кода из acrord32.dll, вызывающая чтение функой ReadFile была хукнута в NtReadFile защитой + каким-то магическим образом проверялся crc этой ветки, а также защита не давала поставить ни софт бряк, ни джамп на ReadFile ни до, ни внутри, ни после... в дрова лезть не будем! Софт бряк нельзя поставить, а против харда защита ничего не имеет против! Вспомнил, что имеется такая функция AddVectoredExceptionHandler и быстро нарисовалась идея (что не я - первооткрыватель, знаю, потому и пишу, что вспомнил) поставить 2 харда на ReadFile и после и обрабтать по своему. Потратил немножко времени на кодинг, но удалось, с первой подзадачей справился, осталось только записать файл.

Записать файл - тут кажется, проще не бывает. Но во-первых под 7кой и выше нужно перевести для этого акроридер в незащищённый режим, чтобы были привилегии, во-вторых - NtWriteFile также хукнута защитой и возвращала жестокий AD. Снимать хук без изучения защиты бесполезно - работать как надо не будет. ReadFile, WriteFile - так защита обменивалась какими-то важными данными. Не стал тратить время на изучение механизмов, сделал проще: против вызова NtWriteFile в месте после хука защита тоже ничего не имела против. Тут, я думаю, подробности излишни, в ntdll индексы всех фунок(nt-сервисов) идут по возрастающей по порядку во всех версиях винды, не встречалось другого(берём адрес хукнутого сервиса, находим следующий/предыдущий, берём оттуда индекс сервиса и минус/плюс 1)

Новичкам с опытом кодинга может быть полезно

В следующий раз (может быть сегодня вечером, может и через года 2) опишу отлом какой-то из версий вмпрота под x64, где тоже есть морально-идеологический аспект

-----
IZ.RU


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


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

Создано: 14 марта 2017 04:48
· Личное сообщение · #2

Детектом только псевдоциклов и непрозрачных предикатов проблему не решить. Попадаются довольно сложные выражения, общий принцип решения которых довольно сложно, почти невозможно реализовать на ЯП. Например, что-то вида

Code:
  1. DWORD a =1;
  2.  
  3. DWORD const1 = 0x2457;
  4. DWORD const2 = 0x7241;
  5. do
  6. {
  7.   //...
  8.   a += const1;
  9.   a *= const2;
  10. }while(& 1);


или
Code:
  1. DWORD const1 = 0x2457;
  2. DWORD const2 = 0x7241;
  3.  
  4. void func()
  5. {
  6.   DWORD var;
  7.   DWORD a = (DWORD)&var;
  8.  
  9.   do
  10.   {
  11.     //...
  12.     a = (DWORD)* const1 + const2;
  13.   }while(& 1);


Проблемно такие выражения решать в статике, без эмулятора сложно обойтись... На помощь приходит Unicorn! Без проблем эмулирует нужные куски ARM-кода. Использование Unicorna облегчает жизнь, но тогда возникает соблазн изменить план для достижения цели - отэмулировать почти всё, не только трудные конструкции кода... В расшифровке строк, что как я читал - одна из основных черт многих запутывающих LLVM-компиляторов, мы преуспели - расшифровываются имена проверяемых файлов и строки команд, запускаемых через system(). Но у Unicorn'а нет поддержки набора инструкций Advanced SIMDv1, который часто используется компилятором для оптимизации кода, (аналогично как и в SSE/SSE2 под x86/x64), и здесь не исключение. Нужны-то всего 2 инструкции: VMOV и VST. Искать и собирать другой эмулятор? - Один из возможных выходов, но в других эмуляторах возможны свои проблемы... Искать и пробовать - тоже нет времени! Решил самостоятельно добавить поддержку эмуляции этих инструкций. Чуть позже выложу скрипт детекта и эмуляции их на питоне.

Добавлено спустя -59 минут
За Unicorn много благодарностей автору!!!

Добавлено спустя 4 часа 16 минут
Даже работает mu.reg_write(UC_ARM_REG_D16, 9)! Эмуляцию регистров не надо делать )

Вот только на UC_ARM_REG_Q8 единорог никак не реагирует.

-----
IZ.RU


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

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

Создано: 14 марта 2017 17:23
· Личное сообщение · #3

уже раза 3 качал юникорна.. все собирался разобраться, так руки и не дошли

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....





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

Создано: 14 марта 2017 18:15
· Личное сообщение · #4

Ну, дело будет - разберёшься. )
По мере работы с ним какие-то скрипты буду выкладывать. Может, помогут.

Юникорн хорош! Достаточно прост в использовании. Правда, ограничения в использовании есть. По архитектуре ARM. например, с которой я сейчас работаю, много задумано и пока не реализовано, оставлено. Но, умеючи, можно эти ограничения обойти... )

Автор aquynh на джитхабе, как я понял = Jupiter здесь? Или ошибаюсь?

-----
IZ.RU





Ранг: 605.2 (!), 341thx
Активность: 0.470.25
Статус: Модератор
Research & Development

Создано: 14 марта 2017 18:21
· Личное сообщение · #5

DenCoder пишет:
Или ошибаюсь

Не не. Это два разных аватара.

-----
EnJoy!





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

Создано: 14 марта 2017 18:33 · Поправил: DenCoder
· Личное сообщение · #6

хм...

Судя по этому поддержка неоновских регистров исправляет баг регистров Q0-Q15. Закоммичено было 6 марта. А в инсталлере этого ещё нет... Надо как-то теснее с джитхабом работать...

Добавлено спустя -59 минут
Jupiter
Ну так подумалось почему-то... Не принимал участие в разработке капители и единорога? )

-----
IZ.RU





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

Создано: 15 марта 2017 14:23
· Личное сообщение · #7

DenCoder пишет:
Автор aquynh на джитхабе, как я понял = Jupiter здесь? Или ошибаюсь?


aquynh это Nguyen Anh Quynh из Вьетнама



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


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


Ранг: 605.2 (!), 341thx
Активность: 0.470.25
Статус: Модератор
Research & Development

Создано: 15 марта 2017 22:16
· Личное сообщение · #8

hors
Совершенно верно, никакого сходства с:


-----
EnJoy!





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

Создано: 18 марта 2017 16:49 · Поправил: DenCoder
· Личное сообщение · #9

Прошло меньше полнедели и более менее освоился в питоне. Передела часть idc-скрипта, адаптировал под нужды "поиска альтернативной ветви кода"(не закончил, пока полуавтоматом ищет). Что это такое? Бывает, в реверсе "LLVM-кода" эмулятор или дебаггер выводит всегда на одну тупиковую ветвь, как будто условие какое-то не срабатывает - то ли файл не в том формате, то ли детект задержек. Этот скрипт проверяет, можно ли избежать этой ветви, и если да, показывает путь. Заодно собирает блоки и циклы, как и в версии idc-скрипта(исправлены некоторые ошибки сбора циклов и блоков). Выглядит красивей и компактней, чем версия на idc и работает много шустрее - не ожидал от питона )

Code:
  1. #coding=iso-8859-1
  2.  
  3. from __future__ import print_function
  4. import sys, traceback
  5. import idaapi
  6. import idautils
  7. import idc
  8.  
  9. def setBackRefs(addr):
  10.          global blockS
  11.          blockS[addr] = []
  12.          for xref in XrefsTo(addr):
  13.                  if(xref.type == fl_F or xref.type == fl_JN):
  14.                         blockS[addr].append(xref.frm)
  15.                  
  16. def setForwardRefs(addr):
  17.          global blockE
  18.          blockE[addr] = []
  19.          for xref in XrefsFrom(addr):
  20.                  if(xref.type == fl_F or xref.type == fl_JN):
  21.                         blockE[addr].append(xref.to)
  22.  
  23. def findPaths(addr, path, addrEnd = BADADDR):
  24.          global blockS, blockE, loops
  25.  
  26.          try:
  27.                  verBack, setVerBack = False, True
  28.                  showPath = False
  29.  
  30.                  # не забыть про mov PC, R0
  31.                  # будет отдельной функцией, похожей
  32.  
  33.                  #print("0 block 0x%x added" %addr)
  34.                  setBackRefs(addr)
  35.                  path.append(addr)
  36.                  curAddr = addr
  37.                  
  38.                  while(True):
  39.                         #print("current address: 0x%x" %curAddr)
  40.                         if(addrEnd != BADADDR and curAddr == addrEnd):
  41.                               print("target address 0x%x is reached" %addrEnd)
  42.                               return 8
  43.                  
  44.                         xrefFrm = idaapi.xrefblk_t()
  45.                         if(not xrefFrm.first_from(curAddr, 0)): showPath = True
  46.                         else:
  47.                               x = xrefFrm.to
  48.                               if(xrefFrm.type != fl_F and xrefFrm.type != fl_JN): showPath = True
  49.                         
  50.                         if(showPath):
  51.                               print("========================")
  52.                               for i in path: print("0x%x " %i)
  53.                               print("========================")
  54.                               return 1
  55.                               
  56.                         if(verBack):
  57.                               xrefTo = idaapi.xrefblk_t()
  58.                               xrefTo.first_to(curAddr, 0)
  59.                               if(xrefTo.type == fl_JN or xrefTo.next_to()):
  60.                                    #print("1 block end 0x%x added" %prevAddr)
  61.                                    setForwardRefs(prevAddr)
  62.  
  63.                                    if(curAddr in path):
  64.                                        #print("1 0x%x in path" %curAddr)
  65.                                        loop = path[path.index(curAddr):]
  66.                                        loops.append(loop)
  67.                                        return 6
  68.                                    
  69.                                    if(curAddr in blockS):
  70.                                        #print("1 0x%x in blockS" %curAddr)
  71.                                        return 7
  72.                                    
  73.                                    #print("1 block 0x%x added" %curAddr)
  74.                                    setBackRefs(curAddr)
  75.                                    path.append(curAddr)
  76.  
  77.                         if(xrefFrm.type == fl_JN):
  78.                               #print("2 block end 0x%x added" %curAddr)
  79.                               setForwardRefs(curAddr)
  80.                               
  81.                               if(in path):
  82.                                    #print("2 0x%x in path" %x)
  83.                                    loop = path[path.index(x):]
  84.                                    loops.append(loop)
  85.                                    return 2
  86.                                    
  87.                               if(in blockS):
  88.                                    #print("2 0x%x in blockS" %x)
  89.                                    return 3
  90.                               
  91.                               #print("2 block 0x%x added" %x)
  92.                               setBackRefs(x)
  93.                               path.append(x)
  94.                               setVerBack = verBack = False
  95.                         else:
  96.                               if(xrefFrm.next_from() and xrefFrm.type == fl_JN):
  97.                                    y = xrefFrm.to
  98.                                    #print("3 block end 0x%x added" %curAddr)
  99.                                    setForwardRefs(curAddr)
  100.                                    
  101.                                    if(in path):
  102.                                        #print("3 0x%x in path" %y)
  103.                                        loop = path[path.index(y):]
  104.                                        loops.append(loop)
  105.                                    elif(not in blockS): findPaths(y, path, addrEnd)
  106.                                    
  107.                                    if(in path):
  108.                                        #print("3 0x%x in path" %x)
  109.                                        loop = path[path.index(x):]
  110.                                        loops.append(loop)
  111.                                        return 4
  112.                                        
  113.                                    if(in blockS):
  114.                                        #print("3 0x%x in blockS" %x)
  115.                                        return 5
  116.                                    
  117.                                    #print("3 block 0x%x added" %x)
  118.                                    setBackRefs(x)
  119.                                    path.append(x)
  120.                                    setVerBack = verBack = False
  121.                               else: prevAddr = curAddr
  122.                         
  123.                         curAddr = x
  124.                         verBack = setVerBack
  125.                         setVerBack = True
  126.                         #print("0x%x: verBack is %s, setVerBack is %s" %(curAddr, verBack, setVerBack))
  127.  
  128.          except:
  129.                  print("Unexpected error: %s" %sys.exc_info()[0])
  130.                  traceback.print_exc()
  131.          finally:
  132.                  #print("addr: 0x%x" %addr)
  133.                  #print("before")
  134.                  #for i in path: print("0x%x" %i)
  135.                  path[path.index(addr):] = []
  136.                  #print("after")
  137.                  #for i in path: print("0x%x" %i)
  138.  
  139. global blockS, blockE, loops
  140.  
  141. blockS = dict()
  142. blockE = dict()
  143. loops = []
  144. path = []
  145.  
  146. findPaths(here(), path, 0x10049f30)
  147. #findPaths(here(), path)
  148.  
  149. = 1
  150. for loop in loops:
  151.          print("loop %d" %i)
  152.          for l in loop:
  153.                  print("0x%x" %l)
  154.          print("================")
  155.          i += 1
  156.  
  157. #blockS.clear()
  158. #blockE.clear()


findPaths(start, path, avoid_addr)
start - адрес начального блока, откуда начинать проверку, у меня here() - аналог idc-функции ScreenEA()
path - список с адресами пройденных блоков
avoid_addr - адрес, которого хотелось бы избежать

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

Добавлено спустя 6 минут
Скрипт эмуляции на юникорне с маппингом и загрузкой секций so-модуля, с добавлением эмуляции неоновских инструкций, с эмуляцией некоторых линуксовых функций весь пока не могу выложить - громоздкий, несколько модулей... Может быть, чуть позже освоюсь на гитхабе...

Добавлено спустя 16 минут
Часть скрипта, как можно инициировать юникорн для эмуляции:
Code:
  1. #mu = Uc(UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_V8)
  2. mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
  3. ADDRESS = seg_ea = FirstSeg()
  4. while(seg_ea != 0xffffffff):
  5.          seg_size = GetSegmentAttr(seg_ea, SEGATTR_END) - seg_ea
  6.          prev_seg_ea = seg_ea
  7.          seg_ea = NextSeg(seg_ea)
  8. SIZE = (prev_seg_ea + seg_size - ADDRESS + 0x10000) & -0x10000
  9.  
  10. STACK_SIZE = 0x100000
  11. sys_vars = STACK_ADDR = (ADDRESS + SIZE + STACK_SIZE + 0x100000) & -0x100000
  12.  
  13. print("Module address: 0x%x, size: 0x%x" %(ADDRESS, SIZE))
  14. print("Stack address: 0x%x, size: 0x%x" %(STACK_ADDR, STACK_SIZE))
  15.  
  16. mu.mem_map(ADDRESS, SIZE)
  17. mu.mem_map(STACK_ADDR - STACK_SIZE, STACK_SIZE)
  18. mu.mem_map(sys_vars, 0x10000)
  19.  
  20. seg_ea = FirstSeg()
  21. while(seg_ea != 0xffffffff):
  22.          seg_size = GetSegmentAttr(seg_ea, SEGATTR_END) - seg_ea
  23.          seg_name = SegName(seg_ea)
  24.          seg_type = GetSegmentAttr(seg_ea, SEGATTR_TYPE)
  25.          print("%s 0x%x 0x%x 0x%x" %(seg_name, seg_ea, seg_size, seg_type))
  26.          if(seg_type == 2 or seg_type == 3):
  27.                  buf = idaapi.get_many_bytes(seg_ea, seg_size)
  28.                  mu.mem_write(seg_ea, buf)
  29.          seg_ea = NextSeg(seg_ea)
  30.  
  31. mu.reg_write(UC_ARM_REG_SP, STACK_ADDR)
  32.  
  33. #mu.mem_protect(0, FUNC_ADDRESS & -0x1000, (UC_PROT_ALL & ~UC_PROT_EXEC))
  34. #mu.mem_protect((FUNC_ADDRESS + FUNC_SIZE + 0x1000) & -0x1000, (SIZE - (FUNC_ADDRESS + FUNC_SIZE + 0x1000)) & -0x1000, UC_PROT_ALL & ~UC_PROT_EXEC)
  35. mu.mem_protect(STACK_ADDR - STACK_SIZE, STACK_SIZE, (UC_PROT_ALL & ~UC_PROT_EXEC))
  36.  
  37. #mu.hook_add(UC_HOOK_BLOCK, hook_block)
  38. mu.hook_add(UC_HOOK_INTR, hook_intr)
  39. mu.hook_add(UC_HOOK_CODE, hook_code, ADDRESS + 0x31FA0, ADDRESS + 0x31FA0)


mu.hook_add(UC_HOOK_INTR, hook_intr) ставит хук на sysenter/sysexit под x86/x64, под ARM - на svc 0, R7 будет индексом системной функции, список которых под ARM можно найти здесь

В mu.hook_add(UC_HOOK_CODE, hook_code, ADDRESS + 0x31FA0, ADDRESS + 0x31FA0) так и не понял, зачем 2 последних аргумента - полный их игнор

Добавлено спустя 1 час 7 минут
Из догадок по аргументам begin, end ф-ции hook_add() -
begin, end == 1, 0 -> вызов колбэка до выполнения инструкции
begin, end == 0, 1 -> вызов колбэка после выполнения инструкции

Добавлено спустя 10 часов 14 минут
День или 2 копался в коде под толстым слоем LLVM, смотрел для чего читается /proc/self/status.
Оказывается, по его содержимому тоже можно определить факт динамического исследования работы кода через TracerPid. Наличие чего-либо, кроме нуля(точнее, там должно быть TracerPid:\t0\n) и попадаем в ловушку - в тупиковую ветвь. Эмулятор так не задетектить, если пример вывода из /proc/self/status взять с реальной машины, а не с сайта

-----
IZ.RU





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

Создано: 20 марта 2017 03:21 · Поправил: DenCoder
· Личное сообщение · #10

Обнаружена непонятная хрень с юникорном, из-за которой пришлось сделать массу экспериментов, чтоб докопаться до причин и потратить ещё один ненужный день. Суть проблемы - невозможно остановить процесс эмуляции кода в колбэке, установленном как UC_HOOK_CODE, если текущая инструкция - BL (на x86 можно проверить это насчёт CALL). Пробовал uc.emu_stop(), пробовал raise - и то, и то игнорится, хотя сообщение какое-то можно вывести. Другие условия несработки останова пока не были выявлены, на других инструкциях хватает uc.emu_stop(), чтоб прервать выполнение...

Хотя на счёт raise - только что провёл ещё один эксперимент. После emu_stop() на инструкции BL единорог отказывается воспринимать raise. Как будто emu_stop() становится на время эмуляции одной инструкции emu_continue_and_ignore_all_errors(). Но без emu_stop() рэйзится нормально и из except уже можно остановить процесс.

Вот в чём там дело? Сие мне стоило одного дня...

Добавлено спустя 18 минут
Оказалось, что и raise на BL не всегда работает...

Добавлено спустя 3 часа 1 минуту
Ещё одна интересная особенность юникорна из инсталлера... даже 2:
1) Если в функции-хуке кода попробовать прочитать из незамапленной памяти кусок даже нулевого размера под идапитоном, зависнет однорогий
2) Вывод при эмуляции идёт параллельным тредом и отстаёт от эмуляции, поэтому вы не увидите, на чём именно зависло. Я увидел это только когда догадался вставить идовскую AskYN(), чтоб пошагово эмулировать.

Добавлено спустя 3 часа 30 минут
А причина такой ошибки проста:
Code:
  1.                                        dst = uc.reg_read(UC_ARM_REG_R0)
  2.                                        src = uc.reg_read(UC_ARM_REG_R1)
  3.                                        size = uc.reg_read(UC_ARM_REG_R2)
  4.                                        print("memcpy(0x%x, 0x%x, 0x%x)" %(dst, src, size))
  5.                                        uc.mem_write(dst, uc.mem_read(src, size))
  6.                                        uc.reg_write(UC_ARM_REG_R0, src)


код эмулирует функцию memcpy(). В функцию, которая её вызывает, передаётся структура, недоинициализированная. Значит, где-то опять проскочил условие и опять угодил в ловушку.

-----
IZ.RU





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

Создано: 20 марта 2017 12:04
· Личное сообщение · #11

DenCoder пишет:
код эмулирует функцию memcpy(). В функцию, которая её вызывает, передаётся структура, недоинициализированная. Значит, где-то опять проскочил условие и опять угодил в ловушку.



Пиши им сюда: https://github.com/unicorn-engine/unicorn/issues

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





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

Создано: 20 марта 2017 14:35 · Поправил: DenCoder
· Личное сообщение · #12

Не уверен, что реакция будет быстрая, и мои найденные баги - приоритетные. Список TODO у автора большой. По ошибке с emu_stop() там уже попадалось. Да, может быть стоит написать, добавить, что почему-то именно на BL такая проблема... По зависанию на чтении/записи незамапленных регионов - решается ассертами. Не лениться их вставлять, от лишних проблем избавит.

-----
IZ.RU





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

Создано: 24 марта 2017 23:19 · Поправил: DenCoder
· Личное сообщение · #13

Ну дальше всё понятно - обходим все ловушки, выходим в JNI_OnLoad() на нужные методы, избавляя себя от их реверса просто эмулируем их код. И уже эмуляция на СИ...

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

-----
IZ.RU





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

Создано: 28 мая 2017 17:00
· Личное сообщение · #14

2 месяца уже как работаю по функциям реверс-инженером, но официально - программистом. З/п не скажу, но достойная. ) Работа нашла меня, повезло... Ввиду этих обстоятельств здесь что-то будет появляться ещё реже, так как времени первые 2-3 месяца не будет на то, чем мог бы поделиться...

Ходит слух что деятельность реверс-инженеров будет строго запрещена в РФ и как-то по закону караться. В америке или где-то там уже слышал, что запретили, но у нас не америка, конечно. Будем надеяться, что это не правда )

-----
IZ.RU





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

Создано: 09 июля 2017 01:24
· Личное сообщение · #15

DenCoder

Так полагаю что это отдел по IT где то в МВД/КГБ/етц ?

-----
vx




Ранг: 16.2 (новичок), 11thx
Активность: 0.030
Статус: Участник

Создано: 09 июля 2017 02:35 · Поправил: Abraham
· Личное сообщение · #16

difexacaw привет! именно.)




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

Создано: 11 июля 2017 10:33 · Поправил: DenCoder
· Личное сообщение · #17

С чего взяли? )

difexacaw
Неуверенных в себе, как Вы изволили не так давно заметить обо мне, туда не берут, особенно в етц

difexacaw пишет:
Так полагаю

Полагай, только не лажай! )

-----
IZ.RU




Ранг: 1.0 (гость)
Активность: 0=0
Статус: Участник

Создано: 21 июля 2017 03:12
· Личное сообщение · #18

С вашего позволения здесь буду описывать процессы обхода/взлома/разбора защит, с которыми приходилось сталкиваться. Продолжение?




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

Создано: 26 июля 2017 15:01
· Личное сообщение · #19

Zoeken
Да возражений нет. Может, возродится активность в моём блоге )

-----
IZ.RU





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

Создано: 23 октября 2019 21:39
· Личное сообщение · #20

Долго не появлялся... Поделюсь интересным наблюдением:

В ws2_32.dll есть неэскпортируемая функция CheckForHookersOrChainers(). Вызывается из WSAStartup(). Её смысл - проверка на наличие хуков в экспорте этой dll. То есть, если перехватить GetProcAddress() и подменить адрес функции на адрес своего обработчика(1 случай), или подменить rva функции в экспорте(2 случай), то функция возвращает -1 и сокеты не заводятся, WSAStartup() возвращает WSASYSNOTREADY(10091).

На первый взгляд защита. В первом случае обходится вставкой в хук на GetProcAddress() кода
Code:
  1. void* __stdcall hGetProcAddress(HMODULE hMod, char* funcName)
  2. {
  3.          void* pAddr = GetProcAddress(hMod, funcName);
  4.  
  5.          DWORD retAddr = *((DWORD*)&hMod - 1);
  6.          HMODULE hModFrom;
  7.          GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (char*)retAddr, &hModFrom);
  8.          if(hModFrom == GetModuleHandle("ws2_32.dll")) return pAddr;
  9.  
  10. ...


Во втором случае аналогично, только при определении вызова GetProcAddress() из ws2_32 в хуке вместо GetProcAddress() подсунуть сохранённый оригинальный адрес.

-----
IZ.RU


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


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

Создано: 12 декабря 2019 22:33
· Личное сообщение · #21

Ох, замучал меня verifier. Так-то неплохой способ через IFEO цепляться. Но verifier.dll много лишнего делает, серьёзное приложение, которое "без ошибок", не загрузишь с ним. Ну или все пишут с ошибками, и тогда добрую половину софта можно браковать.

В общем, начинаю учиться его выгружать.

Добавлено спустя 14 часов 39 минут
И вот пишу из браузера с моей приаттаченой через IFEO dll. Браузер работает более менее нормально, хотя verifier.dll в него тоже подгружена. Кодом
Code:
  1.                                    mov eax, [ebp]
  2.                                    mov eax, [eax]
  3.                                    mov eax, [eax + 8]; <- our dll entry in list
  4.                                    mov ecx, [eax + 4]; <- verifier dll entry in list
  5.                                    ;exclude from list
  6.                                    mov ecx, [eax]; <- header of list
  7.                                    mov [ecx], eax
  8.                                    mov [eax + 4], ecx

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

Добавлено спустя 18 часов 1 минуту
Проблема с 10кой остаётся - способ передачи объекта AVRF-провайдерской структуры отличается (не через стек, а через регистр), структура отличается...

-----
IZ.RU





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

Создано: 13 декабря 2019 20:57
· Личное сообщение · #22

DenCoder

> Ну или все пишут с ошибками, и тогда добрую половину софта можно браковать.

Верно, он весь кривой. Потому что не нэйтив. Именно по этому и валится почти всегда при верификации. Собственно для этого инструмент и нужен. Это лишь системный способ загрузки в процесс, причём обычно не нужный. Никто голый нэйтив не пишет. В очень редких случаях, когда нужно загрузить монитор в последовательность процессов. Иначе достаточно создать процесс остановленным и фиксить в памяти что угодно. Своего рода инжект.

-----
vx



<< . 1 . 2 . 3 .
 eXeL@B —› Дневники и блоги —› Блог DenCoder'а
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


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