​ 因为最近要给校队出题,本来出web,有个同学安排的re,但是他没学过,想和我换,虽然之前没系统接触过re,但是在学pwn的过程中也了解基本的逆向,就和他换了,借此机会简单学学逆向题目的思路.

​ 先来看这个社团ctf竞赛的题目,能够对逆向有个基本的认知,大概就是给你一个编译好了的二进制文件,反汇编反编译后得到伪代码,然后梳理伪代码的逻辑,去逆算法等,找到一个正确的输入值,从而或者输出值(flag)

​ 例如下面这个例子,需要你输入flag,然后和正确的flag进行对比,对比正确则成功

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
#include <stdio.h>

int check_flag(char flag[]);

int main()
{
char flag[30];
printf("输入的flag为:");
fgets(flag,30,stdin);
check_flag(flag);
return 0;
}

int check_flag(char flag[])
{
if(flag[0] == 'f')
{
if(flag[1] == 'l')
{
if(flag[2] == 'a')
{
if(flag[3] == 'g')
{
printf("yes,this is a flag");
getchar();
return 0;
}
}
}
}
else
{
return 0;
}
}


root@VM-24-10-ubuntu:/home/ubuntu/reverse# gcc check.c -o check
root@VM-24-10-ubuntu:/home/ubuntu/reverse# ./check
输入的flag为:flag
yes,this is a flag

待完善

​ 还是用上面链接里的例子,最后一题. 它是windows环境的,我的电脑是mac,进行一个简单修改,换成Linux下能运行的

1

ISCC2018-My math is bad

https://rcoil.me/2018/05/【CTF】ISCC-2018/

​ 这个题需要你给一个输入s,然后s被拆成了8个部分,然后这8个部分需要满足一些条件,都满足后,就可以得到flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__int64 __fastcall main(int a1, char **a2, char **a3)
{
puts("=======================================");
puts("= Welcome to the flag access machine! =");
puts("= Input the password to login ... =");
puts("=======================================");
__isoc99_scanf("%s", s);
if ( (unsigned int)sub_400766("%s", s) )
{
puts("Congratulations! You should get the flag...");
sub_400B16("Congratulations! You should get the flag...");
}
else
{
puts("Wrong password!");
}
return 0LL;
}

​ 输入的s被拆成了很多部分, 为什么呢…

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
.bss:00000000006020A0 s               db 4 dup(?)             ; DATA XREF: sub_400766+8↑o
.bss:00000000006020A0 ; sub_400766:loc_400788↑o ...
.bss:00000000006020A4 ; int dword_6020A4
.bss:00000000006020A4 dword_6020A4 dd ? ; DATA XREF: sub_400766+2F↑o
.bss:00000000006020A8 ; int dword_6020A8
.bss:00000000006020A8 dword_6020A8 dd ? ; DATA XREF: sub_400766+3C↑o
.bss:00000000006020AC ; int dword_6020AC
.bss:00000000006020AC dword_6020AC dd ? ; DATA XREF: sub_400766+49↑o
.bss:00000000006020B0 unk_6020B0 db ? ; ; DATA XREF: sub_400766+56↑o
.bss:00000000006020B1 db ? ;
.bss:00000000006020B2 db ? ;
.bss:00000000006020B3 db ? ;
.bss:00000000006020B4 unk_6020B4 db ? ; ; DATA XREF: sub_400766+63↑o
.bss:00000000006020B5 db ? ;
.bss:00000000006020B6 db ? ;
.bss:00000000006020B7 db ? ;
.bss:00000000006020B8 unk_6020B8 db ? ; ; DATA XREF: sub_400766+70↑o
.bss:00000000006020B9 db ? ;
.bss:00000000006020BA db ? ;
.bss:00000000006020BB db ? ;
.bss:00000000006020BC unk_6020BC db ? ; ; DATA XREF: sub_400766+7D↑o
.bss:00000000006020BD db ? ;
.bss:00000000006020BE db ? ;
.bss:00000000006020BF db ? ;
.bss:00000000006020C0 db ? ;

根据sub_400766可知
v2 = unk_6020B0;
v3 = unk_6020B4;
v4 = unk_6020B8;
v5 = unk_6020BC;

