바이너리 수준 조사를 위한 Linux 명령 주석
다음 명령 실행례의 환경은 여기에 있습니다
[rso@localhost log]$ cat /etc/issue
CentOS release 6.3 (Final)
Kernel \r on an \m
바이너리 파일 읽기 및 쓰기
파일 형식을 찾고 싶습니다.
file
명령으로 간단하게 조사하다.[rso@localhost log]$ file /bin/ls /bin/sh /var/log/messages /dev/sda /dev/tty11 /tmp /tmp/test.pl /tmp/hoge
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
/bin/sh: symbolic link to `bash'
/var/log/messages: ASCII English text
/dev/sda: block special
/dev/tty11: character special
/tmp: sticky directory
/tmp/test.pl: ASCII text
/tmp/hoge: data
바이너리 파일에 포함된 문자열을 추출하고 싶습니다.
strings
.바이너리 파일을 추출하는 문자열이 가장 빠릅니다.[rso@localhost log]$ strings /var/log/wtmp | head
reboot
2.6.32-279.el6.x86_64
runlevel
2.6.32-279.el6.x86_64
tty1
LOGIN
tty2
LOGIN
tty3
LOGIN
참고로 객체 바이너리가 객체 파일(ELF 파일)인 경우
초기화 및 로드 섹션의 문자열만 추출합니다.자세한 내용을 확인한 후
사용strings -a
.
16진수로 바이너리 파일을 저장하려면
od
.[rso@localhost log]$ od -Ax -tx1z /var/log/wtmp |head
000000 02 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 >........~.......<
000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
000020 00 00 00 00 00 00 00 00 7e 7e 00 00 72 65 62 6f >........~~..rebo<
000030 6f 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ot..............<
000040 00 00 00 00 00 00 00 00 00 00 00 00 32 2e 36 2e >............2.6.<
000050 33 32 2d 35 37 33 2e 33 2e 31 2e 65 6c 36 2e 78 >32-573.3.1.el6.x<
000060 38 36 5f 36 34 00 00 00 00 00 00 00 00 00 00 00 >86_64...........<
000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
*
000150 00 00 00 00 ba 75 ff 55 84 37 09 00 00 00 00 00 >.....u.U.7......<```
hexdump
도 가능합니다.나는 어떤 것을 즐겨 쓰느냐.
개인적으로 회고적인 환경hexdump
에서도 사용할 수 없는 곳이 있고od
어디서든 사용할 수 있을 것 같다.[rso@localhost log]$ hexdump -C /var/log/wtmp | head
00000000 02 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 |........~.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 7e 7e 00 00 72 65 62 6f |........~~..rebo|
00000030 6f 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |ot..............|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 32 2e 36 2e |............2.6.|
00000050 33 32 2d 32 37 39 2e 65 6c 36 2e 78 38 36 5f 36 |32-279.el6.x86_6|
00000060 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |4...............|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000150 00 00 00 00 33 8d fc 4f 34 e5 01 00 00 00 00 00 |....3..O4.......|
또한objdump
도 가능합니다.
이것은 뒤에 설명된 ELF 파일을 처리할 때 사용됩니다.[rso@localhost log]$ objdump -s -b binary /var/log/wtmp | head
/var/log/wtmp: file format binary
Contents of section .data:
00000 02000000 00000000 7e000000 00000000 ........~.......
00010 00000000 00000000 00000000 00000000 ................
00020 00000000 00000000 7e7e0000 7265626f ........~~..rebo
00030 6f740000 00000000 00000000 00000000 ot..............
00040 00000000 00000000 00000000 322e362e ............2.6.
00050 33322d32 37392e65 6c362e78 38365f36 32-279.el6.x86_6
바이너리 파일 편집하기
vim
에서 바이너리 모드로 열면 명령%!xxd
으로 바이너리를 표시할 수 있습니다.
편집이 끝나면 :%!xxd -r
로 돌아갑니다.[rso@localhost log]$ vim -b binfile
(省略)
:%!xxd
(16進表示になる。編集する)
:%!xxd -r
(元に戻る)
:wq
또한vim(xxd)
들어가지 않은전시대적인기계에서작업하거나vim
열지 않고열면너무무거운경우dd
아래와 같이편집할 수 있다.[rso@localhost log]$ hexdump binfile2 -C
00000000 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 |bbbbbbbbbbbbbbbb|
00000010 62 62 62 62 62 62 62 62 62 62 0a |bbbbbbbbbb.|
[rso@localhost log]$ echo -en '\x5A\x5A' | dd of=binfile2 bs=1 se
ek=16 conv=notrunc
2+0 records in
2+0 records out
2 bytes (2 B) copied, 6.0608e-05 s, 33.0 kB/s
[rso@localhost log]$ hexdump binfile2 -C
00000000 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 |bbbbbbbbbbbbbbbb|
00000010 5a 5a 62 62 62 62 62 62 62 62 0a |ZZbbbbbbbb.|
ELF 파일 시작
ELF(Exectable and Linking Format)는 Linux에서 실행할 수 있는 프로그램이나 링크된 공유 라이브러리 등 바이너리 파일의 파일 형식을 가리킨다.
ELF 헤더 표시
다음 간단한 Hello world 2진법을 대상으로 합니다.[rso@localhost log]$ cat main.c
#include <stdio.h>
int main(){
printf("hello, world\n");
}
[rso@localhost log]$ gcc main.c
readelf
명령을 사용합니다.[rso@localhost log]$ readelf -h a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4003e0
Start of program headers: 64 (bytes into file)
Start of section headers: 2472 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 27
64bit 2진법, 서열 등을 기록했다.
프로그램 제목 표시
[rso@localhost log]$ readelf -l a.out
(省略)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000068c 0x000000000000068c R E 200000
LOAD 0x0000000000000690 0x0000000000600690 0x0000000000600690
0x00000000000001ec 0x0000000000000200 RW 200000
(省略)
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
(省略)
각 세그먼트의 오프셋을 시작하는 스토리지 읽기와 쓰기 권한, 세그먼트에 포함된 세그먼트에 대한 정보를 표시합니다.
예를 들어, 섹션입니다.rodata는 권한 RE(읽기, 실행)의 LOAD 세그먼트에 있습니다.
섹션 제목 표시
[rso@localhost log]$ cat main.c
#include <stdio.h>
int main(){
printf("hello, world\n");
}
[rso@localhost log]$ gcc main.c
[rso@localhost log]$ readelf -S a.out
There are 30 section headers, starting at offset 0x9a8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400200 00000200
000000000000001c 0000000000000000 A 0 0 1
(省略)
[13] .text PROGBITS 00000000004003e0 000003e0
00000000000001d8 0000000000000000 AX 0 0 16
(省略)
[15] .rodata PROGBITS 00000000004005c8 000005c8
000000000000001d 0000000000000000 A 0 0 8
(省略)
[24] .data PROGBITS 0000000000600878 00000878
0000000000000004 0000000000000000 WA 0 0 4
(省略)
각 절의 제목 종류와 위치를 표시합니다.Offset은 프로그램이 시작하는 거리의 일부를 표시하고 몇 개의 항목 제목 종류를 기록합니다.
[rso@localhost log]$ file /bin/ls /bin/sh /var/log/messages /dev/sda /dev/tty11 /tmp /tmp/test.pl /tmp/hoge
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
/bin/sh: symbolic link to `bash'
/var/log/messages: ASCII English text
/dev/sda: block special
/dev/tty11: character special
/tmp: sticky directory
/tmp/test.pl: ASCII text
/tmp/hoge: data
[rso@localhost log]$ strings /var/log/wtmp | head
reboot
2.6.32-279.el6.x86_64
runlevel
2.6.32-279.el6.x86_64
tty1
LOGIN
tty2
LOGIN
tty3
LOGIN
[rso@localhost log]$ od -Ax -tx1z /var/log/wtmp |head
000000 02 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 >........~.......<
000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
000020 00 00 00 00 00 00 00 00 7e 7e 00 00 72 65 62 6f >........~~..rebo<
000030 6f 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ot..............<
000040 00 00 00 00 00 00 00 00 00 00 00 00 32 2e 36 2e >............2.6.<
000050 33 32 2d 35 37 33 2e 33 2e 31 2e 65 6c 36 2e 78 >32-573.3.1.el6.x<
000060 38 36 5f 36 34 00 00 00 00 00 00 00 00 00 00 00 >86_64...........<
000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
*
000150 00 00 00 00 ba 75 ff 55 84 37 09 00 00 00 00 00 >.....u.U.7......<```
[rso@localhost log]$ hexdump -C /var/log/wtmp | head
00000000 02 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 |........~.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 7e 7e 00 00 72 65 62 6f |........~~..rebo|
00000030 6f 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |ot..............|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 32 2e 36 2e |............2.6.|
00000050 33 32 2d 32 37 39 2e 65 6c 36 2e 78 38 36 5f 36 |32-279.el6.x86_6|
00000060 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |4...............|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000150 00 00 00 00 33 8d fc 4f 34 e5 01 00 00 00 00 00 |....3..O4.......|
[rso@localhost log]$ objdump -s -b binary /var/log/wtmp | head
/var/log/wtmp: file format binary
Contents of section .data:
00000 02000000 00000000 7e000000 00000000 ........~.......
00010 00000000 00000000 00000000 00000000 ................
00020 00000000 00000000 7e7e0000 7265626f ........~~..rebo
00030 6f740000 00000000 00000000 00000000 ot..............
00040 00000000 00000000 00000000 322e362e ............2.6.
00050 33322d32 37392e65 6c362e78 38365f36 32-279.el6.x86_6
[rso@localhost log]$ vim -b binfile
(省略)
:%!xxd
(16進表示になる。編集する)
:%!xxd -r
(元に戻る)
:wq
[rso@localhost log]$ hexdump binfile2 -C
00000000 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 |bbbbbbbbbbbbbbbb|
00000010 62 62 62 62 62 62 62 62 62 62 0a |bbbbbbbbbb.|
[rso@localhost log]$ echo -en '\x5A\x5A' | dd of=binfile2 bs=1 se
ek=16 conv=notrunc
2+0 records in
2+0 records out
2 bytes (2 B) copied, 6.0608e-05 s, 33.0 kB/s
[rso@localhost log]$ hexdump binfile2 -C
00000000 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 |bbbbbbbbbbbbbbbb|
00000010 5a 5a 62 62 62 62 62 62 62 62 0a |ZZbbbbbbbb.|
ELF(Exectable and Linking Format)는 Linux에서 실행할 수 있는 프로그램이나 링크된 공유 라이브러리 등 바이너리 파일의 파일 형식을 가리킨다.
ELF 헤더 표시
다음 간단한 Hello world 2진법을 대상으로 합니다.
[rso@localhost log]$ cat main.c
#include <stdio.h>
int main(){
printf("hello, world\n");
}
[rso@localhost log]$ gcc main.c
readelf
명령을 사용합니다.[rso@localhost log]$ readelf -h a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4003e0
Start of program headers: 64 (bytes into file)
Start of section headers: 2472 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 27
64bit 2진법, 서열 등을 기록했다.프로그램 제목 표시
[rso@localhost log]$ readelf -l a.out
(省略)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000068c 0x000000000000068c R E 200000
LOAD 0x0000000000000690 0x0000000000600690 0x0000000000600690
0x00000000000001ec 0x0000000000000200 RW 200000
(省略)
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
(省略)
각 세그먼트의 오프셋을 시작하는 스토리지 읽기와 쓰기 권한, 세그먼트에 포함된 세그먼트에 대한 정보를 표시합니다.예를 들어, 섹션입니다.rodata는 권한 RE(읽기, 실행)의 LOAD 세그먼트에 있습니다.
섹션 제목 표시
[rso@localhost log]$ cat main.c
#include <stdio.h>
int main(){
printf("hello, world\n");
}
[rso@localhost log]$ gcc main.c
[rso@localhost log]$ readelf -S a.out
There are 30 section headers, starting at offset 0x9a8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400200 00000200
000000000000001c 0000000000000000 A 0 0 1
(省略)
[13] .text PROGBITS 00000000004003e0 000003e0
00000000000001d8 0000000000000000 AX 0 0 16
(省略)
[15] .rodata PROGBITS 00000000004005c8 000005c8
000000000000001d 0000000000000000 A 0 0 8
(省略)
[24] .data PROGBITS 0000000000600878 00000878
0000000000000004 0000000000000000 WA 0 0 4
(省略)
각 절의 제목 종류와 위치를 표시합니다.Offset은 프로그램이 시작하는 거리의 일부를 표시하고 몇 개의 항목 제목 종류를 기록합니다..text
텍스트 세그먼트.실행 프로그램 구성 영역.rodata
...읽기 전용 정수 등이 있는 영역 구성.data
...초기화된 데이터로 구성된 변경 가능 영역[rso@localhost log]$ hexdump a.out -s 0x5c8 -n $((0x01d)) -C
000005c8 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000005d8 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 00 |hello, world.|
상기 프로그램을 포함하는 문자열 상수를 알 수 있습니다.절명을 알고 뽑고 싶다면
objdump
도 된다.[rso@localhost log]$ objdump -s -j .rodata a.out
a.out: file format elf64-x86-64
Contents of section .rodata:
4005c8 01000200 00000000 00000000 00000000 ................
4005d8 68656c6c 6f2c2077 6f726c64 00 hello, world.
그나저나 strings
명령도 다음과 같다.[rso@localhost log]$ strings -tx a.out
200 /lib64/ld-linux-x86-64.so.2
(省略)
5d8 hello, world
ELF 파일에서 기호를 표시합니다.
기호는 함수, 변수, 주소와 관련된 식별자를 가리킨다.
프로그램이나 링크를 실행할 때 사용합니다.
nm
명령은 기호를 표시할 수 있습니다.[rso@localhost ~]$ gcc -o main -c main.o
[rso@localhost ~]$ nm main.o
0000000000000000 T main
U puts
기호의 종류는 여기에 상세하게 쓰여 있지 않지만 U는 정의되지 않은 기호입니다.실행 가능한 파일에도 사용할 수 있습니다.
[rso@localhost ~]$ nm a.out
00000000006006b8 d _DYNAMIC
(省略)
00000000004004c4 T main
U puts@@GLIBC_2.2.5
실행 파일에서 사용하는 공유 라이브러리 보이기
사용
ldd
이 편리합니다.실행할 때 읽은 라이브러리 일람표를 표시합니다.
[rso@localhost log]$ ldd a.out
linux-vdso.so.1 => (0x00007ffe39db9000)
libc.so.6 => /lib64/libc.so.6 (0x0000003bc3e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003bc3600000)
참고 문헌
주로 아래 자료에서 자신이 이해한 내용을 기재하였다.
Reference
이 문제에 관하여(바이너리 수준 조사를 위한 Linux 명령 주석), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/rsooo/items/bb91071685f447ce29db텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)