Page 1 of 5

Эмуляция KolibriOS API

Posted: Sun Mar 04, 2018 9:00 pm
by 0CodErr
Эмулятор mike.dld MeOSEmul работает как интерпретатор, эмулятор diamond-a KlbrInWin — как дебаггер,
ну а я же хочу просто установить свой обработчик исключений и в нём обрабатывать вызовы KolibriOS.

Но для начала нужно загрузить приложение. В самой KolibriOS приложения грузятся по смещению 0.
У diamond-a реализовано с помощью SetLdtEntries, что позволяет грузить не по нулевому смещению.
Я не стану использовать такой способ, а буду загружать именно по нулевому смещению :)

Сперва посмотрим, а что у нас находится по смещению 0 в адресном пространстве приложения после его загрузки.
Посмотрим на скриншот распределения памяти(есть замечательная программа VMMap, спасибо Руссиновичу за это :) )
Spoiler:
mem_map1.PNG
mem_map1.PNG (57.38 KiB)
Viewed 16484 times
Кстати, хорошая статья про распределение памяти https://habrahabr.ru/post/202242/
Как видно, регион 0..64K свободен, значит мы можем его использовать, нужно только выделить память в нуле.
Я буду это делать вот так:

Code: Select all

BaseAddress := Pointer(1); RegionSize  := 1024 * 64 - 1;
NtAllocateVirtualMemory(GetCurrentProcess, @BaseAddress, 0, @RegionSize, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE);   
Функция NtAllocateVirtualMemory из ntdll определена вот так:

Code: Select all

Function NtAllocateVirtualMemory(ProcessHandle: THandle; BaseAddress: PPChar; ZeroBits: Dword; RegionSize: PDword; AllocationType: Dword; Protect: Dword): Pointer; StdCall; External 'ntdll';
Обнаружил ограничения этого:
NULL page mitigations for Windows 8 (both x86 and x64), and even backported the mitigation to Vista+
Я тут нашёл кое-что про EMET https://habrahabr.ru/company/eset/blog/184428/ там есть что-то про NullPage, судя по скриншотам это можно как включить, так и выключить.
То есть, если правильно понимаю, надо отключить NullPage в EMET чтобы выделение памяти в нуле заработало.
Вот здесь https://www.atraining.ru/emet-4-0-windo ... r-2012-r2/ кое-что объясняется:
Что такое Null Page Allocation (NPA)
Это защита от достаточно интересной атаки, базирующаяся на предположении, что зловредный код “займёт” для себя страницу с адресом 0x0 в адресном пространстве приложения.
Для этого сама программа – EMET – занимает адрес 0x0. Впрок, так сказать.
Что интересно, если вызвать VirtualAlloc с параметром 0, то VirtualAlloc (что, в общем-то, логично) выделит память по адресу, который выберет сама, а не по нулевому.
Для того, чтобы “застолбить” за собой такой адрес, как предполагается, применяется вызов NtAllocateVirtualMemory, у которой запрашивается адрес 0x1, при попытке выделения которого выделяется блок, начинающийся с 0x0.
На данный момент зловредов, использующих эту возможность, не обнаружено.
Включить NPA можно как и EAF – только для явно указанных приложений, а не на уровне системы.
Когда эта технология включена, “нулевая” страница при запуске приложения будет занята в профилактических целях.

Да, как видно, память чуть выше уже занята, и её использовать сейчас не получится(хотя всё ещё можно аллоцировать её динамически из кучи, например)
У нас сначала идёт CODE из System, вот если бы можно было вставить в самое начало большой кусок ненужных данных или кода, которые можно было бы потом затереть...

Code: Select all

Detailed map of segments

 0001:00000000 0000277B C=CODE     S=.text    G=(none)   M=System   ACBP=A9
 0001:0000277C 00000140 C=CODE     S=.text    G=(none)   M=SysInit  ACBP=A9
 0001:000028BC 00000038 C=CODE     S=.text    G=(none)   M=Types    ACBP=A9
 0001:000028F4 00000190 C=CODE     S=.text    G=(none)   M=Windows  ACBP=A9
 0001:00002A84 00000038 C=CODE     S=.text    G=(none)   M=Messages ACBP=A9
 0001:00002ABC 00001780 C=CODE     S=.text    G=(none)   M=KEm      ACBP=A9
 0002:00000000 00000088 C=DATA     S=.data    G=DGROUP   M=System   ACBP=A9
 0002:00000088 0000001C C=DATA     S=.data    G=DGROUP   M=SysInit  ACBP=A9
 0002:000000A4 0000000C C=DATA     S=.data    G=DGROUP   M=KEm      ACBP=A9
 0002:00001000 0000064C C=BSS      S=.bss     G=DGROUP   M=System   ACBP=A9
 0002:0000164C 00000010 C=BSS      S=.bss     G=DGROUP   M=SysInit  ACBP=A9
 0002:0000165C 00000004 C=BSS      S=.bss     G=DGROUP   M=Types    ACBP=A9
 0002:00001660 00000004 C=BSS      S=.bss     G=DGROUP   M=Windows  ACBP=A9
 0002:00001664 00000004 C=BSS      S=.bss     G=DGROUP   M=Messages ACBP=A9
 0002:00001668 0000FA34 C=BSS      S=.bss     G=DGROUP   M=KEm      ACBP=A9
