eXeLab
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 июня!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Русский / Russian English / Английский

Сейчас на форуме: SDK, reverser (+4 невидимых)
 · Начало · Статистика · Регистрация · Поиск · ПРАВИЛА ФОРУМА · Язык · RSS · SVN ·

 eXeL@B —› Вопросы новичков —› Помогите определить виртуальную машину из MapEdit (с Geopainting.com)
Посл.ответ Сообщение

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

Создано: 22 сентября 2013 20:08 · Поправил: pinky_p New!
Цитата · Личное сообщение · #1

Итак, есть программа MapEdit для работы с картами.
http://geopainting.com/download/mapedit2-0-77-1.zip

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

Для примера рассмотрим функцию some_gui_func(). Она вызывает функцию VM_ENTER(), и опкоды, идущие после вызова (начиная с адреса some_gui_func_VM_ENTER), исполняются на виртуальной машине. Оригинальные опкоды перезаписаны мусором, а исполняемые виртуализированные опкоды загружаются из ресурсов EXE (LoadResource(GetModuleHandle(0), 1, 0x0A)) функцией VM_LoadOpcodes().

VM_ENTER() сохраняет значения регистров и передает управление VM_ENTER_GATE(), которая вызывает VM_RUN(), которая и исполняет виртуализированные опкоды. Я почти полностью дизассемблировал VM_RUN(), это не сложно. Проблема в том, что VM_RUN() может вызывать дополнительные функции в зависимости от опкода и их довольно много.

Первые два виртуализированных опкода some_gui_func() в запакованном виде в ресурсах EXE выглядят так:
Code:
  1. seg000:0000014C   dd 80000402h
  2. seg000:00000150   dd 0FFBF1913h
  3. seg000:00000154   dd 80000402h
  4. seg000:00000158   dd 0FFBF1917h


Они же в распакованном виде при исполнении:
Code:
  1. debug023:00977DF8 dd 80000402h
  2. debug023:00977DFC dd 40E6EDh
  3. debug023:00977E00 dd 85DEF4h
  4. debug023:00977E04 dd 0FFFFFFFFh
  5. debug023:00977E08 dd 80000402h
  6. debug023:00977E0C dd 40E6E9h
  7. debug023:00977E10 dd 85DEF4h
  8. debug023:00977E14 dd 0FFFFFFFFh


Адрес очередного опкода находится в регистре EDI при исполнении метки next_opcode внутри VM_RUN().

Нужные адреса внутри mapedit.exe:
Code:
  1. 0x00668574    VM_ENTER
  2. 0x006685C9    VM_ENTER_GATE
  3. 0x0066A6D7    VM_RUN
  4. 0x0066A768    next_opcode
  5. 0x006681F5    VM_LoadOpcodes
  6. 0x0040E404    some_gui_func
  7. 0x0040E6E3    some_gui_func_VM_ENTER

Также приаттачен IDC-скрипт для добавления имен в базу.

Может быть кто-то знает, что это за виртуальная машина и имеет дизассемблер для нее? Очень надеюсь сэкономить себе кучу времени.

Дополнительное обсуждение защиты программы:
Как обойти проверку целостности кода в секции

{ Атач доступен только для участников форума } - names.idc


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 22 сентября 2013 21:16 · Поправил: reversecode New!
Цитата · Личное сообщение · #2

вообще то как то так

.text:0066A488 _CALL_VM_sub_66A488
.text:0066A588 _LEAVE_VM_sub_66A588

и вообще они там не один если судить по рефам на
.data:007D77C8 _VM_crit_stru_7D77C8

.data:0078F86C off_78F86C dd offset sub_668647
похоже на сами обработчики опкодов вм

еще там подозрительный аллокатор new и delete
.text:0040327D _new_sub_40327D
там на маленькие куски до 128 байт, по другому срабатывает
лень думать, но как быоно не на саму ВМ работало, да еще и может свою адрессацию,
а может все таки просто соптимизировано для опкодов, что бы ускорить скорость самой вм

дальше интерес пропал

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

Создано: 22 сентября 2013 21:38 New!
Цитата · Личное сообщение · #3

reversecode пишет:
.text:0066A488 _CALL_VM_sub_66A488
.text:0066A588 _LEAVE_VM_sub_66A588


Эти функции - это на самом деле одна функция. Это один из обработчиков опкодов (а именно - CALL), которые вызывает VM_RUN. То есть, VM_RUN формирует указатель на операнд1, операнд2 и передает это в доп обработчик.

reversecode пишет:
data:0078F86C off_78F86C dd offset sub_668647
похоже на сами обработчики опкодов вм

Все верно, только это не сами обработчики, а аллокаторы объектов обработчиков.

Короче, эта VM исполняет те же x86 опкоды, записанные в другой форме. И я надеюсь, что кто-то ее знает и имеет дизассемблер.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 22 сентября 2013 21:44 · Поправил: reversecode New!
Цитата · Личное сообщение · #4

pinky_p пишет:
Эти функции - это на самом деле одна функция.

это и так понятно) рад что вы тоже это видите

pinky_p пишет:
Все верно, только это не сами обработчики, а аллокаторы объектов обработчиков.

это сами обработчики
только опкоды написаны на с++, и для вас это аллокаторы
для меня это обработчики
потому что это таблица соответствий

pinky_p пишет:
И я надеюсь, что кто-то ее знает и имеет дизассемблер.

глупая затея ждать что кто то даже если имеет то поделится)
реверсите сами каждый обработчик


Статус: Пришелец

Создано: 2 октября 2013 19:09 New!
Цитата #5

