代码:请问Unity 项目,怎么实现C++ 方法的手动调用,并得到调用值?

一个Unity项目,没有办法得到一个C++类方法的调用时机,怎么可以手动的调用这个方法

public class A {
   public byte[] afunc() { }. // 需要调用的方法
}

byte[] B(A tex)  /// 可以hook 的方法

现在的情况是,可以hook到一个B 方法,B 方法参数是一个A对象,能否在这个方法里面调用A的 afunc, 并拿到返回的 byte[] 结果。

B 方法的A,暂时只能是一个void* 指针,

假如用 汇编代码直接跳转到需要调用的方法,寄存器和 栈应该怎么构造?

给你举个例子:

Unity 里的一个 cs 类

public class Profile
{
	public void set_Coins(int value) { }
}

通过il2cpp 编译后的cpp方法签名。第一个参数和最后一个是隐藏参数,中间的才是你的参数。(就像Objective-C 方法第一个和第二个参数隐藏了)

void Profile__set_Coins (void* __this, int32_t value, const void* method);

你想调用这个方法,先要找到这个方法的地址,然后构建对应的方法签名(这就是在构造寄存器和栈)。第一个参数是对象的 this 指针,最后一个参数可以给 0 就行。

麻烦问一下:

public sealed class  AClas : AClassSuper {
  public byte[] AFunc() { } /// 需要调用的方法,dump.cs 里面的定义
}

1、我在ida 里面查看AFunc ,没有跟着this 和 MethodInfo,有些方法是有的, 这是为什么?