Пока только пришло на ум следующее:
компилятор позволяет собрать приложение с ImageBase = 64 K:
Spoiler:
mem_map.PNG
mem_map.PNG (56.89 KiB)
Viewed 16484 times
тогда можно сделать сам эмулятор как библиотеку и запустить её из приложения с ImageBase = 64K(сам этот загрузчик можно искусственно раздуть до нужных размеров, чтобы потом после запуска самого эмулятора можно было благополучно затереть), загрузить kex, проверить сколько реально нужно, ненужное освободить.
Имею в виду, в Dll будет функция Main, а загрузчик:

Code: Select all

.DATA
db MEM_SIZE dup ?
.CODE
jmp Main
Может быть кто-то знает более рациональный вариант? Пока что для тестов 64K должно хватить, а дальше дело техники :)

Итак, приложения у нас могут быть упакованные с помощью kpack.
Но не зря же я делал unpack http://board.kolibrios.org/viewtopic.ph ... 118#p69118 :)
То есть, запакованные kex-файлы тоже будут поддерживаться.

После загрузки приложения установим обработчик исключений, по умолчанию обнулим регистры и поехали!

Code: Select all

Asm
  (* set our exception handler *)
    push Offset ExceptionHandler
    push Dword Ptr fs:[0]
    mov  fs:[0], esp  
  (* set registers and flags by default *)  
    xor eax, eax
    xor ebx, ebx
    xor ecx, ecx
    xor edx, edx
    xor esi, esi
    xor edi, edi
    xor ebp, ebp
    push 0; popfd
  (* goto entry point *)  
    jmp  eip
  End;    
     
В обработчике исключений мы проверяем, чем конкретно вызвано исключение, и если это вызов ядра KolibriOS, то соответственно обрабатываем его:

Code: Select all

     If (ExceptionCode = EXCEPTION_ACCESS_VIOLATION) And (Word(ExceptionAddress^) = $40CD) Then

Re: Эмуляция KolibriOS API

Posted: Sun Mar 04, 2018 10:43 pm
by Leency
Жду продолжения этой детективной стории :)

Re: Эмуляция KolibriOS API

Posted: Mon Mar 05, 2018 2:55 pm
by tsdima
Leency wrote:Жду продолжения этой детективной стории :)
В качестве продолжения.

В конце прошлого года я наткнулся на тему "Простой загрузчик ELF для Колибри" и там была ссылка на тему "Эмулятор под Linux", на которую я 10 лет назад не обратил внимание. А поскольку пару лет назад я пересел на Linux, то с интересом посмотрел на изыскания diamond-а и Ghost-а. Посмотрев на примеры и добившись их работы на 64-битной Ubuntu, мне показалось, что сделать эмулятор будет несложно. На деле же я столкнулся с массой проблем, так что разработка эмулятора растянулась на несколько месяцев (свободного от работы времени).

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

Re: Эмуляция KolibriOS API

