D0g3比赛平台 re wp

最近几天都在看题吧,xctf和极客巅峰都看了看,xctf做了一道re签到题,学了点x64汇编,后面的两道题大概尽量分析了下,对win32窗口和动调更熟悉了。极客巅峰的话做了一道re签到题,rc4+xxtea的apk,给了x86的so文件就是香。maze逻辑倒是不难,就是不会写脚本,用pexpect模块写交互或者用pwn交互,准备后面注重写代码能力,学习数据结构。

XCTF-CyBRICS 2021 Listing

asm,64位汇编,AVX2指令,直接看是可以看懂逻辑的,但是由于对64位汇编了解太少,不知道具体过程(什么顺序放入的256bit寄存器),后来一想,可以直接放到x64dbg里面调呀,直接就把指令随便弄到一个exe里面了(64位内敛汇编还不知道怎么弄)。

直接上图

有个指令需要说一下,vpshufb,相当于就是换位置,类似下面的过程,只不过是256bit。

写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 'D1 D3 76 23 35 61 9A AB D5 D5 23 27 35 65 83 F8 C9 D3 61 27 33 6C 85 B9 D5 D6 22 71 31 61 CB F8'
# '83f865352327d5d59aab35617623d1d3 cbf861312271d5d685b9336c6127c9d3'
# str = "010003020504070609080B0A0C0D0F0E 111013121514171619181B1A1C1D1F1E"

import binascii
def hex_to_str1(s):
s = binascii.unhexlify(s)
return s.decode('utf-8')

a = (0x83f865352327d5d59aab35617623d1d3cbf861312271d5d685b9336c6127c9d3 ^ 0xFECA50051345B0B0FECA50051345B0B0FECA50051345B0B0FECA50051345B0B0)
# 7d32353030626565646165646566616335323134313465667b73636972627963
s = hex_to_str1('7d32353030626565646165646566616335323134313465667b73636972627963')
s = s[::-1]
print(s)
for i in s:
print(hex(ord(i)).replace("0x", ""), end=" ")
#cybrics{fe414125cafedeadeeb0052}

极客巅峰 medical_app

3血,apk,so层的chr是检测函数,rc4+改dealt的xxtea,题很简单主要是说说怎么调so文件,由于设备有限,只能用模拟器调调x86的so文件。参考文章https://www.cnblogs.com/ddms/p/8820044.htmlhttps://blog.csdn.net/freeking101/article/details/106701908

1.打开雷电模拟器,这道题比较特别,屏幕大小设置成1600*900才打得开这个apk。

2.用https://www.cnblogs.com/ddms/p/8820044.html文章中的方法,向模拟器中传入android_x86_server。

android_server,和android_server64是真机用的,android_x86_server,和android_x64_server是模拟器用的。

3.用adb链接模拟器。

adb kill-server 这句的意思是终止adb服务

adb devices 意思是查看现在所连接的设备 如果adb服务没开会帮你打开

adb shell 就是拿到设备的shell了

adb forward tcp:23946 tcp:23946 端口转发

4.打开ida,Debugger->Attach->Remote Linux debugger,写本地ip,127.0.0.1,然后ok。选择好要链接的名称,找到so文件名称,找到函数,打断点,f9,然后在模拟器中输入字符串,就发现断了下来。

之前失败的原因是设备对应不上或者是debugger选择错了,真机和模拟器是有区别的,题可能会给4个so文件,就是对应了不同的架构,但是一般都只给一个arm64-v8a,要用root真机。。。。

x86  32位 android_x86_server   Remote Linux debugger 32位模拟器

x86_64 64位 android_x32_server Remote Linux debugger 64位模拟器

armeabi-v7a 32位 android_server  Remote ARM Linux/Android debuggber 32位真机

arm64-v8a 64位 android_server64 Remote ARM Linux/Android debuggber 64位真机

直接上解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

