Выгрузка памяти приложения в iOS8

Выгрузка памяти приложения в iOS8

В январе 2015 года на портале NetSPI была опубликована статья об извлечении памяти с IOS-устройств. Даже несмотря на то, что было представлено средство, упрощающее решение этой задачи, скрипт работал в iOS7 (и ниже) и требовал наличия отладчика GDB. Однако на данный момент не существует версии GDB, которая корректно работала бы в iOS8.

Автор: Steve Kerns

В январе 2015 года на портале NetSPI была опубликована статья об извлечении памяти с IOS-устройств. Даже несмотря на то, что было представлено средство, упрощающее решение этой задачи, скрипт работал в iOS7 (и ниже) и требовал наличия отладчика GDB. Однако на данный момент не существует версии GDB, которая корректно работала бы в iOS8.

Хотя есть несколько альтернатив GDB, извлечение памяти на устройствах, работающих под управлением iOS8+, не является столь простой задачей. Нам потребуются следующие приложения:

Естественно, нам необходим джейлбрейковый iPhone или iPad. В этой статье процедура джейлбрейка рассматриваться не будет.

Подключаемся к устройству через USB при помощи скрипта Tcprelay.py:

$ ./tcprelay.py -t 22:2222 1234:1234
Forwarding local port 2222 to remote port 22
Forwarding local port 1234 to remote port 1234
Incoming connection to 2222
Waiting for devices...
Connecting to device <MuxDevice: ID 17 ProdID 0x12a8 Serial '0ea150b00ba3deeacb42f399492b7990416a0c87' Location 0x14120000>
Connection established, relaying data
Incoming connection to 1234
Waiting for devices...
Connecting to device <MuxDevice: ID 17 ProdID 0x12a8 Serial '0ea150b00ba3deeacb42f399492b7990416a0c87' Location 0x14120000>
Connection established, relaying data
Команда «tcprelay.py -t 22:2222 1234:1234» перенаправляет два локальных порта на устройство. Первый порт (2222) используется для подключения к устройству через SSH. Второй порт необходим для корректной работы debugserver.

Далее нужно подключиться к iOS-устройству и запустить сервер отладки (предполагается, что вы уже скопировали на устройство все необходимые приложения). Если нет, можете воспользоваться scp.

$ ssh root@127.0.0.1 -p 2222
root@127.0.0.1's password:

Далее, если приложение уже запущено, выясняем имя при помощи команды ‘ps aux | grep <appname>’ и подсоединяемся к процессу через debugserver (используем имя, а не PID):

