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)定义关键结构体#
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(同样的流程,不过多赘述#
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,
....
截止这里,前13(0x33-0x20)位输入被^0x12
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直接退出了?
以下才是真正的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指令做了什么
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");
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!