-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathelfcore.py
More file actions
executable file
·175 lines (154 loc) · 6.5 KB
/
Copy pathelfcore.py
File metadata and controls
executable file
·175 lines (154 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python3
import json
import optparse
import elf
def create_option_parser() -> optparse.OptionParser:
parser = optparse.OptionParser(
description='A script that reduces the size of ELF core file files.')
parser.add_option(
'-o', '--outfile',
type='string',
metavar='PATH',
dest='outfile',
default=None,
help='The path to the file to save.')
parser.add_option(
'--elf-headers',
action='store_true',
dest='elf_headers',
default=False,
help='Save all memory regions that contain ELF headers.')
parser.add_option(
'--r-debug',
action='store_true',
dest='r_debug',
default=False,
help='Save any memory regions that contain the r_debug structure points to. This is the list of shared libraries loaded by the process.')
parser.add_option(
'-m', '--minimize',
action='store_true',
dest='minimize',
default=False,
help='Minimize the core file by removing zero PT_LOAD segments and not'
' emitting PT_LOAD entries with no file size.')
parser.add_option(
'--yaml',
action='store_true',
dest='emit_yaml',
default=False,
help='Save as yaml instead of a real core file.')
parser.add_option(
'-a', '--address',
type='int',
metavar='ADDR',
dest='addresses',
action='append',
default=[],
help='Specify an address whose memory contents will be preserved. '
'This can be specified multple times')
parser.add_option(
'-j', '--elf-json',
type='str',
metavar='PATH',
dest='elf_json',
default=[],
help='Specify a JSON file with contents to be added to the output ELF core file.')
return parser
def main():
parser = create_option_parser()
(options, files) = parser.parse_args()
if len(files) != 1:
print("error: a single path to a core file must be given")
return
core_elf = elf.File(path=files[0])
if core_elf.error:
print(core_elf.error)
return
min_core_elf = elf.File(header=core_elf.header)
program_headers = []
if options.outfile is None:
print("error: an output file must be specified with --outfile PATH")
return
if options.elf_headers:
nt_file_note = core_elf.get_note(['CORE', 'LINUX'], elf.NT_LINUX.FILE)
if nt_file_note is None:
return None
nt_files = nt_file_note.get_entries()
if nt_files:
path = None
for nt_file in nt_files.nt_files:
ph = core_elf.get_program_header_by_vaddr_in_file(nt_file.start)
if ph is not None:
if elf.Header.is_elf_file(ph.get_contents_as_extractor()):
nt_file.dump()
options.addresses.append(ph.p_vaddr)
if options.r_debug:
# First make sure we have the PT_DYNAMIC
exe_elf = core_elf.get_core_executable()
if exe_elf is None:
raise ValueError('Unable to read executable ELF from core file')
dynamic_phdrs = exe_elf.get_program_headers_by_type(elf.PT.DYNAMIC)
if len(dynamic_phdrs) == 0:
raise ValueError('Unable to find PT_DYNAMIC program header in ELF executable')
for dynamic_phdr in dynamic_phdrs:
vaddr = dynamic_phdr.get_load_address()
options.addresses.append(vaddr)
print('Adding memory region for exe PT_DYNAMIC: %#16.16x' % (vaddr))
r_debug = core_elf.get_r_debug()
if r_debug is not None:
# Save the memory region that contains the r_debug structure
options.addresses.append(r_debug.addr)
print('Adding memory region for &r_debug: %#16.16x' % (r_debug.addr))
# Save the memory region that contains each r_debug.r_map structure
options.addresses.append(r_debug.r_map)
print('Adding memory region for r_debug.r_map: %#16.16x' % (r_debug.r_map))
for rmap in r_debug.rmaps:
if rmap.l_next:
print('Adding memory region for rmap.l_next: %#16.16x' % (rmap.l_next))
options.addresses.append(rmap.l_next)
print('Adding memory region for rmap.l_name: %#16.16x' % (rmap.l_name))
options.addresses.append(rmap.l_name)
else:
raise ValueError('failed to get r_debug')
if options.minimize:
elf.ProgramHeader.dump_header()
for ph in core_elf.get_program_headers():
if ph.p_type == elf.PT.NOTE:
min_core_elf.add_program_header(ph)
pass
elif ph.p_type == elf.PT.LOAD:
if options.addresses:
for addr in options.addresses:
if ph.contains_vaddr_in_file(addr):
min_core_elf.add_program_header(ph)
break
if options.minimize:
# Many core files have a lot of program headers with zero file
# size and these are not useful as they have no data.
if ph.p_filesz == 0 and ph.p_memsz == 0:
ph.dump(flat=True, suffix=' skipping program header with p_filesz == 0 && p_memsz == 0\n')
continue # Skip
if ph.is_all_zeros() and ph.p_filesz > 0:
ph.dump(flat=True, suffix=' data is all zeros, changing program header to zero fill\n')
ph.p_filesz = 0 # Set the p_filesz to zero so the data doesn't get copied
ph.data = None # If the data had been accessed before, clear it so it doesn't get copied into the new file
min_core_elf.add_program_header(ph)
continue
else:
min_core_elf.add_program_header(ph)
if options.elf_json:
with open(options.elf_json, 'r') as f:
elf_json = json.load(f)
program_headers_json = elf_json.get('program_headers', [])
for ph_dict in program_headers_json:
ph = elf.ProgramHeader.from_dict(min_core_elf, ph_dict)
if ph is not None:
ph.elf = min_core_elf
min_core_elf.add_program_header(ph)
if options.emit_yaml:
with open(options.outfile, 'w') as f:
min_core_elf.encode_yaml(f)
else:
min_core_elf.save(options.outfile)
if __name__ == "__main__":
main()