//xxtea
#include<stdio.h>
void decrypt(unsigned int *code ,unsigned int *key ,unsigned int n)
{
unsigned int next,end,sum;
unsigned int rounds,e,delta=0x9F5776B6;
int i;

rounds=6+52/n;
sum=delta*rounds;
next=code[0];//设置next为code的第一个
do
{
e=(sum>>2)&3;
for(i=n-1;i>0;i--)//解密最后一个到第二个
{
end=code[i-1];
code[i]-=(( (end>>5^next<<2) + (next>>3^end<<4) ) ^ ( (sum^next) + (key[(i&3)^e]^end) ))&0xffffffff;
next=code[i];
}
end=code[n-1];
code[0]-=(( (end>>5^next<<2) + (next>>3^end<<4) ) ^ ( (sum^next) +(key[i&3^e]^end) ))&0xffffffff;
next=code[0];
sum-=delta;
}while(--rounds);
}
int main()
{
unsigned int key[4]={0x00000001,0x00000010,0x00000100,0x00001000};
unsigned int n=9;
int i;
unsigned int code[9]={0x68e5973e,0xc20c7367,0x98afd41b,0xfe4b9de2,0x01a5b60b,0x3d36d646,0xdbcc7baf,0xa0414f00,0x762ce71a};
decrypt(code,key,n);
for(i=0;i<9;i++)
{
//printf("0x%x,",code[i]);
//printf("0x%x,0x%x,0x%x,0x%x,",*((char*)&code[i]+3)&0xff,*((char*)&code[i]+2)&0xff,*((char*)&code[i]+1)&0xff,*((char*)&code[i]+0)&0xff);

printf("0x%x,0x%x,0x%x,0x%x,",*((char*)&code[i]+0)&0xff,*((char*)&code[i]+1)&0xff,*((char*)&code[i]+2)&0xff,*((char*)&code[i]+3)&0xff);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

//rc4
#include<stdio.h>
#include<string.h>
typedef unsigned longULONG;

/*初始化函数*/
void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i<256; i++)
{
s[i] = i;//做一道re的题时这里就改为了,s[i]=256-i
k[i] = key[i& 0xF];
}
for (i = 0; i<256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];//交换s[i]和s[j]
s[j] = tmp;
}
}

/*加解密*/
void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k<36; k++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];//交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
printf("0x%x,",s[t]);
Data[k] ^= s[t];
}
}

int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 };//S-box
char key[256] = { 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00};
char pData[512] = {0x56,0x4,0xb0,0xd4,0x9c,0x63,0x4d,0x30,0x96,0xce,0xc0,0x5,0x93,0xbe,0x3b,0x82,0x52,0x4b,0x16,0xb2,0x8a,0x33,0xb7,0x4d,0x6d,0x7b,0x99,0x50,0xc2,0xb1,0xc,0x12,0xe1,0x84,0xa,0x93};
unsigned long len = strlen(pData);
int i;

rc4_init(s, (unsigned char*)key, 16);

for (i = 0; i<256; i++)
{
s2[i] = s[i];
}
rc4_crypt(s2, (unsigned char*)pData, len);//解密
printf("pData=%s\n\n", pData);
}
//flag{194836950ae9df840e8a94348b901a}

极客巅峰 easymaze

学了数据结构dfs,现在照着学长的思路回来做做,我用的是pwn库交互,学长用的pexpect

将成功判断都改为”1”

exp,python的二维数组真的坑,看了几个小时,发现是二维数组定义错了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

from pwn import *
io = process('./maze1')
next = [[1, 0], [0, -1],[0, 1], [-1, 0]]
way = "SADW"
back = {'W': 'S', 'S': 'W', 'A': 'D', 'D': 'A'}
ans = ''
flag = [0] * 1000


def putstr(a):
ans = ''
for i in a:
if (i == 0):
break
ans += i
print(ans)


def dfs(x, y, step):
putstr(flag)
for i in range(4):
xnew = x + next[i][0]
ynew = y + next[i][1]
flag[step] = way[i]
flag[step+1] = 0

