From 9fbc29e15d97a5f326a645b942cff74d2c6cfdc1 Mon Sep 17 00:00:00 2001
From: ko1N <ko1N1337@gmail.com>
Date: Wed, 30 Apr 2025 12:38:20 +0200
Subject: [PATCH] Add code to download ftdi driver automatically

---
 Cargo.lock                       | 407 ++++++++++++++++++++++++++++++-
 memflow-pcileech/Cargo.toml      |  11 +-
 memflow-pcileech/src/download.rs | 164 +++++++++++++
 memflow-pcileech/src/lib.rs      |   7 +
 4 files changed, 583 insertions(+), 6 deletions(-)
 create mode 100644 memflow-pcileech/src/download.rs

diff --git a/Cargo.lock b/Cargo.lock
index 140c3fd..aad0bc2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -55,6 +55,17 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
 [[package]]
 name = "ahash"
 version = "0.8.11"
@@ -147,6 +158,15 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+dependencies = [
+ "derive_arbitrary",
+]
+
 [[package]]
 name = "as_derive_utils"
 version = "0.10.3"
@@ -209,18 +229,54 @@ version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bzip2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
+dependencies = [
+ "bzip2-sys",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.13+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
 [[package]]
 name = "cc"
 version = "1.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
 dependencies = [
+ "jobserver",
+ "libc",
  "shlex",
 ]
 
@@ -294,6 +350,16 @@ dependencies = [
  "windows-link",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
 [[package]]
 name = "clang-sys"
 version = "1.8.1"
@@ -335,6 +401,12 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.7"
@@ -356,6 +428,30 @@ version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6"
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
 [[package]]
 name = "crc32fast"
 version = "1.4.2"
@@ -380,6 +476,16 @@ version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
 [[package]]
 name = "ctor"
 version = "0.4.2"
@@ -443,6 +549,43 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "50eb3a329e19d78c3a3dfa4ec5a51ecb84fa3a20c06edad04be25356018218f9"
 
+[[package]]
+name = "deflate64"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
+
+[[package]]
+name = "deranged"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "derive_arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
 [[package]]
 name = "dirs"
 version = "5.0.1"
@@ -577,6 +720,16 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.16"
@@ -585,7 +738,21 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -621,6 +788,15 @@ version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
 
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "iana-time-zone"
 version = "0.1.63"
@@ -813,6 +989,15 @@ dependencies = [
  "web-time",
 ]
 
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.13"
@@ -885,6 +1070,16 @@ dependencies = [
  "syn 2.0.101",
 ]
 
+[[package]]
+name = "jobserver"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
+dependencies = [
+ "getrandom 0.3.2",
+ "libc",
+]
+
 [[package]]
 name = "js-sys"
 version = "0.3.77"
@@ -969,6 +1164,27 @@ version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
+[[package]]
+name = "lzma-rs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
+dependencies = [
+ "byteorder",
+ "crc",
+]
+
+[[package]]
+name = "lzma-sys"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.4"
@@ -1027,11 +1243,15 @@ name = "memflow-pcileech"
 version = "0.2.0"
 dependencies = [
  "env_logger",
+ "indicatif",
  "leechcore-sys",
  "log",
  "memflow",
  "memflow-win32",
  "parking_lot 0.12.3",
+ "progress-streams",
+ "ureq",
+ "zip",
 ]
 
 [[package]]
@@ -1109,6 +1329,12 @@ dependencies = [
  "minimal-lexical",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-traits"
 version = "0.2.19"
@@ -1190,6 +1416,16 @@ version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
 [[package]]
 name = "pdb"
 version = "0.8.0"
@@ -1263,6 +1499,12 @@ dependencies = [
  "portable-atomic",
 ]
 
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
 [[package]]
 name = "prettyplease"
 version = "0.2.32"
@@ -1307,6 +1549,12 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
 [[package]]
 name = "rangemap"
 version = "1.5.1"
@@ -1337,7 +1585,7 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.16",
  "libredox",
  "thiserror",
 ]
@@ -1388,7 +1636,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
 dependencies = [
  "cc",
  "cfg-if",
- "getrandom",
+ "getrandom 0.2.16",
  "libc",
  "untrusted",
  "windows-sys 0.52.0",
@@ -1556,12 +1804,29 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
 [[package]]
 name = "shlex"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
 [[package]]
 name = "smallvec"
 version = "1.15.0"
@@ -1645,6 +1910,25 @@ dependencies = [
  "syn 2.0.101",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+
 [[package]]
 name = "tinystr"
 version = "0.7.6"
@@ -1735,6 +2019,12 @@ version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
 
+[[package]]
+name = "typenum"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.18"
@@ -1822,13 +2112,22 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
 [[package]]
 name = "wasix"
 version = "0.12.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d"
 dependencies = [
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -2152,6 +2451,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags 2.9.0",
+]
+
 [[package]]
 name = "write16"
 version = "1.0.0"
@@ -2176,6 +2484,15 @@ dependencies = [
  "volatile",
 ]
 
+[[package]]
+name = "xz2"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
+dependencies = [
+ "lzma-sys",
+]
+
 [[package]]
 name = "yoke"
 version = "0.7.5"
@@ -2246,6 +2563,20 @@ name = "zeroize"
 version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
 
 [[package]]
 name = "zerovec"
@@ -2268,3 +2599,71 @@ dependencies = [
  "quote",
  "syn 2.0.101",
 ]
+
+[[package]]
+name = "zip"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744"
+dependencies = [
+ "aes",
+ "arbitrary",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "deflate64",
+ "flate2",
+ "getrandom 0.3.2",
+ "hmac",
+ "indexmap",
+ "lzma-rs",
+ "memchr",
+ "pbkdf2",
+ "sha1",
+ "time",
+ "xz2",
+ "zeroize",
+ "zopfli",
+ "zstd",
+]
+
+[[package]]
+name = "zopfli"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
+dependencies = [
+ "bumpalo",
+ "crc32fast",
+ "log",
+ "simd-adler32",
+]
+
+[[package]]
+name = "zstd"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.15+zstd.1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/memflow-pcileech/Cargo.toml b/memflow-pcileech/Cargo.toml
index 8261e26..fe556fd 100644
--- a/memflow-pcileech/Cargo.toml
+++ b/memflow-pcileech/Cargo.toml
@@ -21,13 +21,20 @@ leechcore-sys = { version = "0.2", path = "../leechcore-sys" }
 log = "0.4"
 parking_lot = "0.12"
 
+ureq = { version = "2.10", optional = true }
+zip = { version = "2.6", optional = true }
+indicatif = { version = "0.17", optional = true }
+progress-streams = { version = "1.1", optional = true }
+
 [dev-dependencies]
 env_logger = "0.11"
 memflow-win32 = { version = "0.2" }
 
 [features]
-default = [ ]
-bindgen = [ "leechcore-sys/bindgen" ]
+default = ["download_drivers", "download_progress"]
+bindgen = ["leechcore-sys/bindgen"]
+download_drivers = ["ureq", "zip"]
+download_progress = ["indicatif", "progress-streams"]
 
 [[example]]
 name = "read_phys"
diff --git a/memflow-pcileech/src/download.rs b/memflow-pcileech/src/download.rs
new file mode 100644
index 0000000..f7755bc
--- /dev/null
+++ b/memflow-pcileech/src/download.rs
@@ -0,0 +1,164 @@
+use log::info;
+use std::fs::File;
+use std::io::{self, Cursor, Read, Write};
+use std::path::PathBuf;
+use zip::ZipArchive;
+
+use memflow::error::{Error, ErrorKind, ErrorOrigin, Result};
+
+#[cfg(feature = "download_progress")]
+use {
+    indicatif::{ProgressBar, ProgressStyle},
+    progress_streams::ProgressReader,
+    std::sync::atomic::{AtomicBool, AtomicUsize, Ordering},
+    std::sync::Arc,
+};
+
+fn download_file(url: &str) -> Result<Vec<u8>> {
+    info!("downloading file from {}", url);
+    let resp = ureq::get(url).call().map_err(|_| {
+        Error(ErrorOrigin::Connector, ErrorKind::Http).log_error("unable to download file")
+    })?;
+
+    assert!(resp.has("Content-Length"));
+    let len = resp
+        .header("Content-Length")
+        .and_then(|s| s.parse::<usize>().ok())
+        .unwrap();
+
+    let mut reader = resp.into_reader();
+    let buffer = read_to_end(&mut reader, len)?;
+
+    assert_eq!(buffer.len(), len);
+    Ok(buffer)
+}
+
+#[cfg(feature = "download_progress")]
+fn read_to_end<T: Read>(reader: &mut T, len: usize) -> Result<Vec<u8>> {
+    let mut buffer = vec![];
+
+    let total = Arc::new(AtomicUsize::new(0));
+    let mut reader = ProgressReader::new(reader, |progress: usize| {
+        total.fetch_add(progress, Ordering::SeqCst);
+    });
+    let pb = ProgressBar::new(len as u64);
+    pb.set_style(ProgressStyle::default_bar()
+        .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
+        .unwrap()
+        .progress_chars("#>-"));
+
+    let finished = Arc::new(AtomicBool::new(false));
+    let thread = {
+        let finished_thread = finished.clone();
+        let total_thread = total.clone();
+
+        std::thread::spawn(move || {
+            while !finished_thread.load(Ordering::Relaxed) {
+                pb.set_position(total_thread.load(Ordering::SeqCst) as u64);
+                std::thread::sleep(std::time::Duration::from_millis(10));
+            }
+            pb.finish_with_message("downloaded");
+        })
+    };
+
+    reader.read_to_end(&mut buffer).map_err(|_| {
+        Error(ErrorOrigin::Connector, ErrorKind::Http).log_error("unable to read from http request")
+    })?;
+    finished.store(true, Ordering::Relaxed);
+    thread.join().unwrap();
+
+    Ok(buffer)
+}
+
+#[cfg(not(feature = "download_progress"))]
+fn read_to_end<T: Read>(reader: &mut T, _len: usize) -> Result<Vec<u8>> {
+    let mut buffer = vec![];
+    reader.read_to_end(&mut buffer).map_err(|_| {
+        Error(ErrorOrigin::Connector, ErrorKind::Http).log_error("unable to read from http request")
+    })?;
+    Ok(buffer)
+}
+
+#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
+pub fn download_url() -> (&'static str, &'static str) {
+    (
+        "https://ftdichip.com/wp-content/uploads/2023/11/FTD3XXLibrary_v1.3.0.8.zip",
+        "FTD3XXLibrary_v1.3.0.8/x64/DLL/FTD3XX.dll",
+    )
+}
+
+// TODO:
+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+pub fn download_url() -> (&'static str, &'static str) {
+    (
+        "https://ftdichip.com/wp-content/uploads/2023/11/FTD3XXLibrary_v1.3.0.8.zip",
+        "FTD3XXLibrary_v1.3.0.8/x64/DLL/FTD3XX.dll",
+    )
+}
+
+pub fn download_driver() -> Result<()> {
+    let (url, file_to_extract) = download_url();
+
+    let file_to_extract_path: PathBuf = file_to_extract.parse().unwrap();
+    let file_to_extract_name = file_to_extract_path.file_name().unwrap().to_str().unwrap();
+
+    // Get the current executable directory
+    let exe_path = std::env::current_exe().expect("Failed to get current executable path");
+    let exe_dir = exe_path
+        .parent()
+        .expect("Failed to get parent directory of executable");
+
+    // Create the output path
+    let output_path = exe_dir.join(file_to_extract_name);
+
+    // TODO: check hashsum
+    // Check if file exists in current path already and return Ok(())
+    if output_path.exists() {
+        info!("ftdi driver found");
+        return Ok(());
+    }
+
+    let contents = download_file(url)?;
+
+    // Read the zip file in memory
+    let cursor = Cursor::new(contents);
+    let mut archive = ZipArchive::new(cursor).map_err(|_| {
+        Error(ErrorOrigin::Connector, ErrorKind::Http).log_error("Failed to parse zip archive")
+    })?;
+
+    // Find and extract the specific file
+    for i in 0..archive.len() {
+        let mut file = archive
+            .by_index(i)
+            .map_err(|_| Error(ErrorOrigin::Connector, ErrorKind::UnableToReadFile))?;
+        println!("file.name: {}", file.name());
+        if file.name() == file_to_extract {
+            info!("Found file to extract: {}", file_to_extract);
+
+            info!("Extracting to: {}", output_path.display());
+
+            // Create the output file
+            let mut output_file = File::create(&output_path).expect(&format!(
+                "Failed to create output file: {}",
+                output_path.display()
+            ));
+
+            // Copy the file content
+            io::copy(&mut file, &mut output_file).expect("Failed to write extracted file");
+
+            info!(
+                "Successfully extracted {} to {}",
+                file_to_extract,
+                output_path.display()
+            );
+            return Ok(());
+        }
+    }
+
+    Err(
+        Error(ErrorOrigin::Connector, ErrorKind::NotFound).log_error(format!(
+            "file '{}' not found in zip archive",
+            file_to_extract
+        )),
+    )
+}
diff --git a/memflow-pcileech/src/lib.rs b/memflow-pcileech/src/lib.rs
index 843e35f..7ba885e 100644
--- a/memflow-pcileech/src/lib.rs
+++ b/memflow-pcileech/src/lib.rs
@@ -16,6 +16,9 @@ use memflow::prelude::v1::*;
 
 use leechcore_sys::*;
 
+#[cfg(feature = "download_drivers")]
+mod download;
+
 const PAGE_SIZE: usize = 0x1000usize;
 
 // the absolute minimum BUF_ALIGN is 4.
@@ -122,6 +125,10 @@ impl PciLeech {
         mem_map: Option<MemoryMap<(Address, umem)>>,
         auto_clear: bool,
     ) -> Result<Self> {
+        // ensure ftdi driver exists
+        #[cfg(feature = "download_drivers")]
+        download::download_driver().unwrap();
+
         // open device
         let mut conf = build_lc_config(device, remote, mem_map.is_some());
         let p_lc_config_error_info = std::ptr::null_mut::<LC_CONFIG_ERRORINFO>();