Разбудили вы мой интерес к этой программе. ВМ действительно не сложная, обработчики КОПов даже без обфускации. Но все это сделано специально для этой программы! Автор постарался, даже FPU не поленился добавить. Хотя вот логику ту же можно было в NAND или NOR разложить.

Пока сложно догонять, что делают вот такие хендлеры:
Code:
  1. .text:00669B1B mov     eax, [esp+arg_4]
  2. .text:00669B1F mov     byte ptr [eax+3], 1
  3. .text:00669B23 retn    0Ch


Добавлено спустя 9 часов 43 минуты
pinky_p
На данный момент у меня такая таблица. Не совпадения/дополнения есть?
Code:
  1. .rdata:006EDB64 off_6EDB64      dd offset hand_mov      ; DATA XREF: sub_668647+Co
  2. .rdata:006EDB64                                         ; 02A12BA0o
  3. .rdata:006EDB68 off_6EDB68      dd offset hand_mov_i32  ; DATA XREF: sub_668692+Co
  4. .rdata:006EDB68                                         ; 02A12BB8o
  5. .rdata:006EDB6C off_6EDB6C      dd offset hand_push     ; DATA XREF: sub_6686B5+Co
  6. .rdata:006EDB6C                                         ; 02A12BD0o
  7. .rdata:006EDB70 off_6EDB70      dd offset hand_pop      ; DATA XREF: sub_66871C+Co
  8. .rdata:006EDB70                                         ; 02A1FF78o
  9. .rdata:006EDB74 off_6EDB74      dd offset hand_xchg     ; DATA XREF: sub_668774+Co
  10. .rdata:006EDB78 off_6EDB78      dd offset hand_movzx_eax_ax_al ; DATA XREF: sub_6687D1+Co
  11. .rdata:006EDB7C off_6EDB7C      dd offset hand_cwd_cdq  ; DATA XREF: sub_668826+Co
  12. .rdata:006EDB80 off_6EDB80      dd offset hand_mov_i8_i16 ; DATA XREF: sub_668881+Co
  13. .rdata:006EDB84 off_6EDB84      dd offset hand_mov_i8_i16 ; DATA XREF: sub_6688BA+Co
  14. .rdata:006EDB88 off_6EDB88      dd offset sub_6688E6    ; DATA XREF: sub_6688D0+Co
  15. .rdata:006EDB8C off_6EDB8C      dd offset hand_add      ; DATA XREF: sub_668903+Co
  16. .rdata:006EDB90 off_6EDB90      dd offset hand_adc      ; DATA XREF: sub_6689A4+Co
  17. .rdata:006EDB94 off_6EDB94      dd offset hand_sub      ; DATA XREF: sub_668A67+Co
  18. .rdata:006EDB98 off_6EDB98      dd offset hand_sbb      ; DATA XREF: sub_668B08+Co
  19. .rdata:006EDB9C off_6EDB9C      dd offset hand_inc      ; DATA XREF: sub_668BCE+Co
  20. .rdata:006EDBA0 off_6EDBA0      dd offset hand_dec      ; DATA XREF: sub_668C2B+Co
  21. .rdata:006EDBA4 off_6EDBA4      dd offset hand_mul      ; DATA XREF: sub_668C89+Co
  22. .rdata:006EDBA8 off_6EDBA8      dd offset hand_imul     ; DATA XREF: sub_668D70+Co
  23. .rdata:006EDBAC off_6EDBAC      dd offset sub_668E80    ; DATA XREF: sub_668E6A+Co
  24. .rdata:006EDBB0 off_6EDBB0      dd offset hand_div      ; DATA XREF: sub_668F01+Co
  25. .rdata:006EDBB4 off_6EDBB4      dd offset hand_idiv     ; DATA XREF: sub_668FD4+Co
  26. .rdata:006EDBB8 off_6EDBB8      dd offset hand_shl      ; DATA XREF: sub_6690A3+Co
  27. .rdata:006EDBBC off_6EDBBC      dd offset hand_shr      ; DATA XREF: sub_669185+Co
  28. .rdata:006EDBC0 off_6EDBC0      dd offset hand_sar      ; DATA XREF: sub_66925C+Co
  29. .rdata:006EDBC4 off_6EDBC4      dd offset hand_or       ; DATA XREF: sub_6692CB+Co
  30. .rdata:006EDBC8 off_6EDBC8      dd offset hand_and      ; DATA XREF: sub_669339+Co
  31. .rdata:006EDBCC off_6EDBCC      dd offset hand_xor      ; DATA XREF: sub_6693A7+Co
  32. .rdata:006EDBD0 off_6EDBD0      dd offset hand_not      ; DATA XREF: sub_669415+Co
  33. .rdata:006EDBD4 off_6EDBD4      dd offset hand_neg      ; DATA XREF: sub_66945B+Co
  34. .rdata:006EDBD8 off_6EDBD8      dd offset hand_cmp      ; DATA XREF: sub_6694C7+Co
  35. .rdata:006EDBDC off_6EDBDC      dd offset hand_test     ; DATA XREF: sub_669550+Co
  36. .rdata:006EDBE0 off_6EDBE0      dd offset hand_call_x86_func ; DATA XREF: sub_6695B9+Co
  37. .rdata:006EDBE4 off_6EDBE4      dd offset hand_exit_vm  ; DATA XREF: sub_6695E3+Co
  38. .rdata:006EDBE8 off_6EDBE8      dd offset sub_66963B    ; DATA XREF: sub_669625+Co
  39. .rdata:006EDBEC off_6EDBEC      dd offset sub_669665    ; DATA XREF: sub_66964F+Co
  40. .rdata:006EDBF0 off_6EDBF0      dd offset sub_66968F    ; DATA XREF: sub_669679+Co
  41. .rdata:006EDBF4 off_6EDBF4      dd offset sub_6696E1    ; DATA XREF: sub_6696CB+Co
  42. .rdata:006EDBF8 off_6EDBF8      dd offset sub_669711    ; DATA XREF: sub_6696FB+Co
  43. .rdata:006EDBFC off_6EDBFC      dd offset sub_669740    ; DATA XREF: sub_66972A+Co
  44. .rdata:006EDC00 off_6EDC00      dd offset sub_66977A    ; DATA XREF: sub_669764+Co
  45. .rdata:006EDC04 off_6EDC04      dd offset hand_leave    ; DATA XREF: sub_66979E+Co
  46. .rdata:006EDC08 off_6EDC08      dd offset hand_debug    ; DATA XREF: sub_6697CA+Co
  47. .rdata:006EDC0C off_6EDC0C      dd offset sub_6697FF    ; DATA XREF: sub_6697E9+Co
  48. .rdata:006EDC10 off_6EDC10      dd offset hand_setc     ; DATA XREF: sub_66983A+Co
  49. .rdata:006EDC14 off_6EDC14      dd offset hand_setnc    ; DATA XREF: sub_66985B+Co
  50. .rdata:006EDC18 off_6EDC18      dd offset hand_cmc      ; DATA XREF: sub_66987C+Co
  51. .rdata:006EDC1C off_6EDC1C      dd offset hand_bt       ; DATA XREF: sub_6698A3+Co
  52. .rdata:006EDC20 off_6EDC20      dd offset hand_bts      ; DATA XREF: sub_6698EC+Co
  53. .rdata:006EDC24 off_6EDC24      dd offset hand_btr      ; DATA XREF: sub_669946+Co
  54. .rdata:006EDC28 off_6EDC28      dd offset hand_btc      ; DATA XREF: sub_6699A4+Co
  55. .rdata:006EDC2C off_6EDC2C      dd offset hand_bsf      ; DATA XREF: sub_669A13+Co
  56. .rdata:006EDC30 off_6EDC30      dd offset hand_bsr      ; DATA XREF: sub_669A7B+Co
  57. .rdata:006EDC34 off_6EDC34      dd offset hand_cld      ; DATA XREF: sub_669AE4+Co
  58. .rdata:006EDC38 off_6EDC38      dd offset hand_std      ; DATA XREF: sub_669B05+Co
  59. .rdata:006EDC3C off_6EDC3C      dd offset hand_stos_rep ; DATA XREF: sub_669B26+Co
  60. .rdata:006EDC40 off_6EDC40      dd offset hand_lods_rep ; DATA XREF: sub_669BC1+Co
  61. .rdata:006EDC44 off_6EDC44      dd offset hand_movs_rep ; DATA XREF: sub_669C5F+Co
  62. .rdata:006EDC48 off_6EDC48      dd offset hand_scas_rep ; DATA XREF: sub_669CE1+Co
  63. .rdata:006EDC4C off_6EDC4C      dd offset hand_cmps_rep ; DATA XREF: sub_669DD8+Co
  64. .rdata:006EDC50 off_6EDC50      dd offset hand_fld_qword ; DATA XREF: sub_669ECA+Co
  65. .rdata:006EDC54 off_6EDC54      dd offset hand_fld_dword ; DATA XREF: sub_669EF4+Co
  66. .rdata:006EDC58 off_6EDC58      dd offset hand_fstp_qword ; DATA XREF: sub_669F1E+Co
  67. .rdata:006EDC5C off_6EDC5C      dd offset hand_fstp_dword ; DATA XREF: sub_669F46+Co
  68. .rdata:006EDC60 off_6EDC60      dd offset hand_fst_qword ; DATA XREF: sub_669F6E+Co
  69. .rdata:006EDC64 off_6EDC64      dd offset hand_fst_dword ; DATA XREF: sub_669F96+Co
  70. .rdata:006EDC68 off_6EDC68      dd offset hand_fcomp_qword ; DATA XREF: sub_669FBE+Co
  71. .rdata:006EDC6C off_6EDC6C      dd offset hand_fcomp_dword ; DATA XREF: sub_669FE6+Co

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


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

