R0 CREW

Exploit Development Course Part 13 [Internet Explorer 10]: Reverse Engineering IE (Перевод: klaus)

ru
#1

Перейти к содержанию

IE10: Reverse Engineering IE

Для этого эксплойта я использую VirtualBox VM с Windows 7 64-bit SP1 и версия Internet Explorer 10 скачана отсюда.

Что бы успешно эксплуатировать IE 10 над надо обойти ASLR и DEP. Мы собираемся эксплуатировать UAF для модификации длины массива так, чтобы мы могли читать и записывать через всё адресное пространство процесса. Способность читать/записывать куда мы захотим, это очень мощная способность.

Оттуда мы можем пойти двумя путями:

  1. Запустить ActiveX объекты (God mode)
  2. Выполнить обычный шелл-код

Для фазы UAF – произвольного чтения/записи мы будем использовать метод описанный здесь.

Чтение этого файла не обязательно для полного понимания метода из-за того, что я нашел различия между теорией и практикой. Моя цель не просто описать метод, но и показать весь процесс по созданию полноценного эксплойта. Первыми шагами будет маленькое расследование с WinDbg и исследования того, как массивы и другие объекты размещены в памяти.

Реверс инженерия IE

Объекты которые мы хотим проанализировать:

  • Array
  • LargeHeapBlock
  • ArrayBuffer
  • Int32Array

Настройка WinDbg

На данный момент вы должны быть знакомы с WinDbg и уметь настраивать его соответствующим образом. Но давайте всё-таки уверимся. Сперва, загрузите WinDbg (всегда 32-х битную версию, как администратор), нажмите Ctrl + S и введите symbol path.
Вот мой к примеру:

SRV*C:\WinDbgSymbols*http://msdl.microsoft.com/download/symbols

Помните что первая часть, это локальная директория для кэширования скачанных символов из сервера.

Нажмите ОК и потом сохраните рабочее окружение выполнив File→Save Workspace. Теперь запустите Internet Explorer 10 и в WinDbg нажмите F6 для присоединения к процессу (Attach to process). Вы увидите что iexplore.exe появился дважды в списке. Первый экземпляр iexplore.exe это главный процесс, в то время когда второй, это процесс ассоциируемый с первой открытой вкладкой (tab) в IE. Если вы откроете другие вкладки, вы увидите другие экземпляры. Выберите второй экземпляр как показано на изображении ниже:

В WinDbg я использую такую структуру окон:

Настройте структуру окон как вам нравится и сохраните рабочее окружение.

Array

Давайте начнем с объекта Array. Создайте html файл следующего содержания:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array(0x123);
  for (var i = 0; i < 0x123; ++i)
    a[i] = 0x111;
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Откройте файл в IE, разрешите заблокированный контент, и когда диалоговое окно с текстом Start всплывет, тогда запустите WinDbg, нажмите F6 и присоединитесь отладчиком ко второму экземпляру iexplore.exe как делали ранее. Нажмите F5 для продолжения выполнения и закройте диалоговое окно в IE. Теперь вы должны видеть второе диалоговое окно с сообщением Done.
Вернитесь в WinDbg и попробуйте найти память с содержимым массива. Как вы видите, смотря в исходный код, массив содержит последовательность из 0x111.

Вот что мы получили:

0:004> s-d 0 L?ffffffff 111 111 111 111

Мы ничего не получили! Странно… Но даже если бы мы нашли массив в памяти, этого было бы не достаточно для того что бы найти код который выделяет память. Нам нужен другой путь.

