From b4ad4a33a2608e869c8990b491d83986a338755a Mon Sep 17 00:00:00 2001 From: techmetx11 Date: Mon, 29 Apr 2024 09:27:20 +0100 Subject: [PATCH] Can now decrypt `n` parameter signatures --- Cargo.toml | 2 +- src/consts.rs | 2 + src/jobs.rs | 120 +++++++++++++++++++++++++++++++------------------- src/main.rs | 1 + 4 files changed, 78 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 20f7085..832c5a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] regex = "1.10.4" -rquickjs = {version = "0.6.0", features=["futures"]} +rquickjs = {version = "0.6.0", features=["futures", "parallel"]} tokio = { version = "1.37.0", features = ["full", "net", "macros", "rt-multi-thread", "io-std", "io-util"] } reqwest = "0.12.4" lazy-regex = "3.1.0" diff --git a/src/consts.rs b/src/consts.rs index 5659206..42febad 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -8,3 +8,5 @@ pub static REGEX_PLAYER_ID: &Lazy = regex!("\\/s\\/player\\/([0-9a-f]{8}) pub static NSIG_FUNCTION_ARRAY: &Lazy = regex!( "\\.get\\(\"n\"\\)\\)&&\\([a-zA-Z0-9$_]=([a-zA-Z0-9$_]+)(?:\\[(\\d+)])?\\([a-zA-Z0-9$_]\\)" ); + +pub static NSIG_FUNCTION_NAME: &str = "decrypt_nsig"; diff --git a/src/jobs.rs b/src/jobs.rs index 54e9dac..bd9f8d3 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -1,10 +1,10 @@ use regex::Regex; -use rquickjs::{AsyncContext, AsyncRuntime}; -use std::{num::NonZeroUsize, ops::Deref, sync::Arc, thread::available_parallelism}; +use rquickjs::{async_with, AsyncContext, AsyncRuntime, Exception, FromJs, IntoJs}; +use std::{num::NonZeroUsize, sync::Arc, thread::available_parallelism}; use tokio::{runtime::Handle, sync::Mutex, task::block_in_place}; use tub::Pool; -use crate::consts::{NSIG_FUNCTION_ARRAY, REGEX_PLAYER_ID, TEST_YOUTUBE_VIDEO}; +use crate::consts::{NSIG_FUNCTION_ARRAY, NSIG_FUNCTION_NAME, REGEX_PLAYER_ID, TEST_YOUTUBE_VIDEO}; pub enum JobOpcode { ForceUpdate, @@ -12,6 +12,15 @@ pub enum JobOpcode { UnknownOpcode, } +impl std::fmt::Display for JobOpcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ForceUpdate => write!(f, "ForceUpdate"), + Self::DecryptNSignature => write!(f, "DecryptNSignature"), + Self::UnknownOpcode => write!(f, "UnknownOpcode"), + } + } +} impl From for JobOpcode { fn from(value: u8) -> Self { match value { @@ -31,33 +40,9 @@ pub struct PlayerInfo { } pub struct JavascriptInterpreter { - js_runtime: AsyncRuntimeWrapper, - nsig_context: AsyncContextWrapper, - player_id: u32, -} - -// This is to get Rust to shut up, since the types are aliases for non-null pointers -struct AsyncRuntimeWrapper(AsyncRuntime); -struct AsyncContextWrapper(AsyncContext); - -unsafe impl Send for AsyncRuntimeWrapper {} -unsafe impl Send for AsyncContextWrapper {} -unsafe impl Sync for AsyncRuntimeWrapper {} -unsafe impl Sync for AsyncContextWrapper {} -impl Deref for AsyncRuntimeWrapper { - type Target = AsyncRuntime; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Deref for AsyncContextWrapper { - type Target = AsyncContext; - - fn deref(&self) -> &Self::Target { - &self.0 - } + js_runtime: AsyncRuntime, + nsig_context: AsyncContext, + player_id: Mutex, } impl JavascriptInterpreter { @@ -70,17 +55,16 @@ impl JavascriptInterpreter { .unwrap() }); JavascriptInterpreter { - js_runtime: AsyncRuntimeWrapper(js_runtime), - nsig_context: AsyncContextWrapper(nsig_context), - player_id: 0, + js_runtime: js_runtime, + nsig_context: nsig_context, + player_id: Mutex::new(0), } } } pub struct GlobalState { player_info: Mutex, - js_runtime_pool: Mutex>>, - all_runtimes: Mutex>>, + js_runtime_pool: Pool>, } impl GlobalState { @@ -90,21 +74,17 @@ impl GlobalState { .get(); let mut runtime_vector: Vec> = Vec::with_capacity(number_of_runtimes); - for n in 0..number_of_runtimes { + for _n in 0..number_of_runtimes { runtime_vector.push(Arc::new(JavascriptInterpreter::new())); } - // Make a clone of the vector, this will clone all the values inside (Arc) - let mut runtime_vector2: Vec> = - Vec::with_capacity(number_of_runtimes); - runtime_vector2.clone_from(&runtime_vector); - let runtime_pool: Pool> = Pool::from_vec(runtime_vector2); + + let runtime_pool: Pool> = Pool::from_vec(runtime_vector); GlobalState { player_info: Mutex::new(PlayerInfo { nsig_function_code: Default::default(), player_id: Default::default(), }), - js_runtime_pool: Mutex::new(runtime_pool), - all_runtimes: Mutex::new(runtime_vector), + js_runtime_pool: runtime_pool, } } } @@ -191,7 +171,8 @@ pub async fn process_fetch_update(state: Arc) { let nsig_function_code_regex = Regex::new(&nsig_function_code_regex_str).unwrap(); let mut nsig_function_code = String::new(); - nsig_function_code += "decrypt_nsig = function"; + nsig_function_code += "function "; + nsig_function_code += NSIG_FUNCTION_NAME; nsig_function_code += nsig_function_code_regex .captures(&player_javascript) .unwrap() @@ -202,7 +183,54 @@ pub async fn process_fetch_update(state: Arc) { current_player_info = global_state.player_info.lock().await; current_player_info.player_id = player_id; current_player_info.nsig_function_code = nsig_function_code; - println!("{}", current_player_info.nsig_function_code); + println!("Successfully updated the player") } -pub async fn process_decrypt_n_signature(_state: Arc, _sig: String) {} +pub async fn process_decrypt_n_signature(state: Arc, sig: String) { + let global_state = state.clone(); + + println!("Signature to be decrypted: {}", sig); + let interp = global_state.js_runtime_pool.acquire().await; + + let cloned_interp = interp.clone(); + async_with!(cloned_interp.nsig_context => |ctx|{ + let mut current_player_id = interp.player_id.lock().await; + let player_info = global_state.player_info.lock().await; + + if player_info.player_id != *current_player_id { + match ctx.eval::<(),String>(player_info.nsig_function_code.clone()) { + Ok(x) => x, + Err(n) => { + if n.is_exception() { + println!("JavaScript interpreter error (nsig code): {:?}", ctx.catch().as_exception()); + } else { + println!("JavaScript interpreter error (nsig code): {}", n); + } + return; + } + } + *current_player_id = player_info.player_id; + } + drop(player_info); + + let mut call_string: String = String::new(); + call_string += NSIG_FUNCTION_NAME; + call_string += "(\""; + call_string += &sig; + call_string += "\")"; + + let decrypted_string = match ctx.eval::(call_string) { + Ok(x) => x, + Err(n) => { + if n.is_exception() { + println!("JavaScript interpreter error (nsig code): {:?}", ctx.catch().as_exception()); + } else { + println!("JavaScript interpreter error (nsig code): {}", n); + } + return; + } + }; + println!("Decrypted signature: {}", decrypted_string); + }) + .await; +} diff --git a/src/main.rs b/src/main.rs index 122519b..979d8e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,7 @@ async fn process_socket(state: Arc, socket: UnixStream) { let opcode_byte: u8 = break_fail!(bufreader.read_u8().await); let opcode: JobOpcode = opcode_byte.into(); + println!("Received job: {}", opcode); match opcode { JobOpcode::ForceUpdate => { let cloned_state = state.clone();