Создано: 3 октября 2013 12:04 New!
Цитата · Личное сообщение · #6

int
Блин, ну вы просто монстр
У меня сейчас очень мало времени, поэтому я определил hand_call_x86_func и на том забил.
Еще добавлю, что sub_66A37E - это джамп, условный или безусловный (условие проверяется в VM_RUN), причем оно может прыгать за пределы VM (??).
sub_66AC5D вычисляет адрес виртуализированной инструкции, куда прыгать.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 14:12 · Поправил: reversecode New!
Цитата · Личное сообщение · #7

ломать лень) разбирать удовольствие
--> Link <-- дарю)
ну итд, все не стал постить


Статус: Пришелец

Создано: 3 октября 2013 15:23 New!
Цитата #8

pinky_p пишет:
Блин, ну вы просто монстр

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

int пишет:
Пока сложно догонять, что делают вот такие хендлеры:

Вот этот обработчик для примера оказался std. А вот как сейчас выглядит код в IDA:
Code:
  1. .text:00669B1B ; void __stdcall hand_std(int, vm_object_s *vm_object, int)
  2. .text:00669B1B hand_std        proc near               ; DATA XREF: .rdata:off_6EDC38o
  3. .text:00669B1B
  4. .text:00669B1B arg_0           = dword ptr  4
  5. .text:00669B1B vm_object       = dword ptr  8
  6. .text:00669B1B arg_8           = dword ptr  0Ch
  7. .text:00669B1B
  8. .text:00669B1B                 mov     eax, [esp+vm_object]
  9. .text:00669B1F                 mov     [eax+vm_object_s.flags.DF_flag], 1
  10. .text:00669B23                 retn    0Ch
  11. .text:00669B23 hand_std        endp

