Расспаковка Skype средствами динамической инструментализации бинарного кода. Часть 3.
-
Хорошо, теперь когда у нас на руках есть простейший расспаковщик кода, пришло время скомпилировать его, далее запустить его PIN Toolkit'ом с опцией "-appdebug", для того чтобы подключиться к PIN из IDA когда приложение будет запущено. Когда сработает точка остонова, приложение(Skype в данном случае), будет расспаковано и на выходе мы получим дамп памяти с расспакованным кодом целевой программы. Для того чтобы выполнить это действие используя терминал MacOSX вам нужно будет выполнить программу PIN передав ей ключи как это показано ниже:
root@inj3ct0r /h/s/pin unpacker/ ./pin -appdebug -t sanjar/DBI_tools/PinTool/obj-ia32/pinpack.so -- /usr/bin/skype
Application stopped until continued from debugger.
Start GDB, then issue this command at the (gdb) prompt:
target remote :47643
0x83d95b9: W 0x840c35f
0x840bc5e: W 0x805c050
0x840bd3f: W 0x8058ed0
Layer unpacked: 0x805c050
В конечном итоге IDA должна будет получить точку останова приложения в OEP(Original Entry Point)/оригинальной точке входа и вывести сообщение в окне со словами "Layer unpacked": Сообственно это все :-) Это простейший концепт реализации расспаковщика кода с использованием средств динамической инструментализации кода. Но на этом наша работа не заканчивается, теперь же нужно провести анализ ПО с точки зрения безопасности. В таком направлении Инфорамационной Безопасности как Реверс Инженеринг(Reverse Engineering) для более понятного представления того как работает исследуемая программа используют различные методы визуализации. Одним из известных методов является построение CFG(Control Flow Graph) или графа потока исполнения. Т.к выше мы уже имеем слепок памяти с дампом расспакованной программы все что нам остается сделать это генерация dot файла средствами PIN который мы должны будем позже передать визуализатору графа GraphViz. Для этого мы восспользовались скриптами написанными Игорем Скорчински(Igor Skochinsky) которые он опубликовал после своего доклада Compiler Internals: Exceptions and RTTI на конференции RECON. Единственное что мы модифицировали это скрипт gnu_rtti.py задача которого генерация диаграммы в dot формате. Ниже представлен патч для этого файла:
--- ./gcc_rtti.py 2012-12-04 12:47:09.428524252 +0500
+++ ./gcc_rtti_patched.py 2012-12-04 12:46:50.104523402 +0500
@@ -1,4 +1,4 @@
-IS64 = idaapi.getseg(here()).bitness == 2
+IS64 = False #idaapi.getseg(here()).bitness == 2
PTRSIZE = [4, 8][IS64]
@@ -186,9 +186,12 @@
def format_si_type_info(ea):
ea2 = format_type_info(ea)
pbase = ptrval(ea2)
- all_classes[ea].add_base(pbase)
- ea2 = format_struct(ea2, "p")
- return ea2
+ try:
+ all_classes[ea].add_base(pbase)
+ ea2 = format_struct(ea2, "p")
+ return ea2
+ except:
+ return None
# dd `vtable for'__cxxabiv1::__si_class_type_info+8
# dd `typeinfo name for'MyClass
@@ -199,17 +202,20 @@
ea2 = format_type_info(ea)
ea2 = format_struct(ea2, "ii")
base_count = Dword(ea2-4)
- clas = all_classes[ea]
- if base_count > 100:
- print "%08X: over 100 base classes?!" % ea
- return BADADDR
- for i in range(base_count):
- base_ti = ptrval(ea2)
- flags_off = ptrval(ea2 + PTRSIZE)
- off = SIGNEXT(flags_off>>8, 24)
- clas.add_base(base_ti, off, flags_off & 0xFF)
- ea2 = format_struct(ea2, "pl")
- return ea2
+ try:
+ clas = all_classes[ea]
+ if base_count > 100:
+ print "%08X: over 100 base classes?!" % ea
+ return BADADDR
+ for i in range(base_count):
+ base_ti = ptrval(ea2)
+ flags_off = ptrval(ea2 + PTRSIZE)
+ off = SIGNEXT(flags_off>>8, 24)
+ clas.add_base(base_ti, off, flags_off & 0xFF)
+ ea2 = format_struct(ea2, "pl")
+ return ea2
+ except:
+ return None
def find_type_info(idx):
name = ti_names[idx]
@@ -315,6 +321,79 @@
c = ClassChooser("Choose a class")
c.Show(True)
+from idaapi import GraphViewer
+class ClassGraph(GraphViewer):
+ def __init__(self, title):
+ GraphViewer.__init__(self, title)
+
+ def OnRefresh(self):
+ self.Clear()
+ self.class_nodes = {}
+ self.graph = {}
+ self.nodes = []
+ for cls in all_classes:
+ klass = all_classes[cls]
+ name = classname(klass.namestr)
+ print "Adding node", name
+ self.class_nodes[name] = self.AddNode(name)
+ self.graph[name] = []
+ if name not in self.nodes:
+ self.nodes.append(name)
+
+ for cls in all_classes:
+ klass = all_classes[cls]
+ name = classname(klass.namestr)
+ node = self.class_nodes[name]
+ for b in klass.bases:
+ if b.ti in all_classes:
+ bklass = all_classes[b.ti]
+ basename = classname(bklass.namestr)
+ if basename in self.class_nodes:
+ basenode = self.class_nodes[basename]
+ self.graph[name].append(basename)
+ if basenode not in self.nodes:
+ self.nodes.append(basenode)
+ self.AddEdge(basenode, node)
+
+ return True
+
+ def OnGetText(self, node_id):
+ return self[node_id]
+
+ def OnCommand(self, cmd_id):
+ if self.cmd_dot == cmd_id:
+ fname = idc.AskFile(1, "*.dot", "Dot file name")
+ if fname:
+ f = open(fname, "wb")
+ buf = 'digraph G {n graph [overlap=scale]; node [fontname=Courier]; nn'
+ for n in self.graph:
+ num = self.nodes.index(n)
+ buf += ' a%s [shape=box, label = "%s", color="blue"]n' % (num, n)
+ buf += 'n'
+
+ for node in self.graph:
+ p = self.nodes.index(node)
+ for child in self.graph[node]:
+ c = self.nodes.index(child)
+ buf += " a%s -> a%s [style = bold]n" % (p, c)
+
+ buf += 'n'
+ buf += '}'
+ f.write(buf)
+ f.close()
+
+ def Show(self):
+ if not GraphViewer.Show(self):
+ return False
+ self.cmd_dot = self.AddCommand("Export dot", "F2")
+ if self.cmd_dot == 0:
+ print "Failed to add popup menu item!"
+ return True
+
+def show_classes():
+ c = ClassGraph("Class Diagram")
+ c.Show()
+
def main():
# turn on GCC3 demangling
idaapi.cvar.inf.demnames |= idaapi.DEMNAM_GCC3
@@ -330,6 +409,7 @@
handle_classes(TI_SICTINFO, format_si_type_info)
print "Looking for multiple-inheritance classes"
handle_classes(TI_VMICTINFO, format_vmi_type_info)
- choose_class()
+ #choose_class()
+ show_classes()
main()
После запуска модифицированного скрипта мы получим диаграмму которая будет отображена в программе GraphViewer которую мы можем далее экспортировать в формате dot нажав правой кнопкой мыши и выбрав в контекстном меню "Export to dot".
Как видно из визуализированного изображения дампа Skype в ней существуют функции фрэймворка QT : QToolButton, QLineEdit, QDialog, QMessageBox из чего мы можем судить о том что Skype написан на C++ с применением фрэймворка QT4. Более детальный анализ Skype не выявил в программе каких либо "вредоносных" действий направленных против пользователей как считалось до этого ранее. Конечно же специалисты CyberSafe Soft не исключают проблем связанных с безопасностью самой VoIP системы. Нельзя неупомянуть недавнюю брешь в системе восстановления аккаунта на оффициальном сайте Skype. На сегодняшний день программа для шифрования данных CyberSafe – единственная из всех предлагает защиту Skype, используя для этого PKI, который выполняет шифрование входящих и исходящих сообщений.
Таким образом гарантированно что даже при угоне ваше аккаунта никто не сможет получить доступ к вашей переписке.