Skip to content

Commit cf9663b

Browse files
authored
Api-Hooking with windows-rs crate for stability.
Made some Fixes + Changing winapi to official windows-rs api for stability.
2 parents 9e64a02 + af25c15 commit cf9663b

File tree

3 files changed

+110
-111
lines changed

3 files changed

+110
-111
lines changed

Api_Hooking/Cargo.toml

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ edition = "2024"
55

66
[dependencies]
77
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-
] }
8+
windows = { version = "0.61.1", features = [
9+
"Win32_Foundation",
10+
"Win32_System_LibraryLoader",
11+
"Win32_System_Memory",
12+
"Win32_UI_WindowsAndMessaging",
13+
] }

Api_Hooking/README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
2-
# System API Interceptor
3-
4-
## Name of the Code
5-
System API Interceptor (`api_interceptor.rs`)
1+
# API Hooking using Trampoline
62

73
![Demo](./demp.gif)
4+
85
## Explanation
96
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-
7+
d
118
### How It Works [Step-By-Step]
129
1. **Interceptor Structure (`ApiInterceptor`)**:
1310
- Stores the target function address (`MessageBoxA`), replacement function address, original code bytes, and original memory protection state.

Api_Hooking/src/main.rs

Lines changed: 101 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
/*
2-
Windows API Hooking using Trampoline
2+
API Hooking Via Trampoline
33
@5mukx
44
*/
55

6-
use std::{
7-
ffi::{CStr, CString},
8-
ptr::null_mut,
6+
use std::ptr::{null_mut, copy_nonoverlapping};
7+
use windows::{
8+
core::{s, PCSTR, PCWSTR},
9+
Win32::{
10+
Foundation::HWND,
11+
System::{
12+
LibraryLoader::{GetModuleHandleA, GetProcAddress},
13+
Memory::{VirtualProtect, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS},
14+
}, UI::WindowsAndMessaging::{MessageBoxA, MessageBoxW, MB_ICONINFORMATION, MB_OK},
15+
}
916
};
1017

1118
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-
};
2619

2720
const INTERCEPTOR_SIZE: usize = 14;
2821

2922
#[repr(C)]
3023
struct ApiInterceptor {
31-
target_function: LPVOID,
32-
replacement_function: LPVOID,
24+
target_function: *mut std::ffi::c_void,
25+
replacement_function: *mut std::ffi::c_void,
3326
original_code: [u8; INTERCEPTOR_SIZE],
34-
original_protection: DWORD,
27+
original_protection: PAGE_PROTECTION_FLAGS,
3528
}
3629

3730
impl ApiInterceptor {
@@ -40,51 +33,60 @@ impl ApiInterceptor {
4033
target_function: null_mut(),
4134
replacement_function: null_mut(),
4235
original_code: [0; INTERCEPTOR_SIZE],
43-
original_protection: 0,
36+
original_protection: PAGE_PROTECTION_FLAGS(0),
4437
}
4538
}
4639
}
4740

