首页
社区
课程
招聘
[原创]x86汇编指令脚本虚拟机
2016-7-27 13:04 13665

[原创]x86汇编指令脚本虚拟机

2016-7-27 13:04
13665
简介
这是一个可以直接解释执行从ida pro里面提取出来的x86汇编代码的虚拟机。

非常精简,整体架构上不能跟那些成熟的虚拟机相比,主要目标是够用、能用、轻量就行,如果觉得代码架构设计的不是很好的话,也不用过于吐槽哈。。

虽然我还有写过两个比较成熟的虚拟机项目(jvm和avm),虽然架构上比这个更完善,更容易扩展,功能也更强大

但是毕竟是给公司写的,没法拿出来分享。。

背景
先说说,为什么要写这个东西。。

之前有段时间,我在用ida逆向分析某些程序的算法,并且要把它提取出来将其跨平台运行,这个时候我首先考虑到是ida的F5插件

毕竟这个可以直接反成c/c++代码,还是很强大的,基本上98%的x86汇编代码,我在通过f5还原成c/c++代码后,都能正常运行。

原本我以为可以万事大吉了,不过就在当我沾沾自喜的时候,发现其中某个汇编函数的c代码,死活就是运行不正常,输出结果不对。

而且那个函数偏偏代码量出奇的大,光c代码就有上万行,而且里面还对数据结构和明文都做了变换和加密,要是慢慢调试的话,得痛苦死。。哎。。

没办法,只好另想出路,既然ida还原c有时候不一定完全准确,但是其汇编代码的准确度还是可以保证的,并且从ida中提取的汇编代码 基本上,不用怎么改,就能编译通过,因此,我先验证了下直接编译汇编代码,运行看看结果对不对。。

结果跟我想的一样,是ok的。。那么问题来了。。

既然汇编运行结果正常,那怎么把它整成跨平台运行呢,直接从编译后x86的指令集进行模拟?工作量有点大,得不偿失。。

有没有取巧些办法呢?当然有,那就是直接解析和运行源码级的x86汇编代码,相当于写个轻量级的精简版x86的脚本虚拟机,来把它运行起来。。

听上去,貌似更麻烦了,其实由于这里只要能够跑通部分需要的汇编指令就行了,因此写个精简版的还是很方便,不需要多少工作量

我前前后后,也就花了一个礼拜就搞定了,非常精简,当然也不完善(也没必要哈,不能跟那些大部头相比)

我的目标就是够用就行,因此我写的差不多厚,就尝试去加载之前有问题的汇编代码,如果发现有指令没实现,那就去实现它,直到跑通为主。。

最后测试结果:

可以正常跑通那个十几万行的汇编代码,并且在arm下运行的性能还算ok,至少满足我的个人需求了。。: )

特性

* 跨平台运行支持,可以在windows、linux、macosx以及android, ios上运行x86的汇编代码。。
* 支持常用x86汇编指令(例如,逻辑操作,跳转,循环,调用,压栈等指令)
* 支持函数间跳转,以及第三方api调用
* 支持参数传入,以及运行结束后,返回值的获取
* 虚拟机的运行粒度为单个函数,函数间的跳转可以通过多个虚拟机实例来完成(轻量的,性能影响不大)
* 支持线程安全
* 暂时不支持arm64,只能在32位下运行(有兴趣的同学可以自行修改)

例子

我们先从ida中提取一段汇编代码,这段汇编主要是printf库函数打印外部传入的数值

sub_hello  proc near 
arg_0    = dword  ptr  8 
.data 
        format db \"hello: %x\", 0ah, 0dh, 0 
 
off_5A74B0  dd offset loc_6B2B50  ; DATA XREF: sub_589100+1832r 
    dd offset loc_58A945  ; jump table for switch  statement 
 
.code 
        ; hi
        push  ebp ;hello 
    mov  ebp, esp 
 
    loc_6B2B50:        ; CODE XREF: sub_6B2B40+8j
        push    eax 
    mov  eax, [ebp+arg_0] 
        push eax 
        mov eax, offset format 
        push eax 
        call printf 
        add esp, 4 
        pop eax 
        
        mov ecx, 1
        jmp ds:off_5A74B0[ecx*4]
 
loc_58A945:
        push    eax 
    mov  eax, [ebp+arg_0] 
        push eax 
        mov eax, offset format 
        push eax 
        call printf 
        add esp, 4 
        pop eax 
        
  end:
        mov  esp, ebp 
    pop  ebp 
        retn 
sub_hello    endp 

如果用c来调用的话,就是

sub_hello(31415926);

输出结果:

hello: 31415926
hello: 31415926

接下来我们把这段汇编直接放到我们的虚拟机里面执行:

