fix(updater): just get the address by loading the library instead of relying on the linker to do what we want

This commit is contained in:
beerpiss 2024-07-04 23:08:35 +07:00
parent 7145efc237
commit 4fee755ab4
4 changed files with 24 additions and 48 deletions

3
Cargo.lock generated
View File

@ -952,13 +952,14 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "saekawa" name = "saekawa"
version = "0.4.3" version = "0.4.4"
dependencies = [ dependencies = [
"aes", "aes",
"cbc", "cbc",
"chrono", "chrono",
"confy", "confy",
"crochet", "crochet",
"dlopen2",
"env_logger", "env_logger",
"faster-hex", "faster-hex",
"flate2", "flate2",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "saekawa" name = "saekawa"
version = "0.4.3" version = "0.4.4"
edition = "2021" edition = "2021"
license = "0BSD" license = "0BSD"
@ -20,6 +20,7 @@ cbc = "0.1.2"
chrono = "0.4.38" chrono = "0.4.38"
confy = "0.6.1" confy = "0.6.1"
crochet = "0.2.3" crochet = "0.2.3"
dlopen2 = "0.6.0"
env_logger = { version = "0.11.3", default-features = false } env_logger = { version = "0.11.3", default-features = false }
faster-hex = "0.9.0" faster-hex = "0.9.0"
flate2 = "1.0.30" flate2 = "1.0.30"

View File

@ -22,7 +22,7 @@ pub static mut REPLCE_FILE_W_PTR: PROC = ptr::null_mut();
#[link_section = ".rtext"] #[link_section = ".rtext"]
#[used] #[used]
pub static mut LOAD_LIBRARY_W_POINTER: PROC = ptr::null_mut(); pub static mut LOAD_LIBRARY_W_PTR: PROC = ptr::null_mut();
#[link_section = ".rtext"] #[link_section = ".rtext"]
#[used] #[used]
@ -60,7 +60,7 @@ pub unsafe extern "system" fn replace_with_new_library(parameter: *const c_void)
std::mem::transmute::<PROC, GetModuleFileNameAFn>(GET_MODULE_FILE_NAME_A_PTR); std::mem::transmute::<PROC, GetModuleFileNameAFn>(GET_MODULE_FILE_NAME_A_PTR);
let GetProcessHeap = std::mem::transmute::<PROC, GetProcessHeapFn>(GET_PROCESS_HEAP_PTR); let GetProcessHeap = std::mem::transmute::<PROC, GetProcessHeapFn>(GET_PROCESS_HEAP_PTR);
let ReplaceFileW = std::mem::transmute::<PROC, ReplaceFileWFn>(REPLCE_FILE_W_PTR); let ReplaceFileW = std::mem::transmute::<PROC, ReplaceFileWFn>(REPLCE_FILE_W_PTR);
let LoadLibraryW = std::mem::transmute::<PROC, LoadLibraryWFn>(LOAD_LIBRARY_W_POINTER); let LoadLibraryW = std::mem::transmute::<PROC, LoadLibraryWFn>(LOAD_LIBRARY_W_PTR);
let HeapFree = std::mem::transmute::<PROC, HeapFreeFn>(HEAP_FREE_PTR); let HeapFree = std::mem::transmute::<PROC, HeapFreeFn>(HEAP_FREE_PTR);
let Sleep = std::mem::transmute::<PROC, SleepFn>(SLEEP_PTR); let Sleep = std::mem::transmute::<PROC, SleepFn>(SLEEP_PTR);
@ -86,7 +86,7 @@ pub unsafe extern "system" fn replace_with_new_library(parameter: *const c_void)
ptr::null_mut(), ptr::null_mut(),
); );
if result > 0 { if result != 0 {
LoadLibraryW((*args).old.as_ptr()); LoadLibraryW((*args).old.as_ptr());
} else { } else {
LoadLibraryW((*args).new.as_ptr()); LoadLibraryW((*args).new.as_ptr());

View File

@ -14,35 +14,26 @@ use snafu::{prelude::Snafu, ResultExt};
use widestring::U16CString; use widestring::U16CString;
use winapi::{ use winapi::{
shared::{ shared::{
minwindef::{BOOL, DWORD, HMODULE, LPVOID, PROC}, minwindef::PROC,
ntdef::{LPCWSTR, LPSTR},
winerror::{ winerror::{
CERT_E_CHAINING, CERT_E_EXPIRED, CERT_E_UNTRUSTEDROOT, CRYPT_E_SECURITY_SETTINGS, CERT_E_CHAINING, CERT_E_EXPIRED, CERT_E_UNTRUSTEDROOT, CRYPT_E_SECURITY_SETTINGS,
TRUST_E_BAD_DIGEST, TRUST_E_EXPLICIT_DISTRUST, TRUST_E_NOSIGNATURE, TRUST_E_BAD_DIGEST, TRUST_E_EXPLICIT_DISTRUST, TRUST_E_NOSIGNATURE,
}, },
}, },
um::{ um::{
heapapi::HeapAlloc, errhandlingapi::GetLastError, heapapi::{GetProcessHeap, HeapAlloc}, memoryapi::{VirtualAlloc, VirtualProtect}, minwinbase::LMEM_ZEROINIT, processthreadsapi::CreateThread, softpub::WINTRUST_ACTION_GENERIC_VERIFY_V2, winbase::LocalAlloc, wincrypt::{
memoryapi::{VirtualAlloc, VirtualProtect},
minwinbase::LMEM_ZEROINIT,
processthreadsapi::CreateThread,
softpub::WINTRUST_ACTION_GENERIC_VERIFY_V2,
winbase::LocalAlloc,
wincrypt::{
CertCloseStore, CertFindCertificateInStore, CryptMsgClose, CryptMsgGetParam, CertCloseStore, CertFindCertificateInStore, CryptMsgClose, CryptMsgGetParam,
CryptQueryObject, CERT_FIND_SUBJECT_CERT, CERT_INFO, CryptQueryObject, CERT_FIND_SUBJECT_CERT, CERT_INFO,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY,
CERT_QUERY_OBJECT_FILE, CMSG_SIGNER_INFO_PARAM, HCERTSTORE, HCRYPTMSG, CERT_QUERY_OBJECT_FILE, CMSG_SIGNER_INFO_PARAM, HCERTSTORE, HCRYPTMSG,
PCMSG_SIGNER_INFO, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING, PCMSG_SIGNER_INFO, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING,
}, }, winnt::{
winnt::{ HEAP_ZERO_MEMORY, IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32, IMAGE_SECTION_HEADER,
HANDLE, HEAP_ZERO_MEMORY, IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32, IMAGE_SECTION_HEADER,
MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE,
}, }, wintrust::{
wintrust::{
WinVerifyTrust, WINTRUST_DATA, WINTRUST_FILE_INFO, WTD_CHOICE_FILE, WTD_REVOKE_NONE, WinVerifyTrust, WINTRUST_DATA, WINTRUST_FILE_INFO, WTD_CHOICE_FILE, WTD_REVOKE_NONE,
WTD_STATEACTION_CLOSE, WTD_STATEACTION_VERIFY, WTD_UI_NONE, WTD_STATEACTION_CLOSE, WTD_STATEACTION_VERIFY, WTD_UI_NONE,
}, }
}, },
}; };
@ -52,27 +43,6 @@ use crate::{
helpers::winapi_ext::{get_module_file_name, LibraryHandle, ReadStringFnError}, helpers::winapi_ext::{get_module_file_name, LibraryHandle, ReadStringFnError},
}; };
// I don't know what the hell is going on with linking, but you have to link these manually,
// otherwise you end up with the addresses to the intermediary functions, which obviously
// doesn't exist once you unloads the original library.
#[link(name = "kernel32")]
extern "system" {
pub fn GetLastError() -> u32;
pub fn GetModuleFileNameA(hModule: HMODULE, lpFilename: LPSTR, nsize: DWORD) -> u32;
pub fn GetProcessHeap() -> HANDLE;
pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
pub fn LoadLibraryW(lpFileName: LPCWSTR) -> HMODULE;
pub fn ReplaceFileW(
lpReplacedFileName: LPCWSTR,
lpReplacementFileName: LPCWSTR,
lpBackupFileName: LPCWSTR,
dwReplaceFlags: DWORD,
lpExclude: LPVOID,
lpReserved: LPVOID,
) -> BOOL;
pub fn Sleep(dwMilliseconds: DWORD);
}
#[derive(Debug, Snafu)] #[derive(Debug, Snafu)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum SelfUpdateError { pub enum SelfUpdateError {
@ -257,13 +227,16 @@ pub fn self_update(module: &LibraryHandle) -> Result<bool, SelfUpdateError> {
// //
// Thanks to DJTRACKERS and their fervidex hook for the approach. // Thanks to DJTRACKERS and their fervidex hook for the approach.
unsafe { unsafe {
external::GET_LAST_ERROR_PTR = GetLastError as PROC; let kernel32 = dlopen2::raw::Library::open("kernel32.dll")
external::GET_MODULE_FILE_NAME_A_PTR = GetModuleFileNameA as PROC; .expect("kernel32 missing on windows?");
external::GET_PROCESS_HEAP_PTR = GetProcessHeap as PROC;
external::HEAP_FREE_PTR = HeapFree as PROC; external::GET_LAST_ERROR_PTR = kernel32.symbol("GetLastError").unwrap();
external::LOAD_LIBRARY_W_POINTER = LoadLibraryW as PROC; external::GET_MODULE_FILE_NAME_A_PTR = kernel32.symbol("GetModuleFileNameA").unwrap();
external::REPLCE_FILE_W_PTR = ReplaceFileW as PROC; external::GET_PROCESS_HEAP_PTR = kernel32.symbol("GetProcessHeap").unwrap();
external::SLEEP_PTR = Sleep as PROC; external::HEAP_FREE_PTR = kernel32.symbol("HeapFree").unwrap();
external::LOAD_LIBRARY_W_PTR = kernel32.symbol("LoadLibraryW").unwrap();
external::REPLCE_FILE_W_PTR = kernel32.symbol("ReplaceFileW").unwrap();
external::SLEEP_PTR = kernel32.symbol("Sleep").unwrap();
debug!("Locating updater code..."); debug!("Locating updater code...");
let dos_header = module.handle() as *const IMAGE_DOS_HEADER; let dos_header = module.handle() as *const IMAGE_DOS_HEADER;
@ -330,6 +303,7 @@ pub fn self_update(module: &LibraryHandle) -> Result<bool, SelfUpdateError> {
&mut old_protect, &mut old_protect,
); );
// 0x00007FFB13A63A14
if result == 0 { if result == 0 {
return Err(SelfUpdateError::FailedVirtualProtect { return Err(SelfUpdateError::FailedVirtualProtect {
errno: GetLastError(), errno: GetLastError(),