А вот так в лучах:
Code:
  1. void __stdcall hand_std(int a1, vm_object_s *vm_object, int a3)
  2. {
  3.   vm_object->flags.DF_flag = 1;
  4. }

Тут даже думать не надо, о том, что это за обработчик. Сразу видно. Взяли объект класса vm_object, у него в начале переменные типа char с флагами (туда memcpy копирует их - легко проследить). По смещению понятно, что это флаг DF, IDA сама его предлагает в пункте контекстного меню "Structure offset". Ну а дальше справочник по x86 командам - это std (хотя данная инструкция очень популярная, ее и так запомнить не сложно, а вот всякие бит тесты типа bsr, bsf, bts - это не упомнишь, я гуглил их описания).

Поэтому ничего монстерского тут нет. Я вот переходы еще пока не разобрал, VM_x_FLAG_cmp_sub_66A238 очень не хватало) Терпеть не могу флаги разбирать и условные переходы.

pinky_p пишет:
sub_66A37E - это джамп, условный или безусловный

На этом я стормозил, меня vm_exit (0x66A3D3) испугал в теле этой функции.

Ранг: 455.8 (мудрец)
Статус: Участник
Android Reverser

Создано: 3 октября 2013 15:34 New!
Цитата · Личное сообщение · #9

Интег взялся за ВМ - Галичский волосы на жопе рвет

Ранг: -0.7 (нарушитель)
Статус: Участник

Создано: 3 октября 2013 16:23 · Поправил: RebelNeo New!
Цитата · Личное сообщение · #10

Параллельный топик --> Link <--закрыт по просьбам


Статус: Пришелец

Создано: 3 октября 2013 16:53 New!
Цитата #11

reversecode пишет:
VM_x_FLAGS_sub_66A212

