以为又是个算法题,没想到是个逆向加脑洞题
字符串特征 cryptopp、unicorn,加上code.dat文件,分别从输入和unicorn入手
从xml可以找到check_va,引用找到输入获取逻辑,只能确认输入长度限制32位
从code.dat(utf-16)引用可以找到unicorn的调用函数,结合unicorn官方文档,推测出函数调用,关键在写入代码和数据的 uc_mem_write uc_mem_read。
ida启动调试、附加全部崩溃在invalidHandle,推测有反调试。
windows反调试不太熟,于是启动frida
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
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
function seeHexA(addr, length) {
console.log(hexdump(ptr(addr), { length: parseInt(length) }))
}
var base
=
Module.getBaseAddress(
"ctf_app.exe"
)
/
/
Interceptor.attach(ptr(
0x00BC28E0
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(Process.getCurrentThreadId(), this.context.ecx, this.context.esp.add(
4
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
/
/
console.log(Process.getCurrentThreadId(),
"string_from_u16:"
, this.context.esp.add(
4
).readPointer().readUtf16String())
/
/
console.log()
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(Process.getCurrentThreadId(),
"------------------------"
)
/
/
}
/
/
})
/
/
Interceptor.attach(ptr(
0xBC28C0
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(Process.getCurrentThreadId(),
"wrap_SendMessageW "
/
/
, this.context.esp.add(
0x4
).readPointer()
/
/
, this.context.esp.add(
0x8
).readPointer()
/
/
, this.context.esp.add(
0xc
).readPointer()
/
/
, this.context.esp.add(
0x10
).readPointer()
/
/
,
"caller ="
, this.context.esp.readPointer().sub(base)
/
/
)
/
/
console.log()
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(Process.getCurrentThreadId(),
"------------------------"
)
/
/
}
/
/
}
/
/
)
/
/
Interceptor.attach(ptr(
0xBC6850
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(Process.getCurrentThreadId(),
"enc1 "
/
/
, this.context.ecx
/
/
, this.context.edx
/
/
, this.context.ebp
/
/
, this.context.esp.add(
0x4
).readPointer()
/
/
,
"caller ="
, this.context.esp.readPointer()
/
/
)
/
/
console.log()
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(Process.getCurrentThreadId(),
"------------------------"
)
/
/
}
/
/
}
/
/
)
/
/
Interceptor.attach(ptr(
0xBC6D20
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(Process.getCurrentThreadId(),
"enc2 "
/
/
, this.context.edx
/
/
, this.context.ecx
/
/
, this.context.ebp
/
/
, this.context.edi
/
/
, this.context.esi
/
/
, this.context.esp.add(
0x4
).readPointer()
/
/
,
"caller ="
, this.context.esp.readPointer().sub(base)
/
/
)
/
/
console.log()
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(Process.getCurrentThreadId(),
"------------------------"
)
/
/
}
/
/
}
/
/
)
/
/
Interceptor.attach(ptr(
0xBCE670
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(Process.getCurrentThreadId(),
"encn "
/
/
, this.context.ecx
/
/
, this.context.ebp
/
/
, this.context.edi
/
/
, this.context.esi
/
/
, this.context.esp.add(
0x4
).readPointer()
/
/
,
"caller ="
, this.context.esp.readPointer().sub(base)
/
/
)
/
/
console.log()
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(Process.getCurrentThreadId(),
"------------------------"
)
/
/
}
/
/
}
/
/
)
/
/
Interceptor.attach(ptr(
0xBC9B90
+
parseInt(base)
-
0xBC0000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(this.context.ecx, this.context.esp.add(
4
).readPointer(), this.context.esp.add(
8
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
/
/
/
/
console.log(
"newstring:"
,this.context.esp.add(
4
).readPointer().readUtf8String())
/
/
console.log(
"newstring:"
)
/
/
seeHexA(this.context.esp.add(
4
).readPointer(), parseInt(this.context.esp.add(
8
).readPointer()))
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(
"------------------------"
)
/
/
}
/
/
})
/
/
Interceptor.attach(ptr(
0x40A4B0
+
parseInt(base)
-
0x00400000
),
/
/
{
/
/
onEnter: function (args) {
/
/
console.log(this.context.ecx, this.context.esp.add(
4
).readPointer(), this.context.esp.add(
8
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
/
/
/
/
console.log(
"newstring:"
,this.context.esp.add(
4
).readPointer().readUtf8String())
/
/
console.log(
"newstring2:"
)
/
/
seeHexA(this.context.esp.add(
4
).readPointer(), parseInt(this.context.esp.add(
8
).readPointer()))
/
/
/
/
seeHexA(this.context.esp)
/
/
console.log(
"------------------------"
)
/
/
}
/
/
})
Interceptor.attach(ptr(
0xBCDA90
+
parseInt(base)
-
0xBC0000
),
{
onEnter: function (args) {
this.arg0
=
this.context.edx
this.arg1
=
this.context.ecx
console.log(Process.getCurrentThreadId(), this.context.edx, this.context.ecx, this.context.esp.add(
4
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
console.log(Process.getCurrentThreadId(),
"getcodedat:"
, this.context.esp.add(
4
).readPointer().readUtf8String())
console.log()
}
}
)
Interceptor.attach(ptr(
0x00C0E460
+
parseInt(base)
-
0xBC0000
),
{
onEnter: function (args) {
console.log(Process.getCurrentThreadId(),
"uc_mem_write:"
, this.context.esp.add(
4
).readPointer(),
this.context.esp.add(
8
).readPointer(),
this.context.esp.add(
0xc
).readPointer(),
this.context.esp.add(
0x10
).readPointer(),
this.context.esp.add(
0x14
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
seeHexA(this.context.esp.add(
0x10
).readPointer(), this.context.esp.add(
0x14
).readPointer())
console.log(Process.getCurrentThreadId(),
"------------------------"
)
}
}
)
Interceptor.attach(ptr(
0x00C0E1F0
+
parseInt(base)
-
0xBC0000
),
{
onEnter: function (args) {
this.dst
=
this.context.esp.add(
0x10
).readPointer()
this.size
=
this.context.esp.add(
0x14
).readPointer()
console.log(Process.getCurrentThreadId(),
"uc_mem_read:"
,
this.context.esp.add(
4
).readPointer(),
this.context.esp.add(
8
).readPointer(),
this.context.esp.add(
0xc
).readPointer(),
this.context.esp.add(
0x10
).readPointer(),
this.context.esp.add(
0x14
).readPointer(),
"caller ="
, this.context.esp.readPointer().sub(base))
/
/
console. log (
' Context : '
+
JSON. stringify (this. context));
console.log()
}
,
onLeave: function (retval) {
console.log(Process.getCurrentThreadId(),
"uc_mem_read->"
, retval)
seeHexA(this.dst, this.size)
/
/
this.dst.writeU32(
1
)
/
/
this.dst.add(
0x18
).writeU32(
1
)
seeHexA(this.dst, this.size)
console.log(Process.getCurrentThreadId(),
"------------------------"
)
}
}
)
/
/
if
(
hash
(
input
)
=
=
"6749dae311865d64db83d5ae75bac3c9e36b3aa6f24caba655d9682f7f071023"
){}
|
两次write,分别是代码和输入数据的hash。获得代码如下
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
|
ROM:
000436AC
ADR R0, a182b32359558eb ;
"182b32359558eb092511b7166867503ddd83fbe"
...
ROM:
000436B0
NOP
ROM:
000436B4
PUSH {R0}
ROM:
000436B8
ADR R0, aFe5f0fc640cbbc ;
"fe5f0fc640cbbc113406f042d08cc60ba784c77"
...
ROM:
000436BC
NOP
ROM:
000436C0
PUSH {R0}
ROM:
000436C4
ADR R0, a4fc82b26aecb47 ;
"4fc82b26aecb47d2868c4efbe3581732a3e7cbc"
...
ROM:
000436C8
NOP
ROM:
000436CC
PUSH {R0}
ROM:
000436D0
ADR R1, aFlags ;
"flags:"
ROM:
000436D4
NOP
ROM:
000436D8
MOV R1,
#0xC
ROM:
000436DC
ROM:
000436DC
loc_436DC ; CODE XREF: sub_4363C
+
E0↓j
ROM:
000436DC
MOV R0,
#0x4033
ROM:
000436E4
POP {R2}
ROM:
000436E8
MOV R8, R2
ROM:
000436EC
MOV R5,
#0
ROM:
000436F0
SUB R1, R1,
#1
ROM:
000436F4
ROM:
000436F4
loc_436F4 ; CODE XREF: sub_4363C
+
D8↓j
ROM:
000436F4
LDR R3, [R0]
ROM:
000436F8
LDR R4, [R2]
ROM:
000436FC
ADD R5, R5,
#1
ROM:
00043700
CMP
R5,
#0x10
ROM:
00043704
BGE loc_43724
ROM:
00043708
ADD R0, R0,
#4
ROM:
0004370C
ADD R2, R2,
#4
ROM:
00043710
CMP
R3, R4
ROM:
00043714
BEQ loc_436F4
ROM:
00043718
CMP
R1,
#0
ROM:
0004371C
BNE loc_436DC
ROM:
00043720
B loc_43750
ROM:
00043724
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ROM:
00043724
ROM:
00043724
loc_43724 ; CODE XREF: sub_4363C
+
C8↑j
ROM:
00043724
ADR R9, a6749dae311865d ;
"6749dae311865d64db83d5ae75bac3c9e36b3aa"
...
ROM:
00043728
NOP
ROM:
0004372C
CMP
R8, R9
ROM:
00043730
BNE loc_43750
ROM:
00043734
MOV R1,
#0x14390
ROM:
00043744
MOV R2,
#1
ROM:
00043748
STR
R2, [R1]
ROM:
0004374C
STR
R2, [R1,
#0x18]
|
将一堆字符串push,和输入比较,如果相等且为"6749dae311865d64db83d5ae75bac3c9e36b3aa"...这一项则验证成功。
但是输入经过了hash处理,
这个代码现在真是越看越怪,尤其是这个flag:
为了确认输入处理,还是需要调试下,从崩溃时的栈上获取信息,最终定位到
1
2
3
4
5
6
7
8
|
v21
=
CreateTimerQueue();
this[
165
]
=
v21;
if
( v21 )
{
CreateTimerQueueTimer((PHANDLE)this
+
166
, v21, _IsNonwritableInCurrentImage, (PVOID)this[
7
],
0x1F4u
,
0x7D0u
,
0
);
CreateTimerQueueTimer((PHANDLE)this
+
167
, (HANDLE)this[
165
], Callback,
0
,
0x258u
,
0x7D0u
,
0
);
CreateTimerQueueTimer((PHANDLE)this
+
168
, (HANDLE)this[
165
], sub_6E79D0,
0
,
0x2BCu
,
0x7D0u
,
0
);
CreateTimerQueueTimer((PHANDLE)this
+
169
, (HANDLE)this[
165
], sub_6E7A60,
0
,
0x320u
,
0x7D0u
,
0
)
|
跟踪输入逻辑,可以发现先经过sha256,然后rsa加密,使用时再rsa解密。
看了下代码解密逻辑,确认没什么思路,唯一的条件就是
1
2
|
sha256(
input
)
=
=
"6749dae311865d64db83d5ae75bac3c9e36b3aa6f24caba655d9682f7f071023"
len
(
input
)
=
=
32
|
前面的flags:没什么用,明显是个提示,并且这段代码里多了很多无用的字符串。
将其分割成两半试试
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
s
=
[
"e0bc614e4fd035a488619799853b0751"
,
"43deea596c477b8dc077e309c0fe42e9"
,
"6b86b273ff34fce19d6b804eff5a3f57"
,
"47ada4eaa22f1d49c01e52ddb7875b4b"
,
"d8bdf9a0cb27a193a1127de2924b6e5a"
,
"9e4c2d3b3fe42e935e160c011f3df1fc"
,
"d4735e3a265e16eee03f59718b9b5d03"
,
"019c07d8b6c51f90da3a666eec13ab35"
,
"6749dae311865d64db83d5ae75bac3c9"
,
"e36b3aa6f24caba655d9682f7f071023"
,
"ea96b41c1f9365c2c9e6342f5faaeab2"
,
"a44471efe1e65a2356a974646d2588fd"
,
"5b65712d565c1551340998102d418cec"
,
"cb35db8dbfb45f9041c4cae483d8717b"
,
"4e07408562bedb8b60ce05c1decfe3ad"
,
"16b72230967de01f640b7e4729b49fce"
,
"033c339a7975542785be7423a5b32fa8"
,
"047813689726214143cdd7939747709c"
,
"4b227777d4dd1fc61c6f884f48641d02"
,
"b4d121d3fd328cb08b5531fcacdabf8a"
,
"c81d40dbeed369f1476086cf882dd36b"
,
"f1c3dc35e07006f0bec588b983055487"
,
"ef2d127de37b942baad06145e54b0c61"
,
"9a1f22327b2ebbcfbec78f5564afe39d"
,
"9e259b7f6b4c741937a96a9617b3e6b8"
,
"4e166ff6e925e414e7b72936f5a2a51f"
,
"e7f6c011776e8db7cd330b54174fd76f"
,
"7d0216b612387a5ffcfb81e6f0919683"
,
"1048f03db5d45f654b955eae20d84b72"
,
"673680fb13b318e7da22e8dce58df21c"
,
"7902699be42c8a8e46fbbb4501726517"
,
"e86b22c56a189f7625a6da49081b2451"
,
"8f0703d406fdb0ea8011d5de342c3aca"
,
"62214758a8a2b5b8a4e9f1c8c6c42462"
,
"2c624232cdd221771294dfbb310aca00"
,
"0a0df6ac8b66b696d90ef06fdefb64a3"
,
"182b32359558eb092511b7166867503d"
,
"dd83fbe5b42f2545e1903016e721393d"
,
"19581e27de7ced00ff1ce50b2047e7a5"
,
"67c76b1cbaebabe5ef03f7c3017bb5b7"
,
"fe5f0fc640cbbc113406f042d08cc60b"
,
"a784c775f7c3299985665323c5fbcdc4"
,
"4a44dc15364204a80fe80e9039455cc1"
,
"608281820fe2b24f1e5233ade6af1dd5"
,
"4fc82b26aecb47d2868c4efbe3581732"
,
"a3e7cbcc6c2efb32062c08170a05eeb8"
,
"1ba586c0b89202f7307b61f122933097"
,
"8a843afc98589ffc6a62f209225d3528"
,
]
for
x
in
s:
for
x
in
s:
print
(x,
len
(x), hashlib.sha256(x.encode()).hexdigest())
|
全是套路,好!
更多【KCTF 2023 第三题 解题过程】相关视频教程:www.yxfzedu.com