Я использую android termux .
Я установил proot-distro для linux (ubuntu) для запуска файлов Linux ELF.
Я использовал кросс-компилятор i686-linux-gnu-gcc для компиляции x86 32-битный Файлы ELF. < /P>
< /blockquote>
Я использовал x86_64-linux-gnu-objdump < /strong> для разборки. /p>
< /blockquote>
В дампе разборки я заметил эти строки: < /p>
Код: Выделить всё
endbr32
LEA ECX, [ESP+ 0x4]
AND ESP, 0xfffffff0
PUSH DWORD PTR [ECX- 0x4]
< /code>
Я понимаю эту инструкцию: < /p>
AND ESP, 0xFFFFFFF0
Код: Выделить всё
LEA ECX, [esp + 0x4]
PUSH DWORD PTR [ECX- 0x4]
< /code>
Я проанализировал эти инструкции и попытался понять, что они делают и почему они там. Вот моя интерпретация - пожалуйста, поправьте меня, если я ошибаюсь. . < /p>
< /blockquote>
Инструкция push dword ptr [ecx - 0x4] нажимает обратный адрес вызывающего абонента в стек после его выравнивания , гарантируя, что кадр стека правильно выровнен перед инструкцией вызовов. Тем не менее, я заметил, что выравнивание осуществляется, и адрес возврата копируется после выравнивания. Вопрос в том, что аргументы, передаваемые функции, теперь разделены этим выравниванием. Это означает, что выравнивание вставлено между адресом возврата и аргументами функции. Смещения < /p>
Из -за этого разделения аргумент сметается с указателя кадров (EBP) больше не статична. Например, в «нормальной» сборке можно получить доступ к аргументам, используя статические смещения, такие как EBP + 8. Следовательно, аргументы больше не могут быть доступны со статическими смещениями. выравнивания DWORD.
[b] Программа 1: [/b]
#include
int main(int argc, char **argv) {
printf("Count: %d\n", argc);
return 0;
}
< /code>
Разборка основной функции в разделе .Text: < /p>
0000118d :
118d: f3 0f 1e fb endbr32
1191: 8d 4c 24 04 lea ecx, [esp + 0x4]
1195: 83 e4 f0 and esp, 0xfffffff0
1198: ff 71 fc push DWORD PTR [ecx - 0x4]
119b: 55 push ebp
119c: 89 e5 mov ebp, esp
119e: 53 push ebx
119f: 51 push ecx
11a0: e8 2c 00 00 00 call 11d1
11a5: 05 33 2e 00 00 add eax, 0x2e33
11aa: 89 ca mov edx, ecx
11ac: 83 ec 08 sub esp, 0x8
11af: ff 32 push DWORD PTR [edx]
11b1: 8d 90 30 e0 ff ff lea edx, [eax - 0x1fd0]
11b7: 52 push edx
11b8: 89 c3 mov ebx, eax
11ba: e8 81 fe ff ff call 1040
11bf: 83 c4 10 add esp, 0x10
11c2: b8 00 00 00 00 mov eax, 0x0
11c7: 8d 65 f8 lea esp, [ebp - 0x8]
11ca: 59 pop ecx
11cb: 5b pop ebx
11cc: 5d pop ebp
11cd: 8d 61 fc lea esp, [ecx - 0x4]
11d0: c3 ret
Начальный макет стека:
Код: Выделить всё
Argument 2 (Top): [ESP + 8] (0xbfff1230)
Argument 1: [ESP + 4] (0xbfff122c)
Return Address: [ESP] (0xbfff1228)
Код: Выделить всё
Argument 2 (Top): [ESP + 8] (0xbfff1230)
Argument 1: [ESP + 4] (0xbfff122c)
Return Address: [ESP] (0xbfff1228)
макет стека после и esp, 0xfffffff0 : < /p>
Код: Выделить всё
Argument 2 (Top): [OLD ESP + 8] (0xbfff1230)
Argument 1: [OLD ESP + 4] (0xbfff122c)
Return Address: [OLD ESP] (0xbfff1228)
Alignment DWORD 1: (0xbfff1224)
Alignment DWORD 2: (0xbfff1220) 0xbfff1220 [/b]
макет стека после [b] push dword ptr [ecx - 4] : < /p>
[code]
Argument 2 (Top): [OLD ESP + 8] (0xbfff1230)
Argument 1: [OLD ESP + 4] (0xbfff122c)
Return Address: [OLD ESP] (0xbfff1228)
Alignment DWORD 1: (0xbfff1224)
Alignment DWORD 2: (0xbfff1220)
Return Address: 0xbfff121c [/b]
После этих макетов стека я понимаю, что ECX загружается с адресом [ESP + 4], который является адресом первого аргумента. Поскольку аргументы не могут быть доступны с использованием EBP из -за выравнивания на основе наблюдения [b] [/b], ECX используется для хранения начального адреса аргументов функции. Я прав?[code]
#include
int main(int argc, char **argv) {
printf("Count: %d\n", argc);
printf("Filename: %s\n", *argv);
return 0;
}
< /code>
0000118d :
118d: f3 0f 1e fb endbr32
1191: 8d 4c 24 04 lea ecx, [esp + 0x4]
1195: 83 e4 f0 and esp, 0xfffffff0
1198: ff 71 fc push DWORD PTR [ecx - 0x4]
119b: 55 push ebp
119c: 89 e5 mov ebp, esp
119e: 56 push esi
119f: 53 push ebx
11a0: 51 push ecx
11a1: 83 ec 0c sub esp, 0xc
11a4: e8 e7 fe ff ff call 1090
11a9: 81 c3 2f 2e 00 00 add ebx, 0x2e2f
11af: 89 ce mov esi, ecx
11b1: 83 ec 08 sub esp, 0x8
11b4: ff 36 push DWORD PTR [esi]
11b6: 8d 83 30 e0 ff ff lea eax, [ebx - 0x1fd0]
11bc: 50 push eax
11bd: e8 7e fe ff ff call 1040
11c2: 83 c4 10 add esp, 0x10
11c5: 8b 46 04 mov eax, DWORD PTR [esi + 0x4]
11c8: 8b 00 mov eax, DWORD PTR [eax]
11ca: 83 ec 08 sub esp, 0x8
11cd: 50 push eax
11ce: 8d 83 41 e0 ff ff lea eax, [ebx - 0x1fbf]
11d4: 50 push eax
11d5: e8 66 fe ff ff call 1040
11da: 83 c4 10 add esp, 0x10
11dd: b8 00 00 00 00 mov eax, 0x0
11e2: 8d 65 f4 lea esp, [ebp - 0xc]
11e5: 59 pop ecx
11e6: 5b pop ebx
11e7: 5e pop esi
11e8: 5d pop ebp
11e9: 8d 61 fc lea esp, [ecx - 0x4]
11ec: c3 ret
Смещение для второго аргумента рассчитывается относительно базового адреса, указанного ECX .
Здесь используется esi + 4 , но перед этим ecx перемещается в esi Полем Значение esi + 4 затем перемещается в eax , который нажимается в стек. ECX, [ESP + 0x4] используется для сохранения начального адреса аргументов функции (или адреса первого аргумента) для доступа к ним внутри функции. Если эта интерпретация неверна, пожалуйста, не стесняйтесь меня поправить.
Подробнее здесь: https://stackoverflow.com/questions/793 ... isassembly
Мобильная версия