├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Makefile.toml ├── README.md ├── example-shellcode ├── .cargo │ └── config.toml ├── Cargo.lock ├── Cargo.toml └── src │ ├── binding.rs │ └── main.rs ├── images ├── 001.png └── 002.png ├── shellcode ├── .cargo │ └── config.toml ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | shellcode.bin 3 | -------------------------------------------------------------------------------- /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 = "addr2line" 7 | version = "0.15.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "anyhow" 22 | version = "1.0.40" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" 25 | 26 | [[package]] 27 | name = "atty" 28 | version = "0.2.14" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 31 | dependencies = [ 32 | "hermit-abi", 33 | "libc", 34 | "winapi", 35 | ] 36 | 37 | [[package]] 38 | name = "autocfg" 39 | version = "1.0.1" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 42 | 43 | [[package]] 44 | name = "backtrace" 45 | version = "0.3.59" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" 48 | dependencies = [ 49 | "addr2line", 50 | "cc", 51 | "cfg-if", 52 | "libc", 53 | "miniz_oxide", 54 | "object", 55 | "rustc-demangle", 56 | ] 57 | 58 | [[package]] 59 | name = "bitflags" 60 | version = "1.2.1" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 63 | 64 | [[package]] 65 | name = "cc" 66 | version = "1.0.67" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 69 | 70 | [[package]] 71 | name = "cfg-if" 72 | version = "1.0.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 75 | 76 | [[package]] 77 | name = "colored" 78 | version = "2.0.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" 81 | dependencies = [ 82 | "atty", 83 | "lazy_static", 84 | "winapi", 85 | ] 86 | 87 | [[package]] 88 | name = "failure" 89 | version = "0.1.8" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 92 | dependencies = [ 93 | "backtrace", 94 | "failure_derive", 95 | ] 96 | 97 | [[package]] 98 | name = "failure_derive" 99 | version = "0.1.8" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 102 | dependencies = [ 103 | "proc-macro2", 104 | "quote", 105 | "syn", 106 | "synstructure", 107 | ] 108 | 109 | [[package]] 110 | name = "gimli" 111 | version = "0.24.0" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" 114 | 115 | [[package]] 116 | name = "goblin" 117 | version = "0.4.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "532a09cd3df2c6bbfc795fb0434bff8f22255d1d07328180e918a2e6ce122d4d" 120 | dependencies = [ 121 | "log", 122 | "plain", 123 | "scroll", 124 | ] 125 | 126 | [[package]] 127 | name = "hermit-abi" 128 | version = "0.1.18" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 131 | dependencies = [ 132 | "libc", 133 | ] 134 | 135 | [[package]] 136 | name = "iced-x86" 137 | version = "1.11.2" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "6aa39b6a19bdd00ba68e23f80a15557795f85b38789591b2f89d16c7bdfcfecd" 140 | dependencies = [ 141 | "lazy_static", 142 | "static_assertions", 143 | ] 144 | 145 | [[package]] 146 | name = "lazy_static" 147 | version = "1.4.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 150 | 151 | [[package]] 152 | name = "libc" 153 | version = "0.2.94" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" 156 | 157 | [[package]] 158 | name = "log" 159 | version = "0.4.14" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 162 | dependencies = [ 163 | "cfg-if", 164 | ] 165 | 166 | [[package]] 167 | name = "maidism" 168 | version = "0.1.0" 169 | source = "git+https://github.com/2vg/blackcat-rs#c910eb3bc325555f1866ad9d834e6a64cb3aa8ff" 170 | dependencies = [ 171 | "anyhow", 172 | "colored", 173 | "iced-x86", 174 | "winapi", 175 | "winproc", 176 | "wuhu", 177 | ] 178 | 179 | [[package]] 180 | name = "miniz_oxide" 181 | version = "0.4.4" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 184 | dependencies = [ 185 | "adler", 186 | "autocfg", 187 | ] 188 | 189 | [[package]] 190 | name = "num-traits" 191 | version = "0.2.14" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 194 | dependencies = [ 195 | "autocfg", 196 | ] 197 | 198 | [[package]] 199 | name = "object" 200 | version = "0.24.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" 203 | 204 | [[package]] 205 | name = "plain" 206 | version = "0.2.3" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 209 | 210 | [[package]] 211 | name = "proc-macro2" 212 | version = "1.0.26" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 215 | dependencies = [ 216 | "unicode-xid", 217 | ] 218 | 219 | [[package]] 220 | name = "quote" 221 | version = "1.0.9" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 224 | dependencies = [ 225 | "proc-macro2", 226 | ] 227 | 228 | [[package]] 229 | name = "rustc-demangle" 230 | version = "0.1.19" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" 233 | 234 | [[package]] 235 | name = "scroll" 236 | version = "0.10.2" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" 239 | dependencies = [ 240 | "scroll_derive", 241 | ] 242 | 243 | [[package]] 244 | name = "scroll_derive" 245 | version = "0.10.5" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" 248 | dependencies = [ 249 | "proc-macro2", 250 | "quote", 251 | "syn", 252 | ] 253 | 254 | [[package]] 255 | name = "shellcode-builder" 256 | version = "0.1.0" 257 | dependencies = [ 258 | "anyhow", 259 | "goblin", 260 | "maidism", 261 | ] 262 | 263 | [[package]] 264 | name = "static_assertions" 265 | version = "1.1.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 268 | 269 | [[package]] 270 | name = "syn" 271 | version = "1.0.72" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" 274 | dependencies = [ 275 | "proc-macro2", 276 | "quote", 277 | "unicode-xid", 278 | ] 279 | 280 | [[package]] 281 | name = "synstructure" 282 | version = "0.12.4" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" 285 | dependencies = [ 286 | "proc-macro2", 287 | "quote", 288 | "syn", 289 | "unicode-xid", 290 | ] 291 | 292 | [[package]] 293 | name = "unicode-xid" 294 | version = "0.2.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 297 | 298 | [[package]] 299 | name = "widestring" 300 | version = "0.4.3" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" 303 | 304 | [[package]] 305 | name = "winapi" 306 | version = "0.3.9" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 309 | dependencies = [ 310 | "winapi-i686-pc-windows-gnu", 311 | "winapi-x86_64-pc-windows-gnu", 312 | ] 313 | 314 | [[package]] 315 | name = "winapi-i686-pc-windows-gnu" 316 | version = "0.4.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 319 | 320 | [[package]] 321 | name = "winapi-x86_64-pc-windows-gnu" 322 | version = "0.4.0" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 325 | 326 | [[package]] 327 | name = "winproc" 328 | version = "0.6.4" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "979e07b33c6af27e5c454e42d1b946b403ec222e7bad52ef020820708e087b25" 331 | dependencies = [ 332 | "bitflags", 333 | "failure", 334 | "widestring", 335 | "winapi", 336 | ] 337 | 338 | [[package]] 339 | name = "wuhu" 340 | version = "0.1.0" 341 | source = "git+https://github.com/2vg/blackcat-rs#c910eb3bc325555f1866ad9d834e6a64cb3aa8ff" 342 | dependencies = [ 343 | "num-traits", 344 | "winapi", 345 | ] 346 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shellcode-builder" 3 | version = "0.1.0" 4 | authors = ["uru "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | goblin = "0.4.0" 11 | anyhow = "1.0.34" 12 | maidism = { git = "https://github.com/2vg/blackcat-rs", package = "maidism" } 13 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | SHELLCODE_SRC_PATH = "${CARGO_MAKE_WORKING_DIRECTORY}/shellcode/" 3 | 4 | [tasks.clean] 5 | script = [ 6 | "cargo clean" 7 | ] 8 | 9 | [tasks.build-shellcode] 10 | script = [ 11 | "cd %SHELLCODE_SRC_PATH%", 12 | "cargo build --release" 13 | ] 14 | 15 | [tasks.build] 16 | command = "cargo" 17 | args = ["run"] 18 | dependencies = ["build-shellcode"] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | win-shellcode-rs 2 | === 3 | 4 | windows shellcode template that generates improved shellcode based on the project at [b1tg/rust-windows-shellcode](https://github.com/b1tg/rust-windows-shellcode). 5 | 6 | ## Overview 7 | 8 | First of all, I am very grateful to [b1tg/rust-windows-shellcode](https://github.com/b1tg/rust-windows-shellcode).
9 | Because I couldn't find any other resources for doing windows shellcode in Rust.
10 | I like Rust, so I was very impressed to be able to do this.
11 | But, there is a problem with the [b1tg/rust-windows-shellcode](https://github.com/b1tg/rust-windows-shellcode) shellcode.
12 | For example, when execute shellcode as a thread of a any process, the thread does not terminate normally.
13 | Since the loop is called at the end of the main function, the shellcode goes into an infinite loop when it's done.
14 | I wanted the shellcode to terminate the thread normally when it was done, so I decided to fork it and make an improved shellcode.
15 | Specifically, before patching the jmp code, i added another shellcode.
16 | This shellcode is called bootstrap code and can call a specific function correctly according to the [Windows calling convention](https://docs.microsoft.com/ja-jp/cpp/build/x64-calling-convention?view=msvc-160)(but this is for x64),
17 | so the thread can be terminated normally when it returns.
18 | And Since we are assuming only 64-bit and not a 32-bit environment here, another modification is required if want to run on 32-bit.
19 | Also, the main function can have arguments, but bootstrap code needs to be modified.
20 | Find out more about Windows ABIs.
21 | 22 | ## Requirements 23 | - x64 Windows(tested Windows 10 x64), because my bootstrap shellcode assumes x64 only 24 | - as Option, `cargo-make`(if have, its easier to build than manually typing the command) 25 | 26 | ## Usage 27 | Feel free to edit `shellcode/main.rs` and look at the Build section. 28 | 29 | ## Build 30 | `shellcode/main.rs` is almost empty. You need to edit it.
31 | Or, `example-shellcode` has sample code that calls `MessageBoxW`.
32 | So, write your own code, or rename `example-shellcode` to `shellcode`, or edit `win-shellcode-rs/main.rs` like a this:
33 | 34 | ```rust 35 | // let src_path = "shellcode\\target\\x86_64-pc-windows-msvc\\release\\shellcode.exe"; 36 | let src_path = "example-shellcode\\target\\x86_64-pc-windows-msvc\\release\\shellcode.exe"; 37 | ``` 38 | 39 | then, 40 | 41 | if have `cargo-make`, just type `cargo make build` 42 | 43 | if not have, 44 | 45 | ```shell 46 | cd shellcode 47 | cargo build --release 48 | cd ../ 49 | cargo run 50 | ``` 51 | 52 | Done. will generate shellcode.bin to current place.(`win-shelcode-rs\`) 53 | 54 | Try using the shellcode runner and debugger to make sure that the original process is not affected after the shellcode is finished. 55 | 56 | and, The console should show a nice result of disassemble :3 57 | 58 | result of building `example-shellcode`: 59 | 60 | ![alt](images/001.png) 61 | 62 | result of executing `example-shellcode` shellcode on notepad: 63 | 64 | ![alt](images/002.png) 65 | 66 | ## Reference 67 | - [b1tg/rust-windows-shellcode](https://github.com/b1tg/rust-windows-shellcode) 68 | - [x64-calling-convention](https://docs.microsoft.com/ja-jp/cpp/build/x64-calling-convention) 69 | - [mattifestation/PIC_Bindshell](https://github.com/mattifestation/PIC_Bindshell) 70 | - [monoxgas/sRDI](https://github.com/monoxgas/sRDI) 71 | -------------------------------------------------------------------------------- /example-shellcode/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-pc-windows-msvc" 3 | rustflags = [ 4 | "-Z", "pre-link-arg=/NOLOGO", 5 | "-Z", "pre-link-arg=/NODEFAULTLIB", 6 | "-C", "link-arg=/ENTRY:main", 7 | "-C", "link-arg=/MERGE:.edata=.rdata", 8 | "-C", "link-arg=/MERGE:.rustc=.data", 9 | "-C", "link-arg=/MERGE:.rdata=.text", 10 | "-C", "link-arg=/MERGE:.pdata=.text", 11 | "-C", "link-arg=/DEBUG:NONE", 12 | "-C", "link-arg=/EMITPOGOPHASEINFO", 13 | "-C", "target-feature=-mmx,-sse,+soft-float", 14 | "--emit", "asm", 15 | ] 16 | -------------------------------------------------------------------------------- /example-shellcode/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 = "autocfg" 7 | version = "1.0.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 10 | 11 | [[package]] 12 | name = "num-traits" 13 | version = "0.2.14" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 16 | dependencies = [ 17 | "autocfg", 18 | ] 19 | 20 | [[package]] 21 | name = "shellcode" 22 | version = "0.1.0" 23 | dependencies = [ 24 | "num-traits", 25 | "utf16_literal", 26 | ] 27 | 28 | [[package]] 29 | name = "utf16_literal" 30 | version = "0.2.1" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "316f90fe4a7beb941ce0b6806ba7386f1a515155a42def71825f3f9a232e3f48" 33 | -------------------------------------------------------------------------------- /example-shellcode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shellcode" 3 | version = "0.1.0" 4 | authors = ["uru "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [profile.dev] 10 | panic = "abort" 11 | opt-level = "z" 12 | lto = true 13 | 14 | [profile.release] 15 | panic = "abort" 16 | opt-level = "z" 17 | lto = true 18 | 19 | [dependencies] 20 | num-traits = { version = "0.2.14", default-features = false } 21 | utf16_literal = "0.2.1" 22 | -------------------------------------------------------------------------------- /example-shellcode/src/binding.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /*********** 4 | * BINDING * 5 | ***********/ 6 | pub enum c_void {} 7 | pub type c_char = i8; 8 | pub type c_schar = i8; 9 | pub type c_uchar = u8; 10 | pub type c_short = i16; 11 | pub type c_ushort = u16; 12 | pub type c_int = i32; 13 | pub type c_uint = u32; 14 | pub type c_long = i32; 15 | pub type c_ulong = u32; 16 | pub type c_longlong = i64; 17 | pub type c_ulonglong = u64; 18 | pub type c_float = f32; 19 | pub type c_double = f64; 20 | pub type __int8 = i8; 21 | pub type __uint8 = u8; 22 | pub type __int16 = i16; 23 | pub type __uint16 = u16; 24 | pub type __int32 = i32; 25 | pub type __uint32 = u32; 26 | pub type __int64 = i64; 27 | pub type __uint64 = u64; 28 | pub type wchar_t = u16; 29 | 30 | pub type BOOLEAN = UCHAR; 31 | pub type POINTER_64_INT = usize; 32 | pub type INT8 = c_schar; 33 | pub type PINT8 = *mut c_schar; 34 | pub type INT16 = c_short; 35 | pub type PINT16 = *mut c_short; 36 | pub type INT32 = c_int; 37 | pub type PINT32 = *mut c_int; 38 | pub type INT64 = __int64; 39 | pub type PINT64 = *mut __int64; 40 | pub type UINT8 = c_uchar; 41 | pub type PUINT8 = *mut c_uchar; 42 | pub type UINT16 = c_ushort; 43 | pub type PUINT16 = *mut c_ushort; 44 | pub type UINT32 = c_uint; 45 | pub type PUINT32 = *mut c_uint; 46 | pub type UINT64 = __uint64; 47 | pub type PUINT64 = *mut __uint64; 48 | pub type LONG32 = c_int; 49 | pub type PLONG32 = *mut c_int; 50 | pub type ULONG32 = c_uint; 51 | pub type PULONG32 = *mut c_uint; 52 | pub type DWORD32 = c_uint; 53 | pub type PDWORD32 = *mut c_uint; 54 | pub type INT_PTR = isize; 55 | pub type PINT_PTR = *mut isize; 56 | pub type UINT_PTR = usize; 57 | pub type PUINT_PTR = *mut usize; 58 | pub type LONG_PTR = isize; 59 | pub type PLONG_PTR = *mut isize; 60 | pub type ULONG_PTR = usize; 61 | pub type PULONG_PTR = *mut usize; 62 | pub type SHANDLE_PTR = isize; 63 | pub type HANDLE_PTR = usize; 64 | #[cfg(target_pointer_width = "32")] 65 | pub type UHALF_PTR = c_ushort; 66 | #[cfg(target_pointer_width = "64")] 67 | pub type UHALF_PTR = c_uint; 68 | #[cfg(target_pointer_width = "32")] 69 | pub type PUHALF_PTR = *mut c_ushort; 70 | #[cfg(target_pointer_width = "64")] 71 | pub type PUHALF_PTR = *mut c_uint; 72 | #[cfg(target_pointer_width = "32")] 73 | pub type HALF_PTR = c_short; 74 | #[cfg(target_pointer_width = "64")] 75 | pub type HALF_PTR = c_int; 76 | #[cfg(target_pointer_width = "32")] 77 | pub type PHALF_PTR = *mut c_short; 78 | #[cfg(target_pointer_width = "64")] 79 | pub type PHALF_PTR = *mut c_int; 80 | pub type SIZE_T = ULONG_PTR; 81 | pub type PSIZE_T = *mut ULONG_PTR; 82 | pub type SSIZE_T = LONG_PTR; 83 | pub type PSSIZE_T = *mut LONG_PTR; 84 | pub type DWORD_PTR = ULONG_PTR; 85 | pub type PDWORD_PTR = *mut ULONG_PTR; 86 | pub type LONG64 = __int64; 87 | pub type PLONG64 = *mut __int64; 88 | pub type ULONG64 = __uint64; 89 | pub type PULONG64 = *mut __uint64; 90 | pub type DWORD64 = __uint64; 91 | pub type PDWORD64 = *mut __uint64; 92 | pub type KAFFINITY = ULONG_PTR; 93 | pub type PKAFFINITY = *mut KAFFINITY; 94 | 95 | pub type ULONG = c_ulong; 96 | pub type PULONG = *mut ULONG; 97 | pub type USHORT = c_ushort; 98 | pub type PUSHORT = *mut USHORT; 99 | pub type UCHAR = c_uchar; 100 | pub type PUCHAR = *mut UCHAR; 101 | pub type PSZ = *mut c_char; 102 | pub const MAX_PATH: usize = 260; 103 | pub const FALSE: BOOL = 0; 104 | pub const TRUE: BOOL = 1; 105 | pub type DWORD = c_ulong; 106 | pub type BOOL = c_int; 107 | pub type BYTE = c_uchar; 108 | pub type WORD = c_ushort; 109 | pub type FLOAT = c_float; 110 | pub type PFLOAT = *mut FLOAT; 111 | pub type PBOOL = *mut BOOL; 112 | pub type LPBOOL = *mut BOOL; 113 | pub type PBYTE = *mut BYTE; 114 | pub type LPBYTE = *mut BYTE; 115 | pub type PINT = *mut c_int; 116 | pub type LPINT = *mut c_int; 117 | pub type PWORD = *mut WORD; 118 | pub type LPWORD = *mut WORD; 119 | pub type LPLONG = *mut c_long; 120 | pub type PDWORD = *mut DWORD; 121 | pub type LPDWORD = *mut DWORD; 122 | pub type LPVOID = *mut c_void; 123 | pub type LPCVOID = *const c_void; 124 | pub type INT = c_int; 125 | pub type UINT = c_uint; 126 | pub type PUINT = *mut c_uint; 127 | pub type WPARAM = UINT_PTR; 128 | pub type LPARAM = LONG_PTR; 129 | pub type LRESULT = LONG_PTR; 130 | 131 | pub type PVOID = *mut c_void; 132 | pub type PVOID64 = u64; // This is a 64-bit pointer, even when in 32-bit 133 | pub type VOID = c_void; 134 | pub type CHAR = c_char; 135 | pub type SHORT = c_short; 136 | pub type LONG = c_long; 137 | pub type WCHAR = wchar_t; 138 | pub type PWCHAR = *mut WCHAR; 139 | pub type LPWCH = *mut WCHAR; 140 | pub type PWCH = *mut WCHAR; 141 | pub type LPCWCH = *const WCHAR; 142 | pub type PCWCH = *const WCHAR; 143 | pub type NWPSTR = *mut WCHAR; 144 | pub type LPWSTR = *mut WCHAR; 145 | pub type LPTSTR = LPSTR; 146 | pub type PWSTR = *mut WCHAR; 147 | pub type PZPWSTR = *mut PWSTR; 148 | pub type PCZPWSTR = *const PWSTR; 149 | pub type LPUWSTR = *mut WCHAR; // Unaligned pointer 150 | pub type PUWSTR = *mut WCHAR; // Unaligned pointer 151 | pub type LPCWSTR = *const WCHAR; 152 | pub type PCWSTR = *const WCHAR; 153 | pub type PZPCWSTR = *mut PCWSTR; 154 | pub type PCZPCWSTR = *const PCWSTR; 155 | pub type LPCUWSTR = *const WCHAR; // Unaligned pointer 156 | pub type PCUWSTR = *const WCHAR; // Unaligned pointer 157 | pub type PZZWSTR = *mut WCHAR; 158 | pub type PCZZWSTR = *const WCHAR; 159 | pub type PUZZWSTR = *mut WCHAR; // Unaligned pointer 160 | pub type PCUZZWSTR = *const WCHAR; // Unaligned pointer 161 | pub type PNZWCH = *mut WCHAR; 162 | pub type PCNZWCH = *const WCHAR; 163 | pub type PUNZWCH = *mut WCHAR; // Unaligned pointer 164 | pub type PCUNZWCH = *const WCHAR; // Unaligned pointer 165 | pub type LPCWCHAR = *const WCHAR; 166 | pub type PCWCHAR = *const WCHAR; 167 | pub type LPCUWCHAR = *const WCHAR; // Unaligned pointer 168 | pub type PCUWCHAR = *const WCHAR; // Unaligned pointer 169 | pub type UCSCHAR = c_ulong; 170 | pub const UCSCHAR_INVALID_CHARACTER: UCSCHAR = 0xffffffff; 171 | pub const MIN_UCSCHAR: UCSCHAR = 0; 172 | pub const MAX_UCSCHAR: UCSCHAR = 0x0010FFFF; 173 | pub type PUCSCHAR = *mut UCSCHAR; 174 | pub type PCUCSCHAR = *const UCSCHAR; 175 | pub type PUCSSTR = *mut UCSCHAR; 176 | pub type PUUCSSTR = *mut UCSCHAR; // Unaligned pointer 177 | pub type PCUCSSTR = *const UCSCHAR; 178 | pub type PCUUCSSTR = *const UCSCHAR; // Unaligned pointer 179 | pub type PUUCSCHAR = *mut UCSCHAR; // Unaligned pointer 180 | pub type PCUUCSCHAR = *const UCSCHAR; // Unaligned pointer 181 | pub type PCHAR = *mut CHAR; 182 | pub type LPCH = *mut CHAR; 183 | pub type PCH = *mut CHAR; 184 | pub type LPCCH = *const CHAR; 185 | pub type PCCH = *const CHAR; 186 | pub type NPSTR = *mut CHAR; 187 | pub type LPSTR = *mut CHAR; 188 | pub type PSTR = *mut CHAR; 189 | pub type PZPSTR = *mut PSTR; 190 | pub type PCZPSTR = *const PSTR; 191 | pub type LPCSTR = *const CHAR; 192 | pub type PCSTR = *const CHAR; 193 | pub type PZPCSTR = *mut PCSTR; 194 | pub type PCZPCSTR = *const PCSTR; 195 | pub type PZZSTR = *mut CHAR; 196 | pub type PCZZSTR = *const CHAR; 197 | pub type PNZCH = *mut CHAR; 198 | pub type PCNZCH = *const CHAR; 199 | 200 | pub type SPHANDLE = *mut HANDLE; 201 | pub type LPHANDLE = *mut HANDLE; 202 | pub type HGLOBAL = HANDLE; 203 | pub type HLOCAL = HANDLE; 204 | pub type GLOBALHANDLE = HANDLE; 205 | pub type LOCALHANDLE = HANDLE; 206 | pub enum __some_function {} 207 | /// Pointer to a function with unknown type signature. 208 | pub type FARPROC = *mut __some_function; 209 | /// Pointer to a function with unknown type signature. 210 | pub type NEARPROC = *mut __some_function; 211 | /// Pointer to a function with unknown type signature. 212 | pub type PROC = *mut __some_function; 213 | pub type ATOM = WORD; 214 | 215 | pub enum HINSTANCE__ {} 216 | pub type HINSTANCE = *mut HINSTANCE__; 217 | pub type HMODULE = HINSTANCE; 218 | 219 | pub type HANDLE = *mut c_void; 220 | pub type PHANDLE = *mut HANDLE; 221 | pub type FCHAR = UCHAR; 222 | pub type FSHORT = USHORT; 223 | pub type FLONG = ULONG; 224 | pub type HRESULT = c_long; 225 | pub const OBJ_HANDLE_TAGBITS: usize = 0x00000003; 226 | pub type CCHAR = c_char; 227 | pub type CSHORT = c_short; 228 | pub type CLONG = ULONG; 229 | pub type PCCHAR = *mut CCHAR; 230 | pub type PCSHORT = *mut CSHORT; 231 | pub type PCLONG = *mut CLONG; 232 | pub type LCID = ULONG; 233 | pub type PLCID = PULONG; 234 | pub type LANGID = USHORT; 235 | pub type LOGICAL = ULONG; 236 | pub type PLOGICAL = *mut ULONG; 237 | pub type NTSTATUS = LONG; 238 | pub type PNTSTATUS = *mut NTSTATUS; 239 | pub type PCNTSTATUS = *const NTSTATUS; 240 | 241 | pub const PAGE_NOACCESS: DWORD = 0x01; 242 | pub const PAGE_READONLY: DWORD = 0x02; 243 | pub const PAGE_READWRITE: DWORD = 0x04; 244 | pub const PAGE_WRITECOPY: DWORD = 0x08; 245 | pub const PAGE_EXECUTE: DWORD = 0x10; 246 | pub const PAGE_EXECUTE_READ: DWORD = 0x20; 247 | pub const PAGE_EXECUTE_READWRITE: DWORD = 0x40; 248 | pub const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80; 249 | pub const PAGE_GUARD: DWORD = 0x100; 250 | pub const PAGE_NOCACHE: DWORD = 0x200; 251 | pub const PAGE_WRITECOMBINE: DWORD = 0x400; 252 | pub const PAGE_ENCLAVE_THREAD_CONTROL: DWORD = 0x80000000; 253 | pub const PAGE_REVERT_TO_FILE_MAP: DWORD = 0x80000000; 254 | pub const PAGE_TARGETS_NO_UPDATE: DWORD = 0x40000000; 255 | pub const PAGE_TARGETS_INVALID: DWORD = 0x40000000; 256 | pub const PAGE_ENCLAVE_UNVALIDATED: DWORD = 0x20000000; 257 | pub const PAGE_ENCLAVE_DECOMMIT: DWORD = 0x10000000; 258 | pub const MEM_COMMIT: DWORD = 0x1000; 259 | pub const MEM_RESERVE: DWORD = 0x2000; 260 | pub const MEM_DECOMMIT: DWORD = 0x4000; 261 | pub const MEM_RELEASE: DWORD = 0x8000; 262 | pub const MEM_FREE: DWORD = 0x10000; 263 | pub const MEM_PRIVATE: DWORD = 0x20000; 264 | pub const MEM_MAPPED: DWORD = 0x40000; 265 | pub const MEM_RESET: DWORD = 0x80000; 266 | pub const MEM_TOP_DOWN: DWORD = 0x100000; 267 | pub const MEM_WRITE_WATCH: DWORD = 0x200000; 268 | pub const MEM_PHYSICAL: DWORD = 0x400000; 269 | pub const MEM_ROTATE: DWORD = 0x800000; 270 | pub const MEM_DIFFERENT_IMAGE_BASE_OK: DWORD = 0x800000; 271 | pub const MEM_RESET_UNDO: DWORD = 0x1000000; 272 | pub const MEM_LARGE_PAGES: DWORD = 0x20000000; 273 | pub const MEM_4MB_PAGES: DWORD = 0x80000000; 274 | pub const MEM_64K_PAGES: DWORD = MEM_LARGE_PAGES | MEM_PHYSICAL; 275 | pub const SEC_64K_PAGES: DWORD = 0x00080000; 276 | pub const SEC_FILE: DWORD = 0x800000; 277 | pub const SEC_IMAGE: DWORD = 0x1000000; 278 | pub const SEC_PROTECTED_IMAGE: DWORD = 0x2000000; 279 | pub const SEC_RESERVE: DWORD = 0x4000000; 280 | pub const SEC_COMMIT: DWORD = 0x8000000; 281 | pub const SEC_NOCACHE: DWORD = 0x10000000; 282 | pub const SEC_WRITECOMBINE: DWORD = 0x40000000; 283 | pub const SEC_LARGE_PAGES: DWORD = 0x80000000; 284 | pub const SEC_IMAGE_NO_EXECUTE: DWORD = SEC_IMAGE | SEC_NOCACHE; 285 | pub const MEM_IMAGE: DWORD = SEC_IMAGE; 286 | pub const WRITE_WATCH_FLAG_RESET: DWORD = 0x01; 287 | pub const MEM_UNMAP_WITH_TRANSIENT_BOOST: DWORD = 0x01; 288 | pub const ENCLAVE_TYPE_SGX: DWORD = 0x00000001; 289 | pub const ENCLAVE_TYPE_SGX2: DWORD = 0x00000002; 290 | 291 | pub type PFLOAT128 = *mut FLOAT128; 292 | pub type LONGLONG = __int64; 293 | pub type ULONGLONG = __uint64; 294 | pub const MAXLONGLONG: LONGLONG = 0x7fffffffffffffff; 295 | pub type PLONGLONG = *mut LONGLONG; 296 | pub type PULONGLONG = *mut ULONGLONG; 297 | pub type USN = LONGLONG; 298 | 299 | pub struct FLOAT128 { 300 | pub LowPart: __int64, 301 | pub HighPart: __int64, 302 | } 303 | 304 | pub const NULL: PVOID = 0 as PVOID; 305 | pub const NULL64: PVOID64 = 0; 306 | //pub const MINCHAR: CHAR = 0x80; 307 | pub const MAXCHAR: CHAR = 0x7f; 308 | //pub const MINSHORT: SHORT = 0x8000; 309 | pub const MAXSHORT: SHORT = 0x7fff; 310 | //pub const MINLONG: LONG = 0x80000000; 311 | pub const MAXLONG: LONG = 0x7fffffff; 312 | pub const MAXUCHAR: UCHAR = 0xff; 313 | pub const MAXUSHORT: USHORT = 0xffff; 314 | pub const MAXULONG: ULONG = 0xffffffff; 315 | 316 | pub const IMAGE_DOS_SIGNATURE: WORD = 0x5A4D; 317 | pub const IMAGE_NT_SIGNATURE: DWORD = 0x00004550; 318 | 319 | #[repr(C)] 320 | pub struct UNICODE_STRING { 321 | pub Length: USHORT, 322 | pub MaximumLength: USHORT, 323 | pub Buffer: PWCH, 324 | } 325 | 326 | #[repr(C)] 327 | pub struct ANSI_STRING { 328 | pub Length: USHORT, 329 | pub MaximumLength: USHORT, 330 | pub Buffer: PCHAR, 331 | } 332 | 333 | pub const IMAGE_SUBSYSTEM_UNKNOWN: WORD = 0; 334 | pub const IMAGE_SUBSYSTEM_NATIVE: WORD = 1; 335 | pub const IMAGE_SUBSYSTEM_WINDOWS_GUI: WORD = 2; 336 | pub const IMAGE_SUBSYSTEM_WINDOWS_CUI: WORD = 3; 337 | pub const IMAGE_SUBSYSTEM_OS2_CUI: WORD = 5; 338 | pub const IMAGE_SUBSYSTEM_POSIX_CUI: WORD = 7; 339 | pub const IMAGE_SUBSYSTEM_NATIVE_WINDOWS: WORD = 8; 340 | pub const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: WORD = 9; 341 | pub const IMAGE_SUBSYSTEM_EFI_APPLICATION: WORD = 10; 342 | pub const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: WORD = 11; 343 | pub const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: WORD = 12; 344 | pub const IMAGE_SUBSYSTEM_EFI_ROM: WORD = 13; 345 | pub const IMAGE_SUBSYSTEM_XBOX: WORD = 14; 346 | pub const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: WORD = 16; 347 | pub const IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG: WORD = 17; 348 | pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: WORD = 0x0020; 349 | pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: WORD = 0x0040; 350 | pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: WORD = 0x0080; 351 | pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: WORD = 0x0100; 352 | pub const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION: WORD = 0x0200; 353 | pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: WORD = 0x0400; 354 | pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: WORD = 0x0800; 355 | pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: WORD = 0x1000; 356 | pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: WORD = 0x2000; 357 | pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: WORD = 0x4000; 358 | pub const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE: WORD = 0x8000; 359 | pub const IMAGE_DIRECTORY_ENTRY_EXPORT: WORD = 0; 360 | pub const IMAGE_DIRECTORY_ENTRY_IMPORT: WORD = 1; 361 | pub const IMAGE_DIRECTORY_ENTRY_RESOURCE: WORD = 2; 362 | pub const IMAGE_DIRECTORY_ENTRY_EXCEPTION: WORD = 3; 363 | pub const IMAGE_DIRECTORY_ENTRY_SECURITY: WORD = 4; 364 | pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: WORD = 5; 365 | pub const IMAGE_DIRECTORY_ENTRY_DEBUG: WORD = 6; 366 | pub const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: WORD = 7; 367 | pub const IMAGE_DIRECTORY_ENTRY_GLOBALPTR: WORD = 8; 368 | pub const IMAGE_DIRECTORY_ENTRY_TLS: WORD = 9; 369 | pub const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: WORD = 10; 370 | pub const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: WORD = 11; 371 | pub const IMAGE_DIRECTORY_ENTRY_IAT: WORD = 12; 372 | pub const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: WORD = 13; 373 | pub const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: WORD = 14; 374 | 375 | pub const IMAGE_ORDINAL_FLAG64: ULONGLONG = 0x8000000000000000; 376 | pub const IMAGE_ORDINAL_FLAG32: DWORD = 0x80000000; 377 | 378 | #[inline] 379 | pub fn NT_SUCCESS(Status: NTSTATUS) -> bool { 380 | Status >= 0 381 | } 382 | #[inline] 383 | pub fn NT_INFORMATION(Status: NTSTATUS) -> bool { 384 | ((Status as ULONG) >> 30) == 1 385 | } 386 | #[inline] 387 | pub fn NT_WARNING(Status: NTSTATUS) -> bool { 388 | ((Status as ULONG) >> 30) == 2 389 | } 390 | #[inline] 391 | pub fn NT_ERROR(Status: NTSTATUS) -> bool { 392 | ((Status as ULONG) >> 30) == 3 393 | } 394 | #[inline] 395 | pub fn IMAGE_ORDINAL64(Ordinal: ULONGLONG) -> ULONGLONG { 396 | Ordinal & 0xffff 397 | } 398 | #[inline] 399 | pub fn IMAGE_ORDINAL32(Ordinal: DWORD) -> DWORD { 400 | Ordinal & 0xffff 401 | } 402 | #[inline] 403 | pub fn IMAGE_SNAP_BY_ORDINAL64(Ordinal: ULONGLONG) -> bool { 404 | (Ordinal & IMAGE_ORDINAL_FLAG64) != 0 405 | } 406 | #[inline] 407 | pub fn IMAGE_SNAP_BY_ORDINAL32(Ordinal: DWORD) -> bool { 408 | (Ordinal & IMAGE_ORDINAL_FLAG32) != 0 409 | } 410 | 411 | // (pub ){0,1}([a-z A-Z 0-9 _]*): 412 | // pub $2: 413 | 414 | #[repr(C)] 415 | pub struct IMAGE_DOS_HEADER { 416 | pub e_magic: WORD, 417 | pub e_cblp: WORD, 418 | pub e_cp: WORD, 419 | pub e_crlc: WORD, 420 | pub e_cparhdr: WORD, 421 | pub e_minalloc: WORD, 422 | pub e_maxalloc: WORD, 423 | pub e_ss: WORD, 424 | pub e_sp: WORD, 425 | pub e_csum: WORD, 426 | pub e_ip: WORD, 427 | pub e_cs: WORD, 428 | pub e_lfarlc: WORD, 429 | pub e_ovno: WORD, 430 | pub e_res: [WORD; 4], 431 | pub e_oemid: WORD, 432 | pub e_oeminfo: WORD, 433 | pub e_res2: [WORD; 10], 434 | pub e_lfanew: LONG, 435 | } 436 | 437 | #[repr(C)] 438 | pub struct PEB { 439 | pub InheritedAddressSpace: BOOLEAN, 440 | pub ReadImageFileExecOptions: BOOLEAN, 441 | pub BeingDebugged: BOOLEAN, 442 | pub BitField: BOOLEAN, 443 | pub Mutant: HANDLE, 444 | pub ImageBaseAddress: PVOID, 445 | pub Ldr: *mut PEB_LDR_DATA, 446 | pub ProcessParameters: *mut RTL_USER_PROCESS_PARAMETERS, 447 | } 448 | 449 | #[repr(C)] 450 | pub struct PEB_LDR_DATA { 451 | pub Length: ULONG, 452 | pub Initialized: BOOLEAN, 453 | pub SsHandle: HANDLE, 454 | pub InLoadOrderModuleList: LIST_ENTRY, 455 | // ... 456 | } 457 | 458 | #[repr(C)] 459 | pub struct RTL_USER_PROCESS_PARAMETERS { 460 | pub MaximumLength: ULONG, 461 | pub Length: ULONG, 462 | pub Flags: ULONG, 463 | pub DebugFlags: ULONG, 464 | pub ConsoleHandle: HANDLE, 465 | pub ConsoleFlags: ULONG, 466 | pub StandardInput: HANDLE, 467 | pub StandardOutput: HANDLE, 468 | pub StandardError: HANDLE, 469 | } 470 | 471 | #[repr(C)] 472 | pub struct LDR_DATA_TABLE_ENTRY { 473 | pub InLoadOrderLinks: LIST_ENTRY, 474 | pub InMemoryOrderLinks: LIST_ENTRY, 475 | pub u1: LIST_ENTRY, 476 | pub DllBase: PVOID, 477 | pub EntryPoint: PVOID, 478 | pub SizeOfImage: ULONG, 479 | pub FullDllName: UNICODE_STRING, 480 | pub BaseDllName: UNICODE_STRING, 481 | // ... 482 | } 483 | 484 | #[repr(C)] 485 | pub struct LIST_ENTRY { 486 | pub Flink: *mut LIST_ENTRY, 487 | pub Blink: *mut LIST_ENTRY, 488 | } 489 | 490 | pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES: usize = 16; 491 | 492 | #[repr(C)] 493 | pub struct IMAGE_DATA_DIRECTORY { 494 | pub VirtualAddress: DWORD, 495 | pub Size: DWORD, 496 | } 497 | 498 | #[repr(C)] 499 | pub struct IMAGE_OPTIONAL_HEADER64 { 500 | pub Magic: WORD, 501 | pub MajorLinkerVersion: BYTE, 502 | pub MinorLinkerVersion: BYTE, 503 | pub SizeOfCode: DWORD, 504 | pub SizeOfInitializedData: DWORD, 505 | pub SizeOfUninitializedData: DWORD, 506 | pub AddressOfEntryPoint: DWORD, 507 | pub BaseOfCode: DWORD, 508 | pub ImageBase: ULONGLONG, 509 | pub SectionAlignment: DWORD, 510 | pub FileAlignment: DWORD, 511 | pub MajorOperatingSystemVersion: WORD, 512 | pub MinorOperatingSystemVersion: WORD, 513 | pub MajorImageVersion: WORD, 514 | pub MinorImageVersion: WORD, 515 | pub MajorSubsystemVersion: WORD, 516 | pub MinorSubsystemVersion: WORD, 517 | pub Win32VersionValue: DWORD, 518 | pub SizeOfImage: DWORD, 519 | pub SizeOfHeaders: DWORD, 520 | pub CheckSum: DWORD, 521 | pub Subsystem: WORD, 522 | pub DllCharacteristics: WORD, 523 | pub SizeOfStackReserve: ULONGLONG, 524 | pub SizeOfStackCommit: ULONGLONG, 525 | pub SizeOfHeapReserve: ULONGLONG, 526 | pub SizeOfHeapCommit: ULONGLONG, 527 | pub LoaderFlags: DWORD, 528 | pub NumberOfRvaAndSizes: DWORD, 529 | pub DataDirectory: [IMAGE_DATA_DIRECTORY; IMAGE_NUMBEROF_DIRECTORY_ENTRIES], 530 | } 531 | 532 | #[repr(C)] 533 | pub struct IMAGE_FILE_HEADER { 534 | pub Machine: WORD, 535 | pub NumberOfSections: WORD, 536 | pub TimeDateStamp: DWORD, 537 | pub PointerToSymbolTable: DWORD, 538 | pub NumberOfSymbols: DWORD, 539 | pub SizeOfOptionalHeader: WORD, 540 | pub Characteristics: WORD, 541 | } 542 | 543 | #[repr(C)] 544 | pub struct IMAGE_NT_HEADERS64 { 545 | pub Signature: DWORD, 546 | pub FileHeader: IMAGE_FILE_HEADER, 547 | pub OptionalHeader: IMAGE_OPTIONAL_HEADER64, 548 | } 549 | 550 | pub const IMAGE_SIZEOF_SHORT_NAME: usize = 8; 551 | 552 | #[repr(C)] 553 | pub struct IMAGE_SECTION_HEADER_Misc([u32; 1]); 554 | impl Copy for IMAGE_SECTION_HEADER_Misc {} 555 | impl Clone for IMAGE_SECTION_HEADER_Misc { 556 | #[inline] 557 | fn clone(&self) -> IMAGE_SECTION_HEADER_Misc { 558 | *self 559 | } 560 | } 561 | impl IMAGE_SECTION_HEADER_Misc { 562 | pub unsafe fn PhysicalAddress(&self) -> &DWORD { 563 | &*(self as *const _ as *const DWORD) 564 | } 565 | 566 | pub unsafe fn PhysicalAddress_mut(&mut self) -> &mut DWORD { 567 | &mut *(self as *mut _ as *mut DWORD) 568 | } 569 | 570 | pub unsafe fn VirtualSize(&self) -> &DWORD { 571 | &*(self as *const _ as *const DWORD) 572 | } 573 | 574 | pub unsafe fn VirtualSize_mut(&mut self) -> &mut DWORD { 575 | &mut *(self as *mut _ as *mut DWORD) 576 | } 577 | } 578 | 579 | #[repr(C)] 580 | pub struct IMAGE_SECTION_HEADER { 581 | pub Name: [BYTE; IMAGE_SIZEOF_SHORT_NAME], 582 | pub Misc: IMAGE_SECTION_HEADER_Misc, 583 | pub VirtualAddress: DWORD, 584 | pub SizeOfRawData: DWORD, 585 | pub PointerToRawData: DWORD, 586 | pub PointerToRelocations: DWORD, 587 | pub PointerToLinenumbers: DWORD, 588 | pub NumberOfRelocations: WORD, 589 | pub NumberOfLinenumbers: WORD, 590 | pub Characteristics: DWORD, 591 | } 592 | 593 | #[repr(C)] 594 | pub struct IMAGE_EXPORT_DIRECTORY { 595 | pub Characteristics: DWORD, 596 | pub TimeDateStamp: DWORD, 597 | pub MajorVersion: WORD, 598 | pub MinorVersion: WORD, 599 | pub Name: DWORD, 600 | pub Base: DWORD, 601 | pub NumberOfFunctions: DWORD, 602 | pub NumberOfNames: DWORD, 603 | pub AddressOfFunctions: DWORD, 604 | pub AddressOfNames: DWORD, 605 | pub AddressOfNameOrdinals: DWORD, 606 | } 607 | 608 | #[repr(C)] 609 | pub struct IMAGE_IMPORT_BY_NAME { 610 | pub Hint: WORD, 611 | pub Name: [CHAR; 1], 612 | } 613 | 614 | #[repr(C)] 615 | pub struct IMAGE_THUNK_DATA64_u1([u64; 1]); 616 | impl Copy for IMAGE_THUNK_DATA64_u1 {} 617 | impl Clone for IMAGE_THUNK_DATA64_u1 { 618 | #[inline] 619 | fn clone(&self) -> IMAGE_THUNK_DATA64_u1 { 620 | *self 621 | } 622 | } 623 | impl IMAGE_THUNK_DATA64_u1 { 624 | pub unsafe fn ForwarderString(&self) -> &ULONGLONG { 625 | &*(self as *const _ as *const ULONGLONG) 626 | } 627 | 628 | pub unsafe fn ForwarderString_mut(&mut self) -> &mut ULONGLONG { 629 | &mut *(self as *mut _ as *mut ULONGLONG) 630 | } 631 | 632 | pub unsafe fn Function(&self) -> &ULONGLONG { 633 | &*(self as *const _ as *const ULONGLONG) 634 | } 635 | 636 | pub unsafe fn Function_mut(&mut self) -> &mut ULONGLONG { 637 | &mut *(self as *mut _ as *mut ULONGLONG) 638 | } 639 | 640 | pub unsafe fn Ordinal(&self) -> &ULONGLONG { 641 | &*(self as *const _ as *const ULONGLONG) 642 | } 643 | 644 | pub unsafe fn Ordinal_mut(&mut self) -> &mut ULONGLONG { 645 | &mut *(self as *mut _ as *mut ULONGLONG) 646 | } 647 | 648 | pub unsafe fn AddressOfData(&self) -> &ULONGLONG { 649 | &*(self as *const _ as *const ULONGLONG) 650 | } 651 | 652 | pub unsafe fn AddressOfData_mut(&mut self) -> &mut ULONGLONG { 653 | &mut *(self as *mut _ as *mut ULONGLONG) 654 | } 655 | } 656 | 657 | #[repr(C)] 658 | pub struct IMAGE_THUNK_DATA64 { 659 | pub u1: IMAGE_THUNK_DATA64_u1, 660 | } 661 | 662 | #[repr(C)] 663 | pub struct IMAGE_IMPORT_DESCRIPTOR_u([u32; 1]); 664 | impl Copy for IMAGE_IMPORT_DESCRIPTOR_u {} 665 | impl Clone for IMAGE_IMPORT_DESCRIPTOR_u { 666 | #[inline] 667 | fn clone(&self) -> IMAGE_IMPORT_DESCRIPTOR_u { 668 | *self 669 | } 670 | } 671 | impl IMAGE_IMPORT_DESCRIPTOR_u { 672 | pub unsafe fn Characteristics(&self) -> &DWORD { 673 | &*(self as *const _ as *const DWORD) 674 | } 675 | 676 | pub unsafe fn Characteristics_mut(&mut self) -> &mut DWORD { 677 | &mut *(self as *mut _ as *mut DWORD) 678 | } 679 | 680 | pub unsafe fn OriginalFirstThunk(&self) -> &DWORD { 681 | &*(self as *const _ as *const DWORD) 682 | } 683 | 684 | pub unsafe fn OriginalFirstThunk_mut(&mut self) -> &mut DWORD { 685 | &mut *(self as *mut _ as *mut DWORD) 686 | } 687 | } 688 | 689 | #[repr(C)] 690 | pub struct IMAGE_IMPORT_DESCRIPTOR { 691 | pub u: IMAGE_IMPORT_DESCRIPTOR_u, 692 | pub TimeDateStamp: DWORD, 693 | pub ForwarderChain: DWORD, 694 | pub Name: DWORD, 695 | pub FirstThunk: DWORD, 696 | } 697 | 698 | #[repr(C)] 699 | pub struct IMAGE_DELAYLOAD_DESCRIPTOR_Attributes { 700 | pub AllAttributes: DWORD, 701 | } 702 | 703 | #[repr(C)] 704 | pub struct IMAGE_DELAYLOAD_DESCRIPTOR { 705 | pub Attributes: IMAGE_DELAYLOAD_DESCRIPTOR_Attributes, 706 | pub DllNameRVA: DWORD, 707 | pub ModuleHandleRVA: DWORD, 708 | pub ImportAddressTableRVA: DWORD, 709 | pub ImportNameTableRVA: DWORD, 710 | pub BoundImportAddressTableRVA: DWORD, 711 | pub UnloadInformationTableRVA: DWORD, 712 | pub TimeDateStamp: DWORD, 713 | } 714 | 715 | #[repr(C)] 716 | pub struct IMAGE_BASE_RELOCATION { 717 | pub VirtualAddress: DWORD, 718 | pub SizeOfBlock: DWORD, 719 | } 720 | 721 | #[repr(C)] 722 | pub struct IMAGE_TLS_DIRECTORY64 { 723 | pub StartAddressOfRawData: ULONGLONG, 724 | pub EndAddressOfRawData: ULONGLONG, 725 | pub AddressOfIndex: ULONGLONG, 726 | pub AddressOfCallBacks: ULONGLONG, 727 | pub SizeOfZeroFill: DWORD, 728 | pub Characteristics: DWORD, 729 | } 730 | 731 | #[repr(C)] 732 | pub struct IMAGE_RUNTIME_FUNCTION_ENTRY_u([u32; 1]); 733 | impl Copy for IMAGE_RUNTIME_FUNCTION_ENTRY_u {} 734 | impl Clone for IMAGE_RUNTIME_FUNCTION_ENTRY_u { 735 | #[inline] 736 | fn clone(&self) -> IMAGE_RUNTIME_FUNCTION_ENTRY_u { 737 | *self 738 | } 739 | } 740 | impl IMAGE_RUNTIME_FUNCTION_ENTRY_u { 741 | pub unsafe fn UnwindInfoAddress(&self) -> &DWORD { 742 | &*(self as *const _ as *const DWORD) 743 | } 744 | 745 | pub unsafe fn UnwindInfoAddress_mut(&mut self) -> &mut DWORD { 746 | &mut *(self as *mut _ as *mut DWORD) 747 | } 748 | 749 | pub unsafe fn UnwindData(&self) -> &DWORD { 750 | &*(self as *const _ as *const DWORD) 751 | } 752 | 753 | pub unsafe fn UnwindData_mut(&mut self) -> &mut DWORD { 754 | &mut *(self as *mut _ as *mut DWORD) 755 | } 756 | } 757 | 758 | #[repr(C)] 759 | pub struct _IMAGE_RUNTIME_FUNCTION_ENTRY { 760 | pub BeginAddress: DWORD, 761 | pub EndAddress: DWORD, 762 | pub u: IMAGE_RUNTIME_FUNCTION_ENTRY_u, 763 | } 764 | 765 | pub type IMAGE_RUNTIME_FUNCTION_ENTRY = _IMAGE_RUNTIME_FUNCTION_ENTRY; 766 | pub type PRUNTIME_FUNCTION = *mut IMAGE_RUNTIME_FUNCTION_ENTRY; 767 | -------------------------------------------------------------------------------- /example-shellcode/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(non_snake_case)] 3 | #![allow(non_camel_case_types)] 4 | #![allow(non_upper_case_globals)] 5 | #![allow(overflowing_literals)] 6 | #![no_std] 7 | #![no_main] 8 | #![feature(asm)] 9 | 10 | mod binding; 11 | use binding::*; 12 | 13 | use core::mem::transmute; 14 | use utf16_literal::utf16; 15 | 16 | pub type PLoadLibraryA = unsafe extern "system" fn(LPCSTR) -> HMODULE; 17 | pub type PGetProcAddress = unsafe extern "system" fn(HMODULE, LPCSTR) -> LPVOID; 18 | pub type PMessageBoxW = 19 | unsafe extern "system" fn(h: PVOID, text: LPCWSTR, cation: LPCWSTR, t: u32) -> u32; 20 | 21 | #[panic_handler] 22 | fn panic(_: &core::panic::PanicInfo) -> ! { 23 | loop {} 24 | } 25 | 26 | #[no_mangle] 27 | pub unsafe extern "C" fn main() { 28 | let kernel32 = get_module_by_name(utf16!("KERNEL32.DLL\x00").as_ptr()); 29 | let LoadLibraryA: PLoadLibraryA = 30 | transmute(get_func_by_name(kernel32, "LoadLibraryA\x00".as_ptr() as _)); 31 | let GetProcAddress: PGetProcAddress = transmute(get_func_by_name( 32 | kernel32, 33 | "GetProcAddress\x00".as_ptr() as _, 34 | )); 35 | 36 | let u32_dll = LoadLibraryA("user32.dll\x00".as_ptr() as _); 37 | let MessageBoxW: PMessageBoxW = 38 | transmute(GetProcAddress(u32_dll, "MessageBoxW\x00".as_ptr() as _)); 39 | 40 | MessageBoxW( 41 | NULL, 42 | utf16!("Hello, I'm 烏魯\0").as_ptr(), 43 | utf16!("From shellcode\0").as_ptr(), 44 | 0x00, 45 | ); 46 | } 47 | 48 | unsafe fn get_module_by_name(module_name: *const u16) -> PVOID { 49 | let mut ppeb = NULL as *mut PEB; 50 | asm!( 51 | "mov {}, gs:[0x60]", 52 | out(reg) ppeb, 53 | ); 54 | 55 | let p_peb_ldr_data = (*ppeb).Ldr; 56 | let mut module_list = 57 | (*p_peb_ldr_data).InLoadOrderModuleList.Flink as *mut LDR_DATA_TABLE_ENTRY; 58 | 59 | while (*module_list).DllBase != NULL { 60 | let dll_name = (*module_list).BaseDllName.Buffer; 61 | 62 | if compare_raw_str(module_name, dll_name) { 63 | return (*module_list).DllBase; 64 | } 65 | 66 | module_list = (*module_list).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; 67 | } 68 | 69 | NULL 70 | } 71 | 72 | unsafe fn get_func_by_name(module: PVOID, func_name: *const u8) -> PVOID { 73 | let nt_header = (module as u64 + (*(module as *mut IMAGE_DOS_HEADER)).e_lfanew as u64) 74 | as *mut IMAGE_NT_HEADERS64; 75 | let export_dir_rva = (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as u64; 76 | 77 | if export_dir_rva == 0x0 { 78 | return NULL; 79 | }; 80 | 81 | let export_dir = (module as u64 + export_dir_rva) as *mut IMAGE_EXPORT_DIRECTORY; 82 | 83 | let number_of_names = (*export_dir).NumberOfNames; 84 | let addr_of_funcs = (*export_dir).AddressOfFunctions; 85 | let addr_of_names = (*export_dir).AddressOfNames; 86 | let addr_of_ords = (*export_dir).AddressOfNameOrdinals; 87 | for i in 0..number_of_names { 88 | let name_rva_p: *const DWORD = 89 | (module as *const u8).offset((addr_of_names + i * 4) as isize) as *const _; 90 | let name_index_p: *const WORD = 91 | (module as *const u8).offset((addr_of_ords + i * 2) as isize) as *const _; 92 | let name_index = name_index_p.as_ref().unwrap(); 93 | let mut off: u32 = (4 * name_index) as u32; 94 | off = off + addr_of_funcs; 95 | let func_rva: *const DWORD = (module as *const u8).offset(off as _) as *const _; 96 | 97 | let name_rva = name_rva_p.as_ref().unwrap(); 98 | let curr_name = (module as *const u8).offset(*name_rva as isize); 99 | 100 | if *curr_name == 0 { 101 | continue; 102 | } 103 | if compare_raw_str(func_name, curr_name) { 104 | let res = (module as *const u8).offset(*func_rva as isize); 105 | return res as _; 106 | } 107 | } 108 | 109 | return NULL; 110 | } 111 | 112 | use num_traits::Num; 113 | pub fn compare_raw_str(s: *const T, u: *const T) -> bool 114 | where 115 | T: Num, 116 | { 117 | unsafe { 118 | let u_len = (0..).take_while(|&i| !(*u.offset(i)).is_zero()).count(); 119 | let u_slice = core::slice::from_raw_parts(u, u_len); 120 | 121 | let s_len = (0..).take_while(|&i| !(*s.offset(i)).is_zero()).count(); 122 | let s_slice = core::slice::from_raw_parts(s, s_len); 123 | 124 | if s_len != u_len { 125 | return false; 126 | } 127 | for i in 0..s_len { 128 | if s_slice[i] != u_slice[i] { 129 | return false; 130 | } 131 | } 132 | return true; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /images/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2vg/win-shellcode-rs/beab896521e82ea93a1ddb08d65f69c47efdd124/images/001.png -------------------------------------------------------------------------------- /images/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2vg/win-shellcode-rs/beab896521e82ea93a1ddb08d65f69c47efdd124/images/002.png -------------------------------------------------------------------------------- /shellcode/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-pc-windows-msvc" 3 | rustflags = [ 4 | "-Z", "pre-link-arg=/NOLOGO", 5 | "-Z", "pre-link-arg=/NODEFAULTLIB", 6 | "-C", "link-arg=/ENTRY:main", 7 | "-C", "link-arg=/MERGE:.edata=.rdata", 8 | "-C", "link-arg=/MERGE:.rustc=.data", 9 | "-C", "link-arg=/MERGE:.rdata=.text", 10 | "-C", "link-arg=/MERGE:.pdata=.text", 11 | "-C", "link-arg=/DEBUG:NONE", 12 | "-C", "link-arg=/EMITPOGOPHASEINFO", 13 | "-C", "target-feature=-mmx,-sse,+soft-float", 14 | "--emit", "asm", 15 | ] 16 | -------------------------------------------------------------------------------- /shellcode/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 = "shellcode" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /shellcode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shellcode" 3 | version = "0.1.0" 4 | authors = ["uru "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [profile.dev] 10 | panic = "abort" 11 | opt-level = "z" 12 | lto = true 13 | 14 | [profile.release] 15 | panic = "abort" 16 | opt-level = "z" 17 | lto = true 18 | 19 | [dependencies] 20 | -------------------------------------------------------------------------------- /shellcode/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | #[panic_handler] 5 | fn panic(_: &core::panic::PanicInfo) -> ! { 6 | loop {} 7 | } 8 | 9 | #[no_mangle] 10 | pub unsafe extern "C" fn main() { 11 | } 12 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use goblin::pe::PE; 3 | use std::fs::File; 4 | use std::io::prelude::*; 5 | use std::io::BufWriter; 6 | 7 | const BITNESS: u32 = 64; 8 | 9 | fn main() -> Result<()> { 10 | let src_path = "shellcode\\target\\x86_64-pc-windows-msvc\\release\\shellcode.exe"; 11 | let mut buffer = get_binary_from_file(src_path)?; 12 | let pe = PE::parse(&mut buffer)?; 13 | let standard_fileds = pe.header.optional_header.unwrap().standard_fields; 14 | let entry_offset = standard_fileds.address_of_entry_point - standard_fileds.base_of_code; 15 | 16 | for section in pe.sections { 17 | let name = String::from_utf8(section.name.to_vec())?; 18 | if !name.starts_with(".text") { 19 | continue; 20 | } 21 | let start = section.pointer_to_raw_data as usize; 22 | let size = section.size_of_raw_data as usize; 23 | let dst_path = ".\\shellcode.bin"; 24 | let shellcode = File::create(dst_path)?; 25 | let mut bootstrap: Vec = Vec::new(); 26 | 27 | /* 28 | * ;bootstrap shellcode 29 | * call 0x5 30 | * pop rcx 31 | * push rsi 32 | * mov rsi,rsp 33 | * and rsp,0xfffffffffffffff0 34 | * sub rsp,0x20 35 | * call 0x5 36 | * mov rsp,rsi 37 | * pop rsi 38 | * ret 39 | */ 40 | 41 | bootstrap.extend_from_slice(b"\xe8\x00\x00\x00\x00"); 42 | bootstrap.push(b'\x59'); 43 | bootstrap.push(b'\x56'); 44 | bootstrap.extend_from_slice(b"\x48\x89\xe6"); 45 | bootstrap.extend_from_slice(b"\x48\x83\xe4\xf0"); 46 | bootstrap.extend_from_slice(b"\x48\x83\xec\x20"); 47 | bootstrap.push(b'\xe8'); 48 | bootstrap.push(5 as u8); 49 | bootstrap.extend_from_slice(b"\x00\x00\x00"); 50 | bootstrap.extend_from_slice(b"\x48\x89\xf4"); 51 | bootstrap.push(b'\x5e'); 52 | bootstrap.push(b'\xc3'); 53 | 54 | let mut buf_writer = BufWriter::new(shellcode); 55 | 56 | // write bootstrap first 57 | for b in bootstrap { 58 | buf_writer.write(&[b])?; 59 | } 60 | 61 | // write jmp to entry code 62 | buf_writer.write(&[0xe9])?; 63 | 64 | // in most cases, i don't think the entry point address will be greater than u32 ... 65 | // therefore, it is cast to u32 here, but if it becomes a 64-bit address, it needs to be fixed. 66 | for byte in &(entry_offset as u32).to_le_bytes() { 67 | buf_writer.write(&[*byte])?; 68 | } 69 | 70 | // write main code 71 | for i in start..start + size { 72 | buf_writer.write(&[buffer[i]])?; 73 | } 74 | 75 | buf_writer.flush()?; 76 | 77 | println!("== .text section start =="); 78 | let binary = &buffer[start..start + size]; 79 | maidism::disassemble(binary, 0x0, 0x0, 6, BITNESS, true)?; 80 | 81 | println!("== main entry code =="); 82 | let binary = &buffer[entry_offset as usize..entry_offset as usize + size]; 83 | maidism::disassemble(binary, 0x0, 0x0, 6, BITNESS, true)?; 84 | 85 | println!("== shellcode =="); 86 | let binary = get_binary_from_file(dst_path)?; 87 | maidism::disassemble(&binary, 0x0, 0x0, 16, BITNESS, true)?; 88 | 89 | println!("done! shellcode saved in {}", dst_path); 90 | } 91 | Ok(()) 92 | } 93 | 94 | fn get_binary_from_file(file_name: impl Into) -> Result> { 95 | let file_name = file_name.into(); 96 | let mut f = File::open(&file_name) 97 | .with_context(|| format!("could not opening the file: {}", &file_name))?; 98 | let mut buffer = Vec::new(); 99 | f.read_to_end(&mut buffer) 100 | .with_context(|| format!("could not reading from the file: {}", &file_name))?; 101 | Ok(buffer) 102 | } 103 | --------------------------------------------------------------------------------