a1ra1rhthm

VM逆向-定义结构体

Airhthm·2024-03-24 14:00·115 次阅读

VM逆向-定义结构体

VM逆向

一、VM是什么?#

1.模拟一个cpu去执行指令的一个过程。#

2.基于虚拟机的代码保护技术,将可执行代码转换为字节码指令系统的代码。即将程序的代码转换为自定义的操作码(opcode)#

3.解决vm逆向有很多方法,但大致思路都是翻译确定每条opcode进行的操作,或是通过硬件断点+idapython脚本/或是dump下opcode然后使用自己熟悉的语言翻译每条操作/或是暴力破解每条指令操作。#

二、虚拟机的构造:#

1.定义基本寄存器:所以通过引入结构体,同样在反汇编代码中定义寄存器#

_CPU结构体:定义寄存器:__eax, _ebx, _ecx, _edx, _eip,其中eip指向opcode的地址

(这个大佬的视频讲的很好,推荐:【Bugku/CTF/Re/WP】使用IDA结构体解决VM虚拟机保护】https://www.bilibili.com/video/BV1gv4y1u7t1?vd_source=69ffcd703762aa7a204e6cc6f57ba69d)

(再编:本博客尝试用定义结构体的方式便捷查看每个存储器eax/ebx的数据变化,所以浅浅补充一下如何定义结构体:eax、ebx等存储器用来存放特定的数据,所以在汇编中会有固定的大小(对应db/dd/dq等)

2.opcode:操作码,一般是一大段的字节,在程序中通过选择结构运行#

三、以ctf题为例#

1.第七届山东省大学生网络安全技能大赛-re-babyLoginPlus#

1)跟进第二个函数,为40B0B0加载了一段操作#

2)跟进第三个函数,有一个关键判断if,其中对上面的40B0B0进行了引用,所以可以猜测unk_40853C就是opcode#

3)定义关键结构体#

Copy
opcode特征:(动调分析每一条指令的内容) 0xD0, 0x20, 0x00, 0x00, 0x00, 0x00d, 0xD0, 0x21, 0x25, 0x00, 0x00, 0x00, _ebx=0x25 0xD4, input=fa1rhthm0fa1rhthm0fa1rhthm0fa1rhthm00 0xD0, 0x20, 0x00, 0x02, 0x00, 0x00, _eax=0,_eip+6=D0 0xD0, 0x61, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x61, 0x00, 0x00, 0x00, 0x00, 提取eax=input[0] 0xD0, 0x21, 0x09, 0x00, 0x00, 0x00, ebx=9 0xD8, eax-=ebx 0xD0, 0x21, 0x26, 0x00, 0x00, 0x00, ebx=0x26 0xD1, ((input-9)^0x26)^key[]+6 eax^=ebx 0xD0, 0x21, 0x00, 0x02, 0x00, 0x00, ebx=0x200 0xD0, 0x62, 0x00, 0x00, 0x00, 0x00, ebx=0 0xD0, 0x22, 0x2C, 0x01, 0x00, 0x00, ecx=0x12c 0xD7, 0x02, ebx=ebx+ecx 0xD0, 0x62, 0x00, 0x00, 0x00, 0x00, ebx=0x57 0xD1, eax^=ebx 0xD0, 0x21, 0x06, 0x00, 0x00, 0x00, ebx=0x6 0xD7, 0x01, eax+=ebx 0xD0, 0x21, 0x00, 0x02, 0x00, 0x00, ebx=0x200 0xD0, 0x62, 0x00, 0x00, 0x00, 0x00, ebx=0 0xD0, 0x22, 0x90, 0x01, 0x00, 0x00, ecx=0x190 0xD7, 0x02, ebx=0+0x190 0xD0, 0x62, 0x00, 0x00, 0x00, 0x00, ebx=0x32 ...

n1ctf#

这道题貌似没有特别的cpu和opcode特征,函数也是动态加载出来的

(还没解决

gwctf2019-babyvm(同样的流程,不过多赘述#

Copy
airhthmairhthmairhthm 0xF5, 判断长度是否为21 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, eax=input[eip+2]=input[0] 0xF2, ebx=0x12,eax^=ebx 0xF1, 0xE4, 0x20, 0x00, 0x00, 0x00, input[eip+2]=input[0x20]=eax 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00, eax=input[eip+2]=input[1] 0xF2, eax^=ebx,ebx=0x12 0xF1, 0xE4, 0x21, 0x00, 0x00, 0x00, input[eip+2]=input[0x21]=eax 0xF1, 0xE1, 0x02, 0x00, 0x00, 0x00, 这一部分只是将输入简单异或0x12然后存储起来 0xF2, 0xF1, 0xE4, 0x22, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, .... 截止这里,前130x33-0x20)位输入被^0x12
Copy
0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 到0xF4直接退出了?
Copy
以下才是真正的opcode(但是不知道为什么动调是上面那段,大佬的wp说是主动防御? 0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x01, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00, ......

太复杂了选择写个脚本查看每条op指令做了什么

Copy
int main() { unsigned int opcode[] = {... }; int len = sizeof(opcode) / sizeof(opcode[0]); for(int i=0;i<len;i++) { unsigned int tab = opcode[i]; if (tab == 0xF5) { i += 5; } else if (tab == 0xF1) { unsigned int next = opcode[i + 1]; switch (next) { case 0xE1: printf("cpu_eax = input[%d]\n", opcode[i + 2]); i += 5; break; case 0xE2: printf("cpu_ebx = input[%d]\n", opcode[i + 2]); i += 5; break; case 0xE3: printf("cpu_ecx = input[%d]\n", opcode[i + 2]); i += 5; break; case 0xE4: printf("input[%d] = cpu_eax\n", opcode[i + 2]); i += 5; break; case 0xE5: printf("cpu_edx = input[%d]\n", opcode[i + 2]); i += 5; break; case 0xE7: printf("input[%d] = cpu_ebx\n", opcode[i + 2]); i += 5; break; default: printf("Unknown opcode: %X\n", next); i++; // move to next opcode break; } } else if (tab == 0xF2) { printf("cpu_eax^=cpu_ebx"); } else if (tab == 0xF4) { i += 5; } else if (tab == 0xF7) { printf("cpu_eax *= cpu_edx\n"); } else if (tab == 0xF8) { printf("exchange_eax_ebx\n"); } else if (tab == 0xF6) { printf("cpu_eax = cpu_ecx + 2 * cpu_ebx + 3 * cpu_eax\n"); } } }
posted @   天街如水  阅读(115)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示
目录