
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.52] |
![]() |
|
Сообщ.
#1
,
|
|
|
Вот такая программулька.
![]() ![]() .CODE extrn ExitProcess:proc extrn MessageBoxW:proc header dw 'A', 'M', 'D', '6', '4', 0 message dw 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 EntryPoint proc xor rcx, rcx lea rdx, message lea r8, header xor r9, r9 call MessageBoxW xor rcx, rcx call ExitProcess EntryPoint endp END И валится при вызове MessageBoxW: Exception thrown at 0x00007FFB8012971C (user32.dll) in msgbox.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF. Коллстек такой: ![]() ![]() user32.dll!GetMessageBoxFontForDpi(unsigned int) user32.dll!SoftModalMessageBox() user32.dll!MessageBoxWorker(struct _MSGBOXDATA *) user32.dll!MessageBoxTimeoutW() user32.dll!MessageBoxW() msgbox.exe!EntryPoint() Line 16 Может надо какую-то инициализацию для USER32.DLL дополнительную делать? |
Сообщ.
#2
,
|
|
|
1) Надо выделять в стеке место для параметров MessageBoxW
2) Стек необходимо выравнивать на 16 байт ![]() ![]() EntryPoint: enter 32, 0 ; Выравнивает стек запихивая туда rbp и выделяет 32 байта для вызовов MessageBoxW и ExitProcess xor r9, r9 lea r8, header lea rdx, message xor ecx, ecx call MessageBoxW xor ecx, ecx call ExitProcess ADD: чтобы не спрашивать про такие ошибки надо использовать отладчик. Скажем x64dbg |
![]() |
Сообщ.
#3
,
|
|
Как минимум нужно убедиться, что стек выровнен на 16 байт. Добавь в начало
![]() ![]() and rsp, not 0Fh |
Сообщ.
#4
,
|
|
|
Ух ты! Заработало! Спасибо.
Но не понял, зачем выделять в стеке 32 байта для вызовов MessageBoxW и ExitProcess. Почём я знаю, сколько им нужно выделить? Разве они сами не должны этим заниматься? Поэтому я попробовал инструкцию enter 0, 0 - все нормально. Т.е. можно быть уверенным, что инструкция enter однозначно выровняет стек на 16 байт? Заглянул что C-Runtime делает ![]() ![]() extern "C" DWORD wWinMainCRTStartup(LPVOID) { 00007FF6AA37A6F0 mov qword ptr [rsp+8],rcx 00007FF6AA37A6F5 sub rsp,28h return __scrt_common_main(); 00007FF6AA37A6F9 call __scrt_common_main (07FF6AA37A450h) } 00007FF6AA37A6FE add rsp,28h 00007FF6AA37A702 ret Ну и дальше пошагал - как правило первая инструкция sub rsp, минимум 28h Или я не прав и таки надо 32 байта для чего-то выделять? З.Ы. отладчик я использую Visual Studio. Добавлено Цитата Qraizer @ Как минимум нужно убедиться, что стек выровнен на 16 байт. Добавь в начало ![]() ![]() and rsp, not 0Fh Ага, когда вызывается функция, выравнивание сбивается, ибо в стек помещается как минимум 8 байт адреса возврата. В общем с выравниванием понятно. Вопрос только про 32 байта - нужны ли они? |
Сообщ.
#5
,
|
|
|
Цитата GAGARIN @ Но не понял, зачем выделять в стеке 32 байта для вызовов MessageBoxW и ExitProcess. Почём я знаю, сколько им нужно выделить? Разве они сами не должны этим заниматься? Поэтому я попробовал инструкцию enter 0, 0 - все нормально. Прям самый первый же абзац. Первые 4 параметра передаются через регистры, но под них все равно надо выделять место в стеке. Добавлено Цитата GAGARIN @ Ну и дальше пошагал - как правило первая инструкция sub rsp, минимум 28h 028h этот как раз 32 байта + 8 байт на push rbp, которую положит enter 32, 0 |
Сообщ.
#6
,
|
|
|
Всё понятно. Вопрос закрыт. Большое спасибо.
Добавлено Цитата macomics @ 028h этот как раз 32 байта + 8 байт на push rbp, которую положит enter 32, 0 rbp там не пушается. 8 байт - это адрес возврата, который, собственно, и сбивает 16-байтное выравнивание стека. |
Сообщ.
#7
,
|
|
|
Цитата GAGARIN @ rbp там не пушается. 8 байт - это адрес возврата, который, собственно, и сбивает 16-байтное выравнивание стека. rbp запушит enter. enter N,0 эквивалентна последовательности ![]() ![]() ; enter N, 0 push rbp ; этот push rbp вместе с push rip как часть call label как раз и дадут выравнивание стека (8+8) mov rbp, rsp sub rsp, N |
Сообщ.
#8
,
|
|
|
Ну так никто не делает. Во всяком случае MS компилер делает так:
![]() ![]() foo proc sub rsp, 28h ; (+ сколько там нужно на локальные переменные) ... И да, в X64, enter 32, 0 не помещает rbp в стек. Наверное поэтому эта инструкция и не используется, т.к. проще sub rsp сразу выделить сколько нужно. Добавлено Сделал так. ![]() ![]() .CODE extrn ExitProcess:proc extrn MessageBoxW:proc extrn MessageBeep:proc header dw 'A', 'M', 'D', '6', '4', 0 message dw 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 beep proc sub rsp, 28h xor rcx, rcx dec rcx call MessageBeep add rsp, 28h ret beep endp EntryPoint proc sub rsp, 28h call beep xor rcx, rcx lea rdx, message lea r8, header xor r9, r9 call MessageBoxW xor rcx, rcx call ExitProcess EntryPoint endp END Нраицца! |
Сообщ.
#9
,
|
|
|
Цитата GAGARIN @ И да, в X64, enter 32, 0 не помещает rbp в стек. Наверное поэтому эта инструкция и не используется, т.к. проще sub rsp сразу выделить сколько нужно. Скрытый текст ![]() ![]() macomics@home-kde ~/testDir/testEnterPushRBP $ nano main.asm macomics@home-kde ~/testDir/testEnterPushRBP $ cat main.asm format ELF64 executable 3 segment executable entry $ mov rbp, $FEDCBA9876543210 enter 32, 0 mov edx, mess.len lea rsi, [mess] push 1 pop rdi mov eax, edi syscall mov eax, 60 xor dil, dil syscall mess db 'Wellcome text!', 0xa .len = $ - mess macomics@home-kde ~/testDir/testEnterPushRBP $ fasm main.asm flat assembler version 1.73.32 (16384 kilobytes memory, x64) 2 passes, 178 bytes. macomics@home-kde ~/testDir/testEnterPushRBP $ gdb -q ./main Reading symbols from ./main... (No debugging symbols found in ./main) (gdb) define showstack Type commands for definition of "showstack". End with a line saying just "end". >printf "0x%016lX 0x%016lX\n", $rsp+0x00, *(unsigned long long *)($rsp+0x00) >printf "0x%016lX 0x%016lX\n", $rsp+0x08, *(unsigned long long *)($rsp+0x08) >printf "0x%016lX 0x%016lX\n", $rsp+0x10, *(unsigned long long *)($rsp+0x10) >printf "0x%016lX 0x%016lX\n", $rsp+0x18, *(unsigned long long *)($rsp+0x18) >printf "0x%016lX 0x%016lX\n", $rsp+0x20, *(unsigned long long *)($rsp+0x20) >printf "0x%016lX 0x%016lX\n", $rsp+0x28, *(unsigned long long *)($rsp+0x28) >printf "0x%016lX 0x%016lX\n", $rsp+0x30, *(unsigned long long *)($rsp+0x30) >printf "0x%016lX 0x%016lX\n", $rsp+0x38, *(unsigned long long *)($rsp+0x38) >printf "0x%016lX 0x%016lX\n", $rsp+0x40, *(unsigned long long *)($rsp+0x40) >printf "0x%016lX 0x%016lX\n", $rsp+0x48, *(unsigned long long *)($rsp+0x48) >end (gdb) define showcpu Type commands for definition of "showcpu". End with a line saying just "end". >x /5i $pc >info registers >showstack >end (gdb) define stepcmd Type commands for definition of "stepcmd". End with a line saying just "end". >nexti >showcpu >end (gdb) shell readelf -h ./main Заголовок ELF: Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 Класс: ELF64 Данные: дополнение до 2, от младшего к старшему Version: 1 (current) OS/ABI: UNIX - GNU Версия ABI: 0 Тип: EXEC (Исполняемый файл) Машина: Advanced Micro Devices X86-64 Версия: 0x1 Адрес точки входа: 0x400078 Начало заголовков программы: 64 (байт в файле) Начало заголовков раздела: 0 (байт в файле) Флаги: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 1 Size of section headers: 64 (bytes) Number of section headers: 0 Section header string table index: 0 (gdb) break *0x400078 Breakpoint 1 at 0x400078 (gdb) run Starting program: /home/macomics/testDir/testEnterPushRBP/main Breakpoint 1, 0x0000000000400078 in ?? () (gdb) showcpu => 0x400078: movabs rbp,0xfedcba9876543210 0x400082: enter 0x20,0x0 0x400086: mov edx,0xf 0x40008b: lea rsi,[rip+0x11] # 0x4000a3 0x400092: push 0x1 rax 0x0 0 rbx 0x0 0 rcx 0x0 0 rdx 0x0 0 rsi 0x0 0 rdi 0x0 0 rbp 0x0 0x0 rsp 0x7fffffffd560 0x7fffffffd560 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 r13 0x0 0 r14 0x0 0 r15 0x0 0 rip 0x400078 0x400078 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 k0 0x0 0 k1 0x0 0 k2 0x0 0 k3 0x0 0 k4 0x0 0 k5 0x0 0 k6 0x0 0 k7 0x0 0 fs_base 0x0 0 gs_base 0x0 0 0x00007FFFFFFFD560 0x0000000000000001 0x00007FFFFFFFD568 0x00007FFFFFFFD9CC 0x00007FFFFFFFD570 0x0000000000000000 0x00007FFFFFFFD578 0x00007FFFFFFFD9F9 0x00007FFFFFFFD580 0x00007FFFFFFFDA09 0x00007FFFFFFFD588 0x00007FFFFFFFDA5F 0x00007FFFFFFFD590 0x00007FFFFFFFDA71 0x00007FFFFFFFD598 0x00007FFFFFFFDA85 0x00007FFFFFFFD5A0 0x00007FFFFFFFDAC1 0x00007FFFFFFFD5A8 0x00007FFFFFFFDAD6 (gdb) stepcmd 0x0000000000400082 in ?? () => 0x400082: enter 0x20,0x0 0x400086: mov edx,0xf 0x40008b: lea rsi,[rip+0x11] # 0x4000a3 0x400092: push 0x1 0x400094: pop rdi rax 0x0 0 rbx 0x0 0 rcx 0x0 0 rdx 0x0 0 rsi 0x0 0 rdi 0x0 0 rbp 0xfedcba9876543210 0xfedcba9876543210 rsp 0x7fffffffd560 0x7fffffffd560 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 r13 0x0 0 r14 0x0 0 r15 0x0 0 rip 0x400082 0x400082 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 k0 0x0 0 k1 0x0 0 k2 0x0 0 k3 0x0 0 k4 0x0 0 k5 0x0 0 k6 0x0 0 k7 0x0 0 fs_base 0x0 0 gs_base 0x0 0 0x00007FFFFFFFD560 0x0000000000000001 0x00007FFFFFFFD568 0x00007FFFFFFFD9CC 0x00007FFFFFFFD570 0x0000000000000000 0x00007FFFFFFFD578 0x00007FFFFFFFD9F9 0x00007FFFFFFFD580 0x00007FFFFFFFDA09 0x00007FFFFFFFD588 0x00007FFFFFFFDA5F 0x00007FFFFFFFD590 0x00007FFFFFFFDA71 0x00007FFFFFFFD598 0x00007FFFFFFFDA85 0x00007FFFFFFFD5A0 0x00007FFFFFFFDAC1 0x00007FFFFFFFD5A8 0x00007FFFFFFFDAD6 (gdb) stepcmd 0x0000000000400086 in ?? () => 0x400086: mov edx,0xf 0x40008b: lea rsi,[rip+0x11] # 0x4000a3 0x400092: push 0x1 0x400094: pop rdi 0x400095: mov eax,edi rax 0x0 0 rbx 0x0 0 rcx 0x0 0 rdx 0x0 0 rsi 0x0 0 rdi 0x0 0 rbp 0x7fffffffd558 0x7fffffffd558 rsp 0x7fffffffd538 0x7fffffffd538 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 r13 0x0 0 r14 0x0 0 r15 0x0 0 rip 0x400086 0x400086 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 k0 0x0 0 k1 0x0 0 k2 0x0 0 k3 0x0 0 k4 0x0 0 k5 0x0 0 k6 0x0 0 k7 0x0 0 fs_base 0x0 0 gs_base 0x0 0 0x00007FFFFFFFD538 0x0000000000000000 0x00007FFFFFFFD540 0x0000000000000000 0x00007FFFFFFFD548 0x0000000000000000 0x00007FFFFFFFD550 0x0000000000000000 0x00007FFFFFFFD558 0xFEDCBA9876543210 0x00007FFFFFFFD560 0x0000000000000001 0x00007FFFFFFFD568 0x00007FFFFFFFD9CC 0x00007FFFFFFFD570 0x0000000000000000 0x00007FFFFFFFD578 0x00007FFFFFFFD9F9 0x00007FFFFFFFD580 0x00007FFFFFFFDA09 (gdb) continue Continuing. [Inferior 1 (process 30131) exited normally] (gdb) q ![]() ![]() mov rbp, 0xFEDCBA9876543210 И там мы видим 0 в rbp После выполнения команды mov как и ожидалось в rbp появляется 0xFEDCBA9876543210 Ну и после команды enter 32, 0 мы видим, что значение rbp изменилось и стало равно rsp - 32. И в стеке у нас появилось место для 32 байт плюс то самое значение из rbp (0xFEDCBA9876543210). Итого в стек положили 40 байт, из которых 8 это старое значение rbp до выполнения команды enter |
Сообщ.
#10
,
|
|
|
Да? Ну да бог с ним, с этим rbp)
|
Сообщ.
#11
,
|
|
|
Ну можете так же еще заметить, что после enter значение в rbp указывает на адрес в стеке где и лежит предыдущее его же значение.
Обратной командой для enter является команда leave эквивалентная последовательности ![]() ![]() mov rsp, rbp pop rbp |
Сообщ.
#12
,
|
|
|
Да это понятно всё. Я подумал, что это в AMD64 упразднили, ибо не видел, чтобы это использовалось.
|