buuctf signal

32位程序无壳,直接IDA打开
在这里插入图片描述

关键函数为vm_operad,跟进查看
在这里插入图片描述

switch结构里对输入做了大量操作,很明显是一道VM题,分析以下switch各个分支的操作,可以看到case 10对输入进行操作,case 1将加密后的输入存到v4数组里,case 7判断v4数组是否正确
在这里插入图片描述

在这里插入图片描述

了解了这些需要知道每次循环对应执行的是哪一个switch分支,控制switch结构的a1数组可以在数据段里找到
在这里插入图片描述

shift+E将数据dump出来,由于每个switch分支里对v10的操作不是每次自增1,所以需要写脚本把每次循环对应的a1数组的值求出,脚本可以参照switch语句部分,把每个分支的操作语句只留下v10的操作即可,
得到switch的执行流程为10,4,8,3,1,4,8,5,1,3,8,11,1,12,8,4,1,5,8,3,1,11,8,11,1,4,8,3,1,2,8,4,1,12,8,11,1,5,8,2,1,2,8,4,1,2,8,5,1,5,8,2,1,4,8,3,1,2,8,12,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7(0xFFh要删掉,没有用处)
然后再找到v4数组即正确的密文,case 7可以看出密文即为a1数组中值为7的后一个元素,写一个简单的脚本就可以求出,
密文为34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122。
有了执行流程和密文,根据switch分支里的操作写解密脚本即可:

#include <stdio.h>

int main()
{
	int opcode[]={10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1,
	2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1},i=60,k=83;
	int v5,v6=0,v7=14,v8=0,v9=14,v4[100];
	int input[]={34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122};
	int sort[]={10,4,8,3,1,4,8,5,1,3,8,11,1,12,8,4,
	1,5,8,3,1,11,8,11,1,4,8,3,1,2,8,4,1,12,8,11,1,5,8,2,1,2,8,4,1,2,8,5,1,5,8,2,1,4,8,3,1,2,8,12,1};
	char flag[15];
	while(1)
	{
		if(i<=0) break;
		//printf("%d,",opcode[i]);
		switch(sort[i])
		{
			case 1:
				v4[v7]=input[v9];
				printf("s1 v4[%d]=%d\n",v7,v4[v7]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				--v7;
				--v9;
				break;
			case 2:
				v4[v7+1]-=opcode[k+1];
				printf("s2 v4[%d]=%d\n",v7+1,v4[v7+1]);
				i--;
		        if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				printf("opcode=%d,sort=%d\n",opcode[k],sort[i]);
				break;
			case 3:
				v4[v7+1]+=opcode[k+1];
				printf("s3 v4[%d]=%d\n",v7+1,v4[v7+1]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				printf("opcode=%d,sort=%d\n",opcode[k],sort[i]);
				break;
			case 4:
				v4[v7+1]^=opcode[k+1];
				printf("s4 v4[%d]=%d\n",v7+1,v4[v7+1]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				printf("opcode=%d,sort=%d\n",opcode[k],sort[i]);
				
				break;
			case 5:
				v4[v7+1]/=opcode[k+1];
				printf("s5 v4[%d]=%d,opcode[%d]=%d\n",v7+1,v4[v7+1],i,opcode[i+1]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				printf("opcode=%d,sort=%d\n",opcode[k],sort[i]);
				
				break;
			case 6:
				printf("s6\n");
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			case 7:
				printf("s7\n");
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			case 8:
				printf("s8\n");
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			case 10:
				printf("s10\n");
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			case 11:
				v4[v7+1]=v4[v7+1]+1;
				printf("s11 v4[%d]=%d\n",v7+1,v4[v7+1]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			case 12:
				v4[v7+1]=v4[v7+1]-1;
				printf("s12 v4[%d]=%d\n",v7+1,v4[v7+1]);
				i--;
				if(sort[i]==opcode[k-1]&&sort[i]!=opcode[k-2]) k--;
				else k-=2;
				break;
			default:
				continue;
		}
	}
	for(i=0;i<15;i++)
	    flag[i]=v4[i];
	printf("%s",flag); 
	return 0;
}

最后的flag为757515121f3d478

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值