if (maze[xnew][ynew] == 1 or mark[xnew][ynew]==1):#如果该方向为墙或者已经走过,直接下一轮循环。
continue
io.sendline(way[i])#发送当前循环的方向
ans = io.readline()#得到反馈字符串
if (ans == b'1\n'):#如果是正确方向
maze[xnew][ynew] = 0
mark[x][y] = 1#标记旧位置,防止回走
dfs(xnew, ynew, step + 1)
io.sendline(back[way[i]])#如果该路尽头走不通,开始回走,直到找到有多个方向的那个节点。因为迷宫可能有多条路线,某些路线是错的,而且这个程序走错是不会改变位置的,回走就会改变位置,所以回走时要反方向sendline
io.readline()#将回走的反馈接收
mark[x][y] = 0#重新标记为0
elif(ans[0:4]==b"Good"):#终点判定
print("success",end=':')
putstr(flag)
else:
maze[xnew][ynew] = 1#将该方向判定为墙

maze = [[0 for i in range(1000)] for j in range(1000)]#初始化迷宫地图
mark = [[0 for i in range(1000)] for j in range(1000)]#初始化走过的地方,注意这只是一条路线,不包括错误路线,若想要知道所有走过的地方,可再添加一个二维数组。
io.recvuntil("This is the beginning. You can only go south.\n")
dfs(3, 3, 0)#避免边界,可以从偏中间的位置开始,只不过出题人也考虑了的,从左上开始走是没有问题的。

极客巅峰 so get

一道web&re,当时队友getshell后的文件没给对,哈哈,后面看师傅的wp才知道是哪几个文件,看来得学点web了。。。大概就是用aes加密了php文件,这种加密php,记得一个老师傅还做过讲解。

easy re

ida看看逻辑,就是基础的操作

z3来解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

code=[ 0x1B, 0x18, 0x68, 0x5F, 0x34, 0x1B, 0x2D, 0x37, 0x3A, 0x4C,
0x63, 0x0F, 0x3A, 0x04, 0x32, 0x0A, 0x42]
tmp=[1]*17
len=len(code)
#101 01110 010 11011 110 10001
#010 01110 110 11011 101 10001
from z3 import *
s = Solver()
flag = [BitVec('flag[%d]' % i, 8) for i in range(17)]
for i in range(len):
tmp[i]=flag[(i + 1) % len] & 0xE0 | flag[i % len] & 0x1F
for j in range(len):
tmp[j] = tmp[(j + 1) % len] ^ tmp[j % len]
for i in range(len):
s.add(tmp[i]==code[i])

if s.check() == sat:
model = s.model()
str = [chr(model[flag[i]].as_long().real) for i in range(17)]
print("".join(str))
exit()
else:
print("no_sat")
#D_GO0d_Re_s0_EasY

c语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include<stdio.h>

int main()
{
char a[]={0x1B, 0x18, 0x68, 0x5F, 0x34, 0x1B, 0x2D, 0x37, 0x3A, 0x4C,
0x63, 0x0F, 0x3A, 0x04, 0x32, 0x0A, 0x42};
char tmp;
int i;
for(i=16;i>=0;i--)
{
a[i]=a[i]^a[(i+1)%17];
}
tmp=a[16];
for(i=16;i>0;i--)
{
a[i]=a[(i-1)]&0xE0 | a[i]& 0x1F;
}
a[0]=a[0]& 0x1F|tmp&0xE0;
for(i=0;i<17;i++)
{
printf("%c",a[i]);
}
}
//D_GO0d_Re_s0_EasY

basebase

签到题,变表base

1
2
3
4
5
6
7

str1 ='h31DcTJ2d3d5nPoQnSAAnQBel4lihldkikV78nQ='
string1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))
#D0g3{B43E_64_i$_INTERESTING!}

junkcode

这道题,出题人插入了一些汇编,影响了程序逻辑,f5的逻辑是错的,直接撸汇编,看加密过程。

写脚本

1
2
3
4
5
6
7
8
9

