-
Rust: 스타크래프트1 멀티 실행기 만들기 (windows api)컴퓨터/Rust 2024. 4. 22. 14:25728x90반응형
GitHub - somersby10ml/sc_multiloader
Contribute to somersby10ml/sc_multiloader development by creating an account on GitHub.
github.com
위 프로젝트를 보고, Rust로 windows-rs API는 개발이 잘되어가는지 궁금해서
위 앱을 Rust로 만들어보았다. (CLI + GUI)
windows-rs
API 문서 따위 아직 없다. 그냥 알아서 필요한거 찾아서 쓰고, 없는 건 만들어 써야 한다.
docs.rs의 검색 기능 때문에 원하는 구조체, 함수 등 찾기는 쉽다.
https://microsoft.github.io/windows-docs-rs/
microsoft.github.io
우선 "핸들" 이라는 것을 닫는 것이 목표이다.
핸들이란 파일, 레지스트리 키, 이벤트 또는 시스템 객체와 같은 시스템 리소스에 대한 추상적 참조이다.
ProcessHacker: flux.exe 핸들 프로세스 핸들을 작업하기 위해서는 관리자 권한이 필요하다.
Rust로 조금 digging 을 하다 보면 그렇게 어려운 작업은 아니었다.
use std::ptr; use windows::core::PWSTR; use windows::Win32::Foundation::{BOOL, HANDLE, HWND, PSID}; use windows::Win32::Security::{ AllocateAndInitializeSid, CheckTokenMembership, FreeSid, SID_IDENTIFIER_AUTHORITY, }; use windows::Win32::System::SystemServices::{ DOMAIN_ALIAS_RID_ADMINS, SECURITY_BUILTIN_DOMAIN_RID, }; use windows::Win32::UI::Shell::ShellExecuteW; pub fn is_admin() -> bool { unsafe { // pub struct PSID(pub *mut core::ffi::c_void); let mut sid: PSID = PSID(ptr::null_mut()); let nt_authority: SID_IDENTIFIER_AUTHORITY = SID_IDENTIFIER_AUTHORITY { Value: [0, 0, 0, 0, 0, 5], // SECURITY_NT_AUTHORITY }; if AllocateAndInitializeSid( &nt_authority, 2, SECURITY_BUILTIN_DOMAIN_RID as u32, DOMAIN_ALIAS_RID_ADMINS as u32, 0, 0, 0, 0, 0, 0, &mut sid, ) .is_ok() { let mut is_member = BOOL(0); let result = CheckTokenMembership(HANDLE(0), sid, &mut is_member); FreeSid(sid); return result.is_ok() && is_member.as_bool(); } } false } pub fn run_as_admin() -> bool { unsafe { let result = ShellExecuteW( HWND(0), PWSTR("runas".encode_utf16().collect::<Vec<u16>>().as_ptr() as _), PWSTR( std::env::current_exe() .unwrap() .to_str() .unwrap() .encode_utf16() .collect::<Vec<u16>>() .as_ptr() as _, ), PWSTR(ptr::null_mut()), PWSTR(ptr::null_mut()), windows::Win32::UI::WindowsAndMessaging::SW_SHOW, ); !result.is_invalid() } } #[tokio::main] async fn main() { if !is_admin() { println!("관리자 실행 안했네요..."); if run_as_admin() { // 관리자 권한 요청하기 println!("실패, 다시 관리자 권한으로 실행해주세요..."); return; } else { println!("실패, 종료."); return; } } ... }
그러나 버퍼들은 C++에서는 쉽지만, Rust에서는 unsafe 랑 포인터 섞어서 써야 해서 힘들었다.
C++ 코드 ZwQueryInformationProcess는 아직 windows-rs에 없어서 만들어야 했다.
검색해서 파라미터마다 그냥 windows-rs에서 타입 불러서 만들면 된다.
#[link(name = "ntdll.dll", kind = "raw-dylib", modifiers = "+verbatim")] extern "system" { pub fn ZwQueryInformationProcess( ProcessHandle: HANDLE, ProcessInformationClass: PROCESSINFOCLASS, ProcessInformation: *mut std::ffi::c_void, ProcessInformationLength: u32, ReturnLength: *mut u32, ) -> NTSTATUS; } // let mut buffer: Vec<u8> = Vec::new(); let mut dw_length: u32 = 0; let mut status: NTSTATUS = custom_windows::ZwQueryInformationProcess( process_handle, ProcessHandleInformation, std::ptr::null_mut(), // initially pass a null pointer 0, // and a length of 0 &mut dw_length, ); while status == STATUS_INFO_LENGTH_MISMATCH { buffer.resize(dw_length as usize, 0); status = custom_windows::ZwQueryInformationProcess( process_handle, ProcessHandleInformation, buffer.as_mut_ptr() as *mut c_void, buffer.len() as u32, &mut dw_length, ); }
PROCESSENTRY32W 을 쓰면 wide string이라 편하지만, PROCESSENTRY32를 쓴다면
ASCII 문자열이기 때문에 변환해서 프로세스 이름을 찾을 수 있다.
let starcraft_name = b"StarCraft.exe\0"; // ANSI string with null termination if Process32First(h_snapshot.get_handle(), &mut entry as *mut PROCESSENTRY32).is_ok() { ... if unsafe { // 이름 체크 std::ffi::CStr::from_ptr(entry.szExeFile.as_ptr()).to_bytes_with_nul() == starcraft_name } ... }
핸들을 찾고 닫을 때는
// 원하는 이름이 들어가 있는 핸들 닫기 if name .to_string_lossy() .contains("YOOOO") { let status = DuplicateHandle( process_handle, handle, GetCurrentProcess(), &mut copy_handle, MAXIMUM_ALLOWED, false, DUPLICATE_CLOSE_SOURCE, ); // 닫아버리기 if status.is_ok() { println!("Closed"); let _ = CloseHandle(copy_handle); } }
자세한 건 아래 Github에 올려놓은 코드를 확인하면 좋다.
https://github.com/Alfex4936/SC1-Multi-Launcher
GitHub - Alfex4936/SC1-Multi-Launcher: StarCraft I multi launcher in Rust. using windows-rs
StarCraft I multi launcher in Rust. using windows-rs - Alfex4936/SC1-Multi-Launcher
github.com
728x90'컴퓨터 > Rust' 카테고리의 다른 글
Meilisearch: Rust로 작성된 ElasticSearch (0) 2024.07.12 Rust: 비동기 리팩토링 tokio::task::JoinSet (0) 2024.04.06 Rust: OAuth2 구글, Github, 카카오, 네이버 로그인 (1) 2023.08.06