Intel Houdini 比 QEMU 快在哪里?

您所在的位置:网站首页 houdini读法 Intel Houdini 比 QEMU 快在哪里?

Intel Houdini 比 QEMU 快在哪里?

2022-12-29 02:50| 来源: 网络整理| 查看: 265

我猜测其中的一个原因是,Houdini会将一个进程对一些白名单中的函数调用迁移到主机架构上做,所以会快很多。

证据是你用ida去看libhoudini.so的话,应该能看到有一个字符串表,会被引用,里面包含了非常多常见函数。

举个例子,在原本的进程即将调用了puts这个函数的时候,qemu的做法是进入arm 的libc.so 继续模拟arm指令,直到调用syscall时进行调用约定的翻译;houdini的做法是直接获得虚拟cpu的r0,然后调用x86的puts(r0),自然就快了很多。

这意味着如果被模拟的进程如果主要的开销都在这些白名单的函数中,那么就很容易达到和x86一样的执行效率

2016/08/19更新:

今天刚好又找出libhoudini.so拖到IDA里 看了看,我这里再只列出一些分析的结果,希望有一些参考意义吧。。

分析的libhoudini.so是

http://forum.xda-developers.com/showthread.php?t=2528952

处的

Genymotion-ARM-Translation_v1.1.zip

这里只写下我自己的一些分析结果,函数名,类型名都是自己定义的。

首先,在0x0023B680处开始有一个数组,共2986个元素,元素定义如下

struct white_list_item_t { const char *func_name; const char *type_of_args; void *func_in_x86_lib; int fake_virtual_address_of_this_symbol; int unkonwn2; void *wrapper_from_virtual_arm_to_x86; };

这个数组里的元素,func_in_x86_lib初始化都是0, fake_virtual_address_of_this_symbol可能为0或者为一个0x0fxxxx的数值,unkonwn2未知,func_name是一个函数名称,如AMREncodeInit,fputs等等,而type_of_args则是一个如"4_4_4"这样的字符串,似乎说明了这个函数的参数大小和个数,但是没有使用到,所以我没有去进一步确认。

值得关注的是warpper_from_virtual_arm_to_x86,这是一个函数指针。

在这两千多个元素中,这个域被初始化共有几十种不同的值,下面给出的是给出了其中一个代码比较简单函数的IDA反编译结果(手工做出过修正):