s='abcdefghijklmnopqrstuvwxyz'
a=[ 0x25, 0x4C, 0x00, 0x57, 0x1E, 0x0E, 0x22, 0x08, 0x12, 0x25,
0x2C, 0x52, 0x21, 0x23, 0x2C, 0x5D, 0xE2, 0xCD, 0xC4, 0xDB,
0xC2, 0xDB, 0x93, 0xB3, 0xF0, 0xF7]
for i in range(0,26):
print(chr((((ord(s[i])+i))^a[i])+i),end='')

D0g3{jUnk_c0de_1s_So_e4Sy}

funny

apk,jeb打不开,不知道是不是设置了什么,但是可以通过分析解压后的class.dex来看加密逻辑,发现是flag先异或后bit位操作,然后加上md5加密flag组成的字符串。


解包指令java -jar .\apktool_2.3.0.jar d .\app-debug.apk -o QKSword,查看id发现,对应名称为v,然后找到字符串v=”vNIfOQtJIkznEF7117D32B97D82C0607A3A06E7C78C6”

再来看加密函数

了解了加密函数后,通过密文可知道flag有12位,格式又是D0g3{},如果采用爆破来解的话就只用爆破6个字符。但是由于之前做的时候没意识到那个表有多义性,用z3试了试,没解出来,后来发现有多义性后,懒得写md5爆破,就将就了z3,一个一个字符爆嘛,没爆出来就换下表里面的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#D0g3{}
code='vNIfOQtJIkzn'
xor=[45, 13, 55, 71, 94, 9, 4, 80, 60, 71, 11, 54, 0x76, 93]
code1=[116,94,40,58,82,33,26,18,40,59,114,101]#最后发现这个表是对的。
table=['c', 'Z', 'Q', 'X', 'A', 'i', 'i', 'K', 'z', 'q', 'l', 'B', 'j', 'M', 'Y', 'R', 'S', 'C', 'J', 'o', 'o', 'L', 'K', 'n', 'K', 'C', 't', 'a', 'h', 'Z', 'w', 'm', 'l', 'Q', 'H', 'g', 'i', 'a', 'R', 'C', 'I', 'B', 'u', 'S', 'M', 'c', 'x', 'D', 'M', 'h', 'p', 'D', 'm', 'T', 'P', 'n', 'T', 'g', 'f', 'k', 'b', 'F', 'L', 'R', 't', 'q', 'A', 'z', 'E', 's', 'l', 'T', 'P', 'X', 'E', 'j', 'n', 'M', 'P', 'B', 'y', 'q', 'O', 'n', 'F', 'j', 'j', 'e', 'm', 'g', 'F', 's', 'p', 'E', 'N', 'z', 'H', 'C', 'Y', 'W', 'l', 'n', 'S', 'd', 'g', 'd', 'L', 'p', 'J', 'h', 'i', 'M', 'r', 'P', 'z', 'v', 'v', 'C', 'e', 'p', 'M', 'r', 'p', 'Z', 'P', 'w', 'q', 'i', 'I', 'b', 'V', 'H', 'C', 'N', 'p', 'u', 'w', 'A', 'B', 'e', 'J', 'k', 'I', 'k', 'T', 'k', 'I', 'B', 'Y', 'p', 'O', 'C', 'c', 's', 'C', 'k', 'Z', 'u', 'O', 'n', 'Z', 'M', 'b', 'p', 'z', 'D', 'g', 's', 'b', 'q', 'l', 'O', 'T', 'A', 'j', 's', 'q', 'm', 'E', 'g', 't', 'V', 'e', 'L', 'A', 'b', 'N', 'k', 'Z', 'q', 'V', 'v', 's', 'J', 'L', 'h', 'k', 'Q', 'o', 'J', 'u', 'r', 'N', 'E', 'e', 'x', 'c', 'e', 'S', 'q', 'z', 'y', 'e', 'S', 'w', 'W', 'J', 'o', 'u', 'j', 'l', 'd', 's', 'Q', 'g', 'h', 'W', 'P', 'k', 'Y', 'h', 'c', 'C', 'A', 'V', 'L', 'N', 'C', 'y', 'L', 'b', 'W', 'i', 'u', 'h', 'U', 'i', 'p', 'T', 'f', 'I', 'i', 'u', 'q', 'O', 'K']
tmp=[0]*12
len=len(xor)
# for i in range(12):
# print(i,end=': ')
# for j in range(256):
# if(code[i]==table[j]):
# print(j,end=',')
# print(end=' ')
#
# tab='0: 115,116,191, ' \
# '1: 94,133,186,202,236, ' \
# '2: 40,128,142,146,250, ' \
# '3: 58,249, ' \
# '4: 82,150,158,171,254, ' \
# '5: 2,33,197,223, ' \
# '6: 26,64,180, ' \
# '7: 18,108,140,193,199,216, ' \
# '8: 40,128,142,146,250, ' \
# '9: 59,141,143,145,155,187,196,228, ' \
# '10: 8,67,95,114,164,210, ' \
# '11: 23,55,76,83,101,159, 80'