Я назвал set_flags_ZSP. ZSP подчеркивает, что другие флаги метод не трогает. Почти все обработчики распознаны (не без вашей помощи ):
Code:
  1. .rdata:006EDB64 off_6EDB64      dd offset hand_mov      ; DATA XREF: sub_668647+Co
  2. .rdata:006EDB64                                         ; 02A12BA0o
  3. .rdata:006EDB68 off_6EDB68      dd offset hand_mov_i32  ; DATA XREF: sub_668692+Co
  4. .rdata:006EDB68                                         ; 02A12BB8o
  5. .rdata:006EDB6C off_6EDB6C      dd offset hand_push     ; DATA XREF: sub_6686B5+Co
  6. .rdata:006EDB6C                                         ; 02A12BD0o
  7. .rdata:006EDB70 off_6EDB70      dd offset hand_pop      ; DATA XREF: sub_66871C+Co
  8. .rdata:006EDB70                                         ; 02A1FF78o
  9. .rdata:006EDB74 off_6EDB74      dd offset hand_xchg     ; DATA XREF: sub_668774+Co
  10. .rdata:006EDB78 off_6EDB78      dd offset hand_movzx_eax_ax_al ; DATA XREF: sub_6687D1+Co
  11. .rdata:006EDB7C off_6EDB7C      dd offset hand_cwd_cdq  ; DATA XREF: sub_668826+Co
  12. .rdata:006EDB80 off_6EDB80      dd offset hand_mov_i8_i16 ; DATA XREF: sub_668881+Co
  13. .rdata:006EDB84 off_6EDB84      dd offset hand_mov_i8_i16 ; DATA XREF: sub_6688BA+Co
  14. .rdata:006EDB88 off_6EDB88      dd offset hand_mov_base_offset ; DATA XREF: sub_6688D0+Co
  15. .rdata:006EDB8C off_6EDB8C      dd offset hand_add      ; DATA XREF: sub_668903+Co
  16. .rdata:006EDB90 off_6EDB90      dd offset hand_adc      ; DATA XREF: sub_6689A4+Co
  17. .rdata:006EDB94 off_6EDB94      dd offset hand_sub      ; DATA XREF: sub_668A67+Co
  18. .rdata:006EDB98 off_6EDB98      dd offset hand_sbb      ; DATA XREF: sub_668B08+Co
  19. .rdata:006EDB9C off_6EDB9C      dd offset hand_inc      ; DATA XREF: sub_668BCE+Co
  20. .rdata:006EDBA0 off_6EDBA0      dd offset hand_dec      ; DATA XREF: sub_668C2B+Co
  21. .rdata:006EDBA4 off_6EDBA4      dd offset hand_mul      ; DATA XREF: sub_668C89+Co
  22. .rdata:006EDBA8 off_6EDBA8      dd offset hand_imul     ; DATA XREF: sub_668D70+Co
  23. .rdata:006EDBAC off_6EDBAC      dd offset hand_imul_x   ; DATA XREF: sub_668E6A+Co
  24. .rdata:006EDBB0 off_6EDBB0      dd offset hand_div      ; DATA XREF: sub_668F01+Co
  25. .rdata:006EDBB4 off_6EDBB4      dd offset hand_idiv     ; DATA XREF: sub_668FD4+Co
  26. .rdata:006EDBB8 off_6EDBB8      dd offset hand_shl      ; DATA XREF: sub_6690A3+Co
  27. .rdata:006EDBBC off_6EDBBC      dd offset hand_shr      ; DATA XREF: sub_669185+Co
  28. .rdata:006EDBC0 off_6EDBC0      dd offset hand_sar      ; DATA XREF: sub_66925C+Co
  29. .rdata:006EDBC4 off_6EDBC4      dd offset hand_or       ; DATA XREF: sub_6692CB+Co
  30. .rdata:006EDBC8 off_6EDBC8      dd offset hand_and      ; DATA XREF: sub_669339+Co
  31. .rdata:006EDBCC off_6EDBCC      dd offset hand_xor      ; DATA XREF: sub_6693A7+Co
  32. .rdata:006EDBD0 off_6EDBD0      dd offset hand_not      ; DATA XREF: sub_669415+Co
  33. .rdata:006EDBD4 off_6EDBD4      dd offset hand_neg      ; DATA XREF: sub_66945B+Co
  34. .rdata:006EDBD8 off_6EDBD8      dd offset hand_cmp      ; DATA XREF: sub_6694C7+Co
  35. .rdata:006EDBDC off_6EDBDC      dd offset hand_test     ; DATA XREF: sub_669550+Co
  36. .rdata:006EDBE0 off_6EDBE0      dd offset hand_call_x86_func ; DATA XREF: sub_6695B9+Co
  37. .rdata:006EDBE4 off_6EDBE4      dd offset hand_exit_vm  ; DATA XREF: sub_6695E3+Co
  38. .rdata:006EDBE8 off_6EDBE8      dd offset hand_jmp_1    ; DATA XREF: sub_669625+Co
  39. .rdata:006EDBEC off_6EDBEC      dd offset hand_jmp_2    ; DATA XREF: sub_66964F+Co
  40. .rdata:006EDBF0 off_6EDBF0      dd offset hand_jcc      ; DATA XREF: sub_669679+Co
  41. .rdata:006EDBF4 off_6EDBF4      dd offset hand_jecxz    ; DATA XREF: sub_6696CB+Co
  42. .rdata:006EDBF8 off_6EDBF8      dd offset hand_loop     ; DATA XREF: sub_6696FB+Co
  43. .rdata:006EDBFC off_6EDBFC      dd offset sub_669740    ; DATA XREF: sub_66972A+Co
  44. .rdata:006EDC00 off_6EDC00      dd offset sub_66977A    ; DATA XREF: sub_669764+Co
  45. .rdata:006EDC04 off_6EDC04      dd offset hand_leave    ; DATA XREF: sub_66979E+Co
  46. .rdata:006EDC08 off_6EDC08      dd offset hand_debug    ; DATA XREF: sub_6697CA+Co
  47. .rdata:006EDC0C off_6EDC0C      dd offset hand_setcc    ; DATA XREF: sub_6697E9+Co
  48. .rdata:006EDC10 off_6EDC10      dd offset hand_setc     ; DATA XREF: sub_66983A+Co
  49. .rdata:006EDC14 off_6EDC14      dd offset hand_setnc    ; DATA XREF: sub_66985B+Co
  50. .rdata:006EDC18 off_6EDC18      dd offset hand_cmc      ; DATA XREF: sub_66987C+Co
  51. .rdata:006EDC1C off_6EDC1C      dd offset hand_bt       ; DATA XREF: sub_6698A3+Co
  52. .rdata:006EDC20 off_6EDC20      dd offset hand_bts      ; DATA XREF: sub_6698EC+Co
  53. .rdata:006EDC24 off_6EDC24      dd offset hand_btr      ; DATA XREF: sub_669946+Co
  54. .rdata:006EDC28 off_6EDC28      dd offset hand_btc      ; DATA XREF: sub_6699A4+Co
  55. .rdata:006EDC2C off_6EDC2C      dd offset hand_bsf      ; DATA XREF: sub_669A13+Co
  56. .rdata:006EDC30 off_6EDC30      dd offset hand_bsr      ; DATA XREF: sub_669A7B+Co
  57. .rdata:006EDC34 off_6EDC34      dd offset hand_cld      ; DATA XREF: sub_669AE4+Co
  58. .rdata:006EDC38 off_6EDC38      dd offset hand_std      ; DATA XREF: sub_669B05+Co
  59. .rdata:006EDC3C off_6EDC3C      dd offset hand_stos_rep ; DATA XREF: sub_669B26+Co
  60. .rdata:006EDC40 off_6EDC40      dd offset hand_lods_rep ; DATA XREF: sub_669BC1+Co
  61. .rdata:006EDC44 off_6EDC44      dd offset hand_movs_rep ; DATA XREF: sub_669C5F+Co
  62. .rdata:006EDC48 off_6EDC48      dd offset hand_scas_rep ; DATA XREF: sub_669CE1+Co
  63. .rdata:006EDC4C off_6EDC4C      dd offset hand_cmps_rep ; DATA XREF: sub_669DD8+Co
  64. .rdata:006EDC50 off_6EDC50      dd offset hand_fld_qword ; DATA XREF: sub_669ECA+Co
  65. .rdata:006EDC54 off_6EDC54      dd offset hand_fld_dword ; DATA XREF: sub_669EF4+Co
  66. .rdata:006EDC58 off_6EDC58      dd offset hand_fstp_qword ; DATA XREF: sub_669F1E+Co
  67. .rdata:006EDC5C off_6EDC5C      dd offset hand_fstp_dword ; DATA XREF: sub_669F46+Co
  68. .rdata:006EDC60 off_6EDC60      dd offset hand_fst_qword ; DATA XREF: sub_669F6E+Co
  69. .rdata:006EDC64 off_6EDC64      dd offset hand_fst_dword ; DATA XREF: sub_669F96+Co
  70. .rdata:006EDC68 off_6EDC68      dd offset hand_fcomp_qword ; DATA XREF: sub_669FBE+Co
  71. .rdata:006EDC6C off_6EDC6C      dd offset hand_fcomp_dword ; DATA XREF: sub_669FE6+Co