所以s = s + dword_6020A4 + dword_6020A8 + dword_6020AC + unk_6020B0 + unk_6020B4 + unk_6020B8 + unk_6020BC

所以我们的目标就是解出来每个值,然后就得到了正确的输入,输入这个s,就可以得到flag了

python的z3库,解很多约束

https://blog.csdn.net/A951860555/article/details/120177253

https://blog.csdn.net/weixin_52369224/article/details/120922901

把题目给的第一个约束条件转换一下,就得到一个四元一次方程组,进行求解即可

1
2
3
4
5
6
7
8
( dword_6020A4 * s - dword_6020AC * dword_6020A8 == 0x24CDF2E7C953DA56 )

( 3* dword_6020A8 + 4 * dword_6020AC - dword_6020A4 - 2*s == 397958918 )

( 3 *s * dword_6020AC - dword_6020A8 * dword_6020A4 == 0x2E6E497E6415CF3E )

( 27 * dword_6020A4 + s - 11 * dword_6020AC - dword_6020A8 == 0x95AE13337 )

利用python的z3库进行求解.

pip install z3-solver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from z3 import * 

dword_6020A4 = Int('dword_6020A4')
dword_6020AC = Int('dword_6020AC')
dword_6020A8 = Int('dword_6020A8')
s = Int('s')

solve ( dword_6020A4 * s - dword_6020AC * dword_6020A8 == 0x24CDF2E7C953DA56,

3* dword_6020A8 + 4 * dword_6020AC - dword_6020A4 - 2*s == 397958918 ,

3 *s * dword_6020AC - dword_6020A8 * dword_6020A4 == 0x2E6E497E6415CF3E,

27 * dword_6020A4 + s - 11 * dword_6020AC - dword_6020A8 == 0x95AE13337 )

求解得到下面的值

1
2
3
4
5
root@VM-24-10-ubuntu:/home/ubuntu/re# python3 1.py
[dword_6020A4 = 1801073242,
dword_6020AC = 862734414,
dword_6020A8 = 829124174,
s = 1869639009]

然后再进一步往下走,利用c的srand得到随机数种子,然后下面的几个值就确定了,又根据这四个判断条件,即四元一次方程组,又可以解出四个值来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
srand(dword_6020A8 ^ dword_6020A4 ^ *(_DWORD *)s ^ dword_6020AC);
v6 = rand() % 50;
v7 = rand() % 50;
v8 = rand() % 50;
v9 = rand() % 50;
v10 = rand() % 50;
v11 = rand() % 50;
v12 = rand() % 50;
v13 = rand() % 50;

if ( v5 * v7 + v2 * v6 - v3 - v4 != 0xE638C96D3LL )
return 0LL;
return v5 + v2 + v4 * v9 - v3 * v8 == 0xB59F2D0CBLL
&& v2 * v10 + v3 * v11 - v4 - v5 == 0xDCFE88C6DLL
&& v4 * v13 + v2 - v3 - v5 * v12 == 0xC076D98BBLL;

​ 先用c语言把v6-13解出来

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
#include <stdlib.h>
#include <stdio.h>

int main(){
int dword_6020A4 = 1801073242;
int dword_6020AC = 862734414;
int dword_6020A8 = 829124174;
int s = 1869639009;

srand((dword_6020A8)^(dword_6020A4)^(s)^(dword_6020AC));
int v6 = rand() % 50;
int v7 = rand() % 50;
int v8 = rand() % 50;
int v9 = rand() % 50;
int v10 = rand() % 50;
int v11 = rand() % 50;
int v12 = rand() % 50;
int v13 = rand() % 50;
printf("%d\n",v6);
printf("%d\n",v7);
printf("%d\n",v8);
printf("%d\n",v9);
printf("%d\n",v10);
printf("%d\n",v11);
printf("%d\n",v12);
printf("%d\n",v13);
return 0;
}

root@VM-24-10-ubuntu:/home/ubuntu/re# ./a.out
22
39
45
45
35
41
13
36

​ 然后就可以解最后一个方程组了

1
2
3
4
5
6
7
8
9
10
if ( v5 * v7 + v2 * v6 - v3 - v4 != 0xE638C96D3LL )
return 0LL;
return v5 + v2 + v4 * v9 - v3 * v8 == 0xB59F2D0CBLL
&& v2 * v10 + v3 * v11 - v4 - v5 == 0xDCFE88C6DLL
&& v4 * v13 + v2 - v3 - v5 * v12 == 0xC076D98BBLL;

