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]]
name = "saekawa"
version = "0.4.3"
version = "0.4.4"
dependencies = [
"aes",
"cbc",
"chrono",
"confy",
"crochet",
"dlopen2",
"env_logger",
"faster-hex",
"flate2",

View File

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

View File

@ -22,7 +22,7 @@ pub static mut REPLCE_FILE_W_PTR: PROC = ptr::null_mut();
#[link_section = ".rtext"]
#[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"]
#[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);
let GetProcessHeap = std::mem::transmute::<PROC, GetProcessHeapFn>(GET_PROCESS_HEAP_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 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(),
);
if result > 0 {
if result != 0 {
LoadLibraryW((*args).old.as_ptr());
} else {
LoadLibraryW((*args).new.as_ptr());

View File

@ -14,35 +14,26 @@ use snafu::{prelude::Snafu, ResultExt};
use widestring::U16CString;
use winapi::{
shared::{
minwindef::{BOOL, DWORD, HMODULE, LPVOID, PROC},
ntdef::{LPCWSTR, LPSTR},
minwindef::PROC,
winerror::{
CERT_E_CHAINING, CERT_E_EXPIRED, CERT_E_UNTRUSTEDROOT, CRYPT_E_SECURITY_SETTINGS,
TRUST_E_BAD_DIGEST, TRUST_E_EXPLICIT_DISTRUST, TRUST_E_NOSIGNATURE,
},
},
um::{
heapapi::HeapAlloc,
memoryapi::{VirtualAlloc, VirtualProtect},
minwinbase::LMEM_ZEROINIT,
processthreadsapi::CreateThread,
softpub::WINTRUST_ACTION_GENERIC_VERIFY_V2,
winbase::LocalAlloc,
wincrypt::{
errhandlingapi::GetLastError, heapapi::{GetProcessHeap, HeapAlloc}, memoryapi::{VirtualAlloc, VirtualProtect}, minwinbase::LMEM_ZEROINIT, processthreadsapi::CreateThread, softpub::WINTRUST_ACTION_GENERIC_VERIFY_V2, winbase::LocalAlloc, wincrypt::{
CertCloseStore, CertFindCertificateInStore, CryptMsgClose, CryptMsgGetParam,
CryptQueryObject, CERT_FIND_SUBJECT_CERT, CERT_INFO,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY,
CERT_QUERY_OBJECT_FILE, CMSG_SIGNER_INFO_PARAM, HCERTSTORE, HCRYPTMSG,
PCMSG_SIGNER_INFO, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING,
},
winnt::{
HANDLE, HEAP_ZERO_MEMORY, IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32, IMAGE_SECTION_HEADER,
}, winnt::{
HEAP_ZERO_MEMORY, IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32, IMAGE_SECTION_HEADER,
MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE,
},
wintrust::{
}, wintrust::{
WinVerifyTrust, WINTRUST_DATA, WINTRUST_FILE_INFO, WTD_CHOICE_FILE, WTD_REVOKE_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},
};
// 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)]
#[allow(clippy::large_enum_variant)]
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.
unsafe {
external::GET_LAST_ERROR_PTR = GetLastError as PROC;
external::GET_MODULE_FILE_NAME_A_PTR = GetModuleFileNameA as PROC;
external::GET_PROCESS_HEAP_PTR = GetProcessHeap as PROC;
external::HEAP_FREE_PTR = HeapFree as PROC;
external::LOAD_LIBRARY_W_POINTER = LoadLibraryW as PROC;
external::REPLCE_FILE_W_PTR = ReplaceFileW as PROC;
external::SLEEP_PTR = Sleep as PROC;
let kernel32 = dlopen2::raw::Library::open("kernel32.dll")
.expect("kernel32 missing on windows?");
external::GET_LAST_ERROR_PTR = kernel32.symbol("GetLastError").unwrap();
external::GET_MODULE_FILE_NAME_A_PTR = kernel32.symbol("GetModuleFileNameA").unwrap();
external::GET_PROCESS_HEAP_PTR = kernel32.symbol("GetProcessHeap").unwrap();
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...");
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,
);
// 0x00007FFB13A63A14
if result == 0 {
return Err(SelfUpdateError::FailedVirtualProtect {
errno: GetLastError(),