From db0f4cec7ef91f9bc72c58528a522dea4d0de671 Mon Sep 17 00:00:00 2001 From: PandaSec <89774117+p4nd4sec@users.noreply.github.com> Date: Fri, 9 May 2025 12:25:53 +0700 Subject: [PATCH 1/5] update naked for prehook & forward --- proxygen-macros/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxygen-macros/src/lib.rs b/proxygen-macros/src/lib.rs index ff2cd3c..8ad6138 100644 --- a/proxygen-macros/src/lib.rs +++ b/proxygen-macros/src/lib.rs @@ -112,7 +112,7 @@ pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { pub unsafe extern "C" fn #func_name() { #[cfg(target_arch = "x86_64")] { - std::arch::asm!( + std::arch::naked_asm!( "call {wait_dll_proxy_init}", "mov rax, qword ptr [rip + {ORIG_FUNCS_PTR}]", "add rax, {orig_index} * 8", @@ -128,7 +128,7 @@ pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { #[cfg(target_arch = "x86")] { - std::arch::asm!( + std::arch::naked_asm!( "call {wait_dll_proxy_init}", "mov eax, dword ptr [{ORIG_FUNCS_PTR}]", "add eax, {orig_index} * 4", @@ -254,7 +254,7 @@ pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { #[naked] #(#attrs)* pub unsafe extern "C" fn #func_name() { - std::arch::asm!( + std::arch::naked_asm!( // Wait for dll proxy to initialize "call {wait_dll_proxy_init}", "mov rax, qword ptr [rip + {ORIG_FUNCS_PTR}]", From 8c1c6b314a96d134a0e53fde89d29e9c75eaf110 Mon Sep 17 00:00:00 2001 From: PandaSec <89774117+p4nd4sec@users.noreply.github.com> Date: Fri, 9 May 2025 12:30:08 +0700 Subject: [PATCH 2/5] remove noreturn --- proxygen-macros/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/proxygen-macros/src/lib.rs b/proxygen-macros/src/lib.rs index 8ad6138..88b6f35 100644 --- a/proxygen-macros/src/lib.rs +++ b/proxygen-macros/src/lib.rs @@ -122,7 +122,6 @@ pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { wait_dll_proxy_init = sym crate::wait_dll_proxy_init, ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, orig_index = const #orig_index_ident, - options(noreturn) ) } @@ -138,7 +137,6 @@ pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { wait_dll_proxy_init = sym crate::wait_dll_proxy_init, ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, orig_index = const #orig_index_ident, - options(noreturn) ) } } @@ -293,7 +291,6 @@ pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, orig_index = const #orig_index_ident, proxygen_pre_hook_func = sym #hook_func_name, - options(noreturn) ); } )) From 2f43f2b0582e1cabacecfac1e448cd15de25519e Mon Sep 17 00:00:00 2001 From: PandaSec <89774117+p4nd4sec@users.noreply.github.com> Date: Fri, 9 May 2025 14:29:10 +0700 Subject: [PATCH 3/5] implement prehook for x86 --- proxygen-macros/src/lib.rs | 97 ++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/proxygen-macros/src/lib.rs b/proxygen-macros/src/lib.rs index 88b6f35..7bef64c 100644 --- a/proxygen-macros/src/lib.rs +++ b/proxygen-macros/src/lib.rs @@ -239,8 +239,6 @@ pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { let hook_func_name = syn::parse_str::(&format!("Proxygen_PreHook_{}", &func_name)).unwrap(); TokenStream::from(quote!( - #[cfg(not(target_arch = "x86_64"))] - compile_error!("Pre-hooks aren't yet implemented for non x86-64"); #[no_mangle] // TODO: Use the same safety/unsafety modifier as the original here @@ -252,46 +250,93 @@ pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { #[naked] #(#attrs)* pub unsafe extern "C" fn #func_name() { - std::arch::naked_asm!( - // Wait for dll proxy to initialize - "call {wait_dll_proxy_init}", - "mov rax, qword ptr [rip + {ORIG_FUNCS_PTR}]", - "add rax, {orig_index} * 8", - "mov rax, qword ptr [rax]", + #[cfg(target_arch = "x86")] + { + std::arch::naked_asm!( + "call {wait_dll_proxy_init}", + "mov eax, dword ptr [{ORIG_FUNCS_PTR}]", + "add eax, {orig_index} * 4", // 4 bytes per pointer in 32-bit + "mov eax, dword ptr [eax]", // Push the original function onto the stack - "push rax", + "push eax", // Save the general purpose registers - "push rdi; push rsi; push rcx; push rdx; push r8; push r9", + // Note: i686 doesn't have r8, r9, etc. + "push edi; push esi; push ecx; push edx; push ebx", // Save the 128-bit floating point registers - "sub rsp, 64", - "movaps [rsp], xmm0", - "movaps [rsp + 16], xmm1", - "movaps [rsp + 32], xmm2", - "movaps [rsp + 48], xmm3", + // Note: XMM registers are available in i686 with SSE support + "sub esp, 64", + "movaps [esp], xmm0", + "movaps [esp + 16], xmm1", + "movaps [esp + 32], xmm2", + "movaps [esp + 48], xmm3", // Call our hook code here "call {proxygen_pre_hook_func}", // Restore the 128-bit floating point registers - "movaps xmm3, [rsp + 48]", - "movaps xmm2, [rsp + 32]", - "movaps xmm1, [rsp + 16]", - "movaps xmm0, [rsp]", - "add rsp, 64", + "movaps xmm3, [esp + 48]", + "movaps xmm2, [esp + 32]", + "movaps xmm1, [esp + 16]", + "movaps xmm0, [esp]", + "add esp, 64", // Restore the general purpose registers - "pop r9; pop r8; pop rdx; pop rcx; pop rsi; pop rdi", + "pop ebx; pop edx; pop ecx; pop esi; pop edi", // Return to the original function "ret", - wait_dll_proxy_init = sym crate::wait_dll_proxy_init, - ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, - orig_index = const #orig_index_ident, - proxygen_pre_hook_func = sym #hook_func_name, - ); + wait_dll_proxy_init = sym crate::wait_dll_proxy_init, + ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, + orig_index = const #orig_index_ident, + proxygen_pre_hook_func = sym #hook_func_name, + ); + } + #[cfg(target_arch = "x86_64")] + { + std::arch::naked_asm!( + // Wait for dll proxy to initialize + "call {wait_dll_proxy_init}", + "mov rax, qword ptr [rip + {ORIG_FUNCS_PTR}]", + "add rax, {orig_index} * 8", + "mov rax, qword ptr [rax]", + + // Push the original function onto the stack + "push rax", + + // Save the general purpose registers + "push rdi; push rsi; push rcx; push rdx; push r8; push r9", + + // Save the 128-bit floating point registers + "sub rsp, 64", + "movaps [rsp], xmm0", + "movaps [rsp + 16], xmm1", + "movaps [rsp + 32], xmm2", + "movaps [rsp + 48], xmm3", + + // Call our hook code here + "call {proxygen_pre_hook_func}", + + // Restore the 128-bit floating point registers + "movaps xmm3, [rsp + 48]", + "movaps xmm2, [rsp + 32]", + "movaps xmm1, [rsp + 16]", + "movaps xmm0, [rsp]", + "add rsp, 64", + + // Restore the general purpose registers + "pop r9; pop r8; pop rdx; pop rcx; pop rsi; pop rdi", + + // Return to the original function + "ret", + wait_dll_proxy_init = sym crate::wait_dll_proxy_init, + ORIG_FUNCS_PTR = sym crate::ORIG_FUNCS_PTR, + orig_index = const #orig_index_ident, + proxygen_pre_hook_func = sym #hook_func_name, + ); + } } )) } From b471617344b8430d79cec2c64d457c6f1d7814f4 Mon Sep 17 00:00:00 2001 From: PandaSec <89774117+p4nd4sec@users.noreply.github.com> Date: Thu, 22 May 2025 16:58:13 +0700 Subject: [PATCH 4/5] update unsafe --- proxygen-macros/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proxygen-macros/src/lib.rs b/proxygen-macros/src/lib.rs index 7bef64c..6dfe98a 100644 --- a/proxygen-macros/src/lib.rs +++ b/proxygen-macros/src/lib.rs @@ -69,7 +69,7 @@ impl From for ProxySignatureType { // // Note: You may not have any instructions in the function body when forwarding function calls #[proc_macro_attribute] -pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub unsafe fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let func_name = input.sig.clone().ident; let func_body = input.block.stmts.clone(); @@ -145,7 +145,7 @@ pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { // Proc macro to bring the original function into the scope of an interceptor function as `orig_func` #[proc_macro_attribute] -pub fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub unsafe fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.clone().ident; @@ -188,7 +188,7 @@ pub fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { /// /// Note: Returning in this function will skip running the original. #[proc_macro_attribute] -pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub unsafe fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.ident.clone(); @@ -349,7 +349,7 @@ pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { /// /// Note: `orig_result` will be returned unless you choose to return your own result from this function. #[proc_macro_attribute] -pub fn post_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub unsafe fn post_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.clone().ident; From 546fc2b5ed071f86a629f958f497cf6667fcb6f6 Mon Sep 17 00:00:00 2001 From: PandaSec <89774117+p4nd4sec@users.noreply.github.com> Date: Thu, 22 May 2025 16:59:59 +0700 Subject: [PATCH 5/5] update unsafe 1 --- proxygen-macros/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/proxygen-macros/src/lib.rs b/proxygen-macros/src/lib.rs index 6dfe98a..c289bd0 100644 --- a/proxygen-macros/src/lib.rs +++ b/proxygen-macros/src/lib.rs @@ -69,7 +69,8 @@ impl From for ProxySignatureType { // // Note: You may not have any instructions in the function body when forwarding function calls #[proc_macro_attribute] -pub unsafe fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStream { + unsafe{ let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let func_name = input.sig.clone().ident; let func_body = input.block.stmts.clone(); @@ -141,11 +142,12 @@ pub unsafe fn forward(_attr_input: TokenStream, item: TokenStream) -> TokenStrea } } )) + } } // Proc macro to bring the original function into the scope of an interceptor function as `orig_func` #[proc_macro_attribute] -pub unsafe fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.clone().ident; @@ -188,7 +190,7 @@ pub unsafe fn proxy(attr_input: TokenStream, item: TokenStream) -> TokenStream { /// /// Note: Returning in this function will skip running the original. #[proc_macro_attribute] -pub unsafe fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.ident.clone(); @@ -349,7 +351,7 @@ pub unsafe fn pre_hook(attr_input: TokenStream, item: TokenStream) -> TokenStrea /// /// Note: `orig_result` will be returned unless you choose to return your own result from this function. #[proc_macro_attribute] -pub unsafe fn post_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { +pub fn post_hook(attr_input: TokenStream, item: TokenStream) -> TokenStream { let input: ItemFn = syn::parse(item).expect("You may only proxy a function"); let attr_input = syn::parse::(attr_input); let func_name = input.sig.clone().ident;