signal
Start
无壳,直接拖进IDA,F5
qmemcpy()
内存复制,将unk_403040
的内容复制到v4
的地址下
跟进unk_403040
看到一堆数据,整理后得到
[0Ah, 4,10h, 8, 3, 5, 1, 4,20h, 8, 5, 3, 1, 3, 2, 8,0Bh, 1,0Ch, 8, 4, 4, 1, 5, 3, 8, 3,21h , 1,0Bh, 8,0Bh, 1, 4, 9, 8, 3,20h, 1, 2,51h , 8, 4,24h , 1,0Ch, 8,0Bh, 1, 5, 2, 8, 2,25h , 1, 2,36h , 8, 4,41h , 1, 2,20h, 8, 5, 1, 1, 5, 3, 8, 2,25h , 1, 4, 9, 8, 3,20h, 1, 2,41h , 8,0Ch, 1, 7,22h , 7,3Fh , 7,34h , 7,32h , 7,72h , 7,33h , 7,18h, 7,A7h,FFh,FFh,FFh, 7,31h , 7,F1h,FFh,FFh,FFh, 7,28h , 7,84h,FFh,FFh,FFh, 7,C1h,FFh,FFh,FFh, 7,1Eh, 7,7Ah]
之后将该数据传入vm_operad
函数中,并且发现该数组的长度为114.
跟进vm_operad函数
看到关键语句switch_case
, 外面的v4
传入后变成了a1
,通过a1
下的不同值去执行对应的case
。
发现case 7
是对输入的字符串进行验证,然后发现v10
作为索引,初始值为0,也就是说第一次传入的值为0Ah
, 对应case10
case 7:
if ( v4[v8] != a1[v10 + 1] )
{
printf("what a shame...");
exit(0);
}
++v8;
v10 += 2;
break;
该条件下调用了read
函数,参数为v3
case 10:
read(v3);
++v10;
break;
跟进去可以发现,该函数就是输入函数,并将值存储到v3
中,长度为15
size_t __cdecl read(char *a1)
{
size_t result; // eax
printf("string:");
scanf("%s", a1);
result = strlen(a1);
if ( result != 15 )
{
puts("WRONG!\n");
exit(0);
}
return result;
}
之后对case进行分析,可将case分为3类,
第一类:验证case,
case 7:
if ( v4[v8] != a1[v10 + 1] )
{
printf("what a shame...");
exit(0);
}
++v8;
v10 += 2;
break;
这里a1
的值是写死的,说明是对v4
的值的进行验证,也就是说输入的字符串经过一系列操作之后存到了v4
中
第二类:处理字符
case 2:
v5 = a1[v10 + 1] + v3[v9];
v10 += 2;
break;
case 3:
v5 = v3[v9] - LOBYTE(a1[v10 + 1]);
v10 += 2;
break;
case 4:
v5 = a1[v10 + 1] ^ v3[v9];
v10 += 2;
break;
case 5:
v5 = a1[v10 + 1] * v3[v9];
v10 += 2;
break;
case 11:
v5 = v3[v9] - 1;
++v10;
break;
case 12:
v5 = v3[v9] + 1;
++v10;
break;
第三类:其它, 通过之前分析可以知道那段写死的数据并不存在0x06
,并且可以发现case1
就是移动到下一个字符,那么就可以以1
作为分隔符,对那段写死的数据进行整理。case8
就是将运算后的值赋给v3
,因为第一次运算后的值是以v5
当中间变量
case 1:
v4[v7] = v5;
++v10;
++v7;
++v9;
break;
case 6:
++v10;
break;
case 8:
v3[v6] = v5;
++v10;
++v6;
break;
可以发现7
出现了15
次,并且是对数据进行验证,那么7
后面跟着的就是加密后的字符,
再次整理后:
0Ah,
4,10h, 8, 3, 5, 1,
4,20h, 8, 5, 3, 1,
3, 2, 8,0Bh, 1
,0Ch, 8, 4, 4, 1,
5, 3, 8, 3,21h , 1,
0Bh, 8,0Bh, 1,
4, 9, 8, 3,20h, 1,
2,51h , 8, 4,24h , 1,
0Ch, 8,0Bh, 1,
5, 2, 8, 2,25h , 1,
2,36h , 8, 4,41h , 1,
2,20h, 8, 5, 1, 1,
5, 3, 8, 2,25h , 1,
4, 9, 8, 3,20h, 1,
2,41h , 8,0Ch, 1,
7,22h ,
7,3Fh ,
7,34h ,
7,32h ,
7,72h ,
7,33h ,
7,18h,
7,A7h,FFh,FFh,FFh,
7,31h ,
7,F1h,FFh,FFh,FFh,
7,28h ,
7,84h,FFh,FFh,FFh,
7,C1h,FFh,FFh,FFh,
7,1Eh,
7,7Ah
刚好以1结尾的有15个,7开头的有15个
分析case发现,在加密的case中,v5
是作为中间字符的存在,v9
是v3
的下标,v6
也是v3
的下标,所以v9
和v6
这里直接视为同一个,v7
是v4
的下标,但是由于是顺序加密的所以v7
与v6
、v9
的值是相同的
这里会存在0xFFFFFF开头的数据,这里只是自动填充,参与运算的只有低八位,而且v5的宽度也只是八位,所以不影响。
将加密后的数据提取出来得到:
0x22, 0x3F, 0x34, 0x32, 0x72, 0x33, 0x18, 0xA7, 0x31, 0xF1, 0x28, 0x84, 0xC1, 0x1E, 0x7A
将每一个字符要加密的case
和key
分开:
data = [[4, 0x10, 8, 3, 5, 1]
, [4, 0x20, 8, 5, 3, 1]
, [3, 2, 8, 0x0B, 1]
, [0x0C, 8, 4, 4, 1]
, [5, 3, 8, 3, 0x21, 1]
, [0x0B, 8, 0x0B, 1]
, [4, 9, 8, 3, 0x20, 1]
, [2, 0x51, 8, 4, 0x24, 1]
, [0x0C, 8, 0x0B, 1]
, [5, 2, 8, 2, 0x25, 1]
, [2, 0x36, 8, 4, 0x41, 1]
, [2, 0x20, 8, 5, 1, 1]
, [5, 3, 8, 2, 0x25, 1]
, [4, 9, 8, 3, 0x20, 1]
, [2, 0x41, 8, 0x0C, 1]]
尝试了一下,发现逆向写的话比较麻烦,所以这里直接遍历去试出flag
exp.py
encrypts = [0x22, 0x3F, 0x34, 0x32, 0x72, 0x33, 0x18, 0xA7, 0x31, 0xF1, 0x28, 0x84, 0xC1, 0x1E, 0x7A]
data = [[4, 0x10, 8, 3, 5, 1]
, [4, 0x20, 8, 5, 3, 1]
, [3, 2, 8, 0x0B, 1]
, [0x0C, 8, 4, 4, 1]
, [5, 3, 8, 3, 0x21, 1]
, [0x0B, 8, 0x0B, 1]
, [4, 9, 8, 3, 0x20, 1]
, [2, 0x51, 8, 4, 0x24, 1]
, [0x0C, 8, 0x0B, 1]
, [5, 2, 8, 2, 0x25, 1]
, [2, 0x36, 8, 4, 0x41, 1]
, [2, 0x20, 8, 5, 1, 1]
, [5, 3, 8, 2, 0x25, 1]
, [4, 9, 8, 3, 0x20, 1]
, [2, 0x41, 8, 0x0C, 1]]
for_each = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
def encrypted(c, li):
# print(li)
x = 0
while x < len(li):
if li[x] == 2:
c = c + li[x + 1]
x += 2
elif li[x] == 3:
c = c - li[x + 1]
x += 2
elif li[x] == 4:
c = c ^ li[x + 1]
x += 2
elif li[x] == 5:
c = c * li[x + 1]
x += 2
elif li[x] == 11:
c = c - 1
x += 1
elif li[x] == 12:
c = c + 1
x += 1
elif li[x] == 8:
x += 1
elif li[x] == 1:
break
res = c
return res
if __name__ == '__main__':
flag = ''
for x in range(len(encrypts)):
for i in for_each:
tmp = encrypted(ord(i), data[x])
if tmp == encrypts[x]:
flag += i
break
else:
continue
print('flag{%s}' % flag)
# flag{757515121f3d478}