Почему бы не распылить кучу? Давайте изменим код:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x10000; ++i) {
    a[i] = new Array(0x1000/4);     // 0x1000 bytes = 0x1000/4 dwords
    for (var j = 0; j < a[i].length; ++j)
      a[i][j] = 0x111;
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

После обновления html файла, продолжите выполнение в WinDbg (F5), закройте Done диалоговое окно в IE и перезагрузите страницу (F5). Закройте диалоговое окно (Start) и ждите следующего. Теперь посмотрим на использования памяти IE открыв менеджер задач:

Мы выделили приблизительно 550 МБ. Мы можем использовать приложения под названием VMMap (скачать) для получения графического изображения нашего распыления кучи (heap spray).

Откройте VMMap и выберите нужный экземпляр iexplore.exe как показано на изображении ниже:

Теперь перейдите в View→Fragmentation View. Вы увидите что-то типа этого:

Область закрашенная в желтый это память, выделенная через распыление кучи. Давайте попробуем проанализировать память по адресу 0x1ffd0000, что является серединой наших данных:

Убедимся, что это один из наших массивов изменив немного код:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x10000; ++i) {
    a[i] = new Array(0x1234/4);     // 0x1234/4 = 0x48d
    for (var j = 0; j < a[i].length; ++j)
      a[i][j] = 0x123;
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Повторим процесс и вот результат:

Как видим, массив теперь содержит значение 0x247. Попробуем нечто другое:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x10000; ++i) {
    a[i] = new Array(0x1000/4);
    for (var j = 0; j < a[i].length; ++j)
      a[i][j] = j;
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Теперь мы получили следующее:

Массив содержит непарные числа начиная с 1. Мы знаем что наш массив содержит числа:
1 2 3 4 5 6 7 8 9 ...

но мы получили:

3 5 7 9 11 13 15 17 19 ...

Здесь ясно что число n является представлением n*2 + 1. Почему так? Вы должны знать что массивы также могут содержать ссылки на объекты, по этому должен быть для разделения адресов и целых чисел. Начиная с адреса кратного 4, представляя любое целочисленное нечетное значение, он никогда не спутается с ссылкой. Но что насчет номера вида 0x7fffffff который является наибольшим позитивным числом по дополнению к двум?

Давайте немного поэкспериментируем:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x10000; ++i) {
    a[i] = new Array(0x1000/4);
    a[i][0] = 0x7fffffff;
    a[i][1] = -2;
    a[i][2] = 1.2345;
    a[i][3] = document.createElement("div");
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Вот как наш массив выглядит сейчас:

Число 0x7fffffff слишком большое что бы хранится напрямую, вместо этого IE хранит ссылку на объект JavascriptNumber. Число -2 хранится напрямую из-за того, что его невозможно перепутать с адресом (установлен старший бит).
Как вы теперь уже знаете, первый DWORD объекта – это обычно указатель на его vftable. На картинке выше можно увидеть, это полезно для определения идентификатора объекта.

Теперь давайте узнаем какой код выделяет массив. Мы видим что там скорее всего есть два заголовка:

Первый заголовок о размере выделенного блока в 0x1010 байт. Действительно, выделенный блок содержит 0х10 байт заголовка и 0х1000 байт самых данных. Из-за того, что мы знаем о расположении одного из массивов по адресу 0x1ffd0000, мы можем установить аппаратную точку останова (на запись) на поля двух заголовков. Таким образом мы узнаем кто выделяет блок и какой код создает объект.

Сперва перезагрузим страницу и остановимся перед Start диалогом. Переходим в WinDbg b останавливаем выполнением (Ctrl + Break). Теперь устанавливаем две точки останова:

0:004> ba w4 1ffd0000+4
0:004> ba w4 1ffd0000+14
0:004> bl
 0 e 1ffd0004 w 4 0001 (0001)  0:****
 1 e 1ffd0014 w 4 0001 (0001)  0:****

Нажимаем F5 (игнорируем сообщения об ошибках) и закрываем диалоговое окно в IE. Когда сработает первая точка останова, выведите стек:

0:007> k 20
ChildEBP RetAddr  
0671bb30 6ea572d8 jscript9!Recycler::LargeAlloc+0xa1      <----------------------
0671bb4c 6eb02c47 jscript9!Recycler::AllocZero+0x91       <----------------------
0671bb8c 6ea82aae jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3fd     <----------------- (*)
0671bc14 05f2074b jscript9!Js::JavascriptOperators::OP_SetElementI+0x1e0
WARNING: Frame IP not in any known module. Following frames may be wrong.
0671bc48 6ea77461 0x5f2074b
0671bde4 6ea55cf5 jscript9!Js::InterpreterStackFrame::Process+0x4b47
0671bf2c 05f80fe9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
0671bf38 6ea51f60 0x5f80fe9
0671bfb8 6ea520ca jscript9!Js::JavascriptFunction::CallRootFunction+0x140
0671bfd0 6ea5209f jscript9!Js::JavascriptFunction::CallRootFunction+0x19
0671c018 6ea52027 jscript9!ScriptSite::CallRootFunction+0x40
0671c040 6eafdf75 jscript9!ScriptSite::Execute+0x61
0671c0cc 6eafdb57 jscript9!ScriptEngine::ExecutePendingScripts+0x1e9
0671c154 6eafe0b7 jscript9!ScriptEngine::ParseScriptTextCore+0x2ad
0671c1a8 069cb60c jscript9!ScriptEngine::ParseScriptText+0x5b
0671c1e0 069c945d MSHTML!CActiveScriptHolder::ParseScriptText+0x42
0671c230 069bb52f MSHTML!CJScript9Holder::ParseScriptText+0x58
0671c2a4 069cc6a4 MSHTML!CScriptCollection::ParseScriptText+0x1f0
0671c394 069cc242 MSHTML!CScriptData::CommitCode+0x36e
0671c40c 069cbe6e MSHTML!CScriptData::Execute+0x233
0671c420 069c9b49 MSHTML!CHtmScriptParseCtx::Execute+0x89
0671c498 067d77cc MSHTML!CHtmParseBase::Execute+0x17c
0671c4c4 755862fa MSHTML!CHtmPost::Broadcast+0x88
0671c5c4 069c3273 user32!InternalCallWinProc+0x23
0671c5dc 069c31ff MSHTML!CHtmPost::Run+0x1c
0671c5f4 069c34f3 MSHTML!PostManExecute+0x5f
0671c610 069c34b2 MSHTML!PostManResume+0x7b
0671c650 06830dc9 MSHTML!CHtmPost::OnDwnChanCallback+0x3a
0671c660 0677866c MSHTML!CDwnChan::OnMethodCall+0x19
0671c6b4 067784fa MSHTML!GlobalWndOnMethodCall+0x169
0671c700 755862fa MSHTML!GlobalWndProc+0xd7
0671c72c 75586d3a user32!InternalCallWinProc+0x23

Здесь мы видим три вещи:

  1. IE использует стандартные средства выделения памяти.
  2. Массив типа jscript9!Js::JavascriptArray.
  3. Блок, вероятно, выделен в момент, когда мы установили значение первого элемента массива (*).

Вернемся из текущего вызова с помощью Shift + F11. Таким образом перейдем сюда:

6e9e72ce 6a00            push    0
6e9e72d0 50              push    eax
6e9e72d1 51              push    ecx
6e9e72d2 56              push    esi
6e9e72d3 e80f34ffff      call    jscript9!Recycler::LargeAlloc (6e9da6e7)
6e9e72d8 c70000000000    mov     dword ptr [eax],0    ds:002b:1ffd0010=00000000    <----- мы здесь
6e9e72de 5e              pop     esi
6e9e72df 5d              pop     ebp
6e9e72e0 c20400          ret     4

Нажмем Shift + F11 снова:

6ea92c3f 51              push    ecx
6ea92c40 8bca            mov     ecx,edx
6ea92c42 e89a67f4ff      call    jscript9!Recycler::AllocZero (6e9d93e1)
6ea92c47 8b55e8          mov     edx,dword ptr [ebp-18h] ss:002b:04d2c058=04d2c054  <----- мы здесь
6ea92c4a 8b0a            mov     ecx,dword ptr [edx]
6ea92c4c c70000000000    mov     dword ptr [eax],0

EAX указывает на буфер, поэтому мы можем установить точку останова на адрес 6ea92c47. Давайте запишем адрес EIP так, что бы он не зависел от конкретного базового адреса модуля. Для начала нужно сказать что мы в jscript9, убедимся:

0:007> !address @eip

                                     
Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...


Usage:                  Image
Base Address:           6e9d1000
End Address:            6ec54000
Region Size:            00283000
State:                  00001000  MEM_COMMIT
Protect:                00000020  PAGE_EXECUTE_READ
Type:                   01000000  MEM_IMAGE
Allocation Base:        6e9d0000
Allocation Protect:     00000080  PAGE_EXECUTE_WRITECOPY
Image Path:             C:\Windows\SysWOW64\jscript9.dll
Module Name:            jscript9        <-----------------------------------------
Loaded Image Name:      C:\Windows\SysWOW64\jscript9.dll
Mapped Image Name:      
More info:              lmv m jscript9
More info:              !lmi jscript9
More info:              ln 0x6ea92c47
More info:              !dh 0x6e9d0000

Unloaded modules that overlapped the address in the past:
    BaseAddr  EndAddr     Size
    6ea90000 6ebed000   15d000 VBoxOGL-x86.dll
    6e9b0000 6eb0d000   15d000 VBoxOGL-x86.dll


Unloaded modules that overlapped the region in the past:
    BaseAddr  EndAddr     Size
    6ebf0000 6eccb000    db000 wined3dwddm-x86.dll
    6ea90000 6ebed000   15d000 VBoxOGL-x86.dll
    6e940000 6ea84000   144000 VBoxOGLcrutil-x86.dll
    6eb10000 6ebeb000    db000 wined3dwddm-x86.dll
    6e9b0000 6eb0d000   15d000 VBoxOGL-x86.dll

RVA следующий:

0:007> ? @eip-jscript9
Evaluate expression: 797767 = 000c2c47

Создание массива (его данных если быть точными) можно зарегистрировать следующей точкой останова:

bp jscript9+c2c47 ".printf \"new Array Data: addr = 0x%p\\n\",eax;g"

Следует избигать двойных кавычек и обратных слешей из-за того, что мы внутри строки. Также, команда g (go) используется для продолжения выполнения после срабатывания точки останова. Мы хотим вывести сообщение без останова выполнения.

Вернемся к тому что мы делали. Мы установили две аппаратные точки останова и только одна сработала, давайте продолжим. После нажатия F5 сработала вторая точка останова и стек приобрел следующий вид:

0:007> k 20
ChildEBP RetAddr  
0671bb8c 6ea82aae jscript9!Js::JavascriptArray::DirectSetItem_Full+0x40b    <----------------
0671bc14 05f2074b jscript9!Js::JavascriptOperators::OP_SetElementI+0x1e0
WARNING: Frame IP not in any known module. Following frames may be wrong.
0671bc48 6ea77461 0x5f2074b
0671bde4 6ea55cf5 jscript9!Js::InterpreterStackFrame::Process+0x4b47
0671bf2c 05f80fe9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
0671bf38 6ea51f60 0x5f80fe9
0671bfb8 6ea520ca jscript9!Js::JavascriptFunction::CallRootFunction+0x140
0671bfd0 6ea5209f jscript9!Js::JavascriptFunction::CallRootFunction+0x19
0671c018 6ea52027 jscript9!ScriptSite::CallRootFunction+0x40
0671c040 6eafdf75 jscript9!ScriptSite::Execute+0x61
0671c0cc 6eafdb57 jscript9!ScriptEngine::ExecutePendingScripts+0x1e9
0671c154 6eafe0b7 jscript9!ScriptEngine::ParseScriptTextCore+0x2ad
0671c1a8 069cb60c jscript9!ScriptEngine::ParseScriptText+0x5b
0671c1e0 069c945d MSHTML!CActiveScriptHolder::ParseScriptText+0x42
0671c230 069bb52f MSHTML!CJScript9Holder::ParseScriptText+0x58
0671c2a4 069cc6a4 MSHTML!CScriptCollection::ParseScriptText+0x1f0
0671c394 069cc242 MSHTML!CScriptData::CommitCode+0x36e
0671c40c 069cbe6e MSHTML!CScriptData::Execute+0x233
0671c420 069c9b49 MSHTML!CHtmScriptParseCtx::Execute+0x89
0671c498 067d77cc MSHTML!CHtmParseBase::Execute+0x17c
0671c4c4 755862fa MSHTML!CHtmPost::Broadcast+0x88
0671c5c4 069c3273 user32!InternalCallWinProc+0x23
0671c5dc 069c31ff MSHTML!CHtmPost::Run+0x1c
0671c5f4 069c34f3 MSHTML!PostManExecute+0x5f
0671c610 069c34b2 MSHTML!PostManResume+0x7b
0671c650 06830dc9 MSHTML!CHtmPost::OnDwnChanCallback+0x3a
0671c660 0677866c MSHTML!CDwnChan::OnMethodCall+0x19
0671c6b4 067784fa MSHTML!GlobalWndOnMethodCall+0x169
0671c700 755862fa MSHTML!GlobalWndProc+0xd7
0671c72c 75586d3a user32!InternalCallWinProc+0x23
0671c7a4 755877c4 user32!UserCallWinProcCheckWow+0x109
0671c804 7558788a user32!DispatchMessageWorker+0x3bc

Сравнивая два последних вывода стека видим то, что мы всё еще в том же самом вызове jscript9!Js::JavascriptArray::DirectSetItem_Full. DirectSetItem_Full сперва выделяет блок 0х1010 байт через jscript9!Recycler::AllocZero и потом инициализирует объект. Но если всё это случится внутри jscript9!Js::JavascriptArray::DirectSetItem_Full, тогда экземпляр JavascriptArray сразу бы создался. Попробуем прервать выполнение конструктора. Но сперва убедимся существует ли он:

0:007> x jscript9!Js::JavascriptArray::JavascriptArray
6ea898d6          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)
6ead481d          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)
6eb28b61          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)

Мы получили три адреса. Удалим предыдущую точку остановас помощью bc *, далее нажмите F5 и перезагрузите страницу в IE. При первом диалоговом окне вернитесь в WinDbg. Теперь установите точку останова на каждый из трех адресов:

0:006> bp 6ea898d6          
0:006> bp 6ead481d          
0:006> bp 6eb28b61          
0:006> bl
 0 e 6ea898d6     0001 (0001)  0:**** jscript9!Js::JavascriptArray::JavascriptArray
 1 e 6ead481d     0001 (0001)  0:**** jscript9!Js::JavascriptArray::JavascriptArray
 2 e 6eb28b61     0001 (0001)  0:**** jscript9!Js::JavascriptArray::JavascriptArray

Нажмите F5 и закройте диалоговое окно. Ммм… диалоговое окно Done появилось и никакие точки останова не сработали. Как странно…

Давайте посмотрим не нашли ли мы что-то интересное в списке символов:

