Skip to content

acard0/il2cppinterop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

il2cpp resolver but written in rust

setup

#[no_mangle]
pub unsafe extern "system" fn DllMain(h_module: HMODULE, fdw_reason: u32, lp_reserved: *mut c_void) -> i32 {
    match fdw_reason {
        1 => { // DLL_PROCESS_ATTACH
            let params = Box::into_raw(Box::new(MainParams { base: h_module.clone(), reserved: lp_reserved })) as usize;
            _= CloseHandle(sys::thread::spawn(move || {            
                let params = Box::from_raw(params as *mut MainParams);

                // resolves il2cpp exports and rest of the common used mono methods using exported reflection call
                il2cppinterop_core::initialize(params.base, Some(Duration::MAX));

                app::main(*params)
            }));
        },
        0 => { // DLL_PROCESS_DEATTACH
           
        }
        _ => {}
    };

    1
}

finding class definition

    let cz_session = class::find("Game.Session")
        .expect("failed to find Session class");

getting object instances inherited from UnityObject

// UnityEngine.GameObject::FindObjectsOfType(System.Type,System.Boolean)
    let objects = il2cppinterop_core::unity::object::find_objects_of_type_by_name::<&UnityGameObject>(&UNITY_GAMEOBJECT_CLASS, false)
        .expect("Failed to get UNITY_GAMEOBJECT_CLASS instances");

getting object instances via pattern matching

  // il2cpp dump
  struct Il2CppObject // low-level object repr, any System.Object starts from here
  {
      Il2CppClass *klass; // first offset is ptr to class meta
      void *monitor;
  };

    let session: Option<*mut Session> = mono::definitions::object::find(cz_session, |address| { unsafe {
        *(address.add(0x8) as *const isize) == 0x0 
        && *(address.add(0xC) as *const isize) == 0x0
        && *(address.add(0x10) as *const isize) == 0x1a
    }}).expect("Encountered error while searching for Game.Session instance");

setting up a hook to intercept calls

/// Hooks into Game.SessionSystem::Send
unsafe fn hook_setup_SessionSystemSend() {
    // see https://github.com/darfink/detour-rs/forks
    static_detour! { static Hook_SessionSystem_Send: unsafe extern "C" fn(*mut Session, *mut SystemObject); }

    // intercepter
    fn mHook_SessionSystem_Send(_session: *mut Session, _module: *mut SystemObject) { unsafe {
        let module = &*_module;
        debug::intermediate_serialize(module);
       
        Hook_SessionSystem_Send.call(_session, _module);
    }}

    let mp_sessionSystem_Send = class::get_method_pointer_by_name("Game.SessionSystem", "Send", 2)
        .expect("failed to find DarkOrbit.SessionSystem::Send");

    match Hook_SessionSystem_Send
        .initialize(std::mem::transmute(mp_sessionSystem_Send), mHook_SessionSystem_Send)
        .and_then(|_| {
            Hook_SessionSystem_Send.enable()
        }) {
            Ok(_) => log::info!("Game.SessionSystem::Send detour set. Instruction adr: {mp_sessionSystem_Send:p}"),
            Err(err) => log::error!("Failed to set Game.SessionSystem::Send detour. Instruction adr: {mp_sessionSystem_Send:p}. {:?}", err),
        }
}

creating an object reprenstation with 'monomorphism'

// Mono macro
// polymorphism in rust is not built in. to avoid boilerplate code as much as possible
// marking field with #[base] simply sets target for Deref trait. dereferencing all fields and methods from 'parent'.

// still, trait boundaries will require manual implementation.
// currently only PartialEq trait is being chained in favour of Il2cppDictionary<T: PartialEq + ..., V ...>
#[derive(Debug, Mono, Getters, Setters)]
#[getset(set = "pub", get = "pub with_prefix")]
pub struct MoveRequest {
    #[base]
    #[getset(skip)]
    object: SystemObject,
    position_x: i32,
    target_y: i32,
    target_x: i32,
    position_y: i32,
}

creating an object instance

impl MoveRequest {
    pub fn new() -> &'static mut Self {
        object::new_from_namespace("Game.MoveRequest")
            .expect("Failed to create Game.MoveRequest")
    }
}

finding and calling a method

// il2cpp_farproc! is helper macro for reinterpreting c call on 32bit and fastcall on 64bit
fn send_to_session(session: &mut Session, module: &Il2cppObject) -> bool { unsafe {
    class::get_method_pointer_by_name(&GAME_SESSION_SYSTEM, "Send", 2) // +1 if calling non-static method (this, args...)
        .inspect(|mptr| il2cpp_farproc!(fn(&Session, &Il2cppObject), *mptr) (session, module))
        .is_some()
}}

About

A run-time API resolver for IL2CPP Unity.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy