Вызвать функцию GetSystemInfo через ассемблер
У меня есть функция GetSystemInfo которая встроена в winapi (sysinfoapi.h), как мне её вызвать?
А затем поместить ответ вызова функции в ячейку памяти.
C++:
void GetSystemInfo(
LPSYSTEM_INFO lpSystemInfo
);
Официальная документация: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
Это всё что я смог найти.
Ответы (1 шт):
DISCLAIMER:
Нет никакого смысла писать этот код на ассемблере, все то же самое намного проще было бы написать на Си (в конце пример).
Насколько возможно минимальный пример на fasm, результат - 32-битный консольный exe файл:
format PE CONSOLE
entry start
include 'win32a.inc'
section '.text' code readable executable
start:
invoke GetSystemInfo, system_info
; dword перед [system_info.wProcessorArchitecture] нужно из-за того что это 2-байтовое поле (word),
; его нельзя просто так передать с помощью push.
; dword здесь приводит к тому, что по адресу поля читается 4 байта вместо 2.
; Но это корректно работает только потому, что после этого поля идет зарезервированное пустое 2-байтовое поле
; (если бы было не пустое, вывелось бы неправильное значение)
cinvoke printf, format_string, dword [system_info.wProcessorArchitecture], [system_info.dwPageSize]
invoke getch ; ожидание нажатия клавиши перед завершением, можно и без этого, если запускаете из командной строки
invoke ExitProcess,0
section '.data' data readable writeable
system_info SYSTEM_INFO
format_string:
db 'wProcessorArchitecture: %d', 0x0d, 0x0a
db 'dwPageSize: %d', 0x0d, 0x0a, 0
section '.idata' import data readable writeable
library kernel32, 'KERNEL32.DLL',\
msvcrt, 'MSVCRT.DLL'
include 'api/kernel32.inc'
import msvcrt,\
printf,'printf',\
getch,'_getch'
section '.reloc' fixups data readable discardable
Тут для примера вывод значений только первых двух полей - wProcessorArchitecture и dwPageSize.
В 32-битной версии выводит:
wProcessorArchitecture: 0
dwPageSize: 4096
0 соответствует PROCESSOR_ARCHITECTURE_INTEL, см. описание структуры SYSTEM_INFO
Если изменить в коде PE на PE64 и include 'win32a.inc' на include 'win64a.inc', получится 64-битный экзешник, вывод будет такой:
wProcessorArchitecture: 9
dwPageSize: 4096
9 соответствует PROCESSOR_ARCHITECTURE_AMD64.
"Магическая" строка system_info SYSTEM_INFO - это макрос, который при компиляции разворачивается в набор полей соответствующей структуры, например для 32-битного экзешника (взято из файла fasm/include/equates/kernel32.inc):
struct SYSTEM_INFO
wProcessorArchitecture dw ?
wReserved dw ?
dwPageSize dd ?
lpMinimumApplicationAddress dd ?
lpMaximumApplicationAddress dd ?
dwActiveProcessorMask dd ?
dwNumberOfProcessors dd ?
dwProcessorType dd ?
dwAllocationGranularity dd ?
wProcessorLevel dw ?
wProcessorRevision dw ?
ends
Для 64-битной версии все то же самое, только размеры полей-указателей (те, что начинаются на lp) другие - 64-битные (dq) вместо 32-битных (dd).
Также нужно сказать, что invoke, cinvoke - это макросы, которые при компиляции превращаются в разный код в зависимости от подключенного в начале программы файла - win32a.inc или win64a.inc.
Для 32-битной версии invoke превращается в 0 или более push, и call в конце - соглашение stdcall. Для cinvoke порядок push противоположный, и после call еще выравнивается стек на размер переданных через push параметров - соглашение cdecl (используется для функций с переменным числом параметров, как у того же printf). См. Соглашения о вызовах, используемые на x86 при 32-битной адресации.
Для 64-битной версии все несколько сложнее, можете для ознакомления посмотреть здесь: Соглашение о вызовах для 64-разрядных систем
P.S. более-менее эквивалентный код на Си:
include <windows.h>
include <stdio.h>
SYSTEM_INFO system_info;
int main() {
GetSystemInfo(&system_info);
printf("wProcessorArchitecture: %d\n"
"dwPageSize: %d\n",
system_info.wProcessorArchitecture,
system_info.dwPageSize);
// Тут мог быть вызов getch();, но эта функция не входит в стандарт, поэтому не добавляю
return 0;
}