objdump
+ gdb
ví dụ chạy tối thiểu
TL; DR:
Bây giờ cho các thiết lập kiểm tra giáo dục đầy đủ:
C chính
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int myfunc(int i) {
*(int*)(NULL) = i; /* line 7 */
return i - 1;
}
int main(int argc, char **argv) {
/* Setup some memory. */
char data_ptr[] = "string in data segment";
char *mmap_ptr;
char *text_ptr = "string in text segment";
(void)argv;
mmap_ptr = (char *)malloc(sizeof(data_ptr) + 1);
strcpy(mmap_ptr, data_ptr);
mmap_ptr[10] = 'm';
mmap_ptr[11] = 'm';
mmap_ptr[12] = 'a';
mmap_ptr[13] = 'p';
printf("text addr: %p\n", text_ptr);
printf("data addr: %p\n", data_ptr);
printf("mmap addr: %p\n", mmap_ptr);
/* Call a function to prepare a stack trace. */
return myfunc(argc);
}
Biên dịch và chạy để tạo lõi:
gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out
Đầu ra:
text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)
GDB chỉ cho chúng tôi dòng chính xác xảy ra lỗi phân đoạn, đây là điều mà hầu hết người dùng muốn trong khi gỡ lỗi:
gdb -q -nh main.out core
sau đó:
Reading symbols from main.out...done.
[New LWP 27479]
Core was generated by `./main.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000400635 in myfunc (i=1) at main.c:7
7 *(int*)(NULL) = i;
(gdb) bt
#0 0x0000000000400635 in myfunc (i=1) at main.c:7
#1 0x000000000040072b in main (argc=1, argv=0x7ffec6739328) at main.c:28
trong đó chỉ chúng tôi trực tiếp đến dòng lỗi 7.
Đối số CLI được lưu trữ trong tệp lõi và không cần phải truyền lại
Để trả lời các câu hỏi đối số CLI cụ thể, chúng tôi thấy rằng nếu chúng tôi thay đổi các đối số cli, ví dụ như với:
rm -f core
./main.out 1 2
sau đó, điều này sẽ được phản ánh trong bactrace trước mà không có bất kỳ thay đổi nào trong các lệnh của chúng tôi:
Reading symbols from main.out...done.
[New LWP 21838]
Core was generated by `./main.out 1 2'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000564583cf2759 in myfunc (i=3) at main.c:7
7 *(int*)(NULL) = i; /* line 7 */
(gdb) bt
#0 0x0000564583cf2759 in myfunc (i=3) at main.c:7
#1 0x0000564583cf2858 in main (argc=3, argv=0x7ffcca4effa8) at main.c:2
Vì vậy, lưu ý làm thế nào bây giờ argc=3
. Do đó, điều này có nghĩa là tệp lõi lưu trữ thông tin đó. Tôi đoán nó chỉ lưu trữ nó như là đối số của main
, giống như nó lưu trữ các đối số của bất kỳ chức năng nào khác.
Điều này có ý nghĩa nếu bạn xem xét rằng kết xuất lõi phải được lưu trữ toàn bộ bộ nhớ và trạng thái đăng ký của chương trình, và do đó, nó có tất cả thông tin cần thiết để xác định giá trị của các đối số hàm trên ngăn xếp hiện tại.
Ít rõ ràng hơn là cách kiểm tra các biến môi trường: Cách lấy biến môi trường từ kết xuất lõi Các biến môi trường cũng có trong bộ nhớ để objdump có chứa thông tin đó, nhưng tôi không chắc cách liệt kê tất cả chúng một cách thuận tiện , từng người một như sau đã làm bài kiểm tra của tôi:
p __environ[0]
Phân tích Binutils
Bằng cách sử dụng các công cụ binutils như readelf
và objdump
, chúng ta có thể kết xuất hàng loạt thông tin có trong core
tệp như trạng thái bộ nhớ.
Hầu hết / tất cả cũng phải được hiển thị thông qua GDB, nhưng các công cụ binutils đó cung cấp một cách tiếp cận số lượng lớn hơn, thuận tiện cho các trường hợp sử dụng nhất định, trong khi GDB thuận tiện hơn cho việc khám phá tương tác nhiều hơn.
Đầu tiên:
file core
cho chúng ta biết rằng core
tệp thực sự là tệp ELF :
core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'
đó là lý do tại sao chúng ta có thể kiểm tra nó trực tiếp hơn bằng các công cụ binutils thông thường.
Nhìn nhanh vào tiêu chuẩn ELF cho thấy thực sự có một loại ELF dành riêng cho nó:
Elf32_Ehd.e_type == ET_CORE
Thông tin định dạng khác có thể được tìm thấy tại:
man 5 core
Sau đó:
readelf -Wa core
đưa ra một số gợi ý về cấu trúc tập tin. Bộ nhớ dường như được chứa trong các tiêu đề chương trình thông thường:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
NOTE 0x000468 0x0000000000000000 0x0000000000000000 0x000b9c 0x000000 0
LOAD 0x002000 0x0000000000400000 0x0000000000000000 0x001000 0x001000 R E 0x1000
LOAD 0x003000 0x0000000000600000 0x0000000000000000 0x001000 0x001000 R 0x1000
LOAD 0x004000 0x0000000000601000 0x0000000000000000 0x001000 0x001000 RW 0x1000
và có thêm một số siêu dữ liệu trong khu vực ghi chú, đáng chú ý prstatus
có chứa PC :
Displaying notes found at file offset 0x00000468 with length 0x00000b9c:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000080 NT_SIGINFO (siginfo_t data)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00000246 NT_FILE (mapped files)
Page size: 4096
Start End Page Offset
0x0000000000400000 0x0000000000401000 0x0000000000000000
/home/ciro/test/main.out
0x0000000000600000 0x0000000000601000 0x0000000000000000
/home/ciro/test/main.out
0x0000000000601000 0x0000000000602000 0x0000000000000001
/home/ciro/test/main.out
0x00007f8d939ee000 0x00007f8d93bae000 0x0000000000000000
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93bae000 0x00007f8d93dae000 0x00000000000001c0
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93dae000 0x00007f8d93db2000 0x00000000000001c0
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93db2000 0x00007f8d93db4000 0x00000000000001c4
/lib/x86_64-linux-gnu/libc-2.23.so
0x00007f8d93db8000 0x00007f8d93dde000 0x0000000000000000
/lib/x86_64-linux-gnu/ld-2.23.so
0x00007f8d93fdd000 0x00007f8d93fde000 0x0000000000000025
/lib/x86_64-linux-gnu/ld-2.23.so
0x00007f8d93fde000 0x00007f8d93fdf000 0x0000000000000026
/lib/x86_64-linux-gnu/ld-2.23.so
CORE 0x00000200 NT_FPREGSET (floating point registers)
LINUX 0x00000340 NT_X86_XSTATE (x86 XSAVE extended state)
objdump
có thể dễ dàng kết xuất tất cả bộ nhớ với:
objdump -s core
trong đó có:
Contents of section load1:
4007d0 01000200 73747269 6e672069 6e207465 ....string in te
4007e0 78742073 65676d65 6e740074 65787420 xt segment.text
Contents of section load15:
7ffec6739220 73747269 6e672069 6e206461 74612073 string in data s
7ffec6739230 65676d65 6e740000 00a8677b 9c6778cd egment....g{.gx.
Contents of section load4:
1612010 73747269 6e672069 6e206d6d 61702073 string in mmap s
1612020 65676d65 6e740000 11040000 00000000 egment..........
phù hợp chính xác với giá trị xuất chuẩn trong lần chạy của chúng tôi.
Điều này đã được thử nghiệm trên Ubuntu 16.04 amd64, GCC 6.4.0 và binutils 2.26.1.
exe
không phải là tập lệnh shell (để đặt một số biến, v.v.) như ví dụ nhưfirefox
trên Linux không?