Posted: Tue Mar 06, 2018 10:40 am
by 0CodErr
Сейчас приложения действительно грузятся по нулевому смещению, вот в Borland debugger
Spoiler:
KexInBORdbg.PNG
KexInBORdbg.PNG (68.29 KiB)
Viewed 16420 times
а вот в Olly debugger
Spoiler:
KexInOllydbg.PNG
KexInOllydbg.PNG (54.43 KiB)
Viewed 16420 times
При включенном DEBUG_OUTPUT(раскомментированном {$DEFINE DEBUG_OUTPUT}) в исходнике, происходит отладочный вывод в консоль: это значения регистров на момент вызова, а также названия вызываемых функций и переданные параметры, это преобразуется в такой вид, как если бы была вызвана соответствующая функция из KolibriOS.lib(её можно найти в теме Delphi7 examples http://board.kolibrios.org/viewtopic.php?f=33&t=3469):
Spoiler:
test_console.PNG
test_console.PNG (41.02 KiB)
Viewed 16420 times
Внутри сами эти функции имеют такой же интерфейс, например вот вызов DrawRectangle, параметры извлекаются из регистров:

Code: Select all

13: DrawRectangle(Ebx Shr 16, Ecx Shr 16, Ebx And $0000FFFF, Ecx And $0000FFFF, Edx);
Вот так выглядят вызовы программы Pipet(http://board.kolibrios.org/viewtopic.ph ... 926#p68926):
Spoiler:
pipet_console.PNG
pipet_console.PNG (47.56 KiB)
Viewed 16420 times
После того, как вызов функции KolibriOS отработал, нужно увеличить адрес на длину соответствующей инструкции:

Code: Select all

Inc(Eip, SizeOf(Word($40CD)));
Так как я с загрузкой скинов ещё не работал, то в данный момент они не поддерживаются, я знаю, что скины могут быть сжаты kpack-ом, но распаковка таких файлов уже поддерживается для самих приложений, можно будет сделать это и для скинов.

Сейчас программа при запуске грузит файл, переданный в качестве параметра командной строки(например, можно перетащить мышкой значок kex на значок эмулятора)

Code: Select all

  If ParamCount > 0 Then
    FileName := PChar(ParamStr(1))
Также можно загрузить файл, выбранный из OpenDialog(на самом деле приложение перезапускается, в качестве параметра командной строки передаётся путь из OpenDialog(а всё из-за того, что OpenDialog не завершает свои потоки и не освобождает ресурсы)):

Code: Select all

If CommDlg.GetOpenFileName(OpenFile) Then

Re: Эмуляция KolibriOS API

Posted: Fri Mar 09, 2018 2:16 pm
by 0CodErr
Для теста сейчас я взял пример SetPixel из темы Delphi7 examples http://board.kolibrios.org/viewtopic.php?f=33&t=3469

Сейчас скины не поддерживаются, также не учитываются клиентские координаты окна,
но таскать окно за заголовок можно, можно использовать двойной щелчок по заголовку,
ещё можно изменять размеры окна с помощью мыши(хотя это и не очевидно в отсутствие скинов).

Вот для сравнения с KlbrInWin
Spoiler:
KEm_KIW(SetPixel).PNG
KEm_KIW(SetPixel).PNG (10.76 KiB)
Viewed 16357 times
Было бы интересно узнать, как это работает на разных версиях Windows(и работает ли вообще).

Некоторые демо программы работают(bcdclk, cslide);
Spoiler:
bcdclk+setpixel+cslide.PNG
bcdclk+setpixel+cslide.PNG (18 KiB)
Viewed 16357 times
Вот magnify и iconedit:
Spoiler:
magnify+iconedit.PNG
magnify+iconedit.PNG (33.45 KiB)
Viewed 16357 times
В подавляющем большинстве приложения KolibriOS имеют сигнатуру MENUET01, но некоторые старые — MENUET00, некоторые новые — MENUET02, так вот, на текущий момент они не поддерживаются.

В папке Tests есть некоторые примеры, их исходники или на svn, или на форуме(SetPixel http://board.kolibrios.org/viewtopic.ph ... 469#p68384, GetScreenImage http://board.kolibrios.org/viewtopic.ph ... 469#p69039), поэтому не стал их туда включать.
KEm.7z (35.4 KiB)
Downloaded 443 times

Re: Эмуляция KolibriOS API

Posted: Fri Mar 09, 2018 3:00 pm
by Kopa
0CodErr wrote:Было бы интересно узнать, как это работает на разных версиях Windows(и работает ли вообще).
В XP работает. Попробовал запустить Tetris. Запустился, но управления от клавиш нет.
В Win8.1 при попытке загрузить программу в консоле пишет "Read File error"

P.S. В принципе - работает. :)

Re: Эмуляция KolibriOS API

Posted: Fri Mar 09, 2018 3:07 pm
by 0CodErr
Kopa, я писал в первом сообщении про EMET.
Не в курсе просто, как оно там в Win8.1 устроено, может на уровне системы заблокировано, а может быть можно в настройках регулировать.
"Read File error" — значит, что не загружен файл куда надо(по смещению 0).

Re: Эмуляция KolibriOS API

Posted: Fri Mar 09, 2018 3:12 pm
by Kopa
Проверил ещё в ReactOS,тоже принципиально работает.

P.S. Какие то файлы не проходят верификацию загрузки.

Re: Эмуляция KolibriOS API

Posted: Fri Mar 09, 2018 3:16 pm
by 0CodErr
Kopa wrote:Какие то файлы не проходят верификацию загрузки.
0CodErr wrote:В подавляющем большинстве приложения KolibriOS имеют сигнатуру MENUET01, но некоторые старые — MENUET00, некоторые новые — MENUET02, так вот, на текущий момент они не поддерживаются.

Re: Эмуляция KolibriOS API

Posted: Sat Mar 10, 2018 2:30 am
by Kopa
Из игрушек запустилась и играбельна marblematch.
Pong3 запустилась, но без управления.

P.S. Чаще всего происходит крэш программы, как с возможностью сохранить дамп так и без каких либо сообщений.

Re: Эмуляция KolibriOS API

Posted: Sun Mar 11, 2018 11:50 am
by 0CodErr
Kopa wrote:Из игрушек запустилась и играбельна marblematch.
Эта игра почему-то создаёт окно с заголовком Heliothryx :?:

Code: Select all

EIP    = $0000007B; EAX    = $00000000; EBX    = $00640209; ECX    = $00640213
EDX    = $74DDDDFF; ESI    = $34DDDDFF; EDI    = $00005C18; EBP    = $0412FE60
ESP    = $0412FE10; EFLAGS = $00010202
DrawWindow(Left:100, Top:100, Width:521, Height:531, Caption:"Heliothryx", BackC
olor:$ddddff, Style:$74000000, CapStyle:$34ddddff)
Наверное, они просто друг у друга код скопировали :lol:
Kopa wrote:Pong3 запустилась, но без управления.
Ввод с клавиатуры сейчас не поддерживается(вообще, думаю, по исходнику это заметно).
Kopa wrote:Чаще всего происходит крэш программы
Многие приложения используют библиотеки(соответственно, пытаются вызвать функции из них), их загрузка сейчас не поддерживается.
Некоторые приложения пишут\читают изображения "directly to\from LFB" — это тоже не поддерживается.

Сделал DLL-версию.
"Загрузчик", резервирующий 64 мегабайта памяти(константа MEM_SIZE в исходнике), загружается по адресу 64K.
С помощью VirtualProtect устанавливаются атрибуты PAGE_EXECUTE_READWRITE. После чего управление передаётся в Main, которая находится в DLL.
В дальнейшем "загрузчик" можно затереть кодом или данными загруженного KolibriOS приложения.

Теперь поддерживаемых приложений стало чуть больше, например, работает FREE3D04(Fisheye Raycasting Engine Etc. by Dieter Marfurt).
Загружается стартовый экран игры INVADERS, если бы системная функция SysFn2:GetKey поддерживалась, то можно было бы и поиграть :)
Работают демки 3DWAV, TRANTEST, TUBE.
KEm.7z (57.04 KiB)
Downloaded 405 times

Re: Эмуляция KolibriOS API

Posted: Sun Mar 11, 2018 12:48 pm
by Kopa
Здесь какое то видео.
Using EMET to Disable EMET

P.S. Да, поддерживаемых приложений стало гораздо больше. :)
Можно начать перечислять.
Под ReactOS эти тесты не заработaли. Выводит ошибку доступа к памяти Write only.
Можно, наверное, разработчмикам ReаctOS сделать баг-репорт. :)
Где то на Read память ругается.