from z3 import *
s = Solver()
flag = [BitVec('flag[%d]' % i, 8) for i in range(12)]#手动从0~12,满足输出字符是比较舒服的字符就行。
for i in range(12):
tmp[i]=(flag[i]^xor[i % len])&0xff
for i in range(12):
tmp[i]=(tmp[i] >> 7 << 1 | tmp[i] & 1) * 0x40 + ((tmp[i] & 0x7E) >> 1)
for i in range(12):
s.add(tmp[i]==code1[i])

if s.check() == sat:
model = s.model()
str = [chr(model[flag[i]].as_long().real) for i in range(12)]
print("".join(str))
exit()
else:
print("no_sat")
#D0g3{K0tl1n}

当然,这肯定不是出题人想要的,而且如果字符多一点也没法这样做,所以还是得正常md5爆破。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

import hashlib
code='vNIfOQtJIkzn'
xor=[45, 13, 55, 71, 94, 9, 4, 80, 60, 71, 11, 54, 0x76, 93]
code1=[116,94,40,58,82,33,26,18,40,59,114,101]
table=['c', 'Z', 'Q', 'X', 'A', 'i', 'i', 'K', 'z', 'q', 'l', 'B', 'j', 'M', 'Y', 'R', 'S', 'C', 'J', 'o', 'o', 'L', 'K', 'n', 'K', 'C', 't', 'a', 'h', 'Z', 'w', 'm', 'l', 'Q', 'H', 'g', 'i', 'a', 'R', 'C', 'I', 'B', 'u', 'S', 'M', 'c', 'x', 'D', 'M', 'h', 'p', 'D', 'm', 'T', 'P', 'n', 'T', 'g', 'f', 'k', 'b', 'F', 'L', 'R', 't', 'q', 'A', 'z', 'E', 's', 'l', 'T', 'P', 'X', 'E', 'j', 'n', 'M', 'P', 'B', 'y', 'q', 'O', 'n', 'F', 'j', 'j', 'e', 'm', 'g', 'F', 's', 'p', 'E', 'N', 'z', 'H', 'C', 'Y', 'W', 'l', 'n', 'S', 'd', 'g', 'd', 'L', 'p', 'J', 'h', 'i', 'M', 'r', 'P', 'z', 'v', 'v', 'C', 'e', 'p', 'M', 'r', 'p', 'Z', 'P', 'w', 'q', 'i', 'I', 'b', 'V', 'H', 'C', 'N', 'p', 'u', 'w', 'A', 'B', 'e', 'J', 'k', 'I', 'k', 'T', 'k', 'I', 'B', 'Y', 'p', 'O', 'C', 'c', 's', 'C', 'k', 'Z', 'u', 'O', 'n', 'Z', 'M', 'b', 'p', 'z', 'D', 'g', 's', 'b', 'q', 'l', 'O', 'T', 'A', 'j', 's', 'q', 'm', 'E', 'g', 't', 'V', 'e', 'L', 'A', 'b', 'N', 'k', 'Z', 'q', 'V', 'v', 's', 'J', 'L', 'h', 'k', 'Q', 'o', 'J', 'u', 'r', 'N', 'E', 'e', 'x', 'c', 'e', 'S', 'q', 'z', 'y', 'e', 'S', 'w', 'W', 'J', 'o', 'u', 'j', 'l', 'd', 's', 'Q', 'g', 'h', 'W', 'P', 'k', 'Y', 'h', 'c', 'C', 'A', 'V', 'L', 'N', 'C', 'y', 'L', 'b', 'W', 'i', 'u', 'h', 'U', 'i', 'p', 'T', 'f', 'I', 'i', 'u', 'q', 'O', 'K']
tmp=[0]*12
len=len(xor)
table1 = [[] for i in range(12)]
for i in range(12):
for j in range(256):
if(code[i]==table[j]):
if(j<=128):
tmp1=((j&0x3f)<<1)&0xff
tmp2=((((j&0x3f)<<1))+1)&0xff
table1[i].append(tmp1 ^ xor[i] & 0xff)
table1[i].append(tmp2^xor[i]&0xff)
#生成爆破表,由于不可逆,所以将两种情况都包括了。
for a in table1[5]:
for b in table1[6]:
for c in table1[7]:
for d in table1[8]:
for e in table1[9]:
for f in table1[10]:
str1 = 'D0g3{'+chr(a)+chr(b)+chr(c)+chr(d)+chr(e)+chr(f)+'}'
flag = hashlib.md5(str1.encode('utf-8')).hexdigest()
if flag[0:32] == "EF7117D32B97D82C0607A3A06E7C78C6".casefold():
print(str1, end='')
#D0g3{K0tl1n}

