Skip to content

Commit fda05af

Browse files
committed
New PoC Updates + Template Improvements
Added new Code Snippet [API HOOKING] using trampoline and modified readme for better readability.
1 parent 19ebd97 commit fda05af

File tree

8 files changed

+461
-241
lines changed

8 files changed

+461
-241
lines changed

Api_Hooking/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "Api_Hooking"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
widestring = "1.2.0"
8+
winapi = { version = "0.3", features = [
9+
"libloaderapi",
10+
"memoryapi",
11+
"processthreadsapi",
12+
"errhandlingapi",
13+
"minwindef",
14+
"winuser",
15+
"ntdef",
16+
"windef"
17+
] }

Api_Hooking/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
# System API Interceptor
3+
4+
## Name of the Code
5+
System API Interceptor (`api_interceptor.rs`)
6+
7+
![Demo](./demp.gif)
8+
## Explanation
9+
The System API Interceptor is a Rust-based utility for intercepting and monitoring Windows API calls, specifically targeting the `MessageBoxA` function in `user32.dll`. It employs inline function hooking via a trampoline to redirect calls to a custom handler, log parameters, and invoke `MessageBoxW` with modified text.
10+
11+
### How It Works [Step-By-Step]
12+
1. **Interceptor Structure (`ApiInterceptor`)**:
13+
- Stores the target function address (`MessageBoxA`), replacement function address, original code bytes, and original memory protection state.
14+
- Uses a fixed-size array (`INTERCEPTOR_SIZE`) for storing original bytes (14 bytes for 64-bit, 5 bytes for 32-bit).
15+
16+
2. **Setup (`setup_interceptor`)**:
17+
- Resolves `MessageBoxA` address using `GetModuleHandleA` and `GetProcAddress`.
18+
- Copies the first `INTERCEPTOR_SIZE` bytes of `MessageBoxA` to preserve the original code.
19+
- Changes memory protection to `PAGE_EXECUTE_READWRITE` using `VirtualProtect` to allow code modification.
20+
21+
3. **Activation (`activate_interceptor`)**:
22+
- Constructs a trampoline to redirect execution:
23+
- **64-bit**: Uses `jmp [rip+0]` (6 bytes) followed by an 8-byte absolute address of the custom handler.
24+
- **32-bit**: Uses `jmp <relative>` (5 bytes) with a relative offset to the custom handler.
25+
- Writes the trampoline to the `MessageBoxA` entry point, ensuring minimal instruction overwriting.
26+
27+
4. **Custom Handler (`custom_dialog`)**:
28+
- Logs input parameters (`lpText`, `lpCaption`) using `CStr::to_string_lossy`.
29+
- Converts new text to UTF-16 using `WideCString` for `MessageBoxW`.
30+
- Calls `MessageBoxW` with modified text ("Smukx Is Good") and caption ("System Dialog").
31+
32+
5. **Deactivation (`deactivate_interceptor`)**:
33+
- Restores the original `MessageBoxA` bytes from the stored copy.
34+
- Reverts memory protection to its original state using `VirtualProtect`.
35+
- Clears the interceptor structure to prevent reuse.
36+
37+
6. **Safety Considerations**:
38+
- Uses `unsafe` blocks for WinAPI calls and pointer operations, ensuring controlled access.
39+
- Validates pointers and handles errors from WinAPI functions (e.g., `GetLastError`).
40+
- Maintains thread safety by avoiding shared mutable state.
41+
42+
### Key Features
43+
- **Cross-Architecture**: Adapts trampoline construction for 32-bit and 64-bit systems.
44+
- **Non-Invasive**: Preserves original function behavior during deactivation.
45+
- **Error Handling**: Checks for null pointers and failed WinAPI calls.
46+
- **Logging**: Outputs parameter details for debugging and monitoring.
47+
48+
## How to Compile and Use It
49+
50+
1. **Compilation**:
51+
- Build: `cargo build --release`.
52+
- Output: `target/release/Api_Hooking.exe`.
53+
54+
2. **Execution**:
55+
- Run: `target/release/Api_Hooking.exe`.
56+
- Behavior:
57+
- Displays an initial `MessageBoxA` dialog.
58+
- Activates interceptor, showing a modified `MessageBoxW` dialog.
59+
- Deactivates interceptor and shows a final `MessageBoxA` dialog.
60+
- Exits on Enter key press.
61+
- Run as administrator if memory protection changes fail.
62+
63+
3. Download the Snippet: [Download](https://download.5mukx.site/#/home?url=https://github.com/Whitecat18/Rust-for-Malware-Development/tree/main/Api_Hooking)
64+
65+
## Credits
66+
67+
- https://github.com/ZeroMemoryEx/TrampHook
68+
- https://www.ired.team/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++
69+
- https://www.packtpub.com/en-us/product/mastering-malware-analysis-9781789610789/chapter/inspecting-process-injection-and-api-hooking-6/section/inline-api-hooking-with-trampoline-ch06lvl1sec86
70+
71+
## Author
72+
73+
[@5mukx](https://x.com/5mukx)

Api_Hooking/demp.gif

302 KB
Loading

Api_Hooking/src/main.rs

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
Windows API Hooking using Trampoline
3+
@5mukx
4+
*/
5+
6+
use std::{
7+
ffi::{CStr, CString},
8+
ptr::null_mut,
9+
};
10+
11+
use widestring::WideCString;
12+
use winapi::{
13+
shared::{
14+
minwindef::{DWORD, LPVOID, UINT},
15+
ntdef::{LPCSTR, LPWSTR},
16+
windef::HWND,
17+
},
18+
um::{
19+
errhandlingapi::GetLastError,
20+
libloaderapi::{GetModuleHandleA, GetProcAddress},
21+
memoryapi::VirtualProtect,
22+
winnt::PAGE_EXECUTE_READWRITE,
23+
winuser::{MB_ICONINFORMATION, MB_OK, MessageBoxA, MessageBoxW},
24+
},
25+
};
26+
27+
const INTERCEPTOR_SIZE: usize = 14;
28+
29+
#[repr(C)]
30+
struct ApiInterceptor {
31+
target_function: LPVOID,
32+
replacement_function: LPVOID,
33+
original_code: [u8; INTERCEPTOR_SIZE],
34+
original_protection: DWORD,
35+
}
36+
37+
impl ApiInterceptor {
38+
fn new() -> Self {
39+
ApiInterceptor {
40+
target_function: null_mut(),
41+
replacement_function: null_mut(),
42+
original_code: [0; INTERCEPTOR_SIZE],
43+
original_protection: 0,
44+
}
45+
}
46+
}
47+
48+
fn main() {
49+
unsafe {
50+
let user32 = GetModuleHandleA("user32.dll\0".as_ptr() as *const i8);
51+
let dialog_func = GetProcAddress(user32, "MessageBoxA\0".as_ptr() as *const i8);
52+
53+
let mut interceptor = ApiInterceptor::new();
54+
if !setup_interceptor(
55+
dialog_func as LPVOID,
56+
custom_dialog as LPVOID,
57+
&mut interceptor,
58+
) {
59+
println!("[ERROR] Interceptor setup failed");
60+
return;
61+
}
62+
63+
let text1 = CString::new("Testing Smukx System").unwrap();
64+
let caption1 = CString::new("System Info").unwrap();
65+
66+
MessageBoxA(
67+
null_mut(),
68+
text1.as_ptr(),
69+
caption1.as_ptr(),
70+
MB_OK | MB_ICONINFORMATION,
71+
);
72+
73+
println!("[INFO] Activating API interceptor...");
74+
75+
if !activate_interceptor(&mut interceptor) {
76+
println!("[ERROR] Interceptor activation failed");
77+
return;
78+
}
79+
println!("[INFO] Interceptor activated");
80+
81+
let text2 = CString::new("Smukx Is Great").unwrap();
82+
let caption2 = CString::new("System Info").unwrap();
83+
84+
MessageBoxA(
85+
null_mut(),
86+
text2.as_ptr(),
87+
caption2.as_ptr(),
88+
MB_OK | MB_ICONINFORMATION,
89+
);
90+
91+
println!("[INFO] Deactivating API interceptor...");
92+
if !deactivate_interceptor(&mut interceptor) {
93+
println!("[ERROR] Interceptor deactivation failed");
94+
return;
95+
}
96+
println!("[INFO] Interceptor deactivated");
97+
98+
let text3 = CString::new("Smukx System Restored").unwrap();
99+
let caption3 = CString::new("System Info").unwrap();
100+
MessageBoxA(
101+
null_mut(),
102+
text3.as_ptr(),
103+
caption3.as_ptr(),
104+
MB_OK | MB_ICONINFORMATION,
105+
);
106+
}
107+
108+
println!("[INFO] PoC Demonstrated Successfully");
109+
110+
}
111+
112+
fn setup_interceptor(
113+
target_function: LPVOID,
114+
replacement_function: LPVOID,
115+
interceptor: &mut ApiInterceptor,
116+
) -> bool {
117+
if target_function.is_null() || replacement_function.is_null() {
118+
return false;
119+
}
120+
121+
interceptor.target_function = target_function;
122+
interceptor.replacement_function = replacement_function;
123+
124+
unsafe {
125+
std::ptr::copy_nonoverlapping(
126+
target_function as *const u8,
127+
interceptor.original_code.as_mut_ptr(),
128+
INTERCEPTOR_SIZE,
129+
);
130+
131+
let mut old_protection: DWORD = 0;
132+
if VirtualProtect(
133+
target_function,
134+
INTERCEPTOR_SIZE,
135+
PAGE_EXECUTE_READWRITE,
136+
&mut old_protection,
137+
) == 0
138+
{
139+
println!("[!] Memory protection change failed: {}", GetLastError());
140+
return false;
141+
}
142+
interceptor.original_protection = old_protection;
143+
}
144+
true
145+
}
146+
147+
fn activate_interceptor(interceptor: &mut ApiInterceptor) -> bool {
148+
if interceptor.target_function.is_null() || interceptor.replacement_function.is_null() {
149+
return false;
150+
}
151+
152+
unsafe {
153+
{
154+
let interceptor_code: [u8; INTERCEPTOR_SIZE] = [
155+
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156+
];
157+
let patch = interceptor.replacement_function as u64;
158+
std::ptr::copy_nonoverlapping(
159+
&patch as *const _ as *const u8,
160+
(interceptor.target_function as *mut u8).offset(6),
161+
std::mem::size_of::<u64>(),
162+
);
163+
164+
std::ptr::copy_nonoverlapping(
165+
interceptor_code.as_ptr(),
166+
interceptor.target_function as *mut u8,
167+
6,
168+
);
169+
}
170+
}
171+
true
172+
}
173+
174+
fn deactivate_interceptor(interceptor: &mut ApiInterceptor) -> bool {
175+
if interceptor.target_function.is_null() {
176+
return false;
177+
}
178+
179+
unsafe {
180+
std::ptr::copy_nonoverlapping(
181+
interceptor.original_code.as_ptr(),
182+
interceptor.target_function as *mut u8,
183+
INTERCEPTOR_SIZE,
184+
);
185+
186+
std::ptr::write_bytes(interceptor.original_code.as_mut_ptr(), 0, INTERCEPTOR_SIZE);
187+
188+
let mut old_protection: DWORD = 0;
189+
if VirtualProtect(
190+
interceptor.target_function,
191+
INTERCEPTOR_SIZE,
192+
interceptor.original_protection,
193+
&mut old_protection,
194+
) == 0
195+
{
196+
println!(
197+
"[!] Memory protection restoration failed: {}",
198+
GetLastError()
199+
);
200+
return false;
201+
}
202+
203+
interceptor.target_function = null_mut();
204+
interceptor.replacement_function = null_mut();
205+
interceptor.original_protection = 0;
206+
}
207+
208+
true
209+
}
210+
211+
unsafe extern "system" fn custom_dialog(
212+
hwnd: HWND,
213+
lp_text: LPCSTR,
214+
lp_caption: LPCSTR,
215+
u_type: UINT,
216+
) -> i32 {
217+
let text = unsafe { CStr::from_ptr(lp_text) }.to_string_lossy();
218+
let caption = unsafe { CStr::from_ptr(lp_caption) }.to_string_lossy();
219+
220+
println!("[INFO] Dialog Parameters:");
221+
println!("\tText: {}", text);
222+
println!("\tCaption: {}", caption);
223+
224+
let new_text = WideCString::from_str("Smukx Is Good").unwrap();
225+
let new_caption = WideCString::from_str("System Dialog").unwrap();
226+
227+
unsafe {
228+
MessageBoxW(
229+
hwnd,
230+
new_text.as_ptr() as LPWSTR,
231+
new_caption.as_ptr() as LPWSTR,
232+
u_type,
233+
)
234+
}
235+
}

Custom_Shellcode/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Custom Shellcode Template Section
2+
3+
This series Work In Progress .....
4+
5+
![Work](https://havocframework.com/images/Spiderman_work.png)

0 commit comments

Comments
 (0)