На кой черт две инструкции безусловного перехода hand_jmp_1 и hand_jmp_2 пока не пойму. Может по размеру перехода отличаются. Там просто пока классы/структуры используются, которые заполняются в тех местах, где я еще не делал анализ. Флаговые инструкции hand_jcc и hand_setcc тоже легко распознались, благодаря reversecode (спасибо за VM_x_FLAG_cmp_sub_66A238). Также все легко и понятно с hand_jecxz и hand_loop. Но вот что это за конструкции, мне пока непонятно, прошу помощь зала:
Code:
  1. void __stdcall sub_669740(int a1, vm_object_s *vm_object, void *params)
  2. {
  3.   --vm_object->vm_regs.v_ecx;
  4.   if ( vm_object->flags.ZF_flag )
  5.   {
  6.     if ( vm_object->vm_regs.v_ecx )
  7.       vm_jump_handler(vm_object, *((_DWORD *)params + 1), params);
  8.   }
  9. }
  10.  
  11. void __stdcall sub_66977A(int a1, vm_object_s *vm_object, void *params)
  12. {
  13.   --vm_object->vm_regs.v_ecx;
  14.   if ( !vm_object->flags.ZF_flag )
  15.   {
  16.     if ( vm_object->vm_regs.v_ecx )
  17.       vm_jump_handler(vm_object, *((_DWORD *)params + 1), params);
  18.   }
  19. }

Т.е. что-то похожее на переходы/циклы. Только я не припомню, чтобы флаг нуля участвовал при определении необходимости сделать переход.


Ранг: 1983.4 (!!!!)
Статус: Модератор
retired

Создано: 3 октября 2013 17:01 New!
Цитата · Личное сообщение · #12

loopz/loopnz


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 17:03 New!
Цитата · Личное сообщение · #13


Ранг: 651.6 (! !)
Статус: Участник
ALIEN Hack Team

Создано: 3 октября 2013 17:05 · Поправил: ARCHANGEL New!
Цитата · Личное сообщение · #14

Только я не припомню, чтобы флаг нуля участвовал при определении необходимости сделать переход

Эмм, jz/jnz??
Это не test случайно?

Добавлено
А нет - не test.


Статус: Пришелец

Создано: 3 октября 2013 17:08 New!
Цитата #15

Archer
5 баллов) круто) Можно писать декомпилятор

P.S. Интересно, обфускация под ВМ имеется?


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 17:09 · Поправил: reversecode New!
Цитата · Личное сообщение · #16

только опкоды упакованы)) не забывай

имеется shuffle_random_sub... который явно не для просто так)


Статус: Пришелец

Создано: 3 октября 2013 18:01 New!
Цитата #17

reversecode
Да пофиг на него, плагин к IDA, бряк на vm_entry и вперед - Edit -> Plugins -> KillMathaFuckinVM В динамике проще все это.

А вообще еще два года назад у меня была идея создать универсальный декомпилятор для виртуальных машин. По моим оценкам он бы победил вмпротект, фимку, код виртуализер, криптер, обсидиум. И с этой ВМ он бы в два счета бы разобрался. Не удается победить пока StarForce (слишком не шаблонная реализация), Enigma - для этих ВМ нужен частный инструмент, заточенный специально под реализацию ВМ. Вопрос только в том, что для создания такого инструмента нужно очень много времени, которого обычно нет.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 18:03 New!
Цитата · Личное сообщение · #18

отдай дальше детям) пусть ломают свою игрушку


Статус: Пришелец

Создано: 3 октября 2013 18:07 New!
Цитата #19

Да я может попытаюсь хотя бы куски декомпилятора запилить. У меня два раза в год обострение - я осенью обычно что-то делаю и весной. Летом и зимой болт на все кладу. Надо же чем-то себя занять сейчас) Может что полезное выйдет.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 18:12 New!
Цитата · Личное сообщение · #20

int пишет:
А вообще еще два года назад у меня была идея создать универсальный декомпилятор для виртуальных машин

на чем основывается гениальная идея?)


Статус: Пришелец

Создано: 3 октября 2013 19:05 New!
Цитата #21

Да все гениальное просто. Составляем шаблоны всех существующих инструкций x86. Ищем циклическую обработку КОПов - конвеер ленты ВМ. Алгоритм реализован у Вамита в свипере - работает для виртуализера и вмпрота. Далее поиск таблицы КОПов, если таковая имеется, обычно используют или таблицу или switch здоровый - оба варианта легко ловятся, ибо разветвление очень сильное. Следующий этап - деобфускация всех КОПов в таблице. Дальше поиск ленты, это сложный этап, его проще в динамике ловить, ибо каждый норовит ее сделать нелинейной, зашифрованной и т.д. Главное поймать КОПы и их параметры. Потом разворачивание ленты в граф. Замена виртуальных инструкций на их разложения в x86 коде (ест-но не тупым копированием, а лишь то, что осталось после деобфускации). Потом по шаблонам инструкций x86 все сводится к проблеме эквивалентности алгоритмов - просто блоками ловить реальные x86 инструкции и заменять 10 - 20 инструкций на одну x86. Как бы сильно не раскладывали инструкцию на ее атомарные операции, все равно каждая инструкция выполняется в одном потоке выполнения кода ("поток" здесь не в смысле thread, а в смысле control flow) - т.е. мы по-любому получим, что, к примеру, 10 инструкций изменяют стэк, при этом изменяют указатель стэка на 4 байта вниз, изменения регистров гасятся (т.е. init значение участка кода равняется результирующему значению), изменений данных кроме стэка нет, а дальше работает шаблон X86_PUSH=(R_ESP-4, [R_ESP] = DATA) и превращает эти 10 инструкций в PUSH R32 или PUSH I32 (в зависимости от типа DATA). Если разложения в атомарные операции нескольких инструкций между собой перемешаны, т.е. сначала для одной инструкции выполняется какая-то операция, потом для следующей другая, потом снова первая обрабатывается - все равно это разные потоки выполнения, они отделяются друг от друга анализатором и все равно сработает шаблон. Ну а дальше руками разгребать очищенные трассы кода и думать о том, как их вставлять обратно. Но это не тоже самое, что в оригинальной ВМ бегать по VM_RUN. Это уже обычный x86 код, который, возможно, не до конца оптимизирован.

