├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── hooklog.js └── main.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | workflow_dispatch: {} 4 | jobs: 5 | build: 6 | name: build 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | build: [linux, windows] 11 | include: 12 | - build: linux 13 | os: ubuntu-18.04 14 | rust: nightly 15 | target: x86_64-unknown-linux-musl 16 | archive-name: NodeInject-linux.tar.gz 17 | - build: windows 18 | os: windows-2019 19 | rust: nightly-x86_64-msvc 20 | target: x86_64-pc-windows-msvc 21 | archive-name: NodeInject-windows.7z 22 | fail-fast: false 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v2 27 | 28 | - name: Install Rust 29 | uses: actions-rs/toolchain@v1 30 | with: 31 | toolchain: ${{ matrix.rust }} 32 | profile: minimal 33 | override: true 34 | target: ${{ matrix.target }} 35 | 36 | - name: Build binary 37 | run: cargo build --verbose --release --target ${{ matrix.target }} 38 | env: 39 | RUST_BACKTRACE: 1 40 | 41 | - name: Build archive 42 | shell: bash 43 | run: | 44 | mkdir archive 45 | cp LICENSE README.md archive/ 46 | ls -lR 47 | if [ "${{ matrix.build }}" = "windows" ]; then 48 | cp "./target/${{ matrix.target }}/release/node_inject.exe" ./archive/ 49 | cd archive 50 | 7z a "${{ matrix.archive-name }}" LICENSE README.md node_inject.exe 51 | else 52 | cp "./target/${{ matrix.target }}/release/node_inject" ./archive/ 53 | cd archive 54 | tar -czf "${{ matrix.archive-name }}" LICENSE README.md node_inject 55 | fi 56 | - name: Upload archive 57 | uses: actions/upload-artifact@v1 58 | with: 59 | name: ${{ matrix.archive-name }} 60 | path: archive/${{ matrix.archive-name }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Output of the go coverage tool, specifically when used with LiteIDE 9 | *.out 10 | 11 | # Dependency directories (remove the comment below to include it) 12 | # vendor/ 13 | 14 | 15 | # Added by cargo 16 | /target 17 | 18 | /.idea -------------------------------------------------------------------------------- /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 = "ansi_term" 7 | version = "0.12.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 10 | dependencies = [ 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 19 | dependencies = [ 20 | "hermit-abi", 21 | "libc", 22 | "winapi", 23 | ] 24 | 25 | [[package]] 26 | name = "bitflags" 27 | version = "1.3.2" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 30 | 31 | [[package]] 32 | name = "cfg-if" 33 | version = "1.0.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 36 | 37 | [[package]] 38 | name = "clap" 39 | version = "2.34.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 42 | dependencies = [ 43 | "ansi_term", 44 | "atty", 45 | "bitflags", 46 | "strsim", 47 | "textwrap", 48 | "unicode-width", 49 | "vec_map", 50 | ] 51 | 52 | [[package]] 53 | name = "fastrand" 54 | version = "1.8.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 57 | dependencies = [ 58 | "instant", 59 | ] 60 | 61 | [[package]] 62 | name = "glob" 63 | version = "0.3.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 66 | 67 | [[package]] 68 | name = "hermit-abi" 69 | version = "0.1.19" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 72 | dependencies = [ 73 | "libc", 74 | ] 75 | 76 | [[package]] 77 | name = "instant" 78 | version = "0.1.12" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 81 | dependencies = [ 82 | "cfg-if", 83 | ] 84 | 85 | [[package]] 86 | name = "itoa" 87 | version = "1.0.4" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" 90 | 91 | [[package]] 92 | name = "libc" 93 | version = "0.2.137" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 96 | 97 | [[package]] 98 | name = "node_inject" 99 | version = "0.1.0" 100 | dependencies = [ 101 | "random-string", 102 | "rasar", 103 | ] 104 | 105 | [[package]] 106 | name = "random-string" 107 | version = "1.0.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "cf4e63111ec5292d8af9c220f06fe3bb87991cc78b6f1f7e291d1ae6b8a60817" 110 | dependencies = [ 111 | "fastrand", 112 | ] 113 | 114 | [[package]] 115 | name = "rasar" 116 | version = "0.1.6" 117 | source = "git+https://github.com/Zerthox/rasar.git#a384c9413fc905b7eef5f48ef4e2f74f73e7addd" 118 | dependencies = [ 119 | "clap", 120 | "glob", 121 | "serde_json", 122 | ] 123 | 124 | [[package]] 125 | name = "ryu" 126 | version = "1.0.11" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 129 | 130 | [[package]] 131 | name = "serde" 132 | version = "1.0.147" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" 135 | 136 | [[package]] 137 | name = "serde_json" 138 | version = "1.0.87" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" 141 | dependencies = [ 142 | "itoa", 143 | "ryu", 144 | "serde", 145 | ] 146 | 147 | [[package]] 148 | name = "strsim" 149 | version = "0.8.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 152 | 153 | [[package]] 154 | name = "textwrap" 155 | version = "0.11.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 158 | dependencies = [ 159 | "unicode-width", 160 | ] 161 | 162 | [[package]] 163 | name = "unicode-width" 164 | version = "0.1.10" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 167 | 168 | [[package]] 169 | name = "vec_map" 170 | version = "0.8.2" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 173 | 174 | [[package]] 175 | name = "winapi" 176 | version = "0.3.9" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 179 | dependencies = [ 180 | "winapi-i686-pc-windows-gnu", 181 | "winapi-x86_64-pc-windows-gnu", 182 | ] 183 | 184 | [[package]] 185 | name = "winapi-i686-pc-windows-gnu" 186 | version = "0.4.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 189 | 190 | [[package]] 191 | name = "winapi-x86_64-pc-windows-gnu" 192 | version = "0.4.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 195 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node_inject" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | 7 | [dependencies] 8 | rasar = {git = 'https://github.com/Zerthox/rasar.git'} 9 | random-string = "1.0.0" 10 | 11 | [features] 12 | no_embed = [] 13 | default = [] 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DiamondHunters 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 | # NodeInject 2 | An inject tools for injecting js code into electron application 3 | 4 | Please follow DMCA when using this code 5 | ### How it works 6 | 7 | 1. unpack `node_modules.asar` package (in `./resources`) 8 | 2. write `hook.js` into `raven` package directory (raven will be required at the early stage of startup in some application) 9 | 3. modify `index.js` of `raven`,injecting require of `hook.js` 10 | 11 | > Currently using embedded javascript file (`hooklog.js`) 12 | 13 | ### Usage 14 | 15 | 1. modify `hook.js` if you need, or enable `no_embed` feature to use specified js at (`NO_EMBED_HOOK_JS_PATH`) 16 | 2. use `cargo build` to make executable with embedded js, or `cargo build --features no_embed` without embedded js 17 | 3. Move the program to the electron application directory 18 | 4. run 19 | 20 | 21 | ### Compatibility test 22 | 23 | - Windows / Typora 1.9.5 PASSED 24 | - Ubuntu / Typora 1.9.3 PASSED 25 | 26 | Since macos may adopt different packaging methods and webkit as the execution environment, this tool does not support applications under macos. 27 | 28 | ### Examples 29 | 30 | https://github.com/DiamondHunters/NodeInject_Hook_example :Use NodeInject with Typora 31 | 32 | ----------------------------------------- 33 | ### Digression 34 | First airdrop of my life. Let me taste the flavor of web3. 35 | 36 | [](https://api.gitsponsors.com/api/badge/link?p=exYzTP95hmpViuFFwY39DdIpTcvrAz88YJsuboUDIc9QsXBJ9ksc0Nz/VZgodpYLouFImBxFMdxJbgAA4l9UEcL0EGgTolHoCT/W52AT+Lgv17K/MudJjS/QV7BmcurJ) 37 | -------------------------------------------------------------------------------- /src/hooklog.js: -------------------------------------------------------------------------------- 1 | //this file is a little example of how to use injecting ability 2 | //to hook a function and change its behavior 3 | 4 | // JUST FOR LEARNING PURPOSES, DON'T USE THIS TO CRACK SOFTWARE 5 | 6 | 7 | http = require("http") 8 | 9 | function log(str) { 10 | http.get('http://127.0.0.1:3000/log?str=' + str, res => { 11 | }).on('error', err => { 12 | console.log('Error: ', err.message); 13 | }); 14 | } 15 | 16 | log = console.log; 17 | console.log = log 18 | let validator = { 19 | set: function (target, key, value) { 20 | if (key === 'log') { 21 | log('console.log override blocked'); 22 | return; 23 | } 24 | target[key] = value; 25 | } 26 | } 27 | 28 | let proxy = new Proxy(console, validator); 29 | console = proxy 30 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::convert::AsRef; 2 | use std::fs::{File, OpenOptions}; 3 | use std::io::Write; 4 | 5 | 6 | const HOOK_JS_WRITE_PATH: &str = "./node/raven/hook.js"; //path to hook.js in unpacked module, if you change it, change it in append_require_to_file too 7 | #[cfg(feature = "no_embed")] 8 | const NO_EMBED_HOOK_JS_PATH: &str = "./hook.js"; // if no_emded feature is enabled, this file will be used in runtime 9 | #[cfg(not(feature = "no_embed"))] 10 | const EMBED_HOOK_JS_BYTES: &[u8] = include_bytes!("hooklog.js"); // embedded hooking code file,will be embedded in binary file 11 | const INJECT_JS_PATH: &str = "./node/raven/index.js"; //path for unpacked module to inject code into,if you want inject code into another module, change it here and in HOOK_JS_WRITE_PATH 12 | 13 | 14 | fn main() { 15 | if file_exist("./node"){ 16 | println!("You may have already installed the hook.Please check manually."); 17 | return; 18 | } 19 | if !file_exist("./resources/node_modules.asar") { 20 | println!("no node_modules.asar found"); 21 | println!("move me to the root of your typora installation(the same directory as executable of electron)"); 22 | return; 23 | } 24 | println!("extracting node_modules.asar"); 25 | rasar::extract("./resources/node_modules.asar", "./node").unwrap(); 26 | println!("adding hook.js"); 27 | write_js_to_file(); 28 | println!("applying patch"); 29 | append_require_to_file(); 30 | println!("packing node_modules.asar"); 31 | rasar::pack("./node","./resources/node_modules.asar").unwrap(); 32 | println!("done!"); 33 | } 34 | fn file_exist(archive: &str) -> bool { 35 | return std::path::Path::new(archive).exists() 36 | } 37 | 38 | 39 | #[cfg(not(feature = "no_embed"))] 40 | fn write_js_to_file() { 41 | let mut file = File::create(HOOK_JS_WRITE_PATH).unwrap(); 42 | file.write_all(EMBED_HOOK_JS_BYTES).unwrap(); 43 | } 44 | #[cfg(feature = "no_embed")] 45 | fn write_js_to_file() { 46 | let mut file = File::create(HOOK_JS_WRITE_PATH).unwrap(); 47 | let mut hook_js = File::open(NO_EMBED_HOOK_JS_PATH).unwrap(); 48 | std::io::copy(&mut hook_js, &mut file).unwrap(); 49 | } 50 | 51 | fn append_require_to_file() { 52 | let mut file = OpenOptions::new() 53 | .append(true) 54 | .open(INJECT_JS_PATH) 55 | .unwrap(); 56 | file.write_all("\nrequire('./hook')".as_ref()).unwrap(); 57 | } 58 | --------------------------------------------------------------------------------