Есть следующий код: Код (Text): include win64a.inc .code WinMain proc <13> local hWnd:qword local msg:MSG local wnd:WNDCLASSEX mov rdi, offset wndName ;WndName invoke LoadCursorA, 0, IDC_APPSTARTING mov wnd.hCursor, rax invoke LoadIconA, 0, IDI_APPLICATION mov wnd.hIcon, rax mov wnd.hIconSm, rax mov wnd.lpszClassName, rdi mov wnd.hInstance, IMAGE_BASE mov rax, offset Wndproc mov wnd.lpfnWndProc, rax mov wnd.cbSize, sizeof WNDCLASSEX mov wnd.hbrBackground, COLOR_WINDOWFRAME lea rax, wnd invoke RegisterClassExA, rax invoke CreateWindowExA, 0, rdi, rdi, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 600, 800, 0, 0, IMAGE_BASE, 0 mov hWnd, rax ret WinMain endp Wndproc proc <12,8,4,8,8> hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM jmp NtdllDefWindowProc_ ret Wndproc endp .data wndName db "test", 0 end Перед вызовом CreateWindowExA invoke положил все параметры куда надо, со стеком все в порядке. Генерируется следующий код(отладчик): Параметры (в регистрах и на стеке): После вызова CreateWindowExA и соответственно внутри NtUserCreateWindowEx, нарушается RIP и меня выкидывает непонятно куда. В win64a.inc заданы две опции: OPTION PROLOGUE:rbpFramePrologue OPTION EPILOGUE:rbpFrameEpilogue Прикрепляю архив с исходниками и bat файлом с помощью которого компилирую. Также задал вопрос на StackOverFlow, где есть код без invoke, а с полностью ручным управлением стека, но все равно та же ошибка появляется. Пароль от архива: wasm
mantissa, зачем константа IMAGE_BASE , это же 64 бит, оно может собраться хз с какой базой. Мне кажется, лучше брать GetModuleHandle
mantissa, попробуйте найти разницу Код (ASM): ; GUI # include win64a.inc .code WinMain proc local msg:MSG local wnd:WNDCLASSEX mov edi,offset wndName ;WndName invoke LoadCursorA, 0, IDC_ARROW mov wnd.hCursor, rax invoke LoadIconA, 0, IDI_APPLICATION mov wnd.hIcon, rax mov wnd.hIconSm, rax mov wnd.lpszClassName, rdi mov wnd.hInstance, IMAGE_BASE movr wnd.lpfnWndProc,Wndproc mov wnd.cbSize, sizeof WNDCLASSEX mov wnd.hbrBackground, COLOR_WINDOWFRAME lea ecx,wnd invoke RegisterClassExA invoke CreateWindowExA,0,edi,edi,WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT,\ CW_USEDEFAULT, 600, 800, 0, 0, IMAGE_BASE, 0 lea edi,msg @@: invoke GetMessageA,edi,NULL,0,0 invoke DispatchMessageA,edi jmp @b WinMain endp Wndproc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM cmp edx,WM_DESTROY je wmDESTROY leave jmp NtdllDefWindowProc_ wmDESTROY:invoke RtlExitUserProcess,NULL Wndproc endp .data wndName db "test", 0 end
Поменял WndProc на ваш и все заработало. Спасибо. Теперь осталось понять, чего же такого нет в моем WndProc`е.. Причем я не добавлял цикл обработки сообщений.. Итоговый код стал таким: Код (ASM): include win64a.inc .code WinMain proc <13> local hWnd:qword local msg:MSG local wnd:WNDCLASSEX mov rdi, offset wndName ;WndName invoke LoadCursorA, 0, IDC_APPSTARTING mov wnd.hCursor, rax invoke LoadIconA, 0, IDI_APPLICATION mov wnd.hIcon, rax mov wnd.hIconSm, rax mov wnd.lpszClassName, rdi mov wnd.hInstance, IMAGE_BASE mov rax, offset Wndproc mov wnd.lpfnWndProc, rax mov wnd.cbSize, sizeof WNDCLASSEX mov wnd.hbrBackground, COLOR_WINDOWFRAME invoke RegisterClassExA, &wnd invoke CreateWindowExA, 0, rdi, rdi, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 600, 800, 0, 0, IMAGE_BASE, 0 mov hWnd, rax ret WinMain endp Wndproc proc <12,8,4,8,8> hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM cmp edx,WM_DESTROY je wmDESTROY leave jmp NtdllDefWindowProc_ wmDESTROY:invoke RtlExitUserProcess,NULL Wndproc endp .data wndName db "test", 0 end
mantissa, а мне кажется, что причина в отсутствии цикла сообщений. А что у вас в угловых скобках после proc? <13> и <12,8,4,8,8>?
Проверил еще раз, работает с вашим Wndproc и функция CreateWindowExA возвращает корректное значение, а с моим Wndproc RIP повреждается. И все это без цикла. Это можно проверить, добавив в мой код вашу функцию, собрать программу и попробовать запустить, появится окошко и сразу исчезнет, а с моей даже не появится (через отладчик видно, что происходит нарушение RIP в NtUserCreateWindowEx)
Наверное причина в leave перед jmp NtdllDefWindowProc_. Когда в процедуру передаются аргументы или есть локальные переменные компилятор вставляет в процедуру пролог (enter) Без цикла сообщений у меня на семерке, окно появляется на долю секунды и исчезает. А программа закрывается. Только что заметил, что вы уже написали об этом. Это не диалоговая программа и не консольная, цикл просто необходим
В угловых скобках 4 параметра, которые определяют пролог функции и используются следующим образом: 12 означает, что в функции будут вызываться функции не больше чем с 12 параметрами, соответственно все Invoke будут выделять в стеке 12*8 байт, учитывая "домашнее место" для регистров, соответственно параметр не может быть меньше 4. Если совсем не указывать этот параметр, то в стеке выделяется место только для 7 параметров (4 в регистрах и 3 в стеке); В WinMain я вызываю CreateWindowExA с 12 параметрами, поэтому указываю после proc <12> (я указал 13 для теста) и тогда в стеке выделяется точно столько места (96 байт). Остальные четыре числа 8,4,8,8 это размеры в байтах, первых четырёх аргументов которые в начале находятся в регистрах rcx, rdx, r8, r9. Если указать, то они автоматически сохранятся в свое домашнее место в стеке [rsp + 8] и т.д. Я и судя по всему Вы тоже, используем в win64a.inc temphls.inc, который содержит высокоуровневые определения типа Invoke и эти угловые скобки для пролога. Информация отсюда Клик