Исследование файла с помощью dumpbin

Последнее обновление: 27.07.2023

Для исследования сгенерированного объектного/исполняемого файла можно использовать ряд утилит. Так, Microsoft вместе с компилятором для C/C++ предоставляет утилиту dumpbin. Соответственно для использования dumpbin, надо установить компиляторы Visual C++ через программу установки Visual Studio. А для обращения к самой утилите dumpbin в консоли можно использовать программу x64 Native Tools Command Prompt for VS 2022, которая устанавливается вместе с Visual Studio.

Вызов утилиты dumpbin имеет следующую форму:

dumpbin options filename

Параметр filename представляет имя объектного или исполняемого файла в формате PE/COFF, который надо исследовать, а параметр options представляет набор опций, которые указывают, какую именно информацию о файле надо отобразить. Применяются следующие опции:

/ALL
 /ARCHIVEMEMBERS
 /CLRHEADER
 /DEPENDENTS
 /DIRECTIVES
 /DISASM[:{BYTES|NOBYTES}]
 /ERRORREPORT:{NONE|PROMPT|QUEUE|SEND}
 /EXPORTS
 /FPO
 /HEADERS
 /IMPORTS[:filename]
 /LINENUMBERS
 /LINKERMEMBER[:{1|2}]
 /LOADCONFIG
 /NOLOGO
 /OUT:filename
 /PDATA
 /PDBPATH[:VERBOSE]
 /RANGE:vaMin[,vaMax]
 /RAWDATA[:{NONE|1|2|4|8}[,#]]
 /RELOCATIONS
 /SECTION:name
 /SUMMARY
 /SYMBOLS
 /TLS
 /UNWINDINFO

В качестве примера возьмем простейшую программу на ассемблере:

.data
num1 dword 22
num2 dword 32
num3 dword ?
.code
main proc

    mov rax, 20
    mov rbx, 10
    add rax, rbx
    ret
main endp
end

Пусть программа располагается в файле hello.asm, и при компиляции создается объектный файл hello.obj.

/all

Параметр /all позволяет отобразить всю возможную информацию, кроме дизассемблированного кода. Для использования dumpbin запустим x64 Native Tools Command Prompt for VS 2022 и в этой программе перейдем к расположению объектного файла hello.obj и затем выполним команду:

dumpbin hello.exe /all

Нам отобразится вывод типа следующего:

c:\asm>dumpbin hello.obj /all
Microsoft (R) COFF/PE Dumper Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.obj

File Type: COFF OBJECT

FILE HEADER VALUES
            8664 machine (x64)
               3 number of sections
        64C00B7D time date stamp Tue Jul 25 20:50:53 2023
             10A file pointer to symbol table
               9 number of symbols
               0 size of optional header
               0 characteristics

SECTION HEADER #1
.text$mn name
       0 physical address
       0 virtual address
      12 size of raw data
      8C file pointer to raw data (0000008C to 0000009D)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500020 flags
         Code
         16 byte align
         Execute Read

RAW DATA #1
  00000000: 48 C7 C0 14 00 00 00 48 C7 C3 0A 00 00 00 48 03  HЗА....HЗГ....H.
  00000010: C3 C3                                            ГГ

SECTION HEADER #2
   .data name
       0 physical address
       0 virtual address
       C size of raw data
      9E file pointer to raw data (0000009E to 000000A9)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0500040 flags
         Initialized Data
         16 byte align
         Read Write

RAW DATA #2
  00000000: 16 00 00 00 20 00 00 00 00 00 00 00              .... .......

SECTION HEADER #3
.debug$S name
       0 physical address
       0 virtual address
      60 size of raw data
      AA file pointer to raw data (000000AA to 00000109)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42100040 flags
         Initialized Data
         Discardable
         1 byte align
         Read Only

RAW DATA #3
  00000000: 04 00 00 00 F1 00 00 00 52 00 00 00 17 00 01 11  ....с...R.......
  00000010: 00 00 00 00 63 3A 5C 61 73 6D 5C 68 65 6C 6C 6F  ....c:\asm\hello
  00000020: 2E 6F 62 6A 00 37 00 3C 11 03 02 00 00 D0 00 00  .obj.7.<.....Р..
  00000030: 00 00 00 00 00 00 00 0E 00 24 00 14 7F 00 00 4D  .........$.....M
  00000040: 69 63 72 6F 73 6F 66 74 20 28 52 29 20 4D 61 63  icrosoft (R) Mac
  00000050: 72 6F 20 41 73 73 65 6D 62 6C 65 72 00 00 00 00  ro Assembler....

COFF SYMBOL TABLE
000 01037F14 ABS    notype       Static       | @comp.id
001 00000010 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .text$mn
    Section length   12, #relocs    0, #linenums    0, checksum        0
004 00000000 SECT2  notype       Static       | .data
    Section length    C, #relocs    0, #linenums    0, checksum        0
006 00000000 SECT3  notype       Static       | .debug$S
    Section length   60, #relocs    0, #linenums    0, checksum        0
008 00000000 SECT1  notype ()    External     | main

String Table Size = 0x0 bytes

  Summary

           C .data
          60 .debug$S
          12 .text$mn

c:\asm>

Как видно, здесь довольно обширная информация. Чем больше программа, чем больше кода она использует, особенно внешних функций, тем больше подобный вывод. Поэтому, возможно, в большинстве ситуаций целесообразнее применять другие опции для вывода какой-то отдельной информации.

/disasm

Опция /disasm позволяет дизассемблировать файл. Например, дизассемблируем файл hello.obj:

c:\asm>dumpbin hello.obj /disasm
Microsoft (R) COFF/PE Dumper Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.obj

File Type: COFF OBJECT

main:
  0000000000000000: 48 C7 C0 14 00 00  mov         rax,14h
                    00
  0000000000000007: 48 C7 C3 0A 00 00  mov         rbx,0Ah
                    00
  000000000000000E: 48 03 C3           add         rax,rbx
  0000000000000011: C3                 ret

  Summary

           C .data
          60 .debug$S
          12 .text$mn

c:\asm>

Здесь мы видим ассемблерный код, аналогичный тому, который определен в исходном файле hello.asm.

/headers

Параметр /headers выводит содержимое заголовка файла и заголовков разделов. Например, заголовки файла hello.obj:

c:\asm>dumpbin hello.obj /headers
Microsoft (R) COFF/PE Dumper Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.obj

File Type: COFF OBJECT

FILE HEADER VALUES
            8664 machine (x64)
               3 number of sections
        64C00B7D time date stamp Tue Jul 25 20:50:53 2023
             10A file pointer to symbol table
               9 number of symbols
               0 size of optional header
               0 characteristics

SECTION HEADER #1
.text$mn name
       0 physical address
       0 virtual address
      12 size of raw data
      8C file pointer to raw data (0000008C to 0000009D)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500020 flags
         Code
         16 byte align
         Execute Read

SECTION HEADER #2
   .data name
       0 physical address
       0 virtual address
       C size of raw data
      9E file pointer to raw data (0000009E to 000000A9)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0500040 flags
         Initialized Data
         16 byte align
         Read Write

SECTION HEADER #3
.debug$S name
       0 physical address
       0 virtual address
      60 size of raw data
      AA file pointer to raw data (000000AA to 00000109)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42100040 flags
         Initialized Data
         Discardable
         1 byte align
         Read Only

  Summary

           C .data
          60 .debug$S
          12 .text$mn

c:\asm>

/imports

Параметр /imports выводит список всех внешних символов, которые операционная система должна предоставлять при загрузке программы в память.

/relocations

Параметр /relocations выводит список всех релокаций/перемещений в файле. Грубо говоря, релокации представляют замену в программе некоторых адресов по умолчанию на реальные адреса. Часто релокации предполагают перемещение в программу адресов внешних функций. Рассмотрим релокации на другом примере. Пусть у нас будет программа, которая использует внешние функции для вывода сообщения на консоль:

includelib kernel32.lib   ; подключаем библиотеку kernel32.lib
 
; подключаем функции WriteFile и GetStdHandle
extrn WriteFile: PROC
extrn GetStdHandle: PROC
.code
text byte "Hello METANIT.COM!"    ; выводимая строка
 
main proc
  sub  rsp, 48   
  mov  rcx, -11  ; Аргумент для GetStdHandle - STD_OUTPUT
  call GetStdHandle ; вызываем функцию GetStdHandle
  mov  rcx, rax     ; Первый параметр WriteFile - в регистр RCX помещаем дескриптор файла - консоли
  lea  rdx, text    ; Второй параметр WriteFile - загружаем указатель на строку в регистр RDX
  mov  r8d, 18      ; Третий параметр WriteFile - длина строки для записи в регистре R8D 
  xor  r9, r9       ; Четвертый параметр WriteFile - адрес для получения записанных байтов
  mov  qword ptr [rsp + 32], 0  ; Пятый параметр WriteFile
  call WriteFile ; вызываем функцию WriteFile
  add  rsp, 48
  ret
main endp
end

Для получения дескриптора консольного вывода и последующего вывода на консоль сообщения применяются нативные функции Windows - WriteFile и GetStdHandle.

Пусть эта программа компилируется в объектный файл hello.obj. Если мы дизассемблируем его, то мы получим следующий консольный вывод:

c:\asm>dumpbin hello.obj /disasm
Microsoft (R) COFF/PE Dumper Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.obj

File Type: COFF OBJECT

text:
  0000000000000000: 48
  0000000000000001: 65 6C              ins         byte ptr [rdi],dx
  0000000000000003: 6C                 ins         byte ptr [rdi],dx
  0000000000000004: 6F                 outs        dx,dword ptr [rsi]
  0000000000000005: 20 4D 45           and         byte ptr [rbp+45h],cl
  0000000000000008: 54                 push        rsp
  0000000000000009: 41
  000000000000000A: 4E
  000000000000000B: 49 54              push        r12
  000000000000000D: 2E
  000000000000000E: 43
  000000000000000F: 4F
  0000000000000010: 4D 21 48 83        and         qword ptr [r8-7Dh],r9
  0000000000000014: EC                 in          al,dx
  0000000000000015: 30 48 C7           xor         byte ptr [rax-39h],cl
  0000000000000018: C1 F5 FF           sal         ebp,0FFh
  000000000000001B: FF
  000000000000001C: FF E8              jmp         rax
  000000000000001E: 00 00              add         byte ptr [rax],al
  0000000000000020: 00 00              add         byte ptr [rax],al
  0000000000000022: 48 8B C8           mov         rcx,rax
  0000000000000025: 48 8D 15 00 00 00  lea         rdx,[text]
                    00
  000000000000002C: 41 B8 12 00 00 00  mov         r8d,12h
  0000000000000032: 4D 33 C9           xor         r9,r9
  0000000000000035: 48 C7 44 24 20 00  mov         qword ptr [rsp+20h],0
                    00 00 00
  000000000000003E: E8 00 00 00 00     call        WriteFile
  0000000000000043: 48 83 C4 30        add         rsp,30h
  0000000000000047: C3                 ret

  Summary

           0 .data
          60 .debug$S
          19 .drectve
          48 .text$mn

c:\asm>

Обратим внимание в дизассемблированном коде на вызов функции WriteFile:

000000000000003E: E8 00 00 00 00     call        WriteFile

По адресу 0x3E в файле располагается код инструкции call, которая имеет опкод E8 и которая вызывает функцию WriteFile. Причем начиная с адреса 0x3F (адрес сразу после опкода инструкции call) идет ряд нулей 00 00 00 00. Это адрес релокации или перемещаемый адрес (relocatable address)

То же самое касается и инструкции lea, которая загружает в регистр RCX адрес переменной text:

0000000000000025: 48 8D 15 00 00 00 00  lea         rdx,[text]

Здесь после 3-х байтного опкода инструкции lea - 48 8D 15 идут четыре байта 00 00 00 00, которые должны указывать на адрес переменной text. Но опять же адрес перемнной text совсем не 00 00 00 00. И в данном случае это также перемещаемый адрес.

Теперь используем опцию /relocations для просмотра релокаций:

c:\asm>dumpbin hello.obj /relocations

RELOCATIONS #1
                                                Symbol    Symbol
 Offset    Type              Applied To         Index     Name
 --------  ----------------  -----------------  --------  ------
 0000001E  REL32                      00000000         B  GetStdHandle
 00000028  REL32                      00000000         C  text
 0000003F  REL32                      00000000         A  WriteFile

  Summary

           0 .data
          60 .debug$S
          19 .drectve
          48 .text$mn

c:\asm>

Здесь мы видим 3 записи о релокации. В столбце Offset указано смещение в байтах в файле, где должны быть применены перемещения/релокации. Так, инструкция lea начинается со смещения 0x25, поэтому фактическое смещение, куда будет помещаться адрес переменной text, равно смещению 0x28 (адрес инструкции lea плюс размер ее опкода - 3 байта). Точно так же инструкция call начинается со смещения 0x3E, поэтому адрес фактической подпрограммы, которую необходимо изменить, находится на 1 байт дальше - по адресу 0x3F.

При компоновке исполняемого файла компоновщик исправляет эти адреса и вставляет вместо них реальные. Например, дизассемблируем файл hello.exe, в который скомпонована выше указанная программа:

c:\asm>dumpbin hello.exe /disasm
Microsoft (R) COFF/PE Dumper Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.exe

File Type: EXECUTABLE IMAGE

  0000000140001000: 48
  0000000140001001: 65 6C              ins         byte ptr [rdi],dx
  0000000140001003: 6C                 ins         byte ptr [rdi],dx
  0000000140001004: 6F                 outs        dx,dword ptr [rsi]
  0000000140001005: 20 4D 45           and         byte ptr [rbp+45h],cl
  0000000140001008: 54                 push        rsp
  0000000140001009: 41
  000000014000100A: 4E
  000000014000100B: 49 54              push        r12
  000000014000100D: 2E
  000000014000100E: 43
  000000014000100F: 4F
  0000000140001010: 4D 21 48 83        and         qword ptr [r8-7Dh],r9
  0000000140001014: EC                 in          al,dx
  0000000140001015: 30 48 C7           xor         byte ptr [rax-39h],cl
  0000000140001018: C1 F5 FF           sal         ebp,0FFh
  000000014000101B: FF
  000000014000101C: FF E8              jmp         rax
  000000014000101E: 2C 00              sub         al,0
  0000000140001020: 00 00              add         byte ptr [rax],al
  0000000140001022: 48 8B C8           mov         rcx,rax
  0000000140001025: 48 8D 15 D4 FF FF  lea         rdx,[0000000140001000h]
                    FF
  000000014000102C: 41 B8 12 00 00 00  mov         r8d,12h
  0000000140001032: 4D 33 C9           xor         r9,r9
  0000000140001035: 48 C7 44 24 20 00  mov         qword ptr [rsp+20h],0
                    00 00 00
  000000014000103E: E8 05 00 00 00     call        0000000140001048
  0000000140001043: 48 83 C4 30        add         rsp,30h
  0000000140001047: C3                 ret
  0000000140001048: FF 25 BA 0F 00 00  jmp         qword ptr [0000000140002008h]
  000000014000104E: FF 25 AC 0F 00 00  jmp         qword ptr [0000000140002000h]

  Summary

        1000 .rdata
        1000 .text

Здесь уже в качестве адреса переменной text будет использоваться совсем другой - исправленный адрес, а не стандартные 00 00 00 00:

0000000140001025: 48 8D 15 D4 FF FF  lea         rdx,[0000000140001000h]

То же самое касается вызова функции WriteFile:

000000014000103E: E8 05 00 00 00     call        0000000140001048
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850