aboutsummaryrefslogtreecommitdiff
path: root/common/libc.sh
blob: 2135b98f6808d5c56857c750f73d6a5176d00638 (plain)
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
#!/bin/bash

mkdir -p db

die() {
  echo >&2 $1
  exit 1
}

dump_symbols() {
  readelf -Ws $1 | perl -n -e '/: (\w*).*?(\w+)@@GLIBC_/ && print "$2 $1\n"'
}

extract_label() {
  perl -n -e '/(\w+)/ && print $1'
}

dump_libc_start_main_ret() {
  if [ `echo "$2" | egrep "i386|amd64" - ` ] \
    && [ -x "$(command -v objdump)" ]; then
    local call_main=`objdump -D $1 \
      | egrep -A 100 '<__libc_start_main.*>' \
      | grep call \
      | egrep -B 1 '<exit.*>' \
      | head -n 1 \
      | extract_label`
    local offset=`objdump -D $1 | egrep -A 1 "(^| )$call_main:" | tail -n 1 | extract_label`
  elif [ `echo "$2" | egrep "armel|armhf|arm64" - ` ] \
    && [ -x "$(command -v aarch64-linux-gnu-objdump)" ]; then
    local call_main=`aarch64-linux-gnu-objdump -D $1 \
      | egrep -A 100 '<__libc_start_main.*>' \
      | grep -Pe "(bl\t|blr\t|blx\t|bx\t)" \
      | egrep -B 1 '<exit.*>' \
      | head -n 1 \
      | extract_label`
    local offset=`aarch64-linux-gnu-objdump -D $1 \
      | egrep -A 1 "(^| )$call_main:" \
      | tail -n 1 \
      | extract_label`
  fi
  if [[ "$offset" != "" ]]; then
    echo "__libc_start_main_ret $offset"
  fi
}

dump_bin_sh() {
  local offset=`strings -a -t x $1 | grep '/bin/sh' | head -n 1 | extract_label`
  if [[ "$offset" != "" ]]; then
    echo "str_bin_sh $offset"
  fi
}

process_libc() {
  local libc=$1
  local id=$2
  local info=$3
  local sha256=$4
  [[ -d db/$info ]] || mkdir db/$info
  echo "  -> Writing libc to db/${info}/${id}.so"
  cp $libc db/${info}/${id}.so
  echo "  -> Writing symbols to db/${info}/${id}.symbols"
  (dump_symbols $libc; dump_libc_start_main_ret $libc $id; dump_bin_sh $libc) \
     > db/${info}/${id}.symbols
  echo "  -> Writing SHA-256 to db/${info}/${id}.sha256"
  echo "$sha256" > db/${info}/${id}.sha256
}

check_id() {
  local id=$1
  local info=$2
  if [[ -e db/${info}/${id}.sha256 ]]; then
    echo "  -> Already have this version, 'rm db/${info}/${id}.*' to force"
    return 1
  fi
  return 0
}

check_sha256() {
  local sha256=$1
  local libc=`grep -r $sha256 db/ 2>/dev/null | cut -d ':' -f 1 - 2>/dev/null | sed 's/\.sha256/\.so/gI'`
  if [[ "$libc" != "" ]]; then
    echo "  -> Found SHA-256 match: $libc"
    return 1
  fi
  return 0
}

# ===== Debian and Ubuntu ===== #

get_deb() {
  local url="$1"
  local info="$2"
  local tmp=`mktemp -d || mktemp -d -t "libc-database" || die "Cannot get temp dir"`
  echo "Getting $info"
  echo "  -> Location: $url"
  local id=`echo $url | perl -n -e '/(libc6[^\/]*)\./ && print $1' | sed 's/\%2b/+/gI'`
  echo "  -> ID: $id"
  check_id $id $info || return
  echo "  -> Downloading package"
  wget $url 2>/dev/null -O $tmp/pkg.deb || die "Failed to download package from $url"
  echo "  -> Extracting package"
  pushd $tmp 1>/dev/null
  ar x pkg.deb || die "ar failed"
  tar xf data.tar.* || die "tar failed"
  popd 1>/dev/null
  local libc=`find $tmp -name libc.so.6 || die "Cannot locate libc.so.6"`
  if [[ ! -e $libc ]]; then 
    echo "  -> The package does not seem to contain a valid libc (e.g. just contains a broken symbolic link)"
    return
  fi
  local sha256=`sha256sum $libc`
  check_sha256 $sha256 || return
  process_libc $libc $id $info $sha256
  rm -rf $tmp
}

get_current_ubuntu() {
  local version=$1
  local arch=$2
  local pkg=$3
  local info=ubuntu-$version-$arch-$pkg
  echo "Getting package location for ubuntu-$version-$arch"
  local url=`(wget http://packages.ubuntu.com/$version/$arch/$pkg/download -O - 2>/dev/null \
               | grep -oh 'http://[^"]*libc6[^"]*.deb') || die "Failed to get package version"`
  get_deb $url $info
}

get_all_debian() {
  local info=debian-$1
  local url=$2
  for f in `wget $url/ -O - 2>/dev/null | egrep -oh 'libc6(-i386|-i686|-amd64|-armel|-armhf|-arm64)?(-cross)?_[^"]*(i386|amd64|armel|armhf|arm64|all)\.deb' | grep -v "</a>"`; do
    get_deb $url/$f $info
  done
}

get_all_ubuntu() {
  local info=ubuntu-$1
  local url=$2
  for f in `wget $url/ -O - 2>/dev/null | egrep -oh 'libc6(-i386|-i686|-amd64|-armel|-armel-armhf|-armhf|-arm64)?(-cross)?_[^"]*(i386|amd64|armel|armhf|arm64|all)\.deb' | grep -v "</a>"`; do
    get_deb $url/$f $info
  done
}

# ===== Local ===== #

add_local() {
  local libc=$1
  [[ -e $libc ]] || return
  local info="local"
  local id="local-`sha256sum $libc`"
  echo "Adding local libc $libc (id $id)"
  check_id $id $info || return
  local sha256=`sha256sum $libc`
  check_sha256 $sha256 || return
  process_libc $libc $id $info $sha256
}