39*v5 + 22*v2 -v3-v4 == 0xE638C96D3,
v5 + v2 + v4*45 -v3*45 ==0xB59F2D0CB,
v2 * 35 + v3*41 -v4 -v5 == 0xDCFE88C6D,
v4 *36 + v2 - v3 - v5 * 13 == 0xC076D98BB

​ 脚本

1
2
3
4
5
6
7
8
9
10
11
from z3 import * 

v2 = Int('v2')
v3 = Int('v3')
v4 = Int('v4')
v5 = Int('v5')

solve ( 39*v5 + 22*v2 -v3-v4 == 0xE638C96D3,
v5 + v2 + v4*45 -v3*45 ==0xB59F2D0CB,
v2 * 35 + v3*41 -v4 -v5 == 0xDCFE88C6D,
v4 *36 + v2 - v3 - v5 * 13 == 0xC076D98BB)

​ 得到结果

1
2
3
4
5
[v3 = 828593230,
v5 = 1195788129,
v2 = 811816014,
v4 = 1867395930]

根据前面信息可知
v2 = unk_6020B0;
v3 = unk_6020B4;
v4 = unk_6020B8;
v5 = unk_6020BC;

于是就得到了s的7个部分,把这些部分加起来,然后转换成ascii码即可得到输入

1
2
3
4
5
6
7
8
9
10
v3 = 828593230,
v5 = 1195788129,
v2 = 811816014,
v4 = 1867395930
dword_6020A4 = 1801073242,
dword_6020AC = 862734414,
dword_6020A8 = 829124174,
s = 1869639009

1869639009180107324282912417486273441481181601482859323018673959301195788129

​ 刚开始把这些数都连起来,然后每两个输出ascii,发现不对,后来看了wp,自己想了下,他们是10进制数,应该先把每个值转换成16进制,再输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
flag = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]

for i in flag:
i = hex(i)

for j in [2,4,6,8]:
#print(i[j:j+2])
print(chr(int(i[j:j+2],16)),end="")
print("\n")


内循环也可以这样写
for j in range(2,len(i),2):
print(chr(int(i[j:j+2],16)),end="")

​ 这里遇到的问题是怎么把这个串转ascii…因为把10进制转16进制后会被认作为一个字符串,取值的话又成了十进制…用chr(int(原始的数,进制数)) 就可以了!

​ 参考:https://www.jb51.net/article/119202.htm

​ 但是得到的结果为什么是反的????(每四个为一组)opmakZ2Z1knN3lHN0cTN1cTNoN3ZGFGa

和大端小端有关系????????????好像不是的

​ j+2会不会有问题,如果不够了呢?????

​ 那就需要反转一下了

1
2
3
4
5
6
7
8
9
10
11
12
flag = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]
tmp = ""
final = ""
for i in flag:
i = hex(i)
tmp = ""
for j in range(2,len(i),2):
tmp += chr(int(i[j:j+2],16)).strip("\n")
tmp = tmp[::-1]
final += tmp
print(final)
print("\n")

​ 或者用下面的这个库(为什么这个不用反转呢?) [::-1]

1
2
3
4
5
6
7
8
9
10
11
12
#/usr/bin/env python
# coding=utf-8
import libnum

flag = ""
x = [1869639009,1801073242,829124174,862734414,811816014,828593230,1867395930,1195788129]
for y in x:
flag += libnum.n2s(y)[::-1]
print flag
运算结果:
ampoZ2ZkNnk1NHl3NTc0NTc1Z3NoaGFG
opmakZ2Z1knN3lHN0cTN1cTNoN3ZGFGa
1
2
3
4
5
6
7
8
root@VM-24-10-ubuntu:/home/ubuntu/re# ./My\ math\ is\ bad
=======================================
= Welcome to the flag access machine! =
= Input the password to login ... =
=======================================
ampoZ2ZkNnk1NHl3NTc0NTc1Z3NoaGFG
Congratulations! You should get the flag...
flag{th3_Line@r_4lgebra_1s_d1fficult!}