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 """Gathers all issued commands for zsh."""
30
31 from rekall.plugins.overlays import basic
32 from rekall.plugins.linux import heap_analysis
33
34
35 -class Zsh(heap_analysis.HeapAnalysis):
36 """Extracts the zsh command history, similar to the existing bash plugin.
37 """
38
39 __name = "zsh"
40
41 table_header = [
42 dict(name="divider", type="Divider"),
43 dict(name="task", hidden=True),
44 dict(name="counter", width=8),
45 dict(name="started", width=24),
46 dict(name="ended", width=24),
47 dict(name="command")
48 ]
49
51 super(Zsh, self).__init__(**kwargs)
52 self._zsh_profile = None
53
54
56 if self.session.profile.metadata("arch") == 'AMD64':
57 self._zsh_profile = ZshProfile64(session=self.session)
58
59 else:
60
61 self._zsh_profile = ZshProfile32(session=self.session)
62
63 chunk_size = self.get_aligned_size(
64 self._zsh_profile.get_obj_size('histent'))
65
66 for task in self.filter_processes():
67 if self.init_for_task(task):
68
69 yield dict(divider="Task: %s (%s)" % (task.name,
70 task.pid))
71
72 chunks_dict = dict()
73
74 data_offset = self.profile.get_obj_offset("malloc_chunk", "fd")
75
76 chunk_data_pointers = list()
77 for chunk in self.get_all_allocated_chunks():
78 chunks_dict[chunk.v() + data_offset] = chunk
79 chunk_data_pointers.append(chunk.v() + data_offset)
80
81 commands_dict = dict()
82
83 valid_histentry = None
84
85
86
87 for chunk in self.get_all_allocated_chunks():
88
89 if not chunk.chunksize() == chunk_size:
90 continue
91
92 histent = self._zsh_profile.histent(
93 offset=chunk.v()+data_offset, vm=self.process_as)
94
95
96
97
98 pointers = [histent.node.nam, histent.down, histent.up]
99 if not len(set(pointers) & set(chunk_data_pointers)) \
100 == len(pointers):
101 continue
102
103
104
105 if not histent.up.down == histent or not histent.down.up \
106 == histent:
107 continue
108
109
110 valid_histentry = histent
111 break
112
113 if valid_histentry:
114 self.session.logging.info(
115 "We probably found a valid histent chunk and now "
116 "start walking.")
117
118
119
120 for histent in valid_histentry.walk_list('down'):
121
122 command = ''
123
124 try:
125 command = chunks_dict[histent.node.nam.v()]
126 command = command.to_string()
127 command = command[:command.index("\x00")]
128
129 except KeyError:
130 self.session.logging.warn(
131 "Unexpected error: chunk for given "
132 "command-reference does not seem to exist.")
133
134 except ValueError:
135 pass
136
137 if histent.stim == histent.ftim == 0 and command == '':
138 histent_vma = heap_analysis.get_vma_for_offset(
139 self.vmas, histent.v())
140
141 if histent_vma not in self.heap_vmas:
142
143
144
145
146 continue
147
148 command_number = histent.histnum
149 start = self.profile.UnixTimeStamp(value=histent.stim)
150 end = self.profile.UnixTimeStamp(value=histent.ftim)
151 commands_dict[command_number] = [start,
152 end,
153 repr(command)]
154
155
156 for key, value in sorted(commands_dict.items()):
157 yield dict(task=task, counter=key, started=value[0],
158 ended=value[1], command=value[2])
159
160
161
162 -class ZshProfile32(basic.Profile32Bits, basic.BasicClasses):
163 """Profile to parse internal zsh data structures."""
164
165 __abstract = True
166
167
168 zsh_vtype_32 = {
169 "histent": [48, {
170 "down": [16, ["Pointer", {
171 "target": "histent"
172 }]],
173 "ftim": [28, ["long int"]],
174 "histnum": [40, ["long long int"]],
175 "node": [0, ["hashnode"]],
176 "nwords": [36, ["int"]],
177 "stim": [24, ["long int"]],
178 "up": [12, ["Pointer", {
179 "target": "histent"
180 }]],
181 "words": [32, ["Pointer", {
182 "target": "short int"
183 }]],
184 "zle_text": [20, ["Pointer", {
185 "target": "char"
186 }]]
187 }],
188 "hashnode": [12, {
189 "flags": [8, ["int"]],
190 "nam": [4, ["Pointer", {
191 "target": "char"
192 }]],
193 "next": [0, ["Pointer", {
194 "target": "hashnode"
195 }]]
196 }]
197 }
198
202
203
204
206 """Profile to parse internal zsh data structures."""
207
208 __abstract = True
209
210
211 zsh_vtype_64 = {
212 "histent": [88, {
213 "down": [32, ["Pointer", {
214 "target": "histent"
215 }]],
216 "ftim": [56, ["long int"]],
217 "histnum": [80, ["long int"]],
218 "node": [0, ["hashnode"]],
219 "nwords": [72, ["int"]],
220 "stim": [48, ["long int"]],
221 "up": [24, ["Pointer", {
222 "target": "histent"
223 }]],
224 "words": [64, ["Pointer", {
225 "target": "short int"
226 }]],
227 "zle_text": [40, ["Pointer", {
228 "target": "char"
229 }]]
230 }],
231 "hashnode": [24, {
232 "flags": [16, ["int"]],
233 "nam": [8, ["Pointer", {
234 "target": "char"
235 }]],
236 "next": [0, ["Pointer", {
237 "target": "hashnode"
238 }]]
239 }]
240 }
241
245