Пишем программы используя Wow64Transition или системные вызовы на x86
Изначально я хотел показать, как можно использовать системные вызовы на Windows для написания полноценных программ, но системные вызовы доступны только на x64, да и про них все знают, и есть уже куча готовых таблиц с номерами функций и документациями:
https://j00ru.vexillium.org/syscalls/nt/32/
А поэтому я подумал, а как использовать системные вызовы на x86? И тут-то оно, никто не писал документации и статьи на эту тему, и нет готовых таблиц с номерами для сборок на Wow64 номера.
Для начала объясню, что 32-х битные программы в 64-х битных версиях Windows исполняются в среде Wow64, надеюсь это все знают. И если в x64 можно напрямую обращаться к SSDT (таблица с функциями Windows) с помощью системных вызовов, вызывая какой-нибудь NtTerminateProcess, то на 32-х битной программе Вы должны обращаться к функциями через Wow64. У Wow64 есть функция для перехода в ядро - Wow64Transition, и в неё также как и в системных вызовах надо передавать номера.
Поскольку постоянно лезть в отладчик и смотреть номер функции неудобно, я сдампил все номера с помощью скрипта и захостил на сайт. Это первая версия таблицы, и в ней могут быть неточности, но после пары тестов всё совпадало. Есть вероятность, что номера различаются для каждой сборки Windows, позже я обновлю номера и напишу об этом в своём канале, а пока номера доступны для версии Windows 10 - 21H2.
По поводу соглашения о вызовах...
Как Вы уже догадались, вся прелесть состоит в том, что теперь Ваши программы могут состоять лишь из одной функции - Wow64Transition. Через эту функцию будут проходить все обращения к, например, NtAllocateVirtualMemory (для выделения памяти), что достаточно интересно.
Соглашение о вызовах - стандартный 32-х битный stdcall с одним нюансом - вы должны положить в стек адрес возврата из Wow64, иначе будет появляться исключение.
Пример с выделением (NtAllocateVirtualMemory) и освобождением (NtFreeVirtualMemory) памяти:
format PE GUI
entry start
include 'win32a.inc'
section '' readable writeable executable
data 1
library ntdll, 'ntdll.dll'
import ntdll,\
Wow64Transition, 'Wow64Transition'
end data
start:
push PAGE_READWRITE
push MEM_COMMIT or MEM_RESERVE
push size
push 0
push addr
push 0xFFFFFFFF ; CurrentProcess
mov eax, 24 ; http://fasmgenius.prohosts.org/w10_21h2.php?search=NtAllocateVirtualMemory
mov edx, dword[Wow64Transition]
push @f
call dword[edx]
@@:
add esp, 4*7
mov eax, dword[addr]
mov dword[size], 0
push MEM_RELEASE
push size
push addr
push 0xFFFFFFFF ; CurrentProcess
mov eax, 30 ; http://fasmgenius.prohosts.org/w10_21h2.php?search=NtFreeVirtualMemory
mov edx, dword[Wow64Transition]
push @f
call dword[edx]
@@:
add esp, 4*5
ret
Как видим, аргументы кладутся как обычно, если бы использовалась обычная функция NtAllocateVirtualMemory, только мы обращаемся сразу напрямую к Wow64.
Данный подход может использоваться для защиты, обфускации, или просто для написания интересного кода.