Re: Эмуляция KolibriOS API

Posted: Sun Mar 11, 2018 1:02 pm
by paulcodeman
Из-за чего с windows 7 и выше не запускается? Это возможно из-за защиты windows?

Re: Эмуляция KolibriOS API

Posted: Sun Mar 11, 2018 3:28 pm
by Leency
JFYI: KlbrInWin x64, не тестировал.
http://kolibriosandfasm.mybb.ru/viewtopic.php?id=11

Re: Эмуляция KolibriOS API

Posted: Sun Mar 11, 2018 7:30 pm
by 0CodErr
Leency wrote:KlbrInWin x64
В каком месте там x64? Обычный же :)
ALEXS1983 wrote:Проверка работоспособности и настройки KlbrInWin и использование проводились в Windows XP.
Есть такой эмулятор Cxbx.
Cxbx is an emulator for the Xbox video game console that allows users to enjoy Xbox games from their home PCs.
Там использовалось SetLDTEntries(то же, что использовал diamond).
Но там решалась задача с регистром FS.
Потом на 64 bit возникли проблемы с этой функцией(она там просто как заглушка, ничего не делает). У KlbrInWin тоже проблемы с x64.
Трудно сказать, как именно они их решили. Вот тут http://qpdownload.com/cxbx/ написано, что, под все Windows.
Раньше был такой файлик https://github.com/ILOVEPIE/Cxbx-Reload ... 4).cpp#L51
Кому интересно, вот тут функция EmuAllocateLDT https://github.com/ILOVEPIE/Cxbx-Reload ... DT.cpp#L84
Сейчас вот поновее(форк вроде) https://github.com/Cxbx-Reloaded/Cxbx-R ... c/CxbxKrnl
:) Там в шапке каждого файла: Dear PVS-Studio, please check it :)