random

考点,Debug Blocker,双进程保护,win32知识,类似于mrctf的一道题。查windows api的网站http://www.yfvb.com/help/win32sdk/https://docs.microsoft.com/en-us/search/

去花后,分析主函数

对于双进程保护,两种处理方法,https://blog.csdn.net/qq_39249347/article/details/108579376

  • 静态方法,父进程对子进程处理解密后(有些子进程的代码可能是被加密的),直接将ip跳到子进程,调试子进程。
  • 动态方法,比较麻烦,要改汇编这些什么的,让父进程和子进程断开,将我们的调试器和子进程连起来。

这里就采用第一种方法直接在3E1736地址set ip,动调出逻辑。

然后true_main主要分为4步

1.通过rand(),生成16个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

srand((unsigned __int8)v59[0]);
v3 = 16;
do
{
v4 = rand();
v6 = v61;
v67[0] = v4;
if ( v61 >= v62 )
{
LOBYTE(Src) = 0;
sub_3E1E30(v60, v5, (int)Src, v67[0]);
}
else
{
v7 = v60;
if ( v62 >= 0x10 )
v7 = (void **)v60[0];
++v61;
*((_BYTE *)v7 + v6) = v67[0];
*((_BYTE *)v7 + v6 + 1) = 0;
}
--v3;
}
while ( v3 );

2.将flag前16个和rand()的16个数异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

while ( 1 )
{
v9 = v60;
v10 = v60;
if ( v62 >= 0x10 )
v9 = (void **)v60[0];
v11 = v60;
if ( v62 >= 0x10 )
{
v11 = (void **)v60[0];
v10 = (void **)v60[0];
}
v12 = (char *)v9 + v8;
v13 = v60;
if ( v62 >= 0x10 )
v13 = (void **)v60[0];
v67[0] = (*((_BYTE *)v11 + v8 + 32) ^ *((_BYTE *)v10 + v8)) & ~(*v12 & *((_BYTE *)v13 + v8 + 32));
if ( *(_DWORD *)v66 >= v65 )
{
LOBYTE(Src) = 0;
sub_3E1E30(v63, *(int *)v66, (int)Src, v67[0]);
}
else
{
v64 = *(_DWORD *)v66 + 1;
v14 = v63;
if ( v65 >= 0x10 )
v14 = (void **)v63[0];
v15 = (char *)v14 + *(_DWORD *)v66;
v16 = v67[0];
v15[1] = 0;
*v15 = v16;
}
if ( ++v8 >= 16 )
break;
*(_DWORD *)v66 = v64;
}