root# ./debugserver *:1234 -a appname
debugserver-@(#)PROGRAM:debugserver  PROJECT:debugserver-320.2.89
for arm64.
Attaching to process appname...
Listening to port 1234 for a connection from *...
Waiting for debugger instructions for process 0.

Команда ‘./debugserver *:1234 -a appname’ запускает приложение на порту 1234 и подключает отладочный сервер. Весь процесс займет некоторое время, так что будьте терпеливы.

На MAC’е запустите LLDB и подключитесь к отладочному серверу, запущенному на iOS-устройстве. Помните, что мы перенаправили порт 1234, на котором работает debugserver, на локальный порт 1234.

$ lldb
(lldb) process connect connect://127.0.0.1:1234
Process 2017 stopped
* thread #1: tid = 0x517f9, 0x380f54f0 libsystem_kernel.dylib mach_msg_trap + 20, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x380f54f0 libsystem_kernel.dylib mach_msg_trap + 20
libsystem_kernel.dylib mach_msg_trap:
->  0x380f54f0 <+20>: pop    {r4, r5, r6, r8}
0x380f54f4 <+24>: bx     lr
libsystem_kernel.dylib mach_msg_overwrite_trap:
0x380f54f8 <+0>:  mov    r12, sp
0x380f54fc <+4>:  push   {r4, r5, r6, r8}

Теперь вы можете выгрузить информацию о секциях памяти этого приложения.

(lldb) image dump sections appname
Sections for '/private/var/mobile/Containers/Bundle/Application/F3CFF345-71FC-47C4-B1FB-
3DAC523C7627/appname.app/appname(0x0000000000047000)' (armv7):
SectID     Type             Load Address                             File Off.  File Size  Flags      Section Name
---------- ---------------- ---------------------------------------  ---------- ---------- ---------- ----------------------------
0x00000100 container        [0x0000000000000000-0x0000000000004000)* 0x00000000 0x00000000 0x00000000 appname.__PAGEZERO
0x00000200 container        [0x0000000000047000-0x00000000001af000)  0x00000000 0x00168000 0x00000000 appname.__TEXT
0x00000001 code             [0x000000000004e6e8-0x000000000016d794)  0x000076e8 0x0011f0ac 0x80000400 appname.__TEXT.__text
0x00000002 code             [0x000000000016d794-0x000000000016e5e0)  0x00126794 0x00000e4c 0x80000400 appname.__TEXT.__stub_helper
0x00000003 data-cstr        [0x000000000016e5e0-0x0000000000189067)  0x001275e0 0x0001aa87 0x00000002 appname.__TEXT.__cstring
0x00000004 data-cstr        [0x0000000000189067-0x00000000001a5017)  0x00142067 0x0001bfb0 0x00000002 appname.__TEXT.__objc_methname
0x00000005 data-cstr        [0x00000000001a5017-0x00000000001a767a)  0x0015e017 0x00002663 0x00000002 appname.__TEXT.__objc_classname
0x00000006 data-cstr        [0x00000000001a767a-0x00000000001abe0c)  0x0016067a 0x00004792 0x00000002 appname.__TEXT.__objc_methtype
0x00000007 regular          [0x00000000001abe10-0x00000000001ac1b8)  0x00164e10 0x000003a8 0x00000000 appname.__TEXT.__const
0x00000008 regular          [0x00000000001ac1b8-0x00000000001aeb20)  0x001651b8 0x00002968 0x00000000 appname.__TEXT.__gcc_except_tab
0x00000009 regular          [0x00000000001aeb20-0x00000000001aeb46)  0x00167b20 0x00000026 0x00000000 appname.__TEXT.__ustring
0x0000000a code             [0x00000000001aeb48-0x00000000001af000)  0x00167b48 0x000004b8 0x80000408 appname.__TEXT.__symbolstub1
0x00000300 container        [0x00000000001af000-0x00000000001ef000)  0x00168000 0x00040000 0x00000000 appname.__DATA
0x0000000b data-ptrs        [0x00000000001af000-0x00000000001af4b8)  0x00168000 0x000004b8 0x00000007 appname.__DATA.__lazy_symbol
0x0000000c data-ptrs        [0x00000000001af4b8-0x00000000001af810)  0x001684b8 0x00000358 0x00000006 appname.__DATA.__nl_symbol_ptr
0x0000000d regular          [0x00000000001af810-0x00000000001b2918)  0x00168810 0x00003108 0x00000000 appname.__DATA.__const
0x0000000e objc-cfstrings   [0x00000000001b2918-0x00000000001ba8d8)  0x0016b918 0x00007fc0 0x00000000 appname.__DATA.__cfstring
0x0000000f data-ptrs        [0x00000000001ba8d8-0x00000000001baf1c)  0x001738d8 0x00000644 0x10000000 appname.__DATA.__objc_classlist
0x00000010 regular          [0x00000000001baf1c-0x00000000001baf4c)  0x00173f1c 0x00000030 0x10000000 appname.__DATA.__objc_nlclslist
0x00000011 regular          [0x00000000001baf4c-0x00000000001bafa0)  0x00173f4c 0x00000054 0x10000000 appname.__DATA.__objc_catlist
0x00000012 regular          [0x00000000001bafa0-0x00000000001bafa4)  0x00173fa0 0x00000004 0x10000000 appname.__DATA.__objc_nlcatlist
0x00000013 regular          [0x00000000001bafa4-0x00000000001bb078)  0x00173fa4 0x000000d4 0x00000000 appname.__DATA.__objc_protolist
0x00000014 regular          [0x00000000001bb078-0x00000000001bb080)  0x00174078 0x00000008 0x00000000 appname.__DATA.__objc_imageinfo
0x00000015 data-ptrs        [0x00000000001bb080-0x00000000001e0d40)  0x00174080 0x00025cc0 0x00000000 appname.__DATA.__objc_const
0x00000016 data-cstr-ptr    [0x00000000001e0d40-0x00000000001e4420)  0x00199d40 0x000036e0 0x10000005 appname.__DATA.__objc_selrefs
0x00000017 regular          [0x00000000001e4420-0x00000000001e442c)  0x0019d420 0x0000000c 0x00000000 appname.__DATA.__objc_protorefs
0x00000018 data-ptrs        [0x00000000001e442c-0x00000000001e4ab8)  0x0019d42c 0x0000068c 0x10000000 appname.__DATA.__objc_classrefs
0x00000019 data-ptrs        [0x00000000001e4ab8-0x00000000001e4e48)  0x0019dab8 0x00000390 0x10000000 appname.__DATA.__objc_superrefs
0x0000001a regular          [0x00000000001e4e48-0x00000000001e6184)  0x0019de48 0x0000133c 0x00000000 appname.__DATA.__objc_ivar
0x0000001b data-ptrs        [0x00000000001e6184-0x00000000001ea02c)  0x0019f184 0x00003ea8 0x00000000 appname.__DATA.__objc_data
0x0000001c data             [0x00000000001ea030-0x00000000001ed978)  0x001a3030 0x00003948 0x00000000 appname.__DATA.__data
0x0000001d zero-fill        [0x00000000001ed980-0x00000000001edce0)  0x00000000 0x00000000 0x00000001 appname.__DATA.__bss
0x0000001e zero-fill        [0x00000000001edce0-0x00000000001edce8)  0x00000000 0x00000000 0x00000001 appname.__DATA.__common
0x00000400 container        [0x00000000001ef000-0x0000000000207000)  0x001a8000 0x00015bf0 0x00000000 appname.__LINKEDIT

Следующий шаг – конвертирование результатов в команды LLDB для выгрузки данных в этих секциях памяти. Вы можете пропустить секции с именем zero-fill или code. Например, следующий текст:

БсщвуЮ 0x00000003 data-cstr       
[0x000000000016e5e0-0x0000000000189067)  0x001275e0 0x0001aa87 0x00000002 appname.__TEXT.__cstring

Превращается в команду:

Memory read --outfile ~/0x00000003data-cstr 0x000000000016e5e0 0x0000000000189067 –force

Команда выше сообщает LLDB о том, что нужно выгрузить память, начиная с адреса 0x000000000016e5e0 и заканчивая адресом 0x0000000000189067, после чего положить результаты в файл 0x00000003data-cstr.

(lldb) memory read --outfile ~/0x00000003data-cstr 0x000000000016e5e0 0x0000000000189067 –force

После того как все файлы созданы, можно поискать конфиденциальную информацию: номера кредитных карт, пароли и т. д. Файлы будут содержать примерно следующие данные:

0x0016e5e0: 3f 3d 26 2b 00 3a 2f 3d 2c 21 24 26 27 28 29 2a  ?=&+.:/=,!$&'()*
0x0016e5f0: 2b 3b 5b 5d 40 23 3f 00 00 62 72 61 6e 64 4c 6f  +;[]@#?..brandLo
0x0016e600: 67 6f 2e 70 6e 67 00 54 72 61 64 65 47 6f 74 68  go.png.TradeGoth
0x0016e610: 69 63 4c 54 2d 42 6f 6c 64 43 6f 6e 64 54 77 65  icLT-BoldCondTwe
0x0016e620: 6e 74 79 00 4c 6f 61 64 69 6e 67 2e 2e 2e 00 4c  nty.Loading....L
0x0016e630: 6f 61 64 69 6e 67 00 76 31 32 40 3f 30 40 22 4e  oading.v12@?0@"N
0x0016e640: 53 44 61 74 61 22 34 40 22 45 70 73 45 72 72 6f  SData"4@"EpsErro
0x0016e650: 72 22 38 00 6c 6f 61 64 69 6e 67 50 61 67 65 54  r"8.loadingPageT
0x0016e660: 79 70 65 00 54 69 2c 4e 2c 56 5f 6c 6f 61 64 69  ype.Ti,N,V_loadi
0x0016e670: 6e 67 50 61 67 65 54 79 70 65 00 6f 76 65 72 76  ngPageType.overv
0x0016e680: 69 65 77 52 65 71 52 65 73 48 61 6e 64 6c 65 72  iewReqResHandler
0x0016e690: 00 54 40 22 45 70 73 4f 76 65 72 76 69 65 77 52  .T@"EpsOverviewR
0x0016e6a0: 65 71 52 65 73 48 61 6e 64 6c 65 72 22 2c 26 2c  eqResHandler",&,
0x0016e6b0: 4e 2c 56 5f 6f 76 65 72 76 69 65 77 52 65 71 52  N,V_overviewReqR
0x0016e6c0: 65 73 48 61 6e 64 6c 65 72 00 41 50 49 43 61 6c  esHandler.APICal

Пользуйтесь этими техниками себе во благо и с добрыми намерениями J.

Напоследок приведу цитату из статьи, упомянутой в самом начале:

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


Мир сходит с ума, но еще не поздно все исправить. Подпишись на канал SecLabnews и внеси свой вклад в предотвращение киберапокалипсиса!