Эмулятор
mike.dld MeOSEmul работает как интерпретатор, эмулятор
diamond-a
KlbrInWin — как дебаггер,
ну а я же хочу просто установить свой обработчик исключений и в нём обрабатывать вызовы
KolibriOS.
Но для начала нужно загрузить приложение. В самой
KolibriOS приложения грузятся по смещению 0.
У
diamond-a реализовано с помощью
SetLdtEntries, что позволяет грузить не по нулевому смещению.
Я не стану использовать такой способ, а буду загружать именно по нулевому смещению

Сперва посмотрим, а что у нас находится по смещению 0 в адресном пространстве приложения после его загрузки.
Посмотрим на скриншот распределения памяти(есть замечательная программа
VMMap, спасибо Руссиновичу за это

)
Attachment:
mem_map1.PNG [ 57.38 KiB | Viewed 6990 times ]
Кстати, хорошая статья про распределение памяти
https://habrahabr.ru/post/202242/Как видно, регион
0..64K свободен, значит мы можем его использовать, нужно только выделить память в нуле.
Я буду это делать вот так:
Code:
BaseAddress := Pointer(1); RegionSize := 1024 * 64 - 1;
NtAllocateVirtualMemory(GetCurrentProcess, @BaseAddress, 0, @RegionSize, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Функция
NtAllocateVirtualMemory из
ntdll определена вот так:
Code:
Function NtAllocateVirtualMemory(ProcessHandle: THandle; BaseAddress: PPChar; ZeroBits: Dword; RegionSize: PDword; AllocationType: Dword; Protect: Dword): Pointer; StdCall; External 'ntdll';
Обнаружил ограничения этого:
Quote:
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/ кое-что объясняется:
Quote:
Что такое Null Page Allocation (NPA)
Это защита от достаточно интересной атаки, базирующаяся на предположении, что зловредный код “займёт” для себя страницу с адресом 0x0 в адресном пространстве приложения.
Для этого сама программа – EMET – занимает адрес 0x0. Впрок, так сказать.
Что интересно, если вызвать VirtualAlloc с параметром 0, то VirtualAlloc (что, в общем-то, логично) выделит память по адресу, который выберет сама, а не по нулевому.
Для того, чтобы “застолбить” за собой такой адрес, как предполагается, применяется вызов NtAllocateVirtualMemory, у которой запрашивается адрес 0x1, при попытке выделения которого выделяется блок, начинающийся с 0x0.
На данный момент зловредов, использующих эту возможность, не обнаружено.
Включить NPA можно как и EAF – только для явно указанных приложений, а не на уровне системы.
Когда эта технология включена, “нулевая” страница при запуске приложения будет занята в профилактических целях.
Да, как видно, память чуть выше уже занята, и её использовать сейчас не получится(хотя всё ещё можно аллоцировать её динамически из кучи, например)
У нас сначала идёт
CODE из
System, вот если бы можно было вставить в самое начало большой кусок ненужных данных или кода, которые можно было бы потом затереть...
Code:
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:
Attachment:
mem_map.PNG [ 56.89 KiB | Viewed 6990 times ]
тогда можно сделать сам эмулятор как библиотеку и запустить её из приложения с
ImageBase = 64K(сам этот загрузчик можно искусственно раздуть до нужных размеров, чтобы потом после запуска самого эмулятора можно было благополучно затереть), загрузить
kex, проверить сколько реально нужно, ненужное освободить.
Имею в виду, в
Dll будет функция
Main, а загрузчик:
Code:
.DATA
db MEM_SIZE dup ?
.CODE
jmp Main
Может быть кто-то знает более рациональный вариант? Пока что для тестов
64K должно хватить, а дальше дело техники

Итак, приложения у нас могут быть упакованные с помощью
kpack.
Но не зря же я делал
unpack viewtopic.php?f=46&t=355&p=69118#p69118
То есть, запакованные
kex-файлы тоже будут поддерживаться.
После загрузки приложения установим обработчик исключений, по умолчанию обнулим регистры и поехали!
Code:
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:
If (ExceptionCode = EXCEPTION_ACCESS_VIOLATION) And (Word(ExceptionAddress^) = $40CD) Then