-
-
[原创]2021看雪KCTF逆向WP
-
发表于: 2021-5-21 15:11 8221
-
分析:
(查看添加的注释)
使用z3爆破:
拖入IDA分析:
关键就是这个if条件里面的两个函数,后面的只是根据输入的serial序列号执行代码的正确逻辑而已
逐渐分析代码:
sub_941240函数部分:
将一些数据加载到数组中,这里就是我们后面用到的table
这一段就是将我们的输入进行的关键转换的地方,从上面的table中找下标,然后%9 + 1之后存储到另外一个连续的地址空间(数组),并在每行的最后加上一个数字,这个数字等于用9来减去添加到那个地址空间中字符的数目(不理解的话仔细查看我添加的注释)
check_sudu函数部分:
我们逐段进行分析:
每次循环的逻辑(共循环9次)就是,如果if判断给的本来的九宫格的每一行中元素为0,就填充我们上一个函数得到的那个连续地址空间(数组)中的元素
这一段主要就是检测每一行9个元素中是否有元素相等
这一段是检测每一列中是否有元素相等
最后一段是检测,九宫格中的小九宫是否满足:9个元素是否是互不相等且是1-9
很明显第二个函数就是用来检测将我们的数据填充之后的9*9数组是否满足数独
得到:
最后得到序列号serial为:
:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
char input_element;
/
/
al
int
input_index;
/
/
esi
int
table_index;
/
/
ecx
int
v7;
/
/
edx
int
v8;
/
/
eax
unsigned
int
col_index;
/
/
ecx
int
v10;
/
/
eax
int
i;
/
/
edx
int
v12;
/
/
eax
char
*
v13;
/
/
eax
char
*
addr;
/
/
eax
int
judge_number;
/
/
edx
char
*
line_end_addr;
/
/
ecx
int
v17;
/
/
eax
int
v18;
/
/
eax
int
v19;
/
/
eax
int
v20;
/
/
[esp
+
1Ch
] [ebp
-
60h
]
unsigned
int
line_index;
/
/
[esp
+
20h
] [ebp
-
5Ch
]
unsigned
int
v22;
/
/
[esp
+
24h
] [ebp
-
58h
]
char table_element;
/
/
[esp
+
2Bh
] [ebp
-
51h
]
int
v24;
/
/
[esp
+
2Ch
] [ebp
-
50h
]
char input_code[
76
];
/
/
[esp
+
30h
] [ebp
-
4Ch
] BYREF
sub_40AD70();
sub_4AF840((
int
)&dword_4B8860,
"Input your code: "
);
sub_4B0AB0((
int
)&dword_4B8680, input_code);
/
/
输入
if
( strlen(input_code) <
=
0x30
)
/
/
长度小于
48
{
input_element
=
input_code[
0
];
/
/
code首字符
if
( input_code[
0
] )
{
input_index
=
0
;
line_index
=
0
;
v22
=
0
;
v24
=
dword_4B7020;
/
/
v24
=
0x24
(
36
)
table_element
=
table[
0
];
/
/
'0'
-
'9'
和
'A'
-
'Z'
(总共
36
个字符)
LABEL_4:
if
( v24 >
0
)
/
/
当v24>
0
时执行,必执行
{
table_index
=
0
;
if
( table_element
=
=
input_element )
/
/
当输入的code的字符是table中的字符的时候
{
LABEL_11:
v7
=
(input_index
+
table_index
/
6
)
%
6
;
v8
=
table_index
+
input_index;
col_index
=
v22;
v20
=
v7;
v10
=
5
-
v8
%
6
;
/
/
这里v10最开始进入时是由v8更新的
for
( i
=
0
; ; i
=
1
)
/
/
这个循环会执行两次,第一次i
=
0
执行完了之后i才会更新为
1
/
/
然后
for
循环里面那有个判断条件
if
(i
=
=
1
)里面有两个goto,必然会执行一个
/
/
就说明第二次执行
for
循环的时候才会退出,第一次循环结束后v10是被v20更新的
{
switch ( v10 )
{
case
1
:
+
+
col_index;
/
/
列数加一,即往右移
break
;
case
2
:
v17
=
(line_index
+
+
&
1
)
=
=
0
;
/
/
当行为奇行时(比如说第一行,下标为
0
的行),行列都要加一,即往右下角移动
col_index
+
=
v17;
/
/
当行为偶行时(比如说第二行,下标为
1
的行),只是行加一,即往下移
break
;
case
3
:
v12
=
(line_index
+
+
&
1
) !
=
0
;
/
/
当行为奇行时(比如说第一行,下标为
0
的行),行加一,即往下移
col_index
-
=
v12;
/
/
当行为偶行时(比如说第二行,下标为
1
的行),行
+
1
,列
-
1
,即往左下角移
break
;
case
4
:
-
-
col_index;
/
/
列数减一,即往左移
break
;
case
5
:
v19
=
(line_index
-
-
&
1
) !
=
0
;
/
/
当行为奇行时(比如说第
3
行,下标为
2
的行),行数减一,即向上移
col_index
-
=
v19;
/
/
当行为偶行时(比如说第
4
行,下标为
3
的行),行列都减一,即往左上角移
break
;
default:
v18
=
(line_index
-
-
&
1
)
=
=
0
;
/
/
当行为奇行时(比如说第
3
行,下标为
2
的行),行减一,列加一,即往右上角移
col_index
+
=
v18;
/
/
当行为偶行时(比如说第
4
行,下标为
3
的行),行减一,即往上移
break
;
}
if
( col_index >
9
)
/
/
规定了列数的下标不能大于
9
,说明每列就
10
个元素
break
;
if
( line_index >
8
)
/
/
规定了行数的下标不能超过
8
,就说明有
9
行
break
;
v13
=
&maze[
10
*
line_index
+
col_index];
/
/
取数组中元素对应的地址赋给v13
if
(
*
v13 )
/
/
这里就是迷宫
break
;
*
v13
=
1
;
/
/
意思就是每走一步,走到哪就把那个位置填为
1
if
( i
=
=
1
)
{
+
+
input_index;
v22
=
col_index;
input_element
=
input_code[input_index];
if
( input_element )
goto LABEL_4;
goto LABEL_19;
}
/
/
每个输入的code的字符都执行完了上面的过程,才执行这个goto LABEL_19
/
/
LABEL_19是最后要执行的
v10
=
v20;
}
}
else
{
while
( v24 !
=
+
+
table_index )
{
if
( table[table_index]
=
=
input_element )
/
/
若发现table中字符和输入的code的字符相等,v5是对应的index
goto LABEL_11;
}
}
}
/
/
if
( v24 >
0
)的}
}
/
/
if
( v25[
0
] )的}
else
{
LABEL_19:
addr
=
maze;
/
/
先取迷宫的首地址赋给addr
judge_number
=
0
;
do
/
/
这两个嵌套的dowhile循环意思就是判断迷宫是不是全部被填为
1
了
{
line_end_addr
=
addr
+
10
;
/
/
取每一行的最后一个的地址给v16
do
judge_number
+
=
*
addr
+
+
=
=
0
;
/
/
下面v15要为
0
,那么说明addr地址对应的值要全为
1
while
( line_end_addr !
=
addr );
/
/
这个do
while
是当每一行没完的时候循环,用每一行的最后一个元素的地址判断的
}
while
( &unk_4B70DA !
=
(_UNKNOWN
*
)line_end_addr );
/
/
这个do
while
是当迷宫没走完的时候循环,用迷宫的最后一个地址来进行判断的
if
( !judge_number )
/
/
当v15为
0
的时候
{
sub_4ABF30(&dword_4B8860, (
int
)
"Good job!"
,
9
);
sub_4AD980(&dword_4B8860);
return
0
;
}
}
}
sub_4ABF30(&dword_4B8860, (
int
)
"Try again..."
,
12
);
/
/
如果长度不满足(strlen(v25) <
=
0x30
)则执行
sub_4AD980(&dword_4B8860);
return
0
;
}
int
__cdecl main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
char input_element;
/
/
al
int
input_index;
/
/
esi
int
table_index;
/
/
ecx
int
v7;
/
/
edx
int
v8;
/
/
eax
unsigned
int
col_index;
/
/
ecx
int
v10;
/
/
eax
int
i;
/
/
edx
int
v12;
/
/
eax
char
*
v13;
/
/
eax
char
*
addr;
/
/
eax
int
judge_number;
/
/
edx
char
*
line_end_addr;
/
/
ecx
int
v17;
/
/
eax
int
v18;
/
/
eax
int
v19;
/
/
eax
int
v20;
/
/
[esp
+
1Ch
] [ebp
-
60h
]
unsigned
int
line_index;
/
/
[esp
+
20h
] [ebp
-
5Ch
]
unsigned
int
v22;
/
/
[esp
+
24h
] [ebp
-
58h
]
char table_element;
/
/
[esp
+
2Bh
] [ebp
-
51h
]
int
v24;
/
/
[esp
+
2Ch
] [ebp
-
50h
]
char input_code[
76
];
/
/
[esp
+
30h
] [ebp
-
4Ch
] BYREF
sub_40AD70();
sub_4AF840((
int
)&dword_4B8860,
"Input your code: "
);
sub_4B0AB0((
int
)&dword_4B8680, input_code);
/
/
输入
if
( strlen(input_code) <
=
0x30
)
/
/
长度小于
48
{
input_element
=
input_code[
0
];
/
/
code首字符
if
( input_code[
0
] )
{
input_index
=
0
;
line_index
=
0
;
v22
=
0
;
v24
=
dword_4B7020;
/
/
v24
=
0x24
(
36
)
table_element
=
table[
0
];
/
/
'0'
-
'9'
和
'A'
-
'Z'
(总共
36
个字符)
LABEL_4:
if
( v24 >
0
)
/
/
当v24>
0
时执行,必执行
{
table_index
=
0
;
if
( table_element
=
=
input_element )
/
/
当输入的code的字符是table中的字符的时候
{
LABEL_11:
v7
=
(input_index
+
table_index
/
6
)
%
6
;
v8
=
table_index
+
input_index;
col_index
=
v22;
v20
=
v7;
v10
=
5
-
v8
%
6
;
/
/
这里v10最开始进入时是由v8更新的
for
( i
=
0
; ; i
=
1
)
/
/
这个循环会执行两次,第一次i
=
0
执行完了之后i才会更新为
1
/
/
然后
for
循环里面那有个判断条件
if
(i
=
=
1
)里面有两个goto,必然会执行一个
/
/
就说明第二次执行
for
循环的时候才会退出,第一次循环结束后v10是被v20更新的
{
switch ( v10 )
{
case
1
:
+
+
col_index;
/
/
列数加一,即往右移
break
;
case
2
:
v17
=
(line_index
+
+
&
1
)
=
=
0
;
/
/
当行为奇行时(比如说第一行,下标为
0
的行),行列都要加一,即往右下角移动
col_index
+
=
v17;
/
/
当行为偶行时(比如说第二行,下标为
1
的行),只是行加一,即往下移
break
;
case
3
:
v12
=
(line_index
+
+
&
1
) !
=
0
;
/
/
当行为奇行时(比如说第一行,下标为
0
的行),行加一,即往下移
col_index
-
=
v12;
/
/
当行为偶行时(比如说第二行,下标为
1
的行),行
+
1
,列
-
1
,即往左下角移
break
;
case
4
:
-
-
col_index;
/
/
列数减一,即往左移
break
;
case
5
:
v19
=
(line_index
-
-
&
1
) !
=
0
;
/
/
当行为奇行时(比如说第
3
行,下标为
2
的行),行数减一,即向上移
col_index
-
=
v19;
/
/
当行为偶行时(比如说第
4
行,下标为
3
的行),行列都减一,即往左上角移
break
;
default:
v18
=
(line_index
-
-
&
1
)
=
=
0
;
/
/
当行为奇行时(比如说第
3
行,下标为
2
的行),行减一,列加一,即往右上角移
col_index
+
=
v18;
/
/
当行为偶行时(比如说第
4
行,下标为
3
的行),行减一,即往上移
break
;
}
if
( col_index >
9
)
/
/
规定了列数的下标不能大于
9
,说明每列就
10
个元素
break
;
if
( line_index >
8
)
/
/
规定了行数的下标不能超过
8
,就说明有
9
行
break
;
v13
=
&maze[
10
*
line_index
+
col_index];
/
/
取数组中元素对应的地址赋给v13
if
(
*
v13 )
/
/
这里就是迷宫
break
;
*
v13
=
1
;
/
/
意思就是每走一步,走到哪就把那个位置填为
1
if
( i
=
=
1
)
{
+
+
input_index;
v22
=
col_index;
input_element
=
input_code[input_index];
if
( input_element )
goto LABEL_4;
goto LABEL_19;
}
/
/
每个输入的code的字符都执行完了上面的过程,才执行这个goto LABEL_19
/
/
LABEL_19是最后要执行的
v10
=
v20;
}
}
else
{
while
( v24 !
=
+
+
table_index )
{
if
( table[table_index]
=
=
input_element )
/
/
若发现table中字符和输入的code的字符相等,v5是对应的index
goto LABEL_11;
}
}
}
/
/
if
( v24 >
0
)的}
}
/
/
if
( v25[
0
] )的}
else
{
LABEL_19:
addr
=
maze;
/
/
先取迷宫的首地址赋给addr
judge_number
=
0
;
do
/
/
这两个嵌套的dowhile循环意思就是判断迷宫是不是全部被填为
1
了
{
line_end_addr
=
addr
+
10
;
/
/
取每一行的最后一个的地址给v16
do
judge_number
+
=
*
addr
+
+
=
=
0
;
/
/
下面v15要为
0
,那么说明addr地址对应的值要全为
1
while
( line_end_addr !
=
addr );
/
/
这个do
while
是当每一行没完的时候循环,用每一行的最后一个元素的地址判断的
}
while
( &unk_4B70DA !
=
(_UNKNOWN
*
)line_end_addr );
/
/
这个do
while
是当迷宫没走完的时候循环,用迷宫的最后一个地址来进行判断的
if
( !judge_number )
/
/
当v15为
0
的时候
{
sub_4ABF30(&dword_4B8860, (
int
)
"Good job!"
,
9
);
sub_4AD980(&dword_4B8860);
return
0
;
}
}
}
sub_4ABF30(&dword_4B8860, (
int
)
"Try again..."
,
12
);
/
/
如果长度不满足(strlen(v25) <
=
0x30
)则执行
sub_4AD980(&dword_4B8860);
return
0
;
}
# 打印出迷宫
maze
=
[
0x53
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x00
,
0x00
]
for
i
in
range
(
len
(maze)):
if
(i
+
1
)
%
10
=
=
0
:
print
(maze[i])
else
:
if
i !
=
0
:
print
(maze[i], end
=
' '
)
else
:
print
(
chr
(maze[i]), end
=
' '
)
# 使用z3进行解题
from
z3
import
*
circle_one
=
[
1
,
3
,
3
,
1
,
3
,
3
,
1
,
0
,
2
,
0
,
5
,
5
,
3
,
5
,
5
,
1
,
1
,
1
,
1
,
3
,
3
,
2
,
2
]
circle_two
=
[
2
,
4
,
2
,
2
,
4
,
2
,
1
,
1
,
1
,
0
,
0
,
4
,
4
,
0
,
0
,
2
,
0
,
2
,
2
,
4
,
2
,
3
,
1
]
table
=
[
48
,
49
,
50
,
51
,
52
,
53
,
54
,
55
,
56
,
57
,
65
,
66
,
67
,
68
,
69
,
70
,
71
,
72
,
73
,
74
,
75
,
76
,
77
,
78
,
79
,
80
,
81
,
82
,
83
,
84
,
85
,
86
,
87
,
88
,
89
,
90
]
x
=
Int
(
'index'
)
for
i
in
range
(
len
(circle_one)):
#每个code字符会操作两次位移
solve(circle_one[i]
=
=
(
5
-
(i
+
x)
%
6
), circle_two[i]
=
=
((i
+
x
/
6
)
%
6
), x >
=
0
, x <
36
)
index_table
=
[
16
,
19
,
0
,
31
,
4
,
21
,
10
,
4
,
31
,
20
,
14
,
31
,
26
,
35
,
28
,
31
,
12
,
23
,
16
,
19
,
0
,
0
,
23
]
code
=
''
for
i
in
range
(
len
(index_table)):
code
+
=
chr
(table[index_table[i]])
print
(
"输入的序列号为: "
+
code)
# 打印出迷宫
maze
=
[
0x53
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x01
,
0x00
,
0x00
]
for
i
in
range
(
len
(maze)):
if
(i
+
1
)
%
10
=
=
0
:
print
(maze[i])
else
:
if
i !
=
0
:
print
(maze[i], end
=
' '
)
else
:
print
(
chr
(maze[i]), end
=
' '
)
# 使用z3进行解题
from
z3
import
*
circle_one
=
[
1
,
3
,
3
,
1
,
3
,
3
,
1
,
0
,
2
,
0
,
5
,
5
,
3
,
5
,
5
,
1
,
1
,
1
,
1
,
3
,
3
,
2
,
2
]
circle_two
=
[
2
,
4
,
2
,
2
,
4
,
2
,
1
,
1
,
1
,
0
,
0
,
4
,
4
,
0
,
0
,
2
,
0
,
2
,
2
,
4
,
2
,
3
,
1
]
table
=
[
48
,
49
,
50
,
51
,
52
,
53
,
54
,
55
,
56
,
57
,
65
,
66
,
67
,
68
,
69
,
70
,
71
,
72
,
73
,
74
,
75
,
76
,
77
,
78
,
79
,
80
,
81
,
82
,
83
,
84
,
85
,
86
,
87
,
88
,
89
,
90
]
x
=
Int
(
'index'
)
for
i
in
range
(
len
(circle_one)):
#每个code字符会操作两次位移
solve(circle_one[i]
=
=
(
5
-
(i
+
x)
%
6
), circle_two[i]
=
=
((i
+
x
/
6
)
%
6
), x >
=
0
, x <
36
)
index_table
=
[
16
,
19
,
0
,
31
,
4
,
21
,
10
,
4
,
31
,
20
,
14
,
31
,
26
,
35
,
28
,
31
,
12
,
23
,
16
,
19
,
0
,
0
,
23
]
code
=
''
for
i
in
range
(
len
(index_table)):
code
+
=
chr
(table[index_table[i]])
print
(
"输入的序列号为: "
+
code)
if
( serial_length <
=
64
&& sub_941240(serial_length, (
int
)serial, base_addr)
=
=
1
&& check_sudu(base_addr, serial_length
-
9
)
=
=
1
)
if
( serial_length <
=
64
&& sub_941240(serial_length, (
int
)serial, base_addr)
=
=
1
&& check_sudu(base_addr, serial_length
-
9
)
=
=
1
)
arr[
0
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956280);
j
=
0
;
arr[
1
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_9562A0);
serial_index
=
0
;
v11
=
serial_length;
v10
=
serial;
v14
=
113
;
arr[
2
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956270);
arr[
3
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956290);
arr[
4
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956260);
/
/
加载进v13
if
( serial_length <
=
0
)
/
/
长度不能<
=
0
return
1
;
k
=
0
;
arr[
0
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956280);
j
=
0
;
arr[
1
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_9562A0);
serial_index
=
0
;
v11
=
serial_length;
v10
=
serial;
v14
=
113
;
arr[
2
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956270);
arr[
3
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956290);
arr[
4
]
=
(__int128)_mm_load_si128((const __m128i
*
)&xmmword_956260);
/
/
加载进v13
if
( serial_length <
=
0
)
/
/
长度不能<
=
0
return
1
;
k
=
0
;
while
(
1
)
{
serial_char
=
*
(_BYTE
*
)(serial_index
+
serial);
if
( serial_char >
'0'
&& serial_char <
=
'9'
)
/
/
输入的code是数字时退出
while
循环
break
;
arr_index
=
k;
/
/
这个k决定了从arr开始偏移多少个字节开始查找
if
( k >
=
81
)
/
/
k不能大于等于
81
return
0
;
while
( serial_char !
=
*
((_BYTE
*
)arr
+
arr_index) )
/
/
当输入的单个字符不等于那个arr中的字符的时候循环
/
/
这个循环的意思就是遍历然后获取我们输入的单个字符在arr中的下标
{
if
( (unsigned
int
)
+
+
arr_index >
=
81
)
return
0
;
}
v9
=
arr_index
%
9
+
1
;
if
( v9
=
=
-
1
)
/
/
判断v9
return
0
;
*
a3
=
v9;
/
/
从a3对应的地址开始逐渐储存我们的v9
serial
=
v10;
+
+
j;
/
/
j是数字字符之前的其它字符的数量,也代表了a3对应的地址开始储存了多少个数据
+
+
a3;
/
/
a3对应的地址
+
+
serial_length
=
v11;
LABEL_13:
if
(
+
+
serial_index >
=
serial_length )
return
1
;
/
/
这里必须返回
1
}
if
( j
+
serial_char
=
=
'9'
)
/
/
数字必须满足这个逻辑,是数字的时候(
9
-
j就代表了这个数字之前有多少个其它字符)
{
j
=
0
;
/
/
填充了最后一个数字就将j重新置为
0
k
+
=
9
;
/
/
必须满足这个
if
条件,然后将arr开始查找的地方向后偏移
9
个字节
goto LABEL_13;
}
/
/
代表每行剩余了多少个位置没填就补充一个什么数字
return
-
1
;
/
/
如果数字没有满足这个条件就返回
-
1
,失败
}
while
(
1
)
{
serial_char
=
*
(_BYTE
*
)(serial_index
+
serial);
if
( serial_char >
'0'
&& serial_char <
=
'9'
)
/
/
输入的code是数字时退出
while
循环
break
;
arr_index
=
k;
/
/
这个k决定了从arr开始偏移多少个字节开始查找
if
( k >
=
81
)
/
/
k不能大于等于
81
return
0
;
while
( serial_char !
=
*
((_BYTE
*
)arr
+
arr_index) )
/
/
当输入的单个字符不等于那个arr中的字符的时候循环
/
/
这个循环的意思就是遍历然后获取我们输入的单个字符在arr中的下标
{
if
( (unsigned
int
)
+
+
arr_index >
=
81
)
return
0
;
}
v9
=
arr_index
%
9
+
1
;
if
( v9
=
=
-
1
)
/
/
判断v9
return
0
;
*
a3
=
v9;
/
/
从a3对应的地址开始逐渐储存我们的v9
serial
=
v10;
+
+
j;
/
/
j是数字字符之前的其它字符的数量,也代表了a3对应的地址开始储存了多少个数据
+
+
a3;
/
/
a3对应的地址
+
+
serial_length
=
v11;
LABEL_13:
if
(
+
+
serial_index >
=
serial_length )
return
1
;
/
/
这里必须返回
1
}
if
( j
+
serial_char
=
=
'9'
)
/
/
数字必须满足这个逻辑,是数字的时候(
9
-
j就代表了这个数字之前有多少个其它字符)
{
j
=
0
;
/
/
填充了最后一个数字就将j重新置为
0
k
+
=
9
;
/
/
必须满足这个
if
条件,然后将arr开始查找的地方向后偏移
9
个字节
goto LABEL_13;
}
/
/
代表每行剩余了多少个位置没填就补充一个什么数字
return
-
1
;
/
/
如果数字没有满足这个条件就返回
-
1
,失败
}
i
=
0
;
v3
=
&MEMORY[
0x9587C4
];
do
{
if
( !
*
(v3
-
1
) )
{
v4
=
base_addr[i
+
+
];
*
(v3
-
1
)
=
v4;
}
if
( !
*
v3 )
{
v5
=
base_addr[i
+
+
];
*
v3
=
v5;
}
if
( !v3[
1
] )
{
v6
=
base_addr[i
+
+
];
v3[
1
]
=
v6;
}
if
( !v3[
2
] )
{
v7
=
base_addr[i
+
+
];
v3[
2
]
=
v7;
}
if
( !v3[
3
] )
{
v8
=
base_addr[i
+
+
];
v3[
3
]
=
v8;
}
if
( !v3[
4
] )
{
v9
=
base_addr[i
+
+
];
v3[
4
]
=
v9;
}
if
( !v3[
5
] )
{
v10
=
base_addr[i
+
+
];
v3[
5
]
=
v10;
}
if
( !v3[
6
] )
{
v11
=
base_addr[i
+
+
];
v3[
6
]
=
v11;
}
if
( !v3[
7
] )
{
v12
=
base_addr[i
+
+
];
v3[
7
]
=
v12;
}
if
( i >
=
serial_length_9 )
break
;
v3
+
=
9
;
/
/
偏移
9
个
}
while
( (
int
)v3 < (
int
)&dword_958908 );
/
/
一:第一个dowhile循环改变
9
*
9
数组的值(加载第一个函数处理后的数组),就是将给的数组为
0
的值填为对应的输入转换出来的元素
/
/
(我们解开这个数独之后,那些值可以得到,然后就可以得到那个第一函数转换之后的数组)
i
=
0
;
v3
=
&MEMORY[
0x9587C4
];
do
{
if
( !
*
(v3
-
1
) )
{
v4
=
base_addr[i
+
+
];
*
(v3
-
1
)
=
v4;
}
if
( !
*
v3 )
{
v5
=
base_addr[i
+
+
];
*
v3
=
v5;
}
if
( !v3[
1
] )
{
v6
=
base_addr[i
+
+
];
v3[
1
]
=
v6;
}
if
( !v3[
2
] )
{
v7
=
base_addr[i
+
+
];
v3[
2
]
=
v7;
}
if
( !v3[
3
] )
{
v8
=
base_addr[i
+
+
];
v3[
3
]
=
v8;
}
if
( !v3[
4
] )
{
v9
=
base_addr[i
+
+
];
v3[
4
]
=
v9;
}
if
( !v3[
5
] )
{
v10
=
base_addr[i
+
+
];
v3[
5
]
=
v10;
}
if
( !v3[
6
] )
{
v11
=
base_addr[i
+
+
];
v3[
6
]
=
v11;
}
if
( !v3[
7
] )
{
v12
=
base_addr[i
+
+
];
v3[
7
]
=
v12;
}
if
( i >
=
serial_length_9 )
break
;
v3
+
=
9
;
/
/
偏移
9
个
}
while
( (
int
)v3 < (
int
)&dword_958908 );
/
/
一:第一个dowhile循环改变
9
*
9
数组的值(加载第一个函数处理后的数组),就是将给的数组为
0
的值填为对应的输入转换出来的元素
/
/
(我们解开这个数独之后,那些值可以得到,然后就可以得到那个第一函数转换之后的数组)
v13
=
arr1_base_addr;
index0
=
0
;
v41
=
arr1_base_addr;
while
(
2
)
{
/
/
二:这个
while
循环就是检测每一行是否有相同的元素
count
=
1
;
addr
=
v13;
do
{
index1
=
count;
if
( count <
9
)
{
v18
=
*
addr;
while
( v18 )
{
v19
=
arr1_base_addr[index0
+
index1];
if
( !v19 || v18
=
=
v19 )
/
/
查找
9
个元素的后
8
个和每次
+
9
后的首地址对应的值(第
1
个)相等的值,若有相等,则返回
0
break
;
/
/
不能执行这个
break
if
(
+
+
index1 >
=
9
)
goto LABEL_30;
/
/
循环检测完了第一个和另外
8
个是否相等之后,再goto
30
}
return
0
;
}
LABEL_30:
+
+
count;
+
+
addr;
/
/
addr地址
+
+
,偏移到第二个元素,然后之后再次循环,到中间那个地方又去比较第二个元素和另外
8
个是否相等
}
while
( count <
10
);
index0
+
=
9
;
/
/
偏移index0
v13
=
v41
+
9
;
v41
=
v13;
/
/
地址向后偏移
9
个字节
if
( (
int
)v13 < (
int
)&unk_958904 )
/
/
判断是否到达了最后的地址
continue
;
break
;
}
v20
=
&MEMORY[
0x9587E4
];
v39
=
&MEMORY[
0x9587E4
];
v13
=
arr1_base_addr;
index0
=
0
;
v41
=
arr1_base_addr;
while
(
2
)
{
/
/
二:这个
while
循环就是检测每一行是否有相同的元素
count
=
1
;
addr
=
v13;
赞赏
他的文章
看原图
赞赏
雪币:
留言: