2019UNCTF easyvm

虚拟机逆向入门----2019UNCTF easyvm

自己也是个萌新,难得做了一道虚拟机逆向的题目,还是想分享出来

看题目知道这是一个虚拟机逆向题目,运行一下知道这是匹配字符串
在这里插入图片描述
之后用IDA64进行分析,主函数的逻辑还是比较清楚的。
先给s上的96字节置0,再给v3分配40字节空间。调用sub_400C1E初始化v3上的内容。用s接收32字符,如果不是32长度就失败,如果是,则调用 v3函数指针所对应的函数,参数分别是v3, &unk_602080, &unk_6020A0, &s,最后的!=0可以猜测这个函数返回值是逻辑型。
2019UNCTF easyvm_第1张图片
这里的V3是一个函数指针,接着分析比较重要的初始化v3的函数sub_400C1E,注意到有个特别的地方:*(_QWORD *)a1 = off_4010A8
2019UNCTF easyvm_第2张图片
之后查看off_4010A8的内容,发现都是一些函数的偏移量。所以这里也可以知道
v3调用的就是sub_400806这个函数
2019UNCTF easyvm_第3张图片
接着就开始分析sub_400806这个函数(根据理解稍作改动)
2019UNCTF easyvm_第4张图片
这个时候再看一下constvalue和checkcode
2019UNCTF easyvm_第5张图片
2019UNCTF easyvm_第6张图片
接下来重新分析sub_400806函数,函数首先将offset+8被赋值0xa9对应的地址
2019UNCTF easyvm_第7张图片
这样就可以看switch中值为0xA9的内容,发现执行offset+80函数指针对应的函数,参数为offset,之后(offset+8)-6,也就是下一个循环将执行0xA3的内容。这里就相当于执行一条命令之后,某个位置的值减去一个值。有点像IP,结合其他case也可以做出这个大胆的假设----offset+8相当于IP
在这里插入图片描述
接下来分析offset+80对应的函数,这里可以知道*(_BYTE )(a1 + 16)=(_BYTE )(input+(unsigned __int8 *)(a1 + 18))
2019UNCTF easyvm_第8张图片
2019UNCTF easyvm_第9张图片
接着执行0xA3处的代码
在这里插入图片描述
2019UNCTF easyvm_第10张图片
同样可以得到sub_400CD6的代码
2019UNCTF easyvm_第11张图片
依次类推。可以按照这个规则先推到处程序执行switch的顺序
0xA9u 0xA3u 0xA5u 0xA6u 0xA4u 0xABu 0xA7u 0xAEu 0xA2u 0xADu 0xAFu
同理也可以写出其执行的代码过程

A9(){
    *(_BYTE *)(a1 + 16)=*(_BYTE *)(input + *(unsigned __int8 *)(a1 + 18))
}

A3(){
     *(_BYTE *)(a1 + 16) -= *(_BYTE *)(a1 + 18)
}

A5(){
    *(_BYTE *)(a1 + 17) ^= *(_BYTE *)(a1 + 16)
}

A6(){
    *(_BYTE *)(a1 + 16) = 0xCD
}

A4(){
    *(_BYTE *)(a1 + 16) ^= *(_BYTE *)(a1 + 17)
}

AB(){
    if ( *(_BYTE *)(a1 + 16) == *(_BYTE *)(*(_QWORD *)(a1 + 24) + *(unsigned __int8 *)(a1 + 18)) )
        *(_DWORD *)(a1 + 20) = 0
    else if ( *(_BYTE *)(a1 + 16) >= *(_BYTE *)(*(_QWORD *)(a1 + 24) + *(unsigned __int8 *)(a1 + 18)) )
        *(_DWORD *)(a1 + 20) = 1
    else
        *(_DWORD *)(a1 + 20) = -1
}
    
A7(){
    ++*(_BYTE *)(a1 + 16)
}

AE(){
    if ( *(_DWORD *)(a1 + 20) )
        return 0
    else
        goto A2()
}

A2(){
    ++*(_BYTE *)(a1 + 18)
}

AD(){
    if ( *(_BYTE *)(a1 + 18) > 0x1Fu )
         *(_DWORD *)(a1 + 20) = 1
    else
        *(_DWORD *)(a1 + 20) = 0
}

AF(){
    if ( *(_DWORD *)(a1 + 20) != 1 )
        goto A9()
    else
        return 1
}

再回顾一下初始化的赋值,接下来就是逆向这部分的过程了
2019UNCTF easyvm_第12张图片

该虚拟机的逻辑就是从头开始取字符串的字符(假设i=0),之后减去i,然后与0xCD异或,之后这个对这个值进行判断是否的等于i(这里我们是想要他等于i的),然后该值自增,i++,当循环到最后一个字符时,如果能够循环31次,那么就可以返回1,也就是我们想要的值,知道逻辑之后不难写出逆向脚本
2019UNCTF easyvm_第13张图片
在这里插入图片描述
在这里插入图片描述
虚拟机逆向学习资料:
https://www.freebuf.com/column/174623.html
https://www.52pojie.cn/forum.php?mod=viewthread&tid=860237&page=1
题目:
链接:https://pan.baidu.com/s/1EBU7TE1RngN8De7M0_B7DQ
提取码:fqew
复制这段内容后打开百度网盘手机App,操作更方便哦

你可能感兴趣的:(2019UNCTF easyvm)