48-
fn main() {
41+
fn main(){
42+
4943
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);
44+
let user32 = GetModuleHandleA(s!("user32.dll")).expect("Failed to get user32.dll handle");
45+
46+
let dialog_func = GetProcAddress(user32, s!("MessageBoxA")).expect("Failed to get MessageBox Address");
5247

5348
let mut interceptor = ApiInterceptor::new();
49+
5450
if !setup_interceptor(
55-
dialog_func as LPVOID,
56-
custom_dialog as LPVOID,
51+
dialog_func as *mut std::ffi::c_void,
52+
custom_dialog as *mut std::ffi::c_void,
5753
&mut interceptor,
5854
) {
5955
println!("[ERROR] Interceptor setup failed");
6056
return;
6157
}
6258

63-
let text1 = CString::new("Testing Smukx System").unwrap();
64-
let caption1 = CString::new("System Info").unwrap();
59+
let text1 = s!("Testing 5mukx System");
60+
let caption1 = s!("System Info");
6561

6662
MessageBoxA(
67-
null_mut(),
68-
text1.as_ptr(),
69-
caption1.as_ptr(),
63+
None,
64+
text1,
65+
caption1,
7066
MB_OK | MB_ICONINFORMATION,
7167
);
7268

73-
println!("[INFO] Activating API interceptor...");
69+
println!("[INFO] Activating API Interceptor...");
7470

7571
if !activate_interceptor(&mut interceptor) {
7672
println!("[ERROR] Interceptor activation failed");
7773
return;
7874
}
7975
println!("[INFO] Interceptor activated");
8076

81-
let text2 = CString::new("Smukx Is Great").unwrap();
82-
let caption2 = CString::new("System Info").unwrap();
77+
if !activate_interceptor(&mut interceptor) {
78+
println!("[ERROR] Interceptor activation failed");
79+
return;
80+
}
81+
println!("[INFO] Interceptor activated");
82+
83+
let text2 = s!("Smukx Is Bad Guy...");
84+
let caption2 = s!("System Info");
8385

8486
MessageBoxA(
85-
null_mut(),
86-
text2.as_ptr(),
87-
caption2.as_ptr(),
87+
None,
88+
text2,
89+
caption2,
8890
MB_OK | MB_ICONINFORMATION,
8991
);
9092

@@ -95,50 +97,52 @@ fn main() {
9597
}
9698
println!("[INFO] Interceptor deactivated");
9799

98-
let text3 = CString::new("Smukx System Restored").unwrap();
99-
let caption3 = CString::new("System Info").unwrap();
100+
let text3 = s!("Smukx System Restored");
101+
let caption3 = s!("System Info");
102+
100103
MessageBoxA(
101-
null_mut(),
102-
text3.as_ptr(),
103-
caption3.as_ptr(),
104+
None,
105+
text3,
106+
caption3,
104107
MB_OK | MB_ICONINFORMATION,
105108
);
106-
}
107-
108-
println!("[INFO] PoC Demonstrated Successfully");
109+
110+
println!("[INFO] PoC Demonstrated Successfully");
111+
}
109112

110113
}
111114

