FreeBSD 10.3에서 명령을 실행하면 view /bin/ls
수정되지 않은 바이너리를 볼 수 있습니다.
그런 다음 vim/view에서 명령을 실행하면 :%!xxd
아래와 같이 16진수 형식의 파일을 볼 수 있습니다. 나는 페이지 하단에서 vim이 1708행이 추가되고 74행이 삭제되었다고 발표한 것을 보았습니다.
명령어를 통해 vim을 닫았다 :q!
가 다시 열어서 view /bin/ls
vim 명령어를 실행 :%!xxd -b
하면 아래와 같이 바이너리 형식의 파일이 보입니다. 페이지 하단에는 4555줄이 추가되었고 74줄이 삭제되었다고 나와 있습니다.
이제 나는 알고 싶습니다:
vim에서 명령을 실행할
:%!xxd
때 일부 줄이 추가되고 일부 줄이 삭제되는 이유는 무엇입니까?:%!xxd -b
16진수 형식의 경우, 즉
%!xxd
명령을 실행할 때 줄 주소는 00000000, 00000010, 00000020, 00000030 등입니다. 이는 각 줄에 16바이트가 포함되어 있으므로 0x10 증분이 의미가 있기 때문인 것 같습니다.바이너리 형식의 경우, 즉
%!xxd -b
명령을 실행할 때 줄 주소는 00000000, 00000006, 0000000c, 00000012 등입니다. 이는 각 줄에 6바이트가 포함되어 있으므로 0x06 증분이 의미가 있기 때문인 것 같습니다.이전에는 각 바이너리가 한 줄의 각 프로세서 명령어를 포함하고 각 줄의 시작 부분에 해당 명령어의 상대 주소가 있으며 첫 번째 명령어는 0으로 시작한다고 생각했습니다. 그러나 vim에서 바이너리를 관찰한 결과, 이는 사실이 아닙니다. 이제 나는 알고 싶다프로세서가 각 명령어의 opcode와 피연산자를 결정하는 방법, 지시어가 바이너리 파일에서 한 줄씩 형식화되지 않은 경우.
고쳐 쓰다:
16진수 형식의 마지막 5줄은 다음과 같습니다.
00006a70: 0100 0000 3000 0000 0000 0000 4862 0000 ....0.......Hb..
00006a80: 3e03 0000 0000 0000 0000 0000 0100 0000 >...............
00006a90: 0100 0000 0100 0000 0300 0000 0000 0000 ................
00006aa0: 0000 0000 8665 0000 d500 0000 0000 0000 .....e..........
00006ab0: 0000 0000 0100 0000 0000 0000 0a .............
이진 형식의 마지막 5줄은 다음과 같습니다.
00006aa4: 10000110 01100101 00000000 00000000 11010101 00000000 .e....
00006aaa: 00000000 00000000 00000000 00000000 00000000 00000000 ......
00006ab0: 00000000 00000000 00000000 00000000 00000001 00000000 ......
00006ab6: 00000000 00000000 00000000 00000000 00000000 00000000 ......
00006abc: 00001010 .
그래서 16진수 형식과 2진수 형식의 총 바이트 수가 같다고 생각합니다. 즉, 코드의 마지막 바이트 주소가 둘 다 동일하다는 뜻입니다 0x6abc
.
답변1
vim에서 :%!xxd 및 :%!xxd -b 명령을 실행할 때 일부 줄이 추가되고 일부 줄이 삭제되는 이유는 무엇입니까?
vim
줄 바꿈이 계산 0x0a
되고 바이너리에 이러한 내용이 포함되어 있기 때문에 (귀하의 버전에서는 74줄 ls
...) 바이너리의 이 74줄은 원래 바이너리와 다른 형식을 교환할 때 제거되고 새 행이 삭제됩니다. (더 자세한) 16진수 표시를 위해 추가되었습니다. vim
단지 보이는 것을 계산할 뿐입니다 0x0a
.
이제 프로세서가 각 명령어에 대한 opcode와 피연산자를 어떻게 결정하는지 알고 싶습니다.
마법! 그것은 복잡하고 이 주제에 대해 쓰여진 책이 많이 있습니다. 즉, 링커(또는 이에 상응하는) 특정 바이너리 형식(귀하의 경우 ELF, 다른 형식도 존재하지만 a.out, Mach-O 등)은 시작 주소를 나타냅니다.
$ readelf -h /bin/ls
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: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x37f0
...
프로그램이 메모리로 승격된 후 opcode 실행이 시작됩니다. 시작 주소는 일반적으로 .text
바이너리 파일 섹션 어딘가에 있습니다(아마도 아닐 수도 있음).
$ objdump -DS /bin/ls | less -p .text
...
내 OpenBSD 시스템에는 다음이 표시됩니다.
Disassembly of section .text:
00000000000037f0 <revnamecmp-0x460>:
37f0: 49 89 e4 mov %rsp,%r12
37f3: 48 83 ec 08 sub $0x8,%rsp
37f7: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
37fb: 48 83 c4 08 add $0x8,%rsp
...
살펴볼 가치가 있는 책으로는 Jeff Duntemann의 "Assembly Language Step-by-Step"과 Ryan O'Neill의 ELF "Learning Linux Binary Analysis"가 있습니다.