static tb_void_t vm86_demo_proc_exec_hello(tb_uint32_t value)
{
    // 上述汇编代码的字符串表示
    static tb_char_t const s_code_sub_hello[] = 
    {
"sub_hello  proc near \n\
arg_0    = dword  ptr  8 \n\
.data \n\
        format db \"hello: %x\", 0ah, 0dh, 0 \n\
 \n\
off_5A74B0  dd offset loc_6B2B50  ; DATA XREF: sub_589100+1832r \n\
    dd offset loc_58A945  ; jump table for switch  statement \n\
 \n\
.code \n\
        ; hi\n\
        push  ebp ;hello \n\
    mov  ebp, esp \n\
 \n\
    loc_6B2B50:        ; CODE XREF: sub_6B2B40+8j\n\
        push    eax \n\
    mov  eax, [ebp+arg_0] \n\
        push eax \n\
        mov eax, offset format \n\
        push eax \n\
        call printf \n\
        add esp, 4 \n\
        pop eax \n\
        \n\
        mov ecx, 1\n\
        jmp ds:off_5A74B0[ecx*4]\n\
 \n\
loc_58A945:\n\
        push    eax \n\
    mov  eax, [ebp+arg_0] \n\
        push eax \n\
        mov eax, offset format \n\
        push eax \n\
        call printf \n\
        add esp, 4 \n\
        pop eax \n\
        \n\
  end:\n\
        mov  esp, ebp \n\
    pop  ebp \n\
        retn \n\
sub_hello    endp \n\
    "
    };

    // 定义一个虚拟机
    vm86_machine_ref_t machine = vm86_machine();
    if (machine)
    {
        // 锁定虚拟机,保证线程安全(这个根据需要,可选)
        tb_spinlock_ref_t lock = vm86_machine_lock(machine);
        tb_spinlock_enter(lock);

        // 获取虚拟机的堆栈
        vm86_stack_ref_t stack = vm86_machine_stack(machine);

        // 编译上面的汇编代码,并生成一个过程对象的引用
        vm86_proc_ref_t proc = vm86_text_compile(vm86_machine_text(machine), s_code_sub_hello, sizeof(s_code_sub_hello));
        if (proc)
        {
            // 添加汇编里面需要调用到的外部库函数
            vm86_machine_function_set(machine, "printf", vm86_demo_proc_func_printf);

            // 初始化调用参数
            vm86_stack_push(stack, value);

            // 执行这个汇编代码
            vm86_proc_done(proc);

            // 恢复堆栈,获取返回值(这里是void的,传null就行了)
            vm86_stack_pop(stack, tb_null);
        }

        // 解锁虚拟机
        tb_spinlock_leave(lock);
    } 
}

int main(int argc, char** argv)
{
    // 执行这个汇编函数:sub_hello(0x31415926)
    vm86_demo_proc_exec_hello(0x31415926);    
}
如果ok,那么输出结果当然也是:

hello: 31415926
hello: 31415926

后话
最后,在项目的idc目录下,有两个脚本工具:export_function.idc 和 export_data.idc 可以用来辅助我们从ida中导出指定的汇编函数和数据

项目主页
项目源码

有兴趣的同学,可以看看哦。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (47)
雪    币: 435
活跃值: (148)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qqsunqiang 2016-7-27 13:19
2
0
谢谢楼主的分享,楼主辛苦了。
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
luskyc 2016-7-27 13:25
3
0
很好很强大,占个座先
雪    币: 1905
活跃值: (1447)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
z许 2016-7-27 13:42
4
0

好腻害。。。支持一下。。
雪    币: 455
活跃值: (592)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lwykj 2016-7-27 13:49
5
0
牛人
[QUOTE]
[/QUOTE]
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2016-7-27 13:53
6
0
牛逼,我下载源代码调试分析看看
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2016-7-27 14:59
7
0
xmake的作者原来就是楼主本人啊。
雪    币: 269
活跃值: (906)
能力值: ( LV12,RANK:345 )
在线值:
发帖
回帖
粉丝
AJISky 7 2016-7-27 15:36
8
0
顶一下,学而不思则罔,死而不学则怠。下载看看
雪    币: 10251
活跃值: (16514)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhczf 2016-7-27 15:40
9
0
楼主会写虚拟机,技术好牛啊,支持一下
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2016-7-27 15:53
10
0
忙了一下午,总算编译完了。
雪    币: 576
活跃值: (1148)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
hkfans 3 2016-7-27 15:57
11
0
代码看起来好牛逼。。。很有大师的风范
雪    币: 176
活跃值: (558)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
waruqi 3 2016-7-27 15:58
12
0
这个只是以前随便写的,所以代码和架构有点乱,没法跟那些成熟的虚拟机相比哈。。只是个小工具而已
雪    币: 176
活跃值: (558)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
waruqi 3 2016-7-27 16:00
13
0
因为是从以前的个人项目中提取出来的,刚刚新建的工程。所以没怎么去优化编译体验,所以一开始可能会折腾些。。见谅。
雪    币: 177
活跃值: (471)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cooolie 2016-7-27 16:07
14
0
强,无敌~
雪    币: 269
活跃值: (906)
能力值: ( LV12,RANK:345 )
在线值:
发帖
回帖
粉丝
AJISky 7 2016-7-27 16:11
15
0
能加我下qq吗,有些东西想咨询一下。
雪    币: 176
活跃值: (558)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
waruqi 3 2016-7-27 16:18
16
0
可以进我q群。343118190
雪    币: 453
活跃值: (54)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dodou 2016-7-27 17:18
17
0
感觉好强大..........
雪    币: 9939
活跃值: (2138)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
VCKFC 2016-7-27 17:23
18
0
能写虚拟机的都强
雪    币: 291
活跃值: (144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yzwyq 2016-7-28 08:40
19
0
十分高明
雪    币: 135
活跃值: (64)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
fatecaster 1 2016-7-28 09:40
20
0
留个名。。太强了
雪    币: 393
活跃值: (224)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
BinGzL 1 2016-7-28 10:07
21
0
mark,感谢分享
雪    币: 521
活跃值: (3769)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
龙飞雪 2016-7-28 10:11
22
0
看着,好强大的说,吾等菜鸟膜拜了。
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2016-7-28 19:17
23
0
向楼主反应一个问题,我打算启用debug调试,但是总算出现这样的错误:error: cl: 命令行 error D8021 :无效的数值参数“/FS”
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2016-7-28 19:19
24
0
楼主xmake核心在于跨平台和便捷,但是我这样用起来很费劲。我打算把源码拖进vs编译调试,发现tbox工具也是一个坑。本来打算认认真真研究源码的,但是调试目前却很麻烦
雪    币: 74
活跃值: (588)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wodexinren 2016-7-28 19:59
25
0
牛逼,来学习下
游客
登录 | 注册 方可回帖
返回