0x00 查壳
首先拿到的是一个exe文件,所以先查壳,然后看看是32位还是64位的程序
32位的程序,无壳。进入IDA分析:
0x01 IDA分析
很容易就找到mian函数,逻辑简单,就一个函数。直接进入函数分析:
int __cdecl vm_operad(int *a1, int a2)
{
int result; // eax
char v3[100]; // [esp+13h] [ebp-E5h]
char v4[100]; // [esp+77h] [ebp-81h]
char v5; // [esp+DBh] [ebp-1Dh]
int v6; // [esp+DCh] [ebp-1Ch]
int v7; // [esp+E0h] [ebp-18h]
int v8; // [esp+E4h] [ebp-14h]
int v9; // [esp+E8h] [ebp-10h]
int v10; // [esp+ECh] [ebp-Ch]
v10 = 0;
v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
while ( 1 )
{
result = v10;
if ( v10 >= a2 )
return result;
switch ( a1[v10] )
{
case 1: // 调用到1的时候就完成一个v4值得产生
v4[v7] = v5;
++v10;
++v7;
++v9;
break;
case 2:
v5 = a1[v10 + 1] + v3[v9]; // a1当前值得下一个值与v3当前值的和
v10 += 2;
break;
case 3:
v5 = v3[v9] - LOBYTE(a1[v10 + 1]); // v3的当前值减去a1下一个值
v10 += 2;
break;
case 4:
v5 = a1[v10 + 1] ^ v3[v9]; // 异或
v10 += 2;
break;
case 5:
v5 = a1[v10 + 1] * v3[v9]; // 相乘
v10 += 2; // 2,3,4,5下的运算,均为v10 += 2,既他们下一个的数的值即使在运算步骤的取值范围内,也不作为运算步骤
break;
case 6:
++v10;
break;
case 7:
if ( v4[v8] != a1[v10 + 1] ) // 之前产生的v4的值和a1中为7的值的下一个值比较
{
printf("what a shame...");
exit(0); // 不同则停止程序
}
++v8;
v10 += 2;
break;
case 8:
v3[v6] = v5; // 将当前运算的暂时的结果覆盖到当前的v3进行接来下的运算,直到调用1,产生新的v4,取下一个v3进入运算
++v10;
++v6;
break;
case 10:
read(v3); // 写入v3,既将input传入v3
++v10;
break;
case 11:
v5 = v3[v9] - 1; // 减1
++v10;
break;
case 12:
v5 = v3[v9] + 1; // 加1
++v10;
break;
default: // 大于12的值不作为运算方法,但参与其他的的运算的调用。
continue;
}
}
}
通过分析read函数可知,输入的字符长度为15个
在main函数中可知,vm_operad函数的a1是传入的v4,而v4则是cpy的dword_403040。所以我们直接查看dword_403040的值:
将数据提取出来然后处理一下:
10, //输入
4,16,8,3,5,1, //第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, //第8个数
12,8,11,1,
5,2,8,2,37,1,
2,54,8,4,65,1,
2,32,8,5,1,1, //第一个1它前面是5,所以它没有被调用,后面的1才产生了一个v4
5,3,8,2,37,1,
4,9,8,3,32,1,
2,65,8,12,1, //第15个数
7,34,7,63,7,52,7,50,7,114,7,51,7,24,7,-89,7,49,7,-15,7,40,7,-124,7,-63,7,30,7,122 //15次效验
0x02 exp
exp1
起初是写了一个爆破的exp,因为当时没有弄的太明白:
#include<stdio.h>
#include<string.h>
#include<windows.h>
char a1[] = {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,0};
unsigned char a2[] = {34,63,52,50,114,51,24,-89,49,-15,40,-124,-63,30,122,0};
int v10 = 0,v8 = 0,v7 = 0,v9 = 0,v6 = 0;
unsigned char v5,flag;
int crypt(int F,int S){
v10 = S;
while(1){
switch ( a1[v10] ){
case 0:
exit(0);
case 1:
return v5;
case 2:
v5 = a1[v10 + 1] + F;
v10 += 2;
break;
case 3:
v5 = F - (a1[v10 + 1]);
v10 += 2;
break;
case 4:
v5 = a1[v10 + 1] ^ F;
v10 += 2;
break;
case 5:
v5 = a1[v10 + 1] * F;
v10 += 2;
break;
case 6:
++v10;
break;
case 7:
v10 += 2;
break;
case 8:
F = v5;
++v10;
break;
case 10:
++v10;
break;
case 11:
v5 = F - 1;
++v10;
break;
case 12:
v5 = F + 1;
++v10;
break;
default:
continue;
}
}
}
int main(){
int V10 = 0 ,i = 0;
while(1){ //硬爆破,唉,就是玩!
for(flag = 1;flag<=122;flag++){
int Crypt = crypt(flag,V10);
if(Crypt == a2[i]){
printf("%c",flag);
i++;
for(V10;a1[V10] != 1;V10++);
V10++; //匹配一个值进入下一个值的操作数段开头
if(a1[V10] == 1) //两个1的地方,往后跳一下
V10++;
}
}
}
}
exp2
边写笔记边把自己给弄明白了,同时也是为了更好的理解这个题,所以这里又写了一个逆算法和过程的exp:
#include<stdio.h>
#include<string.h>
char a1[] = {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,0};
unsigned char a2[] = {34,63,52,50,114,51,24,-89,49,-15,40,-124,-63,30,122,0};
int v10 = strlen(a1) - 1,v8 = 14,v7 = 0,v9 = 15,v6 = 0;
unsigned char v5 = 0,flag[16];
int main(){
memset(flag,0,16);
while(v10 >= 0){
if(a1[v10-1] <= 5 && a1[v10-1] >= 2){ //这里是跳过非操作数,选出操作步骤
if(a1[v10-2] <= 5 && a1[v10-2] >= 2);
else
v10 --;
}
switch ( a1[v10] ){
case 1:
v5 = a2[v8];
v9--;
v8--;
v10--;
break;
case 2:
flag[v9] = v5 - a1[v10 + 1];
v10--;
break;
case 3:
flag[v9] = v5 + (a1[v10 + 1]);
v10--;
break;
case 4:
flag[v9] = a1[v10 + 1] ^ v5;
v10--;
break;
case 5:
flag[v9] = v5 / a1[v10 + 1];
v10--;
break;
case 6:
--v10;
break;
case 8:
v5 = flag[v9];
--v10;
break;
case 10:
printf("%s",flag);
--v10;
break;
case 11:
flag[v9] = v5 + 1;
--v10;
break;
case 12:
flag[v9] = v5 - 1;
--v10;
break;
default:
v10 -= 1;
break;
}
}
}