解一道vm加密的crackme,simple_vm

这个crackme包含两个文件,vm_rel和p.bin,其中vm_rel是一个简单的虚拟机,p.bin是虚拟机的指令码。原始文件可以在这里下载,(感谢这个github的主人) https://github.com/b1ngoo/VMCTF/tree/master/simplevm

生成虚拟机的伪指令的代码如下:(我还是习惯用c。。)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
	char c[256]={0x0};
	char a4[4]={0x0};
	char dl;

	FILE *fp;
	int length;
	fp=fopen("p.bin","rb");
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	char *p,*p0;
	p=malloc(length);
	fread(p,length,1,fp);
	fclose(fp);
	p0=p;
	unsigned int buf_dwA,buf_dwB;
	while(1){
		if((p+1-p0)>=length){
			free(p0);
			return 0;
		}
		if(*p>0x18){
			if((p+1-p0)>=length){
				free(p0);
				return 0;
			}
			else{
				p=p+1;
				continue;
			}
		}
		else{
			switch(*p){
				case 0x0:
					//memcpy(&buf_dwA,p+1,4);
					printf("%x: return [$+1]\n",p-p0);
					p=p+5;
					//free(p0);
					//return buf_dwA;
					break;
				case 0x1:
					//memcpy(&buf_dwA,p+1,4);
					printf("%x: jmp [$+1]\n",p-p0);
					p=p+5;
					/*
					if(buf_dwA>=length){
						free(p0);
						return 0;
					}
					else{
						//p=p0+buf_dwA;
						p=p+5;
					}
					*/
					break;
				case 0x2:
					/*
					memcpy(&buf_dwA,p+1,4);
					memcpy(&buf_dwB,p+5,4);
					memset(p0+buf_dwA,buf_dwB & 0x000000ff,1);
					*/
					printf("%x: movb [[$+1]],[$+5] & 0x000000ff\n",p-p0);
					p=p+9;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x3:
					/*
					memcpy(&buf_dwA,p+1,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					*/
					printf("%x: movsx c,byte [[$+1]]\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x4:
					//memcpy(&buf_dwA,p+1,4);
					//memcpy(p0+buf_dwA,c,1);
					printf("%x: movb [[$+1]],c\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x5:
					memcpy(&buf_dwA,p+1,4);
					/*
					memcpy(a4,p0+buf_dwA,1);
					if(a4[0]>=128){
						memset(a4+1,0xff,3);
					}
					else{
						memset(a4+1,0x0,3);
					}
					*/
					printf("%x: movsx a4,byte [[$+1]]\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x6:
					//memcpy(&buf_dwA,p+1,4);
					//memcpy(p0+buf_dwA,a4,1);
					printf("%x: movb [[$+1]],a4\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x7:
					/*
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA+buf_dwB;
					memcpy(c,&buf_dwA,4);
					*/
					printf("%x: add c,a4\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x8:
					/*
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA & buf_dwB;
					buf_dwA=~buf_dwA;
					memcpy(c,&buf_dwA,4);
					*/
					printf("%x: c=~(c&a4)\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x9:
					printf("%x: nop\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xa:
					//c[0]=(unsigned char)getchar();
					//memset(c+1,0x0,3);
					printf("%x: c=getchar()\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xb:
					//putchar((int)c[0]);
					printf("%x: putchar(c)\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xc:
					//memcpy(&buf_dwA,p+1,4);
					//这里总出问题
					//memcpy(&dl,p0+buf_dwA,1);
					printf("%x: cmpb 0,[[$+1]]\n",p-p0);
					printf("%x: jz nop\n",p-p0);
					printf("%x: jnz movb [[$+1]],[[$+1]]-1\n",p-p0);
					printf("%x: jmp [$+5]\n",p-p0);
					/*
					if(dl==0){
						p=p+9;
						if((p-p0)>=length){
						free(p0);
						return 0;
						}
					}
					else{
						memcpy(&buf_dwB,p+5,4);
						memset(p0+buf_dwA,dl-1,1);
						if(buf_dwB>=length){
							free(p0);
							return 0;
						}
						else{
							printf("%d: jmp %d\n",p-p0,buf_dwB);
							//p=p0+buf_dwB;
							p=p+9;
						}
					}
					*/
					p=p+9;
					break;
				case 0xd:
					/*
					memcpy(&buf_dwA,c,4);
					buf_dwA=buf_dwA+1;
					memcpy(c,&buf_dwA,4);
					*/
					printf("%x: inc c\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xe:
					/*
					memcpy(&buf_dwA,a4,4);
					buf_dwA=buf_dwA+1;
					memcpy(a4,&buf_dwA,4);
					*/
					printf("%x: inc a4\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xf:
					//memcpy(c,a4,4);
					printf("%x: mov c,a4\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x10:
					//memcpy(a4,c,4);
					printf("%x: mov a4,c\n",p-p0);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x11:
					/*
					memcpy(&buf_dwA,p+1,4);
					memcpy(c,&buf_dwA,4);
					*/
					printf("%x: add c,[$+1]\n",p-p0);
					p=p+5;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x12://a4为偏移,取出给c
					/*
					memcpy(&buf_dwA,&a4,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					*/
					printf("%x: movsx c,byte [a4]\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x13://c为偏移,取出给c
					/*
					memcpy(&buf_dwA,c,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					*/
					printf("%x: movsx c,byte [c]\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x14://取四字节给c		mov c,4字节
						  //				往后移5字节
					//memcpy(&buf_dwA,p+1,4);
					//memcpy(c,&buf_dwA,4);
					printf("%x: mov c,[$+1]\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x15://取四字节给a4	mov a4,4字节
						  //				往后移5字节
					//memcpy(&buf_dwA,p+1,4);
					//memcpy(a4,&buf_dwA,4);
					printf("%x: mov a4,[$+1]\n",p-p0);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x16://movb [a4],c
						  //后移1字节
					/*
					memcpy(&buf_dwA,a4,4);
					memcpy(p0+buf_dwA,c,1);
					*/
					printf("%x: movb [a4],c\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x17://c=c-a4;
						  //后移1字节
					/*
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA-buf_dwB;
					memcpy(c,&buf_dwA,4);
					*/
					printf("%x: sub c,a4\n",p-p0);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x18://cmp 0,c
						  //jz 后移5字节
						  //位移为4字节
					//memcpy(&buf_dwA,c,4);
					//memcpy(&buf_dwB,p+1,4);
					printf("%x: cmp 0,c\n",p-p0);
					printf("%x: jz nop\n",p-p0);
					printf("%x: jmp [$+1]\n",p-p0);
					/*
					if(buf_dwA==0){
						p=p+5;
						if(p-p0>=length){
						free(p0);
						return 0;
						}
					}
					else{
						//memcpy(&buf_dwB,p+1,4);
						if(buf_dwB>=length){
							free(p0);
							return 0;
						}
						else{
							//p=p0+buf_dwB;
							p=p+5;
						}
					}
					*/
					p=p+5;
					break;
				default:
					break;
			}
		}
	}
	free(p0);
}

生成的伪代码以及对伪代码进行分析如下:

0: jmp [$+1]
9: mov a4,[$+1]
10: movsx c,[a4]
14: cmp 0,c
14: jz nop
14: jmp [$+1]
1b: movsx a4,[[$+1]]
21: c=getchar()
22: cmpb 0,[[$+1]]
22: jz nop
22: jnz movb [[$+1]],[[$+1]]-1
22: jmp [$+5]
2b: movb [[$+1]],a4

30: mov a4,[$+1]
35: inc a4
36: movsx c,[a4]
37: putchar(c)
38: cmpb 0,[[$+1]]
38: jz nop
38: jnz movb [[$+1]],[[$+1]]-1
38: jmp [$+5]

42: mov a4,[$+1]
47: inc a4
48: c=getchar()
4a: movb [a4],c
4b: cmpb 0,[[$+1]]
4b: jz nop
4b: jnz movb [[$+1]],[[$+1]]-1
4b: jmp [$+5]

55: movsx c,[[$+1]] :[140]==0x20
5a: mov a4,c :0x20
5b: add c,[$+1] :0x20+0xf1=0x111 
60: movsx c,[c] :flag[0]
61: movb [[$+1]],c :[143]=flag[0]
66: c=~(c&a4) :c=~(flag[0] & 0x20)
67: movb [[$+1]],c :[141]=c
6c: mov a4,c
6d: movsx c,[[$+1]] :[140]=0x20
72: c=~(c&a4) :c=~(0x20 & (~(flag[0] & 0x20)))
73: movb [[$+1]],c :[142]=c
78: movsx c,[[$+1]]
7d: movsx c,[[$+1]] :flag[0]
82: c=~(c&a4) :c=~(flag[0] & (~(flag[0] & 0x20)))
83: mov a4,c
84: movsx c,[[$+1]] :[142]
89: c=~(c&a4) :c=~((~(0x20 & (~(flag[0] & 0x20)))) & (~(flag[0] & (~(flag[0] & 0x20))))) //这句是关键,看着很复杂,其实还是c=flag[0] ^ 0x20
8a: movb [[$+1]],c :[144]=c

90: movsx c,[[$+1]] :[140]==0x20
95: add c,[$+1] :0x20+0xf1
9a: mov a4,c :[flag[0]]
9b: movsx c,[[$+1]] :[144]
a0: movb [a4],c :flag[0]=

a1: movsx a4,[[$+1]] :[140]=0x20
a6: inc a4 :0x21
a7: movb [[$+1]],a4 :[140]=0x21
ac: cmpb 0,[[$+1]] :cmp 0,[145]0x1f
ac: jz nop
ac: jnz movb [[$+1]],[[$+1]]-1
ac: jmp [$+5] :0x55

b6: movsx c,[[$+1]] :[146]0x1f
bb: add c,[$+1] :0x1f+0x5=0x24
c0: movsx c,[c] :09,09000102
c1: mov a4,c :09
c2: movsx c,[[$+1]] :[146]0x1f
c7: add c,[$+1] :0x1f+0x111
cc: movsx c,[c] :[0x130]
cd: sub c,a4 //这里注释一下,c就是[0x130]的内存位置,这个内存位置其实是你输入的flag的最后一位所在的位置,当然现在的值是经过上面那段计算以后的值了;a4呢,就是[0x24]位置的值,如代码bb处所示;因此,程序设计的逻辑就是输入的每一位flag经过计算,值应该与[0x5-0x24]的值相等。这个crackme虚拟化之前的算法确实比较简单,耗时间的是把这个算法给整理出来。。
ce: cmp 0,c //这里是比较,如果结果为0,则继续下一个比较;如果不为0,则直接跳转到打印WRONG的指令
ce: jz nop
ce: jmp [$+1]
d3: cmpb 0,[[$+1]] :[146]
d3: jz nop
d3: jnz movb [[$+1]],[[$+1]]-1 :[146]0x1f-1
d3: jmp [$+5]

dc: jmp [$+1]
e2: return [$+1]
e7: return [$+1]
ec: return [$+1]
f1: return [$+1]
f6: return [$+1]
fb: return [$+1]
100: c=getchar()
10c: return [$+1]
111: return [$+1]
116: return [$+1]
11b: return [$+1]
120: return [$+1]
125: return [$+1]
12a: return [$+1]
12f: return [$+1]
134: return [$+1]
139: return [$+1]
13e: return [$+1]
143: return [$+1]
148: return [$+1]
14d: return [$+1]
156: c=getchar()
15c: c=getchar()
15d: return [$+1]
162: jmp [$+1]
167: putchar(c)
168: cmpb 0,[[$+1]]
168: jz nop
168: jnz movb [[$+1]],[[$+1]]-1
168: jmp [$+5]
171: return [$+1]
176: mov a4,[$+1]
17b: inc a4
17c: movsx c,[a4]
17d: putchar(c)
17e: cmpb 0,[[$+1]]
17e: jz nop
17e: jnz movb [[$+1]],[[$+1]]-1
17e: jmp [$+5]
187: return [$+1]

另以下附上,开始不懂这种crackme怎么做,对着汇编代码,用c把原始的crackme写了一遍。不过这对于整理虚拟机的伪代码还是有好处的。。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
	char c[256]={0x0};
	char a4[4]={0x0};
	char dl;

	FILE *fp;
	int length;
	fp=fopen("p.bin","rb");
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	char *p,*p0;
	p=malloc(length);
	fread(p,length,1,fp);
	fclose(fp);
	p0=p;
	unsigned int buf_dwA,buf_dwB;
	while(1){
		if(*p>0x18){
			if((p+1-p0)>=length){
				free(p0);
				return 0;
			}
			else{
				p=p+1;
				continue;
			}
		}
		else{
			switch(*p){
				case 0x0:
					memcpy(&buf_dwA,p+1,4);
					free(p0);
					return buf_dwA;
					break;
				case 0x1:
					memcpy(&buf_dwA,p+1,4);
					if(buf_dwA>=length){
						free(p0);
						return 0;
					}
					else{
						p=p0+buf_dwA;
					}
					break;
				case 0x2:
					memcpy(&buf_dwA,p+1,4);
					memcpy(&buf_dwB,p+5,4);
					memset(p0+buf_dwA,buf_dwB & 0x000000ff,1);
					p=p+9;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x3:
					memcpy(&buf_dwA,p+1,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x4:
					memcpy(&buf_dwA,p+1,4);
					memcpy(p0+buf_dwA,c,1);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x5:
					memcpy(&buf_dwA,p+1,4);
					memcpy(a4,p0+buf_dwA,1);
					if(a4[0]>=128){
						memset(a4+1,0xff,3);
					}
					else{
						memset(a4+1,0x0,3);
					}
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x6:
					memcpy(&buf_dwA,p+1,4);
					memcpy(p0+buf_dwA,a4,1);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x7:
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA+buf_dwB;
					memcpy(c,&buf_dwA,4);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x8:
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA & buf_dwB;
					buf_dwA=~buf_dwA;
					memcpy(c,&buf_dwA,4);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x9:
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xa:
					c[0]=(unsigned char)getchar();
					memset(c+1,0x0,3);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xb:
					putchar((int)c[0]);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xc:
					memcpy(&buf_dwA,p+1,4);
					memcpy(&dl,p0+buf_dwA,1);
					if(dl==0){
						p=p+9;
						if((p-p0)>=length){
						free(p0);
						return 0;
						}
					}
					else{
						memcpy(&buf_dwB,p+5,4);
						memset(p0+buf_dwA,dl-1,1);
						if(buf_dwB>=length){
							free(p0);
							return 0;
						}
						else{
							p=p0+buf_dwB;
						}
					}
					break;
				case 0xd:
					memcpy(&buf_dwA,c,4);
					buf_dwA=buf_dwA+1;
					memcpy(c,&buf_dwA,4);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xe:
					memcpy(&buf_dwA,a4,4);
					buf_dwA=buf_dwA+1;
					memcpy(a4,&buf_dwA,4);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0xf:
					memcpy(c,a4,4);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x10:
					memcpy(a4,c,4);
					p=p+1;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x11:
					memcpy(&buf_dwA,p+1,4);
					memcpy(&buf_dwB,c,4);
					buf_dwB=buf_dwB+buf_dwA;
					memcpy(c,&buf_dwB,4);
					p=p+5;
					if((p-p0)>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x12://a4为偏移,取出给c
					memcpy(&buf_dwA,&a4,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x13://c为偏移,取出给c
					memcpy(&buf_dwA,c,4);
					memcpy(c,p0+buf_dwA,1);
					if(c[0]>=128){
						memset(c+1,0xff,3);
					}
					else{
						memset(c+1,0x0,3);
					}
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x14://取四字节给c		mov c,4字节
						  //				往后移5字节
					memcpy(&buf_dwA,p+1,4);
					memcpy(c,&buf_dwA,4);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x15://取四字节给c		mov a4,4字节
						  //				往后移5字节
					memcpy(&buf_dwA,p+1,4);
					memcpy(a4,&buf_dwA,4);
					p=p+5;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x16://movb [a4],c
						  //后移1字节
					memcpy(&buf_dwA,a4,4);
					memcpy(p0+buf_dwA,c,1);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x17://c=c-a4;
						  //后移1字节
					memcpy(&buf_dwA,c,4);
					memcpy(&buf_dwB,a4,4);
					buf_dwA=buf_dwA-buf_dwB;
					memcpy(c,&buf_dwA,4);
					p=p+1;
					if(p-p0>=length){
						free(p0);
						return 0;
					}
					break;
				case 0x18://cmp 0,c
						  //jz 后移5字节
						  //位移为4字节
					memcpy(&buf_dwA,c,4);
					if(buf_dwA==0){
						p=p+5;
						if(p-p0>=length){
						free(p0);
						return 0;
						}
					}
					else{
						memcpy(&buf_dwB,p+1,4);
						if(buf_dwB>=length){
							free(p0);
							return 0;
						}
						else{
							p=p0+buf_dwB;
						}
					}
					break;
				default:
					break;
			}
		}
	}
	free(p0);
}

另外,网上看了几篇这道题的writeup,里面有提到用pintool解题的,奈何不会用。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值