这个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解题的,奈何不会用。。