初识虚拟机
当时第一次做这个题目的时候不懂这个奇怪的虚拟机,现在重新捞出来重做了一遍
首先使用普通的IDA7.5 x32会打不开,卡在打开的界面,具体原因可能是某个花指令导致的让IDA控制流分析的时候爆炸?。可以先使用IDA7.5 x64查看下汇编代码,尝试Patch掉一些不正常的代码。
首先是main函数下的经典假跳转,然后就是跳转到指令内部的花指令
发现这个跳转有说法,其实就是内部有inc和dec两个指令构成,非常的巧妙
所以直接Patch掉这一整句jmp指令即可
修复所有这样的花指令之后发现还是无法IDA打开,发现这个函数很奇怪,附近有无法分析的代码
发现就是通过call自己这个小trick来进行跳转,直接patch一下就可,发现可以IDAx32打开了,发现main函数里使用了SEH,用除零异常触发,而逻辑就放在SEH处理函数里面,这导致了IDA F5难以看到,我们直接Patch main函数逻辑,让它直接跳转到SEH处理函数中,就可以F5了。
发现逻辑十分简单,主要是有一个VM函数,我们来分析VM函数
分析虚拟机
大概可以整理一下IDA代码,可以发现这个虚拟机结构体有mem数组还有一个arr数组,然后由ptr1和ptr2来从这两个数组中取数,具体的计算操作发生在arr,还有一个reg的short变量可能用来暂存2字节的数据。
然后似乎这个虚拟机也不是普通的栈结构,这个arr似乎就是个会轮回的数组,和栈似乎没什么关系,具体的计算方式都是输入数据,然后取出开头两位计算之后放入最后一位,然后指针ptr2向前进2位,ptr1进一位,所以ptr2应该是这个数组的头指针,ptr1应该是尾指针。
然后不难想到这个arr数组应该就是用来提供寄存操作,真正算完的结果都得放回mem数组,然后所以这个arr数组应该计算完之后经常保持ptr1==ptr2,不然就很难看。写出解析器,然后开始硬看
char VM_Print(VMState *a1)
{
char result; // al
int v2; // [esp+Ch] [ebp-13Ch]
int v3; // [esp+Ch] [ebp-13Ch]
int v4; // [esp+Ch] [ebp-13Ch]
int v5; // [esp+Ch] [ebp-13Ch]
int v6; // [esp+Ch] [ebp-13Ch]
int v7; // [esp+Ch] [ebp-13Ch]
int v8; // [esp+Ch] [ebp-13Ch]
int v9; // [esp+Ch] [ebp-13Ch]
size_t i; // [esp+E0h] [ebp-68h]
unsigned __int8 v13; // [esp+FBh] [ebp-4Dh]
unsigned __int8 v14; // [esp+107h] [ebp-41h]
unsigned __int8 v15; // [esp+113h] [ebp-35h]
unsigned __int8 v16; // [esp+11Fh] [ebp-29h]
unsigned __int8 v17; // [esp+12Bh] [ebp-1Dh]
int pc; // [esp+134h] [ebp-14h]
pc = 0;
int xx=0;
while ( true )
{
result = a1->opcodes[pc];
if ( !result )
return result;
printf("label_%03d:\n\t",pc);
printf("a1->ptr1%=256;a1->ptr2%=256;\n\t");
switch ( a1->opcodes[pc] )
{
case 0x14u:
printf("a1->arr[a1->ptr1++] = %d;\n",a1->opcodes[pc + 1]); //push IMM
pc += 2;
continue;
case 0x15u:
printf("++a1->ptr2;\n");
++pc;
continue;
case 0x20u:
printf("a1->mem[%d] = a1->arr[a1->ptr2++];\n",a1->opcodes[pc + 1]);
pc += 2;
continue;
case 0x2Au:
printf("a1->arr[a1->ptr1++] = a1->mem[%d];\n",a1->opcodes[pc + 1]);
pc += 2;
continue;
case 0x2Bu:
printf("a1->arr[a1->ptr1++] = a1->mem[a1->arr[a1->ptr2++]];\n");
++pc;
continue;
case 0x2Cu:
printf("tmp = a1->arr[a1->ptr2++];\n");
printf("\ta1->ptr2 %= 256;\n");
printf("\ta1->mem[tmp] = a1->arr[a1->ptr2++];\n");
++pc;
continue;
case 0x30u:
printf("a1->reg = a1->arr[a1->ptr2++] + (a1->reg << 8);\n");
++pc;
continue;
case 0x31u:
printf("a1->arr[a1->ptr1++] = a1->reg % (int)%d;\n",a1->opcodes[pc + 1]);
printf("\ta1->reg /= (int)%d;\n",a1->opcodes[pc + 1]);
pc += 2;
continue;
case 0x32u:
printf("a1->arr[a1->ptr1++] = table[a1->arr[a1->ptr2++]];\n");
++pc;
continue;
case 0x33u:
printf("tmp = a1->arr[a1->ptr2++];\n");
printf("\ta1->ptr2 %= 256;\n");
printf("\ta1->arr[a1->ptr1++] = a1->arr[a1->ptr2++] + tmp;\n");
++pc;
continue;
case 0x34u:
printf("tmp = a1->arr[a1->ptr2++];\n");
printf("\ta1->ptr2 %= 256;\n");
printf("\ta1->arr[a1->ptr1++] = a1->arr[a1->ptr2++] - tmp;\n");
++pc;
continue;
case 0x35u:
printf("tmp = a1->arr[a1->ptr2++];\n");
printf("\ta1->ptr2 %= 256;\n");
printf("\ta1->arr[a1->ptr1++] = a1->arr[a1->ptr2++] * tmp;\n");
++pc;
continue;
case 0x36u:
printf("a1->arr[a1->ptr1++] = a1->reg;\n");
printf("\ta1->reg = 0;\n");
++pc;
continue;
case 0x37u:
printf("tmp = a1->arr[a1->ptr2++];\n");
printf("\ta1->ptr2 %= 256;\n");
printf("\ta1->arr[a1->ptr1++] = a1->arr[a1->ptr2++] ^ tmp;\n");
++pc;
continue;
case 0x3Au:
printf("a1->arr[a1->ptr1++] = strlen((char*)a1->your_input);\n");
++pc;
continue;
case 0x40u:
xx=a1->opcodes[pc + 1];
printf("if(a1->arr[a1->ptr2++]) {goto label_%03d;}\n",pc - xx);
pc += 2;
continue;
case 0x41u:
printf("for (int i = 0; i < strlen((const char *)a1->your_input); ++i )\n\t{\n\t\ta1->arr[a1->ptr1++] = a1->your_input[i];\n\t\ta1->ptr1 %= 256;\n\t}\n\tmemset(a1->your_input, 0, 0x200u);\n");
++pc;
continue;
case 0xABu:
printf("return 1;");
return 1;
case 0xFFu:
printf("if ( a1->arr[a1->ptr2++] ) {return 0;}\n");
++pc;
continue;
default:
return 2;
}
}
}
就按照这种方法慢慢分析最后可以还原出具体算法,就是先base58然后进行一个for循环加密。最后有一个一个个字节比较的过程,dump出数据即可一条龙解出。
for(int i = 0,i<30,i+=3)
{
mem[0x40+i+1] = mem[0x40+i+1]+mem[0x40+i+0];
mem[0x40+i+2] = mem[0x40+i+2]-mem[0x40+i+1];
mem[0x40+i+0] = mem[0x40+i+0]^mem[0x40+i+2];
}