0:006> x jscript9!Js::JavascriptArray::*
6ec61e36          jscript9!Js::JavascriptArray::IsEnumerable (<no parameter info>)
6eabff71          jscript9!Js::JavascriptArray::GetFromIndex (<no parameter info>)
6ec31bed          jscript9!Js::JavascriptArray::BigIndex::BigIndex (<no parameter info>)
6ec300ee          jscript9!Js::JavascriptArray::SetEnumerable (<no parameter info>)
6eb94bd9          jscript9!Js::JavascriptArray::EntrySome (<no parameter info>)
6eace48c          jscript9!Js::JavascriptArray::HasItem (<no parameter info>)
6ea42530          jscript9!Js::JavascriptArray::`vftable' = <no type information>
6ec31a2f          jscript9!Js::JavascriptArray::BigIndex::SetItem (<no parameter info>)
6ec301d1          jscript9!Js::JavascriptArray::IsDirectAccessArray (<no parameter info>)
6eacab83          jscript9!Js::JavascriptArray::Sort (<no parameter info>)
6ecd5500          jscript9!Js::JavascriptArray::EntryInfo::Map = <no type information>
6eb66721          jscript9!Js::JavascriptArray::EntryIsArray (<no parameter info>)
6ec2fd64          jscript9!Js::JavascriptArray::GetDiagValueString (<no parameter info>)
6ec2faeb          jscript9!Js::JavascriptArray::GetNonIndexEnumerator (<no parameter info>)
6ec3043a          jscript9!Js::JavascriptArray::Unshift<Js::JavascriptArray::BigIndex> (<no parameter info>)
6eb4ba72          jscript9!Js::JavascriptArray::EntryReverse (<no parameter info>)
6eaed10f          jscript9!Js::JavascriptArray::SetLength (<no parameter info>)
6eacaadf          jscript9!Js::JavascriptArray::EntrySort (<no parameter info>)
6ec306c9          jscript9!Js::JavascriptArray::ToLocaleString<Js::JavascriptArray> (<no parameter info>)
6eb5f4ce          jscript9!Js::JavascriptArray::BuildSegmentMap (<no parameter info>)
6ec2fef5          jscript9!Js::JavascriptArray::Freeze (<no parameter info>)
6ec31c5f          jscript9!Js::JavascriptArray::GetLocaleSeparator (<no parameter info>)
6ecd54f0          jscript9!Js::JavascriptArray::EntryInfo::LastIndexOf = <no type information>
6eb9b990          jscript9!Js::JavascriptArray::EntryUnshift (<no parameter info>)
6ec30859          jscript9!Js::JavascriptArray::ObjectSpliceHelper<unsigned int> (<no parameter info>)
6ec31ab5          jscript9!Js::JavascriptArray::BigIndex::operator+ (<no parameter info>)
6ea898d6          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)
6eb5f8f5          jscript9!Js::JavascriptArray::ArrayElementEnumerator::ArrayElementEnumerator (<no parameter info>)
6ec30257          jscript9!Js::JavascriptArray::IndexTrace<unsigned int>::SetItem (<no parameter info>)
6ead481d          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)
6eac281d          jscript9!Js::JavascriptArray::ConcatArgs<unsigned int> (<no parameter info>)
6ecd5510          jscript9!Js::JavascriptArray::EntryInfo::Reduce = <no type information>
6ea9bf88          jscript9!Js::JavascriptArray::DirectSetItem_Full (<no parameter info>)
6eb9d5ee          jscript9!Js::JavascriptArray::EntryConcat (<no parameter info>)
6ecd5490          jscript9!Js::JavascriptArray::EntryInfo::ToString = <no type information>
6eb49e52          jscript9!Js::JavascriptArray::GetEnumerator (<no parameter info>)
6ecd5430          jscript9!Js::JavascriptArray::EntryInfo::Reverse = <no type information>
6eb66c77          jscript9!Js::JavascriptArray::EntryIndexOf (<no parameter info>)
6eb93fa5          jscript9!Js::JavascriptArray::EntryEvery (<no parameter info>)
6ecd53e0          jscript9!Js::JavascriptArray::EntryInfo::IsArray = <no type information>
6ec31e6d          jscript9!Js::JavascriptArray::JoinOtherHelper (<no parameter info>)
6ec31d73          jscript9!Js::JavascriptArray::sort (<no parameter info>)
6eb94d8c          jscript9!Js::JavascriptArray::EntryFilter (<no parameter info>)
6ec32052          jscript9!Js::JavascriptArray::EntryToLocaleString (<no parameter info>)
6ec61e52          jscript9!Js::JavascriptArray::IsConfigurable (<no parameter info>)
6ecd5410          jscript9!Js::JavascriptArray::EntryInfo::Join = <no type information>
6ec31d56          jscript9!Js::JavascriptArray::CompareElements (<no parameter info>)
6eb5f989          jscript9!Js::JavascriptArray::InternalCopyArrayElements<unsigned int> (<no parameter info>)
6eaef6d1          jscript9!Js::JavascriptArray::IsItemEnumerable (<no parameter info>)
6eb9d4cb          jscript9!Js::JavascriptArray::EntrySplice (<no parameter info>)
6eacf7f0          jscript9!Js::JavascriptArray::EntryToString (<no parameter info>)
6eb5f956          jscript9!Js::JavascriptArray::CopyArrayElements (<no parameter info>)
6ec325e0          jscript9!Js::JavascriptArray::PrepareDetach (<no parameter info>)
6ecd53f0          jscript9!Js::JavascriptArray::EntryInfo::Push = <no type information>
6ec30a8b          jscript9!Js::JavascriptArray::ObjectSpliceHelper<Js::JavascriptArray::BigIndex> (<no parameter info>)
6ec301f7          jscript9!Js::JavascriptArray::DirectSetItemIfNotExist (<no parameter info>)
6ec30083          jscript9!Js::JavascriptArray::SetWritable (<no parameter info>)
6ec30019          jscript9!Js::JavascriptArray::SetConfigurable (<no parameter info>)
6ec31b1d          jscript9!Js::JavascriptArray::BigIndex::operator++ (<no parameter info>)
6ecd54b0          jscript9!Js::JavascriptArray::EntryInfo::IndexOf = <no type information>
6eba1498          jscript9!Js::JavascriptArray::EntryPush (<no parameter info>)
6ecd5460          jscript9!Js::JavascriptArray::EntryInfo::Sort = <no type information>
6ec2fcbb          jscript9!Js::JavascriptArray::SetItemAttributes (<no parameter info>)
6ea8497f          jscript9!Js::JavascriptArray::ArrayElementEnumerator::Init (<no parameter info>)
6ecd5350          jscript9!Js::JavascriptArray::EntryInfo::NewInstance = <no type information>
6eac0596          jscript9!Js::JavascriptArray::EntryPop (<no parameter info>)
6ea82f23          jscript9!Js::JavascriptArray::GetItem (<no parameter info>)
6ec2ffb1          jscript9!Js::JavascriptArray::SetAttributes (<no parameter info>)
6eae718b          jscript9!Js::JavascriptArray::GetItemReference (<no parameter info>)
6ec2fd46          jscript9!Js::JavascriptArray::GetDiagTypeString (<no parameter info>)
6eb61889          jscript9!Js::JavascriptArray::DeleteItem (<no parameter info>)
6ecd5450          jscript9!Js::JavascriptArray::EntryInfo::Slice = <no type information>
6ec319be          jscript9!Js::JavascriptArray::BigIndex::SetItemIfNotExist (<no parameter info>)
6ecd5530          jscript9!Js::JavascriptArray::EntryInfo::Some = <no type information>
6eb16a13          jscript9!Js::JavascriptArray::EntryJoin (<no parameter info>)
6ecd5470          jscript9!Js::JavascriptArray::EntryInfo::Splice = <no type information>
6ec2fc89          jscript9!Js::JavascriptArray::SetItemAccessors (<no parameter info>)
6ec2ff1d          jscript9!Js::JavascriptArray::Seal (<no parameter info>)
6eb5b713          jscript9!Js::JavascriptArray::GetItemSetter (<no parameter info>)
6eb49dc0          jscript9!Js::JavascriptArray::GetEnumerator (<no parameter info>)
6ec30284          jscript9!Js::JavascriptArray::InternalCopyArrayElements<Js::JavascriptArray::BigIndex> (<no parameter info>)
6ec318bb          jscript9!Js::JavascriptArray::BigIndex::DeleteItem (<no parameter info>)
6eb94158          jscript9!Js::JavascriptArray::EntryLastIndexOf (<no parameter info>)
6eba4b06          jscript9!Js::JavascriptArray::NewInstance (<no parameter info>)  <-------------------------
6ecd5520          jscript9!Js::JavascriptArray::EntryInfo::ReduceRight = <no type information>
6ecd54e0          jscript9!Js::JavascriptArray::EntryInfo::ForEach = <no type information>
6ec31d27          jscript9!Js::JavascriptArray::EnforceCompatModeRestrictions (<no parameter info>)
6ecd5440          jscript9!Js::JavascriptArray::EntryInfo::Shift = <no type information>
6eab5de1          jscript9!Js::JavascriptArray::SetProperty (<no parameter info>)
6ecd5400          jscript9!Js::JavascriptArray::EntryInfo::Concat = <no type information>
6ea5b329          jscript9!Js::JavascriptArray::GetProperty (<no parameter info>)
6ec2ff43          jscript9!Js::JavascriptArray::SetAccessors (<no parameter info>)
6ec2fcea          jscript9!Js::JavascriptArray::SetItemWithAttributes (<no parameter info>)
6ea4768d          jscript9!Js::JavascriptArray::IsObjectArrayFrozen (<no parameter info>)
6eae0c2c          jscript9!Js::JavascriptArray::GetNextIndex (<no parameter info>)
6eab5c21          jscript9!Js::JavascriptArray::Is (<no parameter info>)
6ec3177e          jscript9!Js::JavascriptArray::CopyArrayElements (<no parameter info>)
6ec3251d          jscript9!Js::JavascriptArray::SetLength (<no parameter info>)
6eb28b61          jscript9!Js::JavascriptArray::JavascriptArray (<no parameter info>)
6eaeb83a          jscript9!Js::JavascriptArray::ArraySpliceHelper (<no parameter info>)
6eac3a16          jscript9!Js::JavascriptArray::AllocateHead (<no parameter info>)
6eaffed4          jscript9!Js::JavascriptArray::SetPropertyWithAttributes (<no parameter info>)
6ead00ce          jscript9!Js::JavascriptArray::HasProperty (<no parameter info>)
6ecd54d0          jscript9!Js::JavascriptArray::EntryInfo::Filter = <no type information>
6ec3190f          jscript9!Js::JavascriptArray::BigIndex::SetItem (<no parameter info>)
6eae60d3          jscript9!Js::JavascriptArray::EntryMap (<no parameter info>)
6eb16a9c          jscript9!Js::JavascriptArray::JoinHelper (<no parameter info>)
6ec31b46          jscript9!Js::JavascriptArray::BigIndex::ToNumber (<no parameter info>)
6ea84a80          jscript9!Js::JavascriptArray::ArrayElementEnumerator::ArrayElementEnumerator (<no parameter info>)
6ea8495b          jscript9!Js::JavascriptArray::IsAnyArrayTypeId (<no parameter info>)
6ec2fd1c          jscript9!Js::JavascriptArray::GetSpecialNonEnumerablePropertyName (<no parameter info>)
6ec31bd5          jscript9!Js::JavascriptArray::BigIndex::IsSmallIndex (<no parameter info>)
6eba157a          jscript9!Js::JavascriptArray::EntryForEach (<no parameter info>)
6ea83044          jscript9!Js::JavascriptArray::SetItem (<no parameter info>)
6ec3050a          jscript9!Js::JavascriptArray::ToLocaleString<Js::RecyclableObject> (<no parameter info>)
6ea534e0          jscript9!Js::JavascriptArray::DirectGetItemAt (<no parameter info>)
6ecd5420          jscript9!Js::JavascriptArray::EntryInfo::Pop = <no type information>
6ea59b2d          jscript9!Js::JavascriptArray::ForInLoop (<no parameter info>)
6eafff78          jscript9!Js::JavascriptArray::GetSetter (<no parameter info>)
6eb4ec30          jscript9!Js::JavascriptArray::ArraySegmentSpliceHelper (<no parameter info>)
6eb78e45          jscript9!Js::JavascriptArray::EntryReduce (<no parameter info>)
6eb6697d          jscript9!Js::JavascriptArray::DirectGetItemAtFull (<no parameter info>)
6ec32167          jscript9!Js::JavascriptArray::EntryReduceRight (<no parameter info>)
6eba717f          jscript9!Js::JavascriptArray::EntryShift (<no parameter info>)
6eb99706          jscript9!Js::JavascriptArray::MarshalToScriptContext (<no parameter info>)
6ecd54c0          jscript9!Js::JavascriptArray::EntryInfo::Every = <no type information>
6ec3196b          jscript9!Js::JavascriptArray::BigIndex::DeleteItem (<no parameter info>)
6eb7c0ba          jscript9!Js::JavascriptArray::PreventExtensions (<no parameter info>)
6ecd5480          jscript9!Js::JavascriptArray::EntryInfo::ToLocaleString = <no type information>
6eb93f8b          jscript9!Js::JavascriptArray::DeleteProperty (<no parameter info>)
6ec303b9          jscript9!Js::JavascriptArray::Unshift<unsigned int> (<no parameter info>)
6ea849d5          jscript9!Js::JavascriptArray::FillFromPrototypes (<no parameter info>)
6ea5b3cf          jscript9!Js::JavascriptArray::GetPropertyReference (<no parameter info>)
6ec317e1          jscript9!Js::JavascriptArray::TruncateToProperties (<no parameter info>)
6eabfc81          jscript9!Js::JavascriptArray::EntrySlice (<no parameter info>)
6eae20b0          jscript9!Js::JavascriptArray::JoinToString (<no parameter info>)
6ec30ca8          jscript9!Js::JavascriptArray::ConcatArgs<Js::JavascriptArray::BigIndex> (<no parameter info>)
6ea5c2be          jscript9!Js::JavascriptArray::OP_NewScArray (<no parameter info>)
6eb1682e          jscript9!Js::JavascriptArray::JoinArrayHelper (<no parameter info>)
6ec31f63          jscript9!Js::JavascriptArray::GetFromLastIndex (<no parameter info>)
6eb618a1          jscript9!Js::JavascriptArray::DirectDeleteItemAt (<no parameter info>)
6ead497d          jscript9!Js::JavascriptArray::MakeCopyOnWriteObject (<no parameter info>)
6eb4c512          jscript9!Js::JavascriptArray::EnsureHeadStartsFromZero (<no parameter info>)
6ec31c24          jscript9!Js::JavascriptArray::ToLocaleStringHelper (<no parameter info>)
6eae0be6          jscript9!Js::JavascriptArray::GetBeginLookupSegment (<no parameter info>)
6ecd54a0          jscript9!Js::JavascriptArray::EntryInfo::Unshift = <no type information>

Данная строка выглядит многообещающе:

6eba4b06          jscript9!Js::JavascriptArray::NewInstance (<no parameter info>)

Установим на неё точку останова и попытаем удачу.

0:006> bc *
0:006> bp jscript9!Js::JavascriptArray::NewInstance

Закройте диалоговое окно в IE, перезагрузите страницу и закройте стартовое диалоговое окно. Теперь всё идет по плану:

Трассируя код мы получили такой вот кусок:

6eb02a3c 682870a46e      push    offset jscript9!Recycler::Alloc (6ea47028)
6eb02a41 ff770c          push    dword ptr [edi+0Ch]
6eb02a44 6a20            push    20h
6eb02a46 e84546f4ff      call    jscript9!operator new<Recycler> (6ea47090)     <-------------------
6eb02a4b 8bf0            mov     esi,eax   <--------- ESI = allocated block
6eb02a4d 83c40c          add     esp,0Ch
6eb02a50 85f6            test    esi,esi
6eb02a52 0f841d210a00    je      jscript9!Js::JavascriptArray::NewInstance+0x390 (6eba4b75)
6eb02a58 8b8f00010000    mov     ecx,dword ptr [edi+100h]
6eb02a5e 894e04          mov     dword ptr [esi+4],ecx
6eb02a61 c706b02fa46e    mov     dword ptr [esi],offset jscript9!Js::DynamicObject::`vftable' (6ea42fb0)
6eb02a67 c7460800000000  mov     dword ptr [esi+8],0
6eb02a6e c7460c01000000  mov     dword ptr [esi+0Ch],1
6eb02a75 8b4118          mov     eax,dword ptr [ecx+18h]
6eb02a78 8a4005          mov     al,byte ptr [eax+5]