Поясню почему нельзя натравливать шаблоны инструкций x86 сразу на обработчики. Дело в том, что не всегда это работает. Во-первых, в обработчики часто вставляют не нужный мусор, т.е. то, что к выполнению инструкции не имеет отношения. Это может быть анти-отладка, анти-дамп, что угодно. Но заготовка шаблона не сойдется ни с одной инструкцией. Автоматически зарубить анти-отладочные приемы невозможно. Это должно быть не на плечах декомпилятора. Во-вторых, бывают такие виды ВМ, что в них или не захотели (например, все ВМ в которых логика и арифметика реализована через базовые инструкции - сложение и любая функция Шеффера) или даже нельзя по архитектуре некоторые инструкции запихнуть в один шаблон. В них одна x86 инструкция раскладывается на несколько виртуальных инструкций. А вот когда ленту ВМ разворачиваем, тогда уже шаблоном можно подобрать "оптимизацию" десятка инструкций в одну x86, которая делает все тоже самое.

Проблема почти всех ВМ в том, что люди начитаются книжек или бывшие крекеры их садятся писать, которые пару тройку ВМ разобрали и пришла им в голову гениальная идея написать свою. В итоге получаем очередной штамп. У многих ВМ есть эти параметры:
1. Наличие цикла исполнения кода. А значит ВМ легко задетектить. Цикл, каждый проход которого выполняет новый код - это ВМ. Ну нельзя написать код с циклом, который так себя ведет. Если у кого-то из программистов получится именно это - он написал ВМ, сам того не осознавая.
2. switch-таблица. Здесь я имею в виду, что вызов обработчика в коде выглядит как mov reg, [base + index * mem_multiplier] (где для 32-бит множитель mem_multiplier понятное дело равен 4-ке) или сразу вызов call [base + index * mem_multiplier]. Даже если таблица под обфускацией, как в вмпроте, легко отслеживаем регистры, которые участвуют в индексации и составляем шаблон деобфускации. Потом определяем размер таблицы и КОПы у нас в руках. На каждый обработчик натравливаем деобфускатор.
3. Наличие ленты исполняемого виртуального кода. Ну, и как следствие указатель команд в локальной переменной или чаще в регистре. Ну, хранить виртуальные инструкции как-то же надо? Почти все реализации ВМ используют лобовое решение - тупо массив с КОПами и их параметрами. Бывает, что параметры лежат в отдельном массиве (типа экономия места на ленте). Спалить обращение к ленте с учетом конвейерной обработки данных на ней - не проблема.

Вот еще один штамп, в студенческие годы игрался, написано под DOS (т.е. 16-битная ВМ):
Code:
  1. _start:
  2. mov ax,data
  3. mov ds,ax
  4. mov cx,count
  5. lea bp,ds:codeVm
  6. xor bx,bx
  7. mov IP1,0
  8. _execute:
  9. mov ax,IP1
  10. mov dx,0
  11. push cx
  12. mov cx,5
  13. mul cx
  14. pop cx
  15. mov si,ax
  16. mov bl,ds:[bp+si]; OpCode
  17. push ds:[bp+si+1]; Operand1
  18. push ds:[bp+si+3]; Operand2
  19. shl bx,1
  20. call cs:table[bx]
  21. inc IP1; Следующая команда
  22. loop _execute
  23. readkey
  24. finish


А теперь внимание. Я не ковырял лично StarForce, как-то в игры не играю, соответственно и материал не попадается для работы с игровыми протекторами. Ну так вот, по словам моих знакомых игро-ломателей, в StarForce нет ни одного пункта из выше перечисленных. Там просто нечего ломать) Там вся ВМ заведомо раскручена. Нет ни циклов, никаких таблиц, просто вермишель виртуализованного кода. И каждый обработчик сам определяет, какой обработчик ему выполнять следующим.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 3 октября 2013 20:43 New!
Цитата · Личное сообщение · #22

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

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

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


Ранг: 407.8 (мудрец)
Статус: Участник

Создано: 4 октября 2013 08:42 · Поправил: dosprog New!
Цитата · Личное сообщение · #23

Простой лоадер тут сделать не получится. Нужен непростой.
Который можно было бы закрутить и посвыше... Патч? -
Согласен с ранее прозвучавшим в параллельной (закрытой) теме мнением, что все обсуждения здесь
прямиком пойдут в наработки защиты будущей версии рассматриваемого софта.
Что касается "декомпилятора", то (думаю) много чести делать его индивидуально для отдельной версии отдельной софтины.
Это же не MSVBVM, которую в микрософт уже вряд-ли будут кардинально изменять...
А сама тема разбора VM что-ж, интересная. Но всё это крайне неуниверсально. Трата времени.

P.S.(к следующему посту) -- Int, не обращайте внимания, мысли вслух. Считайте, что спам.


Статус: Пришелец

Создано: 4 октября 2013 15:35 New!
Цитата #24

reversecode
Где я написал, что опкоды надо разбирать?

