Почему выходные данные разборки NASM и dumpbin.exe отличаются для одного и того же исполняемого файла?
Вот шаги, за которыми я следовал.
1) Я взял код на ассемблере для трех разных небольших программ из книги Кипра Ирвина "Язык ассемблера для процессоров x86".
2) Я собрал, связал, чтобы создать действительный исполняемый файл без ошибок в каждом случае.
3) Для каждого из исполняемых файлов я генерировал разборки с помощью NASM
ndisasm -u -p intel add3.exe > add3_ndisasm.txt
4) В каждом случае я получал вывод разборки, используя также dumpbin.exe
dumpbin /disasm add3.exe > add3_dumpbin_disasm.txt
Удивительно, но разборка, которую я получил на шаге 4, полностью отличается от разборки на шаге 3.
Вот код сборки, который я использовал (в одном из 3 случаев).
; This program adds and subtracts 32-bit integers.
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD
DumpRegs PROTO
.code
main PROC
mov eax,10000h ; EAX = 10000h
add eax,40000h ; EAX = 50000h
sub eax,20000h ; EAX = 30000h
call DumpRegs
INVOKE ExitProcess,0
main ENDP
END main
Вот пример разборки с шага 3 ( NDISASM)
00000000 4D dec ebp
00000001 5A pop edx
00000002 90 nop
00000003 0003 add [ebx],al
00000005 0000 add [eax],al
00000007 000400 add [eax+eax],al
0000000A 0000 add [eax],al
0000000C FF db 0xff
0000000D FF00 inc dword [eax]
и это из шага 4 (dumpbin.exe)
Microsoft (R) COFF/PE Dumper Version 14.11.25508.2
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file add3.exe
File Type: EXECUTABLE IMAGE
00401000: 50 push eax
00401001: E8 EF 0F 00 00 call 00401FF5
00401006: C3 ret
00401007: 55 push ebp
00401008: 8B EC mov ebp,esp
0040100A: 83 C4 E8 add esp,0FFFFFFE8h
0040100D: 60 pushad
0040100E: 80 3D 00 40 40 00 cmp byte ptr ds:[00404000h],0
00
00401015: 75 05 jne 0040101C
Я взял несколько кодов инструкций из вывода шага 3 и попытался найти их в списке разборки шага 4, но не смог их найти.
5) Затем я взял шестнадцатеричный дамп исполняемого файла (используя frhed) и сравнил значения байтов в нем с выходными данными в обоих шагах.
0000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 b8 00 00 00 00 00 00 00 40 00 00 MZ..........ÿÿ..¸.......@..
001b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...........................
0036 00 00 00 00 00 00 d8 00 00 00 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 73 ......Ø.....º..´.Í!¸.LÍ!Ths
0051 69 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f 74 20 62 65 20 72 75 6e 20 69 6e 20 i program cannot be run in
006c 44 4f 53 20 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 5b 39 0b f3 1f 58 65 DOS mode....$.......[9.ó.Xe
Значения байтов, которые я вижу на шаге 5, соответствуют значениям на шаге 3, но не шагу 4.
Чем объясняются эти различия? Я, должно быть, упускаю какую-то простую маленькую деталь где-то, что это?
1 ответ
Короткий ответ: .exe
≠ .com
Подсказка: обратите внимание на MZ
подпись в виде двух первых байтов на выходе шага 5:-P
Длинный ответ:
Исполняемый файл Microsoft .exe
Формат имеет больше, чем просто код. Прежде всего, он начинается со специальной подписи (инициалы создателя формата), за которой следует довольно много информации, которая описывает организацию кода.
В отличие от .com
file - это просто код, то есть самый первый его байт - это то, что исполняется, когда файл загружается в память.
Первая дизассемблирование, которое вы получаете, является неправильным (да, первый - неправильным, а не вторым!), Так как он пытается начать синтаксический анализ с первого байта вместо того, чтобы перейти к реальному коду.
dumpbin
достаточно умен, чтобы правильно разобрать заголовок этого .exe
файл и начинается разборка фактического кода.
Решение
Если вы хотите сравнить выходные данные дизассемблирования, вы должны либо убедиться, что ваш NASM знает тип файла и правильно анализирует его заголовок, либо... упростить свою жизнь и преобразовать .exe
в .com
в этом случае обе операции разборки должны давать одинаковый результат (конечно, исключая возможные ошибки)
В прошлый раз я конвертировал .exe
файл в .com
было много лет назад с утилитой под названием exe2bin
, Быстрый поиск в Интернете показывает, что это было во времена Windows XP и больше не поставляется с ОС. Хотя я не вижу причин, по которым он не работает, если вы загружаете его из какого-то места.
Общий ответ таков: ваши ожидания необоснованны.
Только специально разработанные ассемблеры и дизассемблеры со специально разработанной аппаратурой мнемоники могут справиться с этим. Это может проиллюстрировать простой пример. Предположим, у вас есть
MOV RCX, RBX ; Intel destination then source.
Для этой инструкции есть два возможных машинных кода. Ассемблер выбирает произвольный. Поэтому, если вы дизассемблируете и повторно соберете рабочий код, содержащий эту инструкцию, вы можете не получить обратно исходный код. Это простой пример. Как только вы перейдете к более коротким специальным кодам для AX, байтам масштабированного индекса, вариантам смещения и тому подобному, все станет намного хуже.
http://home.hccnet.nl/a.w.m.van.der.horst/ciasdis.html предоставляет такой ассемблер.
В приведенном выше примере в этой комбинации ассемблер / дизассемблер у вас есть две однозначно определенные инструкции
MOV, X| F| CX'| R| BX|
а также
MOV, X| Т | BX'| R| CX|
Таким образом, вы можете сами протестировать ассемблер, который собираетесь использовать. Если он содержит только одну инструкцию для копирования регистра BX в регистры CX, все ставки уже отключены. (предупреждение о спойлере, никто из известных ассемблеров не подойдет.)