Вызвать функцию 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 шт):

Автор решения: insolor

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;
}
→ Ссылка