il2cpp:00000000022D4784
il2cpp:00000000022D4784 UnityEngine.Class$$AFunc      ; CODE XREF: Facebook.Unity.CodelessCrawler$$
il2cpp:00000000022D4784                                         ; DATA XREF: __data:0000000003A014C0↓o
il2cpp:00000000022D4784
il2cpp:00000000022D4784 var_10          = -0x10
il2cpp:00000000022D4784 var_s0          =  0
il2cpp:00000000022D4784
il2cpp:00000000022D4784                 STP             X20, X19, [SP,#-0x10+var_10]!
il2cpp:00000000022D4788                 STP             X29, X30, [SP,#0x10+var_s0]
il2cpp:00000000022D478C                 ADD             X29, SP, #0x10
il2cpp:00000000022D4790                 ADRP            X19, #byte_3A7F900@PAGE
il2cpp:00000000022D4794                 LDRB            W8, [X19,#byte_3A7F900@PAGEOFF]
il2cpp:00000000022D4798                 TBNZ            W8, #0, loc_22D47B4

2、这是我直接调用的AFunc代码, 通过打断点,我确定是已经走到AFunc 的里面去了,但是程序到这里就死了,不会走后面的代码,这个地方应该怎么设置lr、pc,可以让程序继续走下去

   static uint8_t* (*my_Afunc)(); /// 这是函数定义,因为我看ida 里面没有this 和 method Info
   
   /// 这是绑定
   unsigned long my_Afunc_addr  = _dyld_get_image_vmaddr_slide(i) + 0x22ab784;
   my_Afunc = (uint8_t*(*)())my_Afunc_addr;
     
    // 这是调用
    uint8_t* data = my_Afunc();
    if (data2) {/// 没有执行
        printf("success");
    } else {
        printf("fail");
    }

3、因为AFunc 没有this 指针,我手动将对象的地址弄到X0 里面去,我猜测this 指针就是在X0里面,是否可行?

    __asm__ volatile ("stp x8, x9, [sp, #-16]!\n");
    __asm__ volatile ("mov X0, %0 \n"
                :
                : "r" (objc)
                );
    __asm__ volatile ("ldp x8, x9, [sp], #16\n");

谢谢你!

就拿你这个 public byte[] AFunc() { } 方法来说
你至少这这样声明啊 static uint8_t* (*my_Afunc)(void* __this, const void* method);
你用 Perfare/Il2CppDumper: Unity il2cpp reverse engineer (github.com) 导出的文件有对应的 cpp 头文件声明,你看一下就知道了。

我就是用 Il2CppDumper 导出的dump.cs 文件看的代码,ida 也用 导出的script 文件跑过,确实没有后面的那个。

我对比了一下同一个类的其他方法,有些方法是会加上void *this 和 const MethodInfo *method,但这个确实没有

我也试过这样声明,也还是不行。

对汇编代码一步步debug下去,发现是Unity 内抛出异常了,所以没有正确的返回,谢谢你。

方便说一下是什么应用吗

这个不好意思,不太方便说出来

在这个文件找方法签名。这是我随便翻的一个unity游戏的dump出的数据,所有的方法都有这两个隐藏参数,这是调用约定。你想调用成功this是关键,否则肯定奔溃

给你参考一下

/*
// Namespace:
public class Profile // TypeDefIndex: 2129
{
	// Fields
	private int m_coins; // 0x18
	// Methods
	// RVA: 0xFD7A4 Offset: 0xFD7A4 VA: 0x1000FD7A4
	public void .ctor(string udid) { }
	// RVA: 0xFE860 Offset: 0xFE860 VA: 0x1000FE860
	public int get_Coins() { }
	// RVA: 0xFE868 Offset: 0xFE868 VA: 0x1000FE868
	public void set_Coins(int value) { }
}
// Namespace:
public class GUIShopCoinButton : GUIButton // TypeDefIndex: 2052
{
	// Fields
	public GUIShopTabButton productTabButton; // 0x60
	public int productItemIndex; // 0x68
	public GameObject clickEffectPrefab; // 0x70
	public GameObject coinCountText; // 0x78
	private GameObject m_clickEffect; // 0x80
	// Methods
	// RVA: 0xBC0D0 Offset: 0xBC0D0 VA: 0x1000BC0D0
	public void .ctor() { }
	// RVA: 0xB5858 Offset: 0xB5858 VA: 0x1000B5858
	public void OnBuyFail() { }
	// RVA: 0xBC0D8 Offset: 0xBC0D8 VA: 0x1000BC0D8
	private void ShowClickEffect() { }
	// RVA: 0xBC1AC Offset: 0xBC1AC VA: 0x1000BC1AC Slot: 4
	public override void Click(Vector3 position) { }
	// RVA: 0xBC2B0 Offset: 0xBC2B0 VA: 0x1000BC2B0 Slot: 7
	protected override void OnActivate() { }
}
*/

#include <mach-o/dyld.h>
#include <substrate.h>

struct UnityEngine_Vector3_Fields {
    float x;
    float y;
    float z;
};

struct UnityEngine_Vector3_o {
    struct UnityEngine_Vector3_Fields fields;
};


void *profile_o;

int32_t (*Profile__get_Coins) (void* __this, const void* method);
void (*Profile__set_Coins) (void* __this, int32_t value, const void* method);


void (*Profile___ctor) (void* __this, void* udid, const void* method);
void new_Profile___ctor (void* __this, void* udid, const void* method) {
    if (!profile_o) {
        profile_o = __this;
    }
    Profile___ctor(__this, udid, method);
}

void (*GUIShopCoinButton__Click) (void* __this, struct UnityEngine_Vector3_o position, const void* method);
void new_GUIShopCoinButton__Click (void* __this, struct UnityEngine_Vector3_o position, const void* method) {
    if (profile_o) {
        int32_t coins = Profile__get_Coins(profile_o, NULL) + 1000;
        Profile__set_Coins(profile_o, coins, NULL);
    }
}

%ctor {
    intptr_t slide = _dyld_get_image_vmaddr_slide(0);
    Profile__get_Coins = (void *)(slide + 0x1000FE860);
    Profile__set_Coins = (void *)(slide + 0x1000FE868);

    MSHookFunction((void *)(slide + 0x1000FD7A4), (void *)new_Profile___ctor, (void **)&Profile___ctor);
    MSHookFunction((void *)(slide + 0x1000BC1AC), (void *)new_GUIShopCoinButton__Click, (void **)&GUIShopCoinButton__Click);
}
2 Likes

谢谢你!