Это делает автомат, которые вычленяет их код из цикла ВМ (это просто ветки графа), очищает и преобразует в шаблоны. У Вамита, например, именно так и происходит. Только он не использует шаблоны в чистом виде, он их сравнивает с теми, которые заведомо разобраны. Я не могу публиковать детали реализации его инструмента, мой труд внесенный в Sweeper минимален и авторские права, включая детали реализации, остаются по праву у Вамита. Я только составлял шаблоны под вмпрот. В создании анализаторов не участвовал.

Мой же метод не требует первоначального изучения ВМ. Только его реализовать надо.

reversecode пишет:
а бывают реализации самой логики на с++ где огого какой код избыточный

Примеры в студию!

dosprog
А вас кто-то заставляет что-то делать по этой программе и этой ВМ? Смысл комментария не понятен. Что касается MSVBVM - уже достаточно создано декомпиляторов P-кода. И кардинально изменять ее (ВМ) тоже не будут, просто потому, что VB 6 был последний нативный продукт и его разработка прекращена.

P.S. И не пытайтесь доказать, что это невозможно или не универсально. VMSweeper же работает. Просто я хотел пойти дальше и избавиться вообще от шаблонов. Шаблоны плохо использовать хотя бы потому, что одно изменение реализации хотя бы одного обработчика ломает возможность использования инструмента. У нас на этом месте с Вамитом возник спор, но только его инструмент работает, а мой существует только на бумаге и в виде кусков кода, который надо переписывать.


Ранг: 1006.7 (!!!!)
Статус: Участник

Создано: 4 октября 2013 16:11 · Поправил: reversecode New!
Цитата · Личное сообщение · #25

int пишет:
Это делает автомат, которые вычленяет их код из цикла ВМ (это просто ветки графа), очищает и преобразует в шаблоны.

это будет работать на очень узком кругу вм

мысленно рисую ситуацию ... вм... в ней один опкод это не опкод из x86, а вымышленый опкод который делает сразу md5 или md5(md5(x)) и реализация этого md5 на С++ с обьектами где ты ни в какой шаблон это не выкрутишь, потому что контекст привязан на ВМ, которая инициализируется гараздо раньше самого вхождения в ВМ цикл...


вот как твой метод будет работать в этой ситуации?
а то что то до меня туго доходит))

sweeper все реверсили видели, опокды там видны все понятно, лишний раз рассказывать не надо)

add
идея в том что бы опкоды разворачивать в их реализации и выплевывать в таком виде код? или как


Статус: Пришелец

Создано: 4 октября 2013 17:28 New!
Цитата #26

reversecode пишет:
идея в том что бы опкоды разворачивать в их реализации и выплевывать в таком виде код? или как

Приблизительно, да. Только не в таком виде, а чистить. Самое интересное - это чистить. Это потребует чтобы каждая инструкция была разложена в атомарное представление. И когда одна инструкция представлена через другие - находить наиболее оптимальные замены. Код в таком случае, может и не соответствовать оригинальному, который был еще до виртуализации. Но он будет достаточно понятным для анализа. Это и есть ключевая идея и самая сложная часть.

Кстати, иногда ВМ не мешает, а наоборот открывает возможности. Я как-то ломал программу под вмпротом, мне нужен был бряк на данные. Легко! Ставим бряк на обработчик команды, которая читает данные (такой обработчик может быть не один - на все сразу ставится точка останова). И вуаля! Условный бряк в IDA дал мне то, что нужно! А как бы я решал эту же задачу (пусть для определенности ida 5.2 - в ней нет точек останова на память встроенных в отладчик)? Ставил бы точки останова на все подряд инструкции? Где искать нужные данные я тогда не знал. Возможности использовать железные бряки тоже не было. А вмпрот очень мило классифицировал все инструкции на их типы (заметьте - один бряк на стрелке Пирса дает отлов ВСЕЙ логики, если ее только какой-нибудь умник сдвигами и сложениями не реализовал, кстати не проверял такую возможность). Понятно, что много мусора будет ловить, но правильный фильтр решает все проблемы.

reversecode
Шаблонов с MD5 не будет просто по определению инструмента. А как будет работать инструмент со старфорс? Да тоже никак, ибо не подходит под решаемую задачу. А сделать крутую ВМ, которую не возьмет ни один девм тоже легко: применить всякие интересные штуки типа великой теоремы ферма и повесить мертвую ветку, выполнение которой будет противоречить этой теореме. Девм не знает содержимого сотен книг по кибернетике, непрерывной математики и криптографии. Можно запутать средства авто анализа так, что даже человек будет неделями вылавливать трюк за трюком вручную. Просто никто эти идеи в жизнь не воплатил. Деобфускация, вообще говоря, алгоритмически не разрешимая задача, равно как и обфускация. Можно легко написать код, который при виртуализации тем же вмпротом сломается и будет не работоспособен. И что теперь делать? Можно ничего не делать. А можно решать задачи под частные случаи и это довольно эффективно на практике.

Возвращаясь к основной теме, хочу сказать, что данная ВМ имеет одну неприятную особенность. Часть обработчиков перехватывается на уровне цикла ВМ и они исполняются прямо внутри цикла, без вызова обработчиков, хотя обработчики соответствующие есть. Т.е. тупо вынесли часть обработчиков в тело цикла. Я уже получил трассу выполнения одной виртуализованной функции, приятного в ней мало.


Ранг: 70.5 (постоянный)
Статус: Участник

Создано: 4 октября 2013 18:41 · Поправил: Модератор New!
Цитата · Личное сообщение · #27

От модератора: надоело уже весь этот мат читать. забанен на неделю
 eXeL@B —› Вопросы новичков —› Помогите определить виртуальную машину из MapEdit (с Geopainting.com)

Оригинальный DVD-ROM: eXeL@B DVD !

Вы находитесь на форуме сайта EXELAB.RU
Проект ReactOS