Оператор new вызывает следующим образом:

operator new(20h, arg, jscript9!Recycler::Alloc);

Посмотри на код в области оператора new:

jscript9!operator new<Recycler>:
6ea47090 8bff            mov     edi,edi
6ea47092 55              push    ebp
6ea47093 8bec            mov     ebp,esp
6ea47095 ff7508          push    dword ptr [ebp+8]      <----- push 20h
6ea47098 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
6ea4709b ff5510          call    dword ptr [ebp+10h]    <----- call jscript9!Recycler::Alloc
6ea4709e 5d              pop     ebp
6ea4709f c3              ret

Давайте вернемся к основному коду:
6eb02a3c 682870a46e      push    offset jscript9!Recycler::Alloc (6ea47028)
6eb02a41 ff770c          push    dword ptr [edi+0Ch]
6eb02a44 6a20            push    20h
6eb02a46 e84546f4ff      call    jscript9!operator new<Recycler> (6ea47090)     <-------------------
6eb02a4b 8bf0            mov     esi,eax   <--------- ESI = выделенный блок
6eb02a4d 83c40c          add     esp,0Ch
6eb02a50 85f6            test    esi,esi
6eb02a52 0f841d210a00    je      jscript9!Js::JavascriptArray::NewInstance+0x390 (6eba4b75)
6eb02a58 8b8f00010000    mov     ecx,dword ptr [edi+100h]
6eb02a5e 894e04          mov     dword ptr [esi+4],ecx
6eb02a61 c706b02fa46e    mov     dword ptr [esi],offset jscript9!Js::DynamicObject::`vftable' (6ea42fb0)
6eb02a67 c7460800000000  mov     dword ptr [esi+8],0
6eb02a6e c7460c01000000  mov     dword ptr [esi+0Ch],1
6eb02a75 8b4118          mov     eax,dword ptr [ecx+18h]
6eb02a78 8a4005          mov     al,byte ptr [eax+5]
6eb02a7b a808            test    al,8
6eb02a7d 0f85e8200a00    jne     jscript9!Js::JavascriptArray::NewInstance+0x386 (6eba4b6b)
6eb02a83 b803000000      mov     eax,3
6eb02a88 89460c          mov     dword ptr [esi+0Ch],eax
6eb02a8b 8b4104          mov     eax,dword ptr [ecx+4] ds:002b:060e9a64=060fb000
6eb02a8e 8b4004          mov     eax,dword ptr [eax+4]
6eb02a91 8b4918          mov     ecx,dword ptr [ecx+18h]
6eb02a94 8bb864040000    mov     edi,dword ptr [eax+464h]
6eb02a9a 8b01            mov     eax,dword ptr [ecx]
6eb02a9c ff5014          call    dword ptr [eax+14h]
6eb02a9f 8b4e04          mov     ecx,dword ptr [esi+4]
6eb02aa2 8b4918          mov     ecx,dword ptr [ecx+18h]
6eb02aa5 8b4908          mov     ecx,dword ptr [ecx+8]
6eb02aa8 3bc1            cmp     eax,ecx
6eb02aaa 0f8f0d9f1900    jg      jscript9!memset+0x31562 (6ec9c9bd)
6eb02ab0 8b4604          mov     eax,dword ptr [esi+4]
6eb02ab3 c7063025a46e    mov     dword ptr [esi],offset jscript9!Js::JavascriptArray::`vftable' (6ea42530)
6eb02ab9 c7461c00000000  mov     dword ptr [esi+1Ch],0
6eb02ac0 8b4004          mov     eax,dword ptr [eax+4]

Важной инструкцией является:

