objdump
+ gdb
ตัวอย่างที่รันได้น้อยที่สุด
TL; DR:
ตอนนี้สำหรับการตั้งค่าการทดสอบการศึกษาเต็มรูปแบบ:
main.c
#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);
}
คอมไพล์และรันเพื่อสร้างคอร์:
gcc -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
ulimit -c unlimited
rm -f core
./main.out
เอาท์พุท:
text addr: 0x4007d4
data addr: 0x7ffec6739220
mmap addr: 0x1612010
Segmentation fault (core dumped)
GDB ชี้ให้เราเห็นถึงบรรทัดที่แน่นอนที่เกิดข้อผิดพลาดในการแบ่งส่วนซึ่งเป็นสิ่งที่ผู้ใช้ส่วนใหญ่ต้องการขณะทำการดีบัก:
gdb -q -nh main.out core
แล้ว:
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
ซึ่งชี้ให้เราตรงไปที่รถบั๊กกี้ไลน์ 7
อาร์กิวเมนต์ CLI ถูกเก็บไว้ในไฟล์ core และไม่จำเป็นต้องส่งผ่านอีกครั้ง
ในการตอบคำถามอาร์กิวเมนต์ CLI เฉพาะเราจะเห็นว่าถ้าเราเปลี่ยนอาร์กิวเมนต์ cli เช่นด้วย:
rm -f core
./main.out 1 2
ดังนั้นสิ่งนี้จะปรากฏใน bactrace ก่อนหน้าโดยไม่มีการเปลี่ยนแปลงคำสั่งของเรา:
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
argc=3
ดังนั้นวิธีการที่ทราบในขณะนี้ ดังนั้นสิ่งนี้ต้องหมายความว่าไฟล์หลักเก็บข้อมูลนั้น ฉันเดาว่ามันแค่เก็บไว้เป็นข้อโต้แย้งmain
เหมือนเก็บอาร์กิวเมนต์ของฟังก์ชั่นอื่น ๆ
สิ่งนี้เหมาะสมถ้าคุณพิจารณาว่าดัมพ์หลักต้องถูกเก็บหน่วยความจำทั้งหมดและสถานะการลงทะเบียนของโปรแกรมดังนั้นจึงมีข้อมูลทั้งหมดที่จำเป็นในการกำหนดค่าของฟังก์ชันอาร์กิวเมนต์ในสแต็กปัจจุบัน
ชัดเจนน้อยกว่าคือวิธีการตรวจสอบตัวแปรสภาพแวดล้อม: วิธีรับตัวแปรสภาพแวดล้อมจากแกนดัมพ์ตัวแปรสภาพแวดล้อมก็มีอยู่ในหน่วยความจำด้วยดังนั้น objdump จึงมีข้อมูลนั้น แต่ฉันไม่แน่ใจว่าจะแสดงรายการทั้งหมดในครั้งเดียวอย่างสะดวก ทีละคนดังต่อไปนี้ทำงานทดสอบของฉันแม้ว่า:
p __environ[0]
การวิเคราะห์ Binutils
โดยใช้เครื่องมือ binutils เช่นreadelf
และobjdump
เราสามารถถ่ายโอนข้อมูลจำนวนมากที่มีอยู่ในcore
ไฟล์เช่นสถานะหน่วยความจำ
ส่วนใหญ่ / ทั้งหมดจะต้องมองเห็นได้ผ่าน GDB แต่เครื่องมือ binutils เหล่านั้นมีวิธีการจำนวนมากซึ่งสะดวกสำหรับการใช้งานบางกรณีในขณะที่ GDB สะดวกกว่าสำหรับการสำรวจเชิงโต้ตอบมากขึ้น
ครั้งแรก:
file core
บอกเราว่าcore
ไฟล์นั้นเป็นไฟล์ELF :
core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './main.out'
นี่คือเหตุผลที่เราสามารถตรวจสอบได้โดยตรงด้วยเครื่องมือ binutils ปกติ
ดูอย่างรวดเร็วเกี่ยวกับมาตรฐาน ELFแสดงให้เห็นว่าจริง ๆ แล้วมันมีประเภทของเอลฟ์ที่อุทิศตน:
Elf32_Ehd.e_type == ET_CORE
ข้อมูลรูปแบบเพิ่มเติมสามารถดูได้ที่:
man 5 core
แล้ว:
readelf -Wa core
ให้คำแนะนำบางอย่างเกี่ยวกับโครงสร้างไฟล์ ดูเหมือนว่าหน่วยความจำจะอยู่ในส่วนหัวของโปรแกรมปกติ:
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
และยังมีข้อมูลเมตาอีกจำนวนหนึ่งอยู่ในพื้นที่บันทึกย่อโดยprstatus
มีพีซี :
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
สามารถถ่ายโอนข้อมูลหน่วยความจำทั้งหมดได้อย่างง่ายดายด้วย:
objdump -s core
ซึ่งประกอบด้วย:
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..........
ซึ่งตรงกับค่า stdout ในการทำงานของเรา
สิ่งนี้ถูกทดสอบบน Ubuntu 16.04 amd64, GCC 6.4.0 และ binutils 2.26.1
exe
ไม่ใช่สคริปต์เชลล์ (เพื่อตั้งค่าตัวแปรบางอย่าง ฯลฯ ) อย่างเช่นfirefox
อยู่ใน Linux