112115
fn setup_interceptor(
113-
target_function: LPVOID,
114-
replacement_function: LPVOID,
116+
target_function: *mut std::ffi::c_void,
117+
replacement_function: *mut std::ffi::c_void,
115118
interceptor: &mut ApiInterceptor,
116-
) -> bool {
117-
if target_function.is_null() || replacement_function.is_null() {
119+
) -> bool{
120+
if target_function.is_null() || replacement_function.is_null(){
118121
return false;
119122
}
120123

121124
interceptor.target_function = target_function;
122125
interceptor.replacement_function = replacement_function;
123126

124127
unsafe {
125-
std::ptr::copy_nonoverlapping(
128+
copy_nonoverlapping(
126129
target_function as *const u8,
127130
interceptor.original_code.as_mut_ptr(),
128131
INTERCEPTOR_SIZE,
129132
);
130133

131-
let mut old_protection: DWORD = 0;
132-
if VirtualProtect(
134+
let mut old_protection = PAGE_PROTECTION_FLAGS(0);
135+
if let Err(e) = VirtualProtect(
133136
target_function,
134137
INTERCEPTOR_SIZE,
135138
PAGE_EXECUTE_READWRITE,
136139
&mut old_protection,
137-
) == 0
138-
{
139-
println!("[!] Memory protection change failed: {}", GetLastError());
140+
141+
) {
142+
println!("[!] Memory Protection change failed: {:?}", e);
140143
return false;
141144
}
145+
142146
interceptor.original_protection = old_protection;
143147
}
144148
true
@@ -150,24 +154,30 @@ fn activate_interceptor(interceptor: &mut ApiInterceptor) -> bool {
150154
}
151155

152156
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-
}
157+
// far jump instruction (JMP)
158+
// 6 bytes for the JMP instruction (0xFF 0x25 0x00 0x00 0x00 0x00).
159+
// 8 bytes for the 64-bit address of the target function.
160+
161+
let interceptor_code: [u8; INTERCEPTOR_SIZE] = [
162+
// JMP [RIP + 0]
163+
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164+
];
165+
166+
let patch = interceptor.replacement_function as u64;
167+
168+
copy_nonoverlapping(
169+
&patch as *const _ as *const u8,
170+
(interceptor.target_function as *mut u8).offset(6),
171+
std::mem::size_of::<u64>(),
172+
);
173+
174+
copy_nonoverlapping(
175+
interceptor_code.as_ptr(),
176+
interceptor.target_function as *mut u8,
177+
6,
178+
);
170179
}
180+
171181
true
172182
}
173183

@@ -177,59 +187,55 @@ fn deactivate_interceptor(interceptor: &mut ApiInterceptor) -> bool {
177187
}
178188

179189
unsafe {
180-
std::ptr::copy_nonoverlapping(
190+
copy_nonoverlapping(
181191
interceptor.original_code.as_ptr(),
182192
interceptor.target_function as *mut u8,
183193
INTERCEPTOR_SIZE,
184194
);
185195

186196
std::ptr::write_bytes(interceptor.original_code.as_mut_ptr(), 0, INTERCEPTOR_SIZE);
187197

188-
let mut old_protection: DWORD = 0;
189-
if VirtualProtect(
198+
let mut old_protection = PAGE_PROTECTION_FLAGS(0);
199+
if let Err(e) = VirtualProtect(
190200
interceptor.target_function,
191201
INTERCEPTOR_SIZE,
192202
interceptor.original_protection,
193203
&mut old_protection,
194-
) == 0
195-
{
196-
println!(
197-
"[!] Memory protection restoration failed: {}",
198-
GetLastError()
199-
);
204+
) {
205+
println!("[!] Memory protection restoration failed: {:?}", e);
200206
return false;
201207
}
202208

203209
interceptor.target_function = null_mut();
204210
interceptor.replacement_function = null_mut();
205-
interceptor.original_protection = 0;
211+
interceptor.original_protection = PAGE_PROTECTION_FLAGS(0);
206212
}
207213

208214
true
209215
}
210216

211217
unsafe extern "system" fn custom_dialog(
212218
hwnd: HWND,
213-
lp_text: LPCSTR,
214-
lp_caption: LPCSTR,
215-
u_type: UINT,
219+
lp_text: PCSTR,
220+
lp_caption: PCSTR,
221+
u_type: u32,
216222
) -> 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();
223+
let text = unsafe { lp_text.to_string().unwrap_or_default() };
224+
let caption = unsafe { lp_caption.to_string().unwrap_or_default() } ;
219225

220226
println!("[INFO] Dialog Parameters:");
221227
println!("\tText: {}", text);
222228
println!("\tCaption: {}", caption);
223229

224-
let new_text = WideCString::from_str("Smukx Is Good").unwrap();
230+
let new_text = WideCString::from_str("5mukx Is a Good Guy").unwrap();
225231
let new_caption = WideCString::from_str("System Dialog").unwrap();
226232

227233
unsafe {
228234
MessageBoxW(
229-
hwnd,
230-
new_text.as_ptr() as LPWSTR,
231-
new_caption.as_ptr() as LPWSTR,
232-
u_type,
233-
)
235+
Some(hwnd),
236+
PCWSTR::from_raw(new_text.as_ptr()),
237+
PCWSTR::from_raw(new_caption.as_ptr()),
238+
windows::Win32::UI::WindowsAndMessaging::MESSAGEBOX_STYLE(u_type),
239+
).0
234240
}
235-
}
241+
}

0 commit comments

Comments
 (0)