6eb02ab3 c7063025a46e    mov     dword ptr [esi],offset jscript9!Js::JavascriptArray::`vftable' (6ea42530)

которая переписывает первый DWORD блока памяти таблицой vftable объекта JavascriptArray.

Другая важная часть кода такая:

6eb02ac3 8b4004          mov     eax,dword ptr [eax+4]
6eb02ac6 8b8864040000    mov     ecx,dword ptr [eax+464h]
6eb02acc 6a50            push    50h        <------- 50h байт?
6eb02ace c7461000000000  mov     dword ptr [esi+10h],0
6eb02ad5 e80769f4ff      call    jscript9!Recycler::AllocZero (6ea493e1)    <------ выделяет блок
6eb02ada c70000000000    mov     dword ptr [eax],0
6eb02ae0 c7400400000000  mov     dword ptr [eax+4],0
6eb02ae7 c7400810000000  mov     dword ptr [eax+8],10h
6eb02aee c7400c00000000  mov     dword ptr [eax+0Ch],0
6eb02af5 894618          mov     dword ptr [esi+18h],eax   <------ смотрим на картинке
6eb02af8 894614          mov     dword ptr [esi+14h],eax   <------ смотрим на картинкеpicture
6eb02afb e951200a00      jmp     jscript9!Js::JavascriptArray::NewInstance+0x24f (6eba4b51)

Изображение ниже иллюстрирует происходящее в коде выше:

Теперь у нас есть два важных адреса:

239d9340          address of the JavascriptArray
2c1460a0          structure pointed to by the JavascriptArray

Удалим точки останова и продолжим выполнение программы. Когда диалоговое окно Done появится, вернитесь в WinDbg. Теперь прервите выполнение в WinDbg и посмотрите по адресу 239d9340h:

Как видно с рисунка, наш JavascriptArray (по смещению 0x14 и 0x18) указывает на разные адреса. Из-за того, что JavascriptArray рассширяемый, вполне вероятно, что при выделении большего буфера два указателя 0x14 и 0x18 начинают указывать на новый буфер. Так же можно увидеть что JavascriptArray по адресу 239d9340 соответствует массиву a в javascript-коде. Он в самом деле содержит 10000h ссылок на другие массивы.

Мы увидели что объект JavascriptArray выделен в функции jscript9!Js::JavascriptArray::NewInstance:

6eb02a46 e84546f4ff      call    jscript9!operator new<Recycler> (6ea47090)     <-------------------
6eb02a4b 8bf0            mov     esi,eax   <--------- ESI = выделенный блок

Если в данном месте вы вернемся из jscript9!Js::JavascriptArray::NewInstance нажатием комбинации клавиш Shift + F11, мы увидим следующий код:

6ea125cc ff75ec          push    dword ptr [ebp-14h]
6ea125cf ff75e8          push    dword ptr [ebp-18h]
6ea125d2 ff55e4          call    dword ptr [ebp-1Ch]   (jscript9!Js::JavascriptArray::NewInstance)
6ea125d5 8b65e0          mov     esp,dword ptr [ebp-20h] ss:002b:04d2c0e0=04d2c0c4

После вызова NewInstance, EAX указывает на структуру JavascriptArray. Так что мы можем поместить точку останова либо на 6eb02a4b либо на 6ea125d5.

Выберем второе:

bp jscript9+425d5 ".printf \"new Array: addr = 0x%p\\n\",eax;g"

Вот полная картина того что мы обнаружили до теперешнего времени:

LargeHeapBlock

Что такое LargeHeapBlock? Попробуем найти какие-то относящиеся к этому символы:

0:007> x jscript9!*largeheapblock*
6f696af3          jscript9!HeapInfo::DeleteLargeHeapBlockList (<no parameter info>)
6f5d654d          jscript9!HeapInfo::ReinsertLargeHeapBlock (<no parameter info>)
6f6a8699          jscript9!LargeHeapBlock::SweepObjects<2> (<no parameter info>)
6f6ab0cf          jscript9!LargeHeapBlock::IsValidObject (<no parameter info>)
6f6a82a8          jscript9!LargeHeapBlock::SweepObjects<1> (<no parameter info>)
6f755d4d          jscript9!LargeHeapBlock::GetHeader (<no parameter info>)
6f5a160e          jscript9!LargeHeapBlock::ResetMarks (<no parameter info>)
6f5a0672          jscript9!LargeHeapBlock::Rescan (<no parameter info>)
6f59f32f          jscript9!LargeHeapBlock::IsObjectMarked (<no parameter info>)
6f59a7ca          jscript9!HeapInfo::AddLargeHeapBlock (<no parameter info>)    <------------------------
6f657a87          jscript9!LargeHeapBlock::AddObjectToFreeList (<no parameter info>)
6f755f80          jscript9!LargeHeapBlock::Alloc (<no parameter info>)    <--------------------------
6f755dba          jscript9!LargeHeapBlock::GetObjectHeader (<no parameter info>)
6f755b43          jscript9!HeapBucket::EnumerateObjects<LargeHeapBlock> (<no parameter info>)
6f755daf          jscript9!LargeHeapBlock::GetRealAddressFromInterior (<no parameter info>)
6f755dee          jscript9!LargeHeapBlock::SetMemoryProfilerOldObjectBit (<no parameter info>)
6f755d9b          jscript9!LargeHeapBlock::GetObjectSize (<no parameter info>)
6f5a096b          jscript9!HeapInfo::Rescan<LargeHeapBlock> (<no parameter info>)
6f696b24          jscript9!LargeHeapBlock::ReleasePagesShutdown (<no parameter info>)
6f755e23          jscript9!LargeHeapBlock::SetObjectMarkedBit (<no parameter info>)
6f755eaf          jscript9!LargeHeapBlock::FinalizeObjects (<no parameter info>)
6f59ef52          jscript9!LargeHeapBlock::SweepObjects<0> (<no parameter info>)
6f755e66          jscript9!LargeHeapBlock::TestObjectMarkedBit (<no parameter info>)
6f755daf          jscript9!LargeHeapBlock::MarkInterior (<no parameter info>)
6f596e18          jscript9!LargeHeapBlock::`vftable' = <no type information>

Вот наиболее подходящии на первый взгляд функции:

6f59a7ca          jscript9!HeapInfo::AddLargeHeapBlock (<no parameter info>)
6f755f80          jscript9!LargeHeapBlock::Alloc (<no parameter info>)

Поставит точки останова на них обеих и перезагрузим страницу в IE. Когда вы закроем диалоговое окно Start, сработает первая точка останова и в конечном итоге мы окажемся здесь:

6f59a7c5 90              nop
6f59a7c6 90              nop
6f59a7c7 90              nop
6f59a7c8 90              nop
6f59a7c9 90              nop
jscript9!HeapInfo::AddLargeHeapBlock:
6f59a7ca 8bff            mov     edi,edi     <------------ мы здесь
6f59a7cc 55              push    ebp
6f59a7cd 8bec            mov     ebp,esp
6f59a7cf 83ec1c          sub     esp,1Ch
6f59a7d2 53              push    ebx
6f59a7d3 56              push    esi
6f59a7d4 8b750c          mov     esi,dword ptr [ebp+0Ch]

Также взглянем на трассировку стека:

0:007> k 10
ChildEBP RetAddr  
04dbbc90 6f59a74d jscript9!HeapInfo::AddLargeHeapBlock
04dbbcb4 6f5a72d8 jscript9!Recycler::LargeAlloc+0x66
04dbbcd0 6f652c47 jscript9!Recycler::AllocZero+0x91
04dbbd10 6f5d2aae jscript9!Js::JavascriptArray::DirectSetItem_Full+0x3fd
04dbbd98 6f5fed13 jscript9!Js::JavascriptOperators::OP_SetElementI+0x1e0
04dbbf34 6f5a5cf5 jscript9!Js::InterpreterStackFrame::Process+0x3579
04dbc084 03fd0fe9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
WARNING: Frame IP not in any known module. Following frames may be wrong.
04dbc090 6f5a1f60 0x3fd0fe9
04dbc110 6f5a20ca jscript9!Js::JavascriptFunction::CallRootFunction+0x140
04dbc128 6f5a209f jscript9!Js::JavascriptFunction::CallRootFunction+0x19
04dbc170 6f5a2027 jscript9!ScriptSite::CallRootFunction+0x40
04dbc198 6f64df75 jscript9!ScriptSite::Execute+0x61
04dbc224 6f64db57 jscript9!ScriptEngine::ExecutePendingScripts+0x1e9
04dbc2ac 6f64e0b7 jscript9!ScriptEngine::ParseScriptTextCore+0x2ad
04dbc300 6e2db60c jscript9!ScriptEngine::ParseScriptText+0x5b
04dbc338 6e2d945d MSHTML!CActiveScriptHolder::ParseScriptText+0x42

Очень интересно! LargeHeapBlock создан с помощью LargeAlloc (также называемой AllocZero) при первой инициализации (что-то присвоили первому элементу) первого элемента JavascriptArray. Вернемся из AddLargeHeapBlock прожав Shift+F11 и посмотрим на память по указателю из EAX:

0:007> dd eax
25fcbe80  6f596e18 00000003 046b1000 00000002
25fcbe90  00000000 00000000 00000004 046b1000
25fcbea0  046b3000 25fcbee0 00000000 00000000
25fcbeb0  00000000 00000000 04222e98 00000000
25fcbec0  00000000 00000000 00000000 00000004
25fcbed0  00000000 00000000 734a1523 8c000000
25fcbee0  6f596e18 00000003 046a6000 00000003
25fcbef0  00000002 00000000 00000004 046a8820
0:007> ln poi(eax)
(6f596e18)   jscript9!LargeHeapBlock::`vftable'   |  (6f596e3c)   jscript9!PageSegment::`vftable'
Exact matches:
    jscript9!LargeHeapBlock::`vftable' = <no type information>

EAX указывает на только что созданный LargeHeapBlock. Посмотрем был ли данный блок выделен прямо в куче:

0:007> !heap -p -a @eax
    address 25fcbe80 found in
    _HEAP @ 300000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        25fcbe78 000c 0000  [00]   25fcbe80    00054 - (busy)
          jscript9!LargeHeapBlock::`vftable'

Да, именно так как мы и предполагали! Его размер 0x54 байт и он предшествует выделенному заголовку с его 8-ми байтами (UserPtr – HEAP_ENTRY == 8). Это всё что нам надо знать.

Мы можем установить точку останова сразу после вызова AddLargeHeapBlock:

bp jscript9!Recycler::LargeAlloc+0x66 ".printf \"new LargeHeapBlock: addr = 0x%p\\n\",eax;g"

