-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathreadsyms.sh
202 lines (170 loc) · 5.38 KB
/
readsyms.sh
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/bin/bash
# Copyright (c) 2017 Rory McNamara
shopt -s lastpipe # used for setting env vars in pipes to limit use of subshells
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
PROGBITS=1
SYMTAB=2
STRTAB=3
DYNSYM=11
source utils.sh
readgeneric() {
# file, offset, count, echo result
file=""
[[ "${1}" != "-" ]] && file="if=${1}"
IFS=' ' data=($(dd ${file} skip=${2} count=${3} status=none bs=1 | tohex ${3}))
# reverse to get the correct byte order
rdata=""
for ((x=${#data[@]}; x>=0; x--)); do
rdata=${rdata}${data[${x}]}
done
if [[ ! -z ${4} ]]; then
echo $((16#${rdata}))
elif [[ ${3} -eq 2 ]]; then
retshort=$((16#${rdata}))
elif [[ ${3} -eq 4 ]]; then
retint=$((16#${rdata}))
elif [[ ${3} -eq 8 ]]; then
retlong=$((16#${rdata}))
else
echo $((16#${rdata}))
fi
}
readshort() {
readgeneric ${1} ${2} 2 ${3}
}
readint() {
readgeneric ${1} ${2} 4 ${3}
}
readlong() {
readgeneric ${1} ${2} 8 ${3}
}
getsecstrtab() {
# return a string from secstrtab
skip=${1}
secstr=(${shstrtab:${skip}})
secstr=${secstr[0]}
}
getstrtab() {
# return a string from strtab
skip=${1}
symstr=(${strtab:${skip}})
symstr=${symstr[0]}
}
parsesect() {
# return elements of section struct. name, type, offset and size
# we are consuming now, so offsets are relevant to the start of the struct to begin
# and then relative to wherever that element ends
readint "-" 0
sh_name=${retint}
readint "-" 0
sh_type=${retint}
readlong "-" $((16#10))
sh_offset=${retlong}
readlong "-" 0
sh_size=${retlong}
}
getsect() {
LIB="${1}"
# return offset and size from a section
genlookup "${LIB}" false
e_shoff=$(readlong ${LIB} $((16#28)) 1) # start of the section header table
e_shnum=$(readshort ${LIB} $((16#3C)) 1) # number of section header entries
e_shentsize=$(readshort ${LIB} $((16#3A)) 1) # section header table entry size
e_shstrndx=$(readshort ${LIB} $((16#3E)) 1) # index to section names section entry
shstrtab_offset=$(readlong ${LIB} $((${e_shoff}+$((${e_shstrndx}*${e_shentsize}))+$((16#18)))) 1) # offset to shstrtab
shstrtab_size=$(readlong ${LIB} $((${e_shoff}+$((${e_shstrndx}*${e_shentsize}))+$((16#20)))) 1) # size of shstrtab
for ((i=0; i <= $((${e_shnum}-1)); i++)); do
# read the whole struct in one so we thrash less
dd if=${1} skip=$((${e_shoff}+$((${i}*${e_shentsize})))) count=$((16#28)) bs=1 status=none | parsesect
if [[ ! -z "${3}" ]]; then # if a type is specified
if [[ "${sh_type}" != "${3}" ]]; then # and it's not the same as the current sect
continue # don't check the name
fi
fi
getsecstrtab "$((${sh_name}+1))"
if [[ "${secstr}" = "${2}" ]]; then
echo "${sh_offset} ${sh_size}"
break
fi
done
}
getstrsect() {
unset strtab_offset strtab_size
getsect "${1}" ".strtab" ${STRTAB} | read strtab_offset strtab_size
if [[ ! -z "${strtab_offset}" && ! -z "${strtab_size}" ]]; then
echo "${strtab_offset} ${strtab_size}"
else
getsect "${1}" ".dynstr" ${STRTAB}
fi
}
getsymsect() {
unset symtab_offset symtab_size
getsect "${1}" ".symtab" ${SYMTAB} | read symtab_offset symtab_size
if [[ ! -z "${symtab_offset}" && ! -z "${symtab_size}" ]]; then
echo "${symtab_offset} ${symtab_size}"
else
getsect "${1}" ".dynsym" ${DYNSYM}
fi
}
checksym() {
# start at idx 0 for the first item
readint "-" 0
if [[ ${retint} -eq ${2} ]]; then
symfound="0"
return
fi
# then we jump to idx 20 for the rest of the items
local i
for ((i=0; i < $((${1}*24)); i+=24)); do
readint "-" 20
if [[ ${retint} -eq ${2} ]]; then
# +1 for the read at idx 0
symfound="$(($((${i}/24))+1))"
break
fi
done
}
genlookup() {
LIB=${1}
e_shoff=$(readlong ${LIB} $((16#28)) 1) # start of the section header table
e_shnum=$(readshort ${LIB} $((16#3C)) 1) # number of section header entries
e_shentsize=$(readshort ${LIB} $((16#3A)) 1) # section header table entry size
e_shstrndx=$(readshort ${LIB} $((16#3E)) 1) # index to section names section entry
shstrtab_offset=$(readlong ${LIB} $((${e_shoff}+$((${e_shstrndx}*${e_shentsize}))+$((16#18)))) 1) # offset to shstrtab
shstrtab_size=$(readlong ${LIB} $((${e_shoff}+$((${e_shstrndx}*${e_shentsize}))+$((16#20)))) 1) # size of shstrtab
# needs to be global
shstrtab=
while IFS= read -r -d '' sect; do
shstrtab="${shstrtab} ${sect}"
done < <(dd if=${LIB} skip=${shstrtab_offset} bs=1 count=${shstrtab_size} status=none)
if [[ -z "${2}" ]]; then
getstrsect "${LIB}" | IFS=' ' read strtab_offset strtab_size
strtab=
while IFS= read -r -d '' sect; do
strtab="${strtab} ${sect}"
done < <(dd if=${LIB} skip=${strtab_offset} bs=1 count=${strtab_size} status=none)
strtab=${strtab:1} # remove the leading space
fi
}
getsym() {
# get the address of a symbol
LIB="${1}"
genlookup "${LIB}"
getsymsect "${LIB}" | IFS=' ' read symtab_offset symtab_size
poststrtab=${strtab%%${2} *}
[[ "${poststrtab}" = "${strtab}" ]] && idx=-1 || idx=${#poststrtab}
CHUNKSIZE=2048 # 2048*24 = 49,152 bytes
# sizeof(elf64_sym) == 24
for ((i=${symtab_offset}; i <= $((${symtab_offset}+${symtab_size})); i+=$((${CHUNKSIZE}*24)))); do
dd if=${LIB} skip=${i} count=$((${CHUNKSIZE}*24)) bs=1 status=none | checksym ${CHUNKSIZE} ${idx}
if [[ -n "${symfound}" ]]; then
readint ${LIB} $((${i}+$((${symfound}*24))))
getstrtab ${retint}
if [[ "${symstr}" = "${2}" ]]; then
readlong ${LIB} $((${i}+$((${symfound}*24+8))))
symaddr=$(printf '%x\n' ${retlong})
break
fi
fi
done
}