3.flag后16位和原flag前16位异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

for ( i = 16; i < 32; ++i )
{
v18 = v60;
v19 = v60;
if ( v62 >= 0x10 )
v18 = (void **)v60[0];
v20 = v60;
if ( v62 >= 0x10 )
{
v20 = (void **)v60[0];
v19 = (void **)v60[0];
}
v21 = (char *)v18 + i;
v22 = v60;
if ( v62 >= 0x10 )
v22 = (void **)v60[0];
v23 = *v21 & *((_BYTE *)v22 + i - 16);
v24 = v64;
v66[0] = (*((_BYTE *)v20 + i - 16) ^ *((_BYTE *)v19 + i)) & ~v23;
if ( v64 >= v65 )
{
LOBYTE(Src) = 0;
sub_3E1E30(v63, v64, (int)Src, v66[0]);
}
else
{
++v64;
v25 = v63;
if ( v65 >= 0x10 )
v25 = (void **)v63[0];
v26 = (char *)v25 + v24;
v27 = v66[0];
v26[1] = 0;
*v26 = v27;
}
}

4.和key[32]相减

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

for ( j = 0; j < 8; ++j )
{
v29 = v63;
if ( v65 >= 0x10 )
v29 = (void **)v63[0];
LOBYTE(v29[j]) -= byte_3E6038[j * 4];
v30 = v63;
if ( v65 >= 0x10 )
v30 = (void **)v63[0];
BYTE1(v30[j]) -= byte_3E6039[j * 4];
v31 = v63;
if ( v65 >= 0x10 )
v31 = (void **)v63[0];
BYTE2(v31[j]) -= byte_3E603A[j * 4];
v32 = v63;
if ( v65 >= 0x10 )
v32 = (void **)v63[0];
HIBYTE(v32[j]) -= byte_3E603B[j * 4];
}

要解这道题呢,由于我们知道flag格式D0g3{},我们就可以通过爆破seed,也就是我们guess的数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

//flag{101010101010194836950ae9df}
//D0g3{c97d0d4cd003451c4c95ce9a5f}
#include<stdio.h>
#include<stdlib.h>
void random(unsigned char send,unsigned char Xor[])
{
int i ;
srand((unsigned __int8)send);
for(i=0;i<16;i++)
{
Xor[i]=rand()&0xff;
}
}
int main()
{
char key[]={0x13, 0x09, 0x0A, 0x20, 0x98, 0x42, 0x8F, 0x82, 0x1C, 0x37,
0xA9, 0xCB, 0xFD, 0xE5, 0x30, 0x03, 0x6E, 0xBF, 0x9D, 0x4C,
0x61, 0xFE, 0x14, 0xCD, 0xAB, 0x38, 0xA2, 0xF0, 0x62, 0x34,
0xC3, 0xCC};
char code[]={
0x2F, 0x1E, 0x76, 0xF3, 0x7A, 0x3F, 0x4F, 0x8D, 0x56, 0xD7,
0xE2, 0x70, 0x69, 0x46, 0x21, 0x39, 0x09, 0x45, 0xB5, 0xB6,
0xB7, 0x59, 0x46, 0x41, 0xA6, 0x1B, 0x5F, 0x1D, 0xA0, 0x1D,
0x93, 0x81};
unsigned char Xor[16]={};
int send;
int i;

for(i=0;i<32;i++)
{
code[i]=(key[i]+code[i])&0xff;
}
for(send=0;send<255;send++)
{
random(147,Xor);//爆破出来seed是147
//printf("%d: ",send);
for(i=0;i<16;i++)
{
code[i]=code[i]^Xor[i];
//printf("%c",code[i]);
}
//printf("\n");
}
for(i=16;i<32;i++)
{
code[i]=code[i]^code[i-16];
}
printf("%s",code);
}
//D0g3{c97d0d4cd003451c4c95ce9a5f}