int __cdecl sub_17CC30(int a1, int a2, int a3, int a4) { int v4; // ebx@0 //省略.. int v20; // [sp-4h] [bp-8h]@0 v7 = v4; v8 = (int (__stdcall *)(int, int, int, int, _DWORD))white_list[a1].func_in_x86_lib; v9 = (int *)sub_12CEC0(); //省略若干。。 sub_175500(); *v9 = (v8)( *v9, v9[1], v9[2], v9[3], *(_DWORD *)v9[13] ); //省略若干 return result; }

v9 = (int *)sub_12CEC0();

这里应该是获得了当前的虚拟arm cpu context的结构体指针,然后v8则是这个函数对应的func_in_x86_lib。

*v9 = (v8)( *v9, v9[1], v9[2], v9[3], *(_DWORD *)v9[13] );

这句话翻译过来则是r0 = func_in_x86_lib(r0, r1, r2, r3, *(sp)); 也就是从寄存器和栈上取了5个参数,完成调用之后将返回值放回到r0中。。(因为arm里sp也就是r13,返回地址放在寄存器而不是栈上,所以当时的栈顶就是第5个参数)

如果你看sub12CEC0这个函数所在的white_list_item_t元素的话,会发现func_name是

_ZN7android14SurfaceFlinger15postMessageSyncERKNS_2spINS_11MessageBaseEEExj

也就是

android::SurfaceFlinger::postMessageSync(android::sp const&, long long, unsigned int)

算上指向对象自己的this指针以及long long 64位,刚好是5个。。

之前提到 white_item_t中的func_in_x86_lib都是0,那么代码中理应有地方对他进行了赋值。。我这里仅找到一处在下面

int *__usercall sub_E5F50@(int a1@) { int v1; // edi@1 int v2; // eax@1 int v3; // esi@2 int (__stdcall *v4)(_DWORD, int, int, int, int, int, int, int, int, int); // ebx@3 unsigned int v5; // edi@4 int v6; // eax@5 void *v7; // ebx@5 white_list_item_t *v8; // eax@8 int *result; // eax@10 int v10; // ebx@12 _DWORD *v11; // eax@13 int v12; // ebx@14 _DWORD *v13; // eax@15 int *v14; // [sp-3Ch] [bp-40h]@12 int v15; // [sp-38h] [bp-3Ch]@12 int v16; // [sp-34h] [bp-38h]@5 int v17; // [sp-30h] [bp-34h]@5 int v18; // [sp-2Ch] [bp-30h]@5 int v19; // [sp-28h] [bp-2Ch]@5 int v20; // [sp-24h] [bp-28h]@5 int v21; // [sp-20h] [bp-24h]@5 int v22; // [sp-1Ch] [bp-20h]@5 int v23; // [sp-18h] [bp-1Ch]@5 int v24; // [sp-14h] [bp-18h]@5 white_list_item_t *v25; // [sp-Ch] [bp-10h]@3 signed int v26; // [sp-8h] [bp-Ch]@8 signed int v27; // [sp-4h] [bp-8h]@8 int (*v28)(); // [sp+0h] [bp-4h]@8 v1 = a1; v2 = sub_E76F0("libEGL.so", 0); if ( v2 ) { v3 = sub_E7830(v2, *(_DWORD *)__readfsdword(4)); if ( v3 ) goto LABEL_3; } else { v3 = 0; } v14 = &v15; v10 = sub_E76F0("libGLESv1_CM.so", 0); if ( !v10 || (v11 = (_DWORD *)sub_12CEC0(), v14 = &v15, (v3 = sub_E7830(v10, *v11)) == 0) ) { v14 = &v15; v12 = sub_E76F0("libGLESv2.so", 0); if ( v12 ) { v13 = (_DWORD *)sub_12CEC0(); v14 = &v15; v3 = sub_E7830(v12, *v13); } } LABEL_3: v4 = *(int (__stdcall **)(_DWORD, int, int, int, int, int, int, int, int, int))(v1 + 8); v25 = *(white_list_item_t **)(v1 + 16); if ( *(_DWORD *)(v1 + 16) == 1 ) { v5 = __readfsdword(28); __writefsdword(28, 3u); sub_C22D0(0); } else { v5 = 3; } v6 = v4(*(_DWORD *)__readfsdword(4), v16, v17, v18, v19, v20, v21, v22, v23, v24); v7 = (void *)v6; if ( v25 == (white_list_item_t *)1 ) __writefsdword(28, v5); if ( v6 ) { v28 = sub_CB5F0; v27 = 24; v26 = 2986; v25 = white_list; v8 = sub_BDA30(*(_DWORD *)__readfsdword(4), white_list, 2986, 24, (int (__cdecl *)(int, int))sub_CB5F0); if ( v8 ) v8->func_in_x86_lib = v7; } result = (int *)__readfsdword(4); *result = v3; return result; }

这个函数的最后:

v8->func_in_x86_lib = v7;

完成了这个赋值。。

然后在前面"libGLESv1_CM.so"等等字符串也一定程度上提示了这个函数是和动态链接库加载相关的(sub_E76F0这个函数中还调用了dlopen)

不过我已经看不下去了= =~

总结一下就是说,确实有一些逻辑进行了类似利用调用约定直接调用x86函数的过程。。

但是具体这里的x86函数究竟就是原本一个x86 so中的函数,还是说是一个arm中的对应函数进行binary translation的结果,亦或是别的可能。。。我就不知道了。。。

&以上的分析很大程度是以来于自己的主观猜测。。恩。。。。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3