Мы должны взгянуть на LargeHeapBlock. Сперва давайте изменим javascript-код так, что бы LargeHeapBlock создавался меньшее количество раз:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x100; ++i) {     // <------ just 0x100
    a[i] = new Array(0x1000/4);
    a[i][0] = 0x7fffffff;
    a[i][1] = -2;
    a[i][2] = 1.2345;
    a[i][3] = document.createElement("div");
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Установим точку останова о которой только что говорили:

bp jscript9!Recycler::LargeAlloc+0x66 ".printf \"new LargeHeapBlock: addr = 0x%p\\n\",eax;g"

Теперь перезагрузите страницу IE и закройте первое диалоговое окно.

Ваш вывод должен быть схожим с этим:

new LargeHeapBlock: addr = 0x042a7368
new LargeHeapBlock: addr = 0x042a73c8
new LargeHeapBlock: addr = 0x042a7428
new LargeHeapBlock: addr = 0x042a7488
new LargeHeapBlock: addr = 0x042a74e8
new LargeHeapBlock: addr = 0x042a7548
new LargeHeapBlock: addr = 0x042a75a8
new LargeHeapBlock: addr = 0x042a7608
new LargeHeapBlock: addr = 0x042a7668
new LargeHeapBlock: addr = 0x042a76c8
new LargeHeapBlock: addr = 0x042a7728
new LargeHeapBlock: addr = 0x042a7788
new LargeHeapBlock: addr = 0x042a77e8
new LargeHeapBlock: addr = 0x042a7848
new LargeHeapBlock: addr = 0x042a78a8
new LargeHeapBlock: addr = 0x042a7908
new LargeHeapBlock: addr = 0x042a7968
new LargeHeapBlock: addr = 0x042a79c8
new LargeHeapBlock: addr = 0x042a7a28
new LargeHeapBlock: addr = 0x042a7a88
new LargeHeapBlock: addr = 0x042a7ae8
new LargeHeapBlock: addr = 0x042a7b48
new LargeHeapBlock: addr = 0x042a7ba8
new LargeHeapBlock: addr = 0x042a7c08
new LargeHeapBlock: addr = 0x042a7c68
new LargeHeapBlock: addr = 0x042a7cc8
new LargeHeapBlock: addr = 0x042a7d28
new LargeHeapBlock: addr = 0x042a7d88
new LargeHeapBlock: addr = 0x042a7de8
new LargeHeapBlock: addr = 0x042a7e48
new LargeHeapBlock: addr = 0x042a7ea8
new LargeHeapBlock: addr = 0x042a7f08
new LargeHeapBlock: addr = 0x042a7f68
new LargeHeapBlock: addr = 0x042a7fc8
new LargeHeapBlock: addr = 0x042a8028
new LargeHeapBlock: addr = 0x042a8088
new LargeHeapBlock: addr = 0x042a80e8
new LargeHeapBlock: addr = 0x134a9020
new LargeHeapBlock: addr = 0x134a9080
new LargeHeapBlock: addr = 0x134a90e0
new LargeHeapBlock: addr = 0x134a9140
new LargeHeapBlock: addr = 0x134a91a0
new LargeHeapBlock: addr = 0x134a9200
new LargeHeapBlock: addr = 0x134a9260
new LargeHeapBlock: addr = 0x134a92c0
new LargeHeapBlock: addr = 0x134a9320
new LargeHeapBlock: addr = 0x134a9380
new LargeHeapBlock: addr = 0x134a93e0
new LargeHeapBlock: addr = 0x134a9440
new LargeHeapBlock: addr = 0x134a94a0
new LargeHeapBlock: addr = 0x134a9500
new LargeHeapBlock: addr = 0x134a9560
new LargeHeapBlock: addr = 0x134a95c0
new LargeHeapBlock: addr = 0x134a9620
new LargeHeapBlock: addr = 0x134a9680
new LargeHeapBlock: addr = 0x134a96e0
new LargeHeapBlock: addr = 0x134a9740
new LargeHeapBlock: addr = 0x134a97a0
new LargeHeapBlock: addr = 0x134a9800
new LargeHeapBlock: addr = 0x134a9860
new LargeHeapBlock: addr = 0x134a98c0
new LargeHeapBlock: addr = 0x134a9920
new LargeHeapBlock: addr = 0x134a9980
new LargeHeapBlock: addr = 0x134a99e0
new LargeHeapBlock: addr = 0x134a9a40
new LargeHeapBlock: addr = 0x134a9aa0
new LargeHeapBlock: addr = 0x134a9b00
new LargeHeapBlock: addr = 0x134a9b60
new LargeHeapBlock: addr = 0x134a9bc0
new LargeHeapBlock: addr = 0x134a9c20
new LargeHeapBlock: addr = 0x134a9c80
new LargeHeapBlock: addr = 0x134a9ce0
new LargeHeapBlock: addr = 0x134a9d40
new LargeHeapBlock: addr = 0x134a9da0
new LargeHeapBlock: addr = 0x134a9e00
new LargeHeapBlock: addr = 0x134a9e60
new LargeHeapBlock: addr = 0x134a9ec0
new LargeHeapBlock: addr = 0x134a9f20
new LargeHeapBlock: addr = 0x134a9f80
new LargeHeapBlock: addr = 0x1380e060
new LargeHeapBlock: addr = 0x1380e0c0
new LargeHeapBlock: addr = 0x1380e120
new LargeHeapBlock: addr = 0x1380e180
new LargeHeapBlock: addr = 0x1380e1e0
new LargeHeapBlock: addr = 0x1380e240
new LargeHeapBlock: addr = 0x1380e2a0
new LargeHeapBlock: addr = 0x1380e300
new LargeHeapBlock: addr = 0x1380e360
new LargeHeapBlock: addr = 0x1380e3c0
new LargeHeapBlock: addr = 0x1380e420
new LargeHeapBlock: addr = 0x1380e480
new LargeHeapBlock: addr = 0x1380e4e0
new LargeHeapBlock: addr = 0x1380e540
new LargeHeapBlock: addr = 0x1380e5a0
new LargeHeapBlock: addr = 0x1380e600
new LargeHeapBlock: addr = 0x1380e660
new LargeHeapBlock: addr = 0x1380e6c0
new LargeHeapBlock: addr = 0x1380e720
new LargeHeapBlock: addr = 0x1380e780
new LargeHeapBlock: addr = 0x1380e7e0
new LargeHeapBlock: addr = 0x1380e840
new LargeHeapBlock: addr = 0x1380e8a0
new LargeHeapBlock: addr = 0x1380e900
new LargeHeapBlock: addr = 0x1380e960
new LargeHeapBlock: addr = 0x1380e9c0
new LargeHeapBlock: addr = 0x1380ea20
new LargeHeapBlock: addr = 0x1380ea80
new LargeHeapBlock: addr = 0x1380eae0
new LargeHeapBlock: addr = 0x1380eb40
new LargeHeapBlock: addr = 0x1380eba0
new LargeHeapBlock: addr = 0x1380ec00
new LargeHeapBlock: addr = 0x1380ec60
new LargeHeapBlock: addr = 0x1380ecc0
new LargeHeapBlock: addr = 0x1380ed20
new LargeHeapBlock: addr = 0x1380ed80
new LargeHeapBlock: addr = 0x1380ede0
new LargeHeapBlock: addr = 0x1380ee40
new LargeHeapBlock: addr = 0x1380eea0
new LargeHeapBlock: addr = 0x1380ef00
new LargeHeapBlock: addr = 0x1380ef60
new LargeHeapBlock: addr = 0x1380efc0
new LargeHeapBlock: addr = 0x16ccb020
new LargeHeapBlock: addr = 0x16ccb080
new LargeHeapBlock: addr = 0x16ccb0e0
new LargeHeapBlock: addr = 0x16ccb140
new LargeHeapBlock: addr = 0x16ccb1a0
new LargeHeapBlock: addr = 0x16ccb200
new LargeHeapBlock: addr = 0x16ccb260
new LargeHeapBlock: addr = 0x16ccb2c0
new LargeHeapBlock: addr = 0x16ccb320
new LargeHeapBlock: addr = 0x16ccb380
new LargeHeapBlock: addr = 0x16ccb3e0
new LargeHeapBlock: addr = 0x16ccb440
new LargeHeapBlock: addr = 0x16ccb4a0
new LargeHeapBlock: addr = 0x16ccb500
new LargeHeapBlock: addr = 0x16ccb560
new LargeHeapBlock: addr = 0x16ccb5c0
new LargeHeapBlock: addr = 0x16ccb620
new LargeHeapBlock: addr = 0x16ccb680
new LargeHeapBlock: addr = 0x16ccb6e0
new LargeHeapBlock: addr = 0x16ccb740
new LargeHeapBlock: addr = 0x16ccb7a0
new LargeHeapBlock: addr = 0x16ccb800
new LargeHeapBlock: addr = 0x16ccb860
new LargeHeapBlock: addr = 0x16ccb8c0
new LargeHeapBlock: addr = 0x16ccb920
new LargeHeapBlock: addr = 0x16ccb980
new LargeHeapBlock: addr = 0x16ccb9e0
new LargeHeapBlock: addr = 0x16ccba40
new LargeHeapBlock: addr = 0x16ccbaa0
new LargeHeapBlock: addr = 0x16ccbb00
new LargeHeapBlock: addr = 0x16ccbb60
new LargeHeapBlock: addr = 0x16ccbbc0
new LargeHeapBlock: addr = 0x16ccbc20
new LargeHeapBlock: addr = 0x16ccbc80
new LargeHeapBlock: addr = 0x16ccbce0
new LargeHeapBlock: addr = 0x16ccbd40
new LargeHeapBlock: addr = 0x16ccbda0
new LargeHeapBlock: addr = 0x16ccbe00
new LargeHeapBlock: addr = 0x16ccbe60
new LargeHeapBlock: addr = 0x16ccbec0
new LargeHeapBlock: addr = 0x16ccbf20
new LargeHeapBlock: addr = 0x16ccbf80
new LargeHeapBlock: addr = 0x16ccc020
new LargeHeapBlock: addr = 0x16ccc080
new LargeHeapBlock: addr = 0x16ccc0e0
new LargeHeapBlock: addr = 0x16ccc140
new LargeHeapBlock: addr = 0x16ccc1a0
new LargeHeapBlock: addr = 0x16ccc200
new LargeHeapBlock: addr = 0x16ccc260
new LargeHeapBlock: addr = 0x16ccc2c0
new LargeHeapBlock: addr = 0x16ccc320
new LargeHeapBlock: addr = 0x16ccc380
new LargeHeapBlock: addr = 0x16ccc3e0
new LargeHeapBlock: addr = 0x16ccc440
new LargeHeapBlock: addr = 0x16ccc4a0
new LargeHeapBlock: addr = 0x16ccc500
new LargeHeapBlock: addr = 0x16ccc560
new LargeHeapBlock: addr = 0x16ccc5c0
new LargeHeapBlock: addr = 0x16ccc620
new LargeHeapBlock: addr = 0x16ccc680
new LargeHeapBlock: addr = 0x16ccc6e0
new LargeHeapBlock: addr = 0x16ccc740
new LargeHeapBlock: addr = 0x16ccc7a0
new LargeHeapBlock: addr = 0x16ccc800
new LargeHeapBlock: addr = 0x16ccc860
new LargeHeapBlock: addr = 0x16ccc8c0
new LargeHeapBlock: addr = 0x16ccc920
new LargeHeapBlock: addr = 0x16ccc980
new LargeHeapBlock: addr = 0x16ccc9e0
new LargeHeapBlock: addr = 0x16ccca40
new LargeHeapBlock: addr = 0x16cccaa0
new LargeHeapBlock: addr = 0x16cccb00
new LargeHeapBlock: addr = 0x16cccb60
new LargeHeapBlock: addr = 0x16cccbc0
new LargeHeapBlock: addr = 0x16cccc20
new LargeHeapBlock: addr = 0x16cccc80
new LargeHeapBlock: addr = 0x16cccce0
new LargeHeapBlock: addr = 0x16cccd40
new LargeHeapBlock: addr = 0x16cccda0
new LargeHeapBlock: addr = 0x16ccce00
new LargeHeapBlock: addr = 0x16ccce60
new LargeHeapBlock: addr = 0x16cccec0
new LargeHeapBlock: addr = 0x16cccf20
new LargeHeapBlock: addr = 0x16cccf80
new LargeHeapBlock: addr = 0x1364e060
new LargeHeapBlock: addr = 0x1364e0c0
new LargeHeapBlock: addr = 0x1364e120
new LargeHeapBlock: addr = 0x1364e180
new LargeHeapBlock: addr = 0x1364e1e0
new LargeHeapBlock: addr = 0x1364e240
new LargeHeapBlock: addr = 0x1364e2a0
new LargeHeapBlock: addr = 0x1364e300
new LargeHeapBlock: addr = 0x1364e360
new LargeHeapBlock: addr = 0x1364e3c0
new LargeHeapBlock: addr = 0x1364e420
new LargeHeapBlock: addr = 0x1364e480
new LargeHeapBlock: addr = 0x1364e4e0
new LargeHeapBlock: addr = 0x1364e540
new LargeHeapBlock: addr = 0x1364e5a0
new LargeHeapBlock: addr = 0x1364e600
new LargeHeapBlock: addr = 0x1364e660
new LargeHeapBlock: addr = 0x1364e6c0
new LargeHeapBlock: addr = 0x1364e720
new LargeHeapBlock: addr = 0x1364e780
new LargeHeapBlock: addr = 0x1364e7e0
new LargeHeapBlock: addr = 0x1364e840
new LargeHeapBlock: addr = 0x1364e8a0
new LargeHeapBlock: addr = 0x1364e900
new LargeHeapBlock: addr = 0x1364e960
new LargeHeapBlock: addr = 0x1364e9c0
new LargeHeapBlock: addr = 0x1364ea20
new LargeHeapBlock: addr = 0x1364ea80
new LargeHeapBlock: addr = 0x1364eae0
new LargeHeapBlock: addr = 0x1364eb40
new LargeHeapBlock: addr = 0x1364eba0
new LargeHeapBlock: addr = 0x1364ec00
new LargeHeapBlock: addr = 0x1364ec60
new LargeHeapBlock: addr = 0x1364ecc0
new LargeHeapBlock: addr = 0x1364ed20
new LargeHeapBlock: addr = 0x1364ed80
new LargeHeapBlock: addr = 0x1364ede0
new LargeHeapBlock: addr = 0x1364ee40
new LargeHeapBlock: addr = 0x1364eea0
new LargeHeapBlock: addr = 0x1364ef00
new LargeHeapBlock: addr = 0x1364ef60
new LargeHeapBlock: addr = 0x1364efc0
new LargeHeapBlock: addr = 0x1364f060
new LargeHeapBlock: addr = 0x1364f0c0
new LargeHeapBlock: addr = 0x1364f120
new LargeHeapBlock: addr = 0x1364f180
new LargeHeapBlock: addr = 0x1364f1e0
new LargeHeapBlock: addr = 0x1364f240
new LargeHeapBlock: addr = 0x1364f2a0
new LargeHeapBlock: addr = 0x1364f300
new LargeHeapBlock: addr = 0x1364f360
new LargeHeapBlock: addr = 0x1364f3c0

Смотрим на последние 6 адресов:

new LargeHeapBlock: addr = 0x1364f1e0
new LargeHeapBlock: addr = 0x1364f240
new LargeHeapBlock: addr = 0x1364f2a0
new LargeHeapBlock: addr = 0x1364f300
new LargeHeapBlock: addr = 0x1364f360
new LargeHeapBlock: addr = 0x1364f3c0

Стоит заметить, что они разделены по 0х60 байт: 0х8 байт для выделенного заголовка и 0х58 для объекта LargeHeapBlock. Вот последние 6 LargeHeapBlocks в памяти:

Как видно из рисунка выше, каждый LargeHeapBlock содержит смещение 0х24 и указатель на предыдущий LargeHeapBlock. Этот указатель будет использовать позже, с целью определения адреса самого LeageHeapBlock.

ArrayBuffer & Int32Array

Вот что говорит MDN (Mozilla Developer Network) о ArrayBuffer:

Рассмотрим следующий пример:

// Создает ArrayBuffer вручную.
buf = new ArrayBuffer(400*1024*1024);
a = new Int32Array(buf);
 
// Создает ArrayBuffer автоматически.
a2 = new Int32Array(100*1024*1024);

Массивы a и а2 эквивалентны и имеют одинаковый размер. При создании ArrayBuffer напрямую, нам надо указать размер в байтах, в отличии от Int32Array, где надо указать длину количеством элементов (32-х битных целых чисел - integer). Стоит обратить внимание на тот факт, что при создании Int32Array, ArrayBuffer создает внутри и Int32Array использует его.

Что бы разобраться какой код создает ArrayBuffer, нам надо произвести «распыление кучи» (heap spray) до этого. Воспользуемся следующим javascript кодом:

<html>
<head>
<script language="javascript">
  alert("Start");
  var a = new Array();
  for (var i = 0; i < 0x10000; ++i) {
    a[i] = new Int32Array(0x1000/4);
    for (var j = 0; j < a[i].length; ++j)
      a[i][j] = 0x123;
  }
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Когда диалоговое окно Done появится, мы сможем посмотреть на память используя VMMap.

Вот что мы увидим:

В этот раз нам говорят Heap (Private D …, что значит - ArrayBuffers выделен прямо в куче. Если посмотрим по адресу f650000 в WinDbg, мы увидим следующее:

0f650000: 03964205 0101f3c5 ffeeffee 00000000 10620010 0e680010 00450000 0f650000
0f650020: 00000fd0 0f650040 10620000 0000000f 00000001 00000000 10610ff0 10610ff0
0f650040: 839ec20d 0801f3cd 0a73f528 0c6dcc48 00000012 f0e0d0c0 39682cf0 88000000
0f650060: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f650080: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500a0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500c0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500e0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123

Наши данные начинаются с f650060. Так как это в куче, используем !heap:

0:012> !heap -p -a f650060
    address 0f650060 found in
    _HEAP @ 450000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0f650058 0201 0000  [00]   0f650060    01000 - (busy)

Как всегда, здесь 8 байт выделенного заголовка. Если перезагрузим страницу в IE и вернемся в WinDbg, мы увидим что ситуация изменилась:

0f650000: 03964205 0101f3c5 ffeeffee 00000000 10620010 0e680010 00450000 0f650000
0f650020: 00000fd0 0f650040 10620000 000000cc 00000004 00000000 10310ff0 10610ff0
0f650040: 839ec20d 0801f3cd 129e0158 11119048 00000012 f0e0d0c0 2185d880 88000000
0f650060: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f650080: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500a0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500c0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123
0f6500e0: 00000123 00000123 00000123 00000123 00000123 00000123 00000123 00000123

Это значит, что мы можем установить аппаратную точку останова по адресу 0f650058 (выше HEAP_ENTRY) и прерватся в коде который производит выделение блоков памяти в куче. Перезагрузите страницу в IE и установите точку останова в WinDbg:

0:013> ba w4 f650058

После закрытия диалогового окна в IE, мы окажемся здесь:

772179ff 331da4002e77    xor     ebx,dword ptr [ntdll!RtlpLFHKey (772e00a4)]
77217a05 c6410780        mov     byte ptr [ecx+7],80h
77217a09 33d8            xor     ebx,eax
77217a0b 33de            xor     ebx,esi
77217a0d ff4df4          dec     dword ptr [ebp-0Ch]
77217a10 8919            mov     dword ptr [ecx],ebx
77217a12 c60200          mov     byte ptr [edx],0           ds:002b:0f65005e=00  <----------- мы здесь
77217a15 75be            jne     ntdll!RtlpSubSegmentInitialize+0xe5 (772179d5)
77217a17 8b5d08          mov     ebx,dword ptr [ebp+8]
77217a1a 8b45f8          mov     eax,dword ptr [ebp-8]
77217a1d baffff0000      mov     edx,0FFFFh
77217a22 66895108        mov     word ptr [ecx+8],dx
77217a26 668b4df0        mov     cx,word ptr [ebp-10h]
77217a2a 66894e10        mov     word ptr [esi+10h],cx

Вывод стека:

0:004> k 10
ChildEBP RetAddr  
057db90c 77216e87 ntdll!RtlpSubSegmentInitialize+0x122
057db9a8 7720e0f2 ntdll!RtlpLowFragHeapAllocFromContext+0x882
057dba1c 75de9d45 ntdll!RtlAllocateHeap+0x206
057dba3c 6f7f4613 msvcrt!malloc+0x8d
057dba4c 6f643cfa jscript9!memset+0x3a4c2
057dba64 6f79fc00 jscript9!Js::JavascriptArrayBuffer::Create+0x3c   <----------------
057dba90 6f79af10 jscript9!Js::TypedArrayBase::CreateNewInstance+0x1cf   <----------------
057dbb08 6f5c7461 jscript9!Js::TypedArray<int>::NewInstance+0x55   <----------------
057dbca4 6f5a5cf5 jscript9!Js::InterpreterStackFrame::Process+0x4b47
057dbdd4 04a70fe9 jscript9!Js::InterpreterStackFrame::InterpreterThunk<1>+0x305
WARNING: Frame IP not in any known module. Following frames may be wrong.
057dbde0 6f5a1f60 0x4a70fe9
057dbe60 6f5a20ca jscript9!Js::JavascriptFunction::CallRootFunction+0x140
057dbe78 6f5a209f jscript9!Js::JavascriptFunction::CallRootFunction+0x19
057dbec0 6f5a2027 jscript9!ScriptSite::CallRootFunction+0x40
057dbee8 6f64df75 jscript9!ScriptSite::Execute+0x61
057dbf74 6f64db57 jscript9!ScriptEngine::ExecutePendingScripts+0x1e9

Отлично! Мы видим что ArrayBuffer выделен с помощью функции malloc языка программирования С, которая была вызвана внутри jscript9!Js::JavascriptArrayBuffer::Create. TypedArray скорее всего наш Int32Array и TypedArrayBase его базовый класс. Следуя этому, jscript9!Js::TypedArray::NewInstance создает новый Int32Array и новый JavascriptArrayBuffer. Теперь мы должны взглянуть на Int32Array в памяти. Нам больше не нужно выполнять распыление кучи, просто изменим код:

<html>
<head>
<script language="javascript">
  alert("Start");
  a = new Int32Array(0x1000);
  for (var j = 0; j < a.length; ++j)
    a[j] = 0x123;
  alert("Done");
</script>
</head>
<body>
</body>
</html>

Установим точку останова на момент создания нового Int32Array:

0:013> bp jscript9!Js::TypedArray<int>::NewInstance
Couldn't resolve error at 'jscript9!Js::TypedArray<int>::NewInstance'
The breakpoint expression "jscript9!Js::TypedArray<int>::NewInstance" evaluates to the inline function.
Please use bm command to set breakpoints instead of bp.

Попробуем использовать mb вместо bp:

0:013> bm jscript9!Js::TypedArray<int>::NewInstance
  1: 6f79aebb          @!"jscript9!Js::TypedArray<int>::NewInstance"
0:013> bl
 1 e 6f79aebb     0001 (0001)  0:**** jscript9!Js::TypedArray<int>::NewInstance

ОК, кажеться работает. Теперь перезагрузите страницу в IE. Когда мы закроем диалоговое окно то мы попадем на jscript9!Js::TypedArray::NewInstance.

Код функции целиком:

0:004> uf 6f79aebb
jscript9!Js::TypedArray<int>::NewInstance:
6f79aebb 8bff            mov     edi,edi
6f79aebd 55              push    ebp
6f79aebe 8bec            mov     ebp,esp
6f79aec0 83e4f8          and     esp,0FFFFFFF8h
6f79aec3 83ec0c          sub     esp,0Ch
6f79aec6 53              push    ebx
6f79aec7 8b5d08          mov     ebx,dword ptr [ebp+8]
6f79aeca 8b4304          mov     eax,dword ptr [ebx+4]
6f79aecd 8b4004          mov     eax,dword ptr [eax+4]
6f79aed0 8b4804          mov     ecx,dword ptr [eax+4]
6f79aed3 56              push    esi
6f79aed4 57              push    edi
6f79aed5 6a00            push    0
6f79aed7 51              push    ecx
6f79aed8 8b8934020000    mov     ecx,dword ptr [ecx+234h]
6f79aede ba00040000      mov     edx,400h
6f79aee3 e8b2e7e0ff      call    jscript9!ThreadContext::ProbeStack (6f5a969a)
6f79aee8 8d4510          lea     eax,[ebp+10h]
6f79aeeb 50              push    eax
6f79aeec 8d7d0c          lea     edi,[ebp+0Ch]
6f79aeef 8d742414        lea     esi,[esp+14h]
6f79aef3 e8cb93e0ff      call    jscript9!Js::ArgumentReader::ArgumentReader (6f5a42c3)
6f79aef8 8b4304          mov     eax,dword ptr [ebx+4]
6f79aefb 8b4004          mov     eax,dword ptr [eax+4]
6f79aefe 6850bd726f      push    offset jscript9!Js::TypedArray<int>::Create (6f72bd50)
6f79af03 6a04            push    4
6f79af05 ff7004          push    dword ptr [eax+4]
6f79af08 8bc6            mov     eax,esi
6f79af0a 50              push    eax
6f79af0b e8214b0000      call    jscript9!Js::TypedArrayBase::CreateNewInstance (6f79fa31)
6f79af10 5f              pop     edi
6f79af11 5e              pop     esi
6f79af12 5b              pop     ebx
6f79af13 8be5            mov     esp,ebp
6f79af15 5d              pop     ebp
6f79af16 c3              ret

Заходя внутрь функции jscript9!Js::TypedArrayBase::CreateNewInstance мы наткнемся на jscript9!Js::TypedArray::Create:

6f79fc16 ffb608060000    push    dword ptr [esi+608h]
6f79fc1c 57              push    edi
6f79fc1d 51              push    ecx
6f79fc1e 53              push    ebx
6f79fc1f ff5514          call    dword ptr [ebp+14h]  ss:002b:057dba9c={jscript9!Js::TypedArray<int>::Create (6f72bd50)}
Если мы зайдем внутрь jscript9!Js::TypedArray<int>::Create, мы окажемся возле вызова Alloc:
6f72bd88 8b7514          mov     esi,dword ptr [ebp+14h] ss:002b:057dba64=04b6b000
6f72bd8b 8b4e0c          mov     ecx,dword ptr [esi+0Ch]
6f72bd8e 6a24            push    24h      <----------------- 24h байта
6f72bd90 e893b2e6ff      call    jscript9!Recycler::Alloc (6f597028)
6f72bd95 ffb61c010000    push    dword ptr [esi+11Ch]
6f72bd9b ff7510          push    dword ptr [ebp+10h]
6f72bd9e ff750c          push    dword ptr [ebp+0Ch]
6f72bda1 57              push    edi
6f72bda2 50              push    eax
6f72bda3 e898f7ffff      call    jscript9!Js::TypedArray<int>::TypedArray<int> (6f72b540)
6f72bda8 5f              pop     edi
6f72bda9 5e              pop     esi
6f72bdaa c9              leave
6f72bdab c21000          ret     10h

Мы видим что размер TypedArray равен 24h байтов. Заметьте что объект сперва был выделен, а потом инициализирован конструктором.
Что бы вывести сообщение при создании Int32Array, мы просто установим точку останова на конец jscript9!Js::TypedArray::NewInstance, сразу после вызова jscript9!Js::TypedArrayBase::CreateNewInstance (смотрите на указатель в коде):

jscript9!Js::TypedArray<int>::NewInstance:
6f79aebb 8bff            mov     edi,edi
6f79aebd 55              push    ebp
6f79aebe 8bec            mov     ebp,esp
6f79aec0 83e4f8          and     esp,0FFFFFFF8h
6f79aec3 83ec0c          sub     esp,0Ch
6f79aec6 53              push    ebx
6f79aec7 8b5d08          mov     ebx,dword ptr [ebp+8]
6f79aeca 8b4304          mov     eax,dword ptr [ebx+4]
6f79aecd 8b4004          mov     eax,dword ptr [eax+4]
6f79aed0 8b4804          mov     ecx,dword ptr [eax+4]
6f79aed3 56              push    esi
6f79aed4 57              push    edi
6f79aed5 6a00            push    0
6f79aed7 51              push    ecx
6f79aed8 8b8934020000    mov     ecx,dword ptr [ecx+234h]
6f79aede ba00040000      mov     edx,400h
6f79aee3 e8b2e7e0ff      call    jscript9!ThreadContext::ProbeStack (6f5a969a)
6f79aee8 8d4510          lea     eax,[ebp+10h]
6f79aeeb 50              push    eax
6f79aeec 8d7d0c          lea     edi,[ebp+0Ch]
6f79aeef 8d742414        lea     esi,[esp+14h]
6f79aef3 e8cb93e0ff      call    jscript9!Js::ArgumentReader::ArgumentReader (6f5a42c3)
6f79aef8 8b4304          mov     eax,dword ptr [ebx+4]
6f79aefb 8b4004          mov     eax,dword ptr [eax+4]
6f79aefe 6850bd726f      push    offset jscript9!Js::TypedArray<int>::Create (6f72bd50)
6f79af03 6a04            push    4
6f79af05 ff7004          push    dword ptr [eax+4]
6f79af08 8bc6            mov     eax,esi
6f79af0a 50              push    eax
6f79af0b e8214b0000      call    jscript9!Js::TypedArrayBase::CreateNewInstance (6f79fa31)
6f79af10 5f              pop     edi      <---------------------- точка останова тут
6f79af11 5e              pop     esi
6f79af12 5b              pop     ebx
6f79af13 8be5            mov     esp,ebp
6f79af15 5d              pop     ebp
6f79af16 c3              ret

Вот точка останова:

bp jscript9+20af10 ".printf \"new TypedArray<int>: addr = 0x%p\\n\",eax;g"

Мы также должны обратить внимание на jscript9!Js::JavascriptArrayBuffer::Create:

0:004> uf jscript9!Js::JavascriptArrayBuffer::Create
jscript9!Js::JavascriptArrayBuffer::Create:
6f643cbe 8bff            mov     edi,edi
6f643cc0 55              push    ebp
6f643cc1 8bec            mov     ebp,esp
6f643cc3 53              push    ebx
6f643cc4 8b5d08          mov     ebx,dword ptr [ebp+8]
6f643cc7 56              push    esi
6f643cc8 57              push    edi
6f643cc9 8bf8            mov     edi,eax
6f643ccb 8b4304          mov     eax,dword ptr [ebx+4]
6f643cce 8b4004          mov     eax,dword ptr [eax+4]
6f643cd1 8bb064040000    mov     esi,dword ptr [eax+464h]
6f643cd7 01be04410000    add     dword ptr [esi+4104h],edi
6f643cdd e85936f5ff      call    jscript9!Recycler::CollectNow<402722819> (6f59733b)
6f643ce2 6a18            push    18h     <----------- 18h bytes
6f643ce4 8bce            mov     ecx,esi
6f643ce6 e8b958f5ff      call    jscript9!Recycler::AllocFinalized (6f5995a4)
6f643ceb ff353cb1826f    push    dword ptr [jscript9!_imp__malloc (6f82b13c)]   <--------------------
6f643cf1 8bf0            mov     esi,eax
6f643cf3 8bcb            mov     ecx,ebx
6f643cf5 e863010000      call    jscript9!Js::ArrayBuffer::ArrayBuffer<void * (__cdecl*)(unsigned int)> (6f643e5d)
6f643cfa 5f              pop     edi
6f643cfb c706103d646f    mov     dword ptr [esi],offset jscript9!Js::JavascriptArrayBuffer::`vftable' (6f643d10)
6f643d01 8bc6            mov     eax,esi
6f643d03 5e              pop     esi
6f643d04 5b              pop     ebx
6f643d05 5d              pop     ebp
6f643d06 c20400          ret     4    <----------- ставим точку останова тут

Из вывода следует что ArrayBuffer это объект размером в 18h выделенный через jscript9!Recycler::AllocFinalized. Можно с уверенностью сказать, что ArrayBuffer содержит указатель на блок памяти с пользовательсскими данными. По сути, вы можете видеть как jscript9!_imp__malloc передается в конструктор ArrayBuffer и мы знаем что буфер с необработанными данными действительно выделяется с помощью С функции malloc.

Теперь мы можем поставить точку останова на конец функции:

bp jscript9!Js::JavascriptArrayBuffer::Create+0x48 ".printf \"new JavascriptArrayBuffer: addr = 0x%p\\n\",eax;g"

Эти объекти легки для анализа. Вот что мы изучили на протяжении статьи:

© Translated by klaus (r0 Crew)