考察C++逆向。
总体思路:动态调试,黑盒测试。
Windows 32位程序,无壳。
注:以下分析如未作特殊说明,默认基址为0x251000
题目存在一些花指令,不多做阐述,nop修复即可。
比较多的虚函数,同时能看到关键词DuiLib
有关DuiLib
能够从网上找到N篇文章介绍切入点,随便挂一个
Dump微信PC端的界面Duilib文件-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com
通过虚函数跳转最终定位到按钮回调函数sub_26D2D0
简单调试分析后,能够发现首先是进行了变表的base64编码,具体位置在0x26E530
,伪代码分析特征还是比较明显的
当然最大的特征当属编码表,其特征位于函数0x26E250
,伪代码如下
下面进行验证
动态调试得到编码串
尝试变表解密
解得lovectf{mas0n}
,验证成功
进入下一步
经过调试分析确定总体逻辑如下图
单步调试过程中会发现在verify
运行至一个段间跳转时出现异常。
反复调试后,最终发现突破点在于其进行原跳转前,32位至64位模式的切换。
只不过在这里的表现形式与往常有所不同
关于32位程序至64位程序的切换,可以参考文章
CTF中32位程序调用64位代码的逆向方法 - 安全客,安全资讯平台 (anquanke.com)
知晓其模式切换后,强制指定PE64标识
放入IDA,为方便定位函数,Rebase Segment,基址设为0
通过调试得到调用函数地址,减去基址后得到偏移量0x146f0
定位函数,得到伪代码后,看到了函数调用
汇编下形式为call rdi
翻找之后能够知道rdi
来自于指令mov rdi, [rsp+arg_0]
向上分析
确定函数偏移为0x145AC
简单分析伪代码,结合代码复用,能够确定其check逻辑如下
简单异或还原明文验证猜想
最终解题脚本如下
int
__cdecl base64Maps(
int
a1)
{
int
*
v1;
/
/
eax
char v3[
8
];
/
/
[esp
+
4h
] [ebp
-
68h
] BYREF
int
v4;
/
/
[esp
+
Ch] [ebp
-
60h
]
_BYTE base64[
65
];
/
/
[esp
+
10h
] [ebp
-
5Ch
] BYREF
unsigned
int
v6[
2
];
/
/
[esp
+
51h
] [ebp
-
1Bh
] BYREF
int
v7;
/
/
[esp
+
68h
] [ebp
-
4h
]
v4
=
0
;
sub_26D5D0((char
*
)v6
+
3
,
8u
);
qmemcpy(base64,
"prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
, sizeof(base64));
v1
=
(
int
*
)__FrameHandler3::TryBlockMap::TryBlockMap(
(__FrameHandler3::TryBlockMap
*
)v3,
(const struct _s_FuncInfo
*
)base64,
(unsigned
int
)v6);
sub_26EA90((char
*
)v6
+
3
,
*
v1, v1[
1
]);
v7
=
0
;
sub_26EAD0((void
*
)a1, (
int
)v6
+
3
);
v4 |
=
1u
;
v7
=
-
1
;
sub_26EA70();
return
a1;
}
int
__cdecl base64Maps(
int
a1)
{
int
*
v1;
/
/
eax
char v3[
8
];
/
/
[esp
+
4h
] [ebp
-
68h
] BYREF
int
v4;
/
/
[esp
+
Ch] [ebp
-
60h
]
_BYTE base64[
65
];
/
/
[esp
+
10h
] [ebp
-
5Ch
] BYREF
unsigned
int
v6[
2
];
/
/
[esp
+
51h
] [ebp
-
1Bh
] BYREF
int
v7;
/
/
[esp
+
68h
] [ebp
-
4h
]
v4
=
0
;
sub_26D5D0((char
*
)v6
+
3
,
8u
);
qmemcpy(base64,
"prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
, sizeof(base64));
v1
=
(
int
*
)__FrameHandler3::TryBlockMap::TryBlockMap(
(__FrameHandler3::TryBlockMap
*
)v3,
(const struct _s_FuncInfo
*
)base64,
(unsigned
int
)v6);
sub_26EA90((char
*
)v6
+
3
,
*
v1, v1[
1
]);
v7
=
0
;
sub_26EAD0((void
*
)a1, (
int
)v6
+
3
);
v4 |
=
1u
;
v7
=
-
1
;
sub_26EA70();
return
a1;
}
import
base64
baseMaps
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
newMaps
=
"prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
cipherText
=
"EHsnG0bjGT44BqIhETj!"
cipherText
=
cipherText.translate(cipherText.maketrans(newMaps, baseMaps))
print
(base64.b64decode(cipherText.encode(
'utf-8'
)).decode())
import
base64
baseMaps
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
newMaps
=
"prvo9CHSJOcPIb6xRVUXQz0qBGDE72LNZduaefYT5K_8-4FAhlimjkngt1yMWs3w!"
cipherText
=
"EHsnG0bjGT44BqIhETj!"
cipherText
=
cipherText.translate(cipherText.maketrans(newMaps, baseMaps))
print
(base64.b64decode(cipherText.encode(
'utf-8'
)).decode())
__int64 __fastcall sub_145AC(char
*
a1, __int64 a2)
{
unsigned
int
v4;
/
/
edx
char v5;
/
/
al
__int64 v6;
/
/
rcx
int
v7;
/
/
edx
char v8;
/
/
al
char
*
v9;
/
/
rcx
__int64 v10;
/
/
rax
unsigned
int
v11;
/
/
edx
char v12;
/
/
al
__int64 v13;
/
/
rcx
char v14;
/
/
cl
__int64 v15;
/
/
r8
int
*
v16;
/
/
rax
char v17;
/
/
al
__int64 v18;
/
/
rcx
char v19;
/
/
cl
__int64 v20;
/
/
r8
int
*
v21;
/
/
rax
int
v23;
/
/
[rsp
+
4h
] [rbp
-
3Ch
] BYREF
char v24;
/
/
[rsp
+
8h
] [rbp
-
38h
]
__int16 v25;
/
/
[rsp
+
9h
] [rbp
-
37h
]
char v26;
/
/
[rsp
+
Bh] [rbp
-
35h
]
unsigned
int
v27;
/
/
[rsp
+
Ch] [rbp
-
34h
]
char v28[
48
];
/
/
[rsp
+
10h
] [rbp
-
30h
] BYREF
v27
=
44
;
v4
=
0
;
*
(__m128i
*
)v28
=
_mm_load_si128((const __m128i
*
)&xmmword_14408);
*
(__m128i
*
)&v28[
32
]
=
_mm_load_si128((const __m128i
*
)&xmmword_143F8);
*
(__m128i
*
)&v28[
16
]
=
_mm_load_si128(xmmword_14418);
do
{
v5
=
v4
-
52
;
v6
=
v4
+
+
;
v28[v6] ^
=
v5;
}
while
( v4 < v27 );
/
/
还原base64编码串
v28[v27]
=
0
;
v7
=
0
;
v8
=
*
a1;
if
(
*
a1 )
{
v9
=
a1;
do
{
if
( v8 !
=
v9[v28
-
a1] )
/
/
strcmp
break
;
+
+
v9;
+
+
v7;
v8
=
*
v9;
}
while
(
*
v9 );
}
v10
=
v7;
v11
=
0
;
v24
=
-
48
;
if
( a1[v10]
=
=
v28[v10] )
/
/
bingo
{
v23
=
0x78063019
;
/
/
正确
v25
=
0
;
v26
=
0
;
do
{
v12
=
v11
-
52
;
v13
=
v11
+
+
;
*
((_BYTE
*
)&v23
+
v13) ^
=
v12;
}
while
( v11 <
4
);
v24
=
0
;
v14
=
v23;
if
( (_BYTE)v23 )
{
v15
=
a2
-
(_QWORD)&v23;
v16
=
&v23;
do
{
*
((_BYTE
*
)v16
+
v15)
=
v14;
v16
=
(
int
*
)((char
*
)v16
+
1
);
v14
=
*
(_BYTE
*
)v16;
}
while
(
*
(_BYTE
*
)v16 );
}
}
else
{
v23
=
0x3C002078
;
/
/
错误
v25
=
0
;
v26
=
0
;
do
{
v17
=
v11
-
52
;
v18
=
v11
+
+
;
*
((_BYTE
*
)&v23
+
v18) ^
=
v17;
}
while
( v11 <
4
);
v24
=
0
;
v19
=
v23;
if
( (_BYTE)v23 )
{
v20
=
a2
-
(_QWORD)&v23;
v21
=
&v23;
do
{
*
((_BYTE
*
)v21
+
v20)
=
v19;
v21
=
(
int
*
)((char
*
)v21
+
1
);
v19
=
*
(_BYTE
*
)v21;
}
while
(
*
(_BYTE
*
)v21 );
}
}
return
0i64
;
}
__int64 __fastcall sub_145AC(char
*
a1, __int64 a2)
{
unsigned
int
v4;
/
/
edx
char v5;
/
/
al
__int64 v6;
/
/
rcx
int
v7;
/
/
edx
char v8;
/
/
al
char
*
v9;
/
/
rcx
__int64 v10;
/
/
rax
unsigned
int
v11;
/
/
edx
char v12;
/
/
al
__int64 v13;
/
/
rcx
char v14;
/
/
cl
__int64 v15;
/
/
r8
int
*
v16;
/
/
rax
char v17;
/
/
al
__int64 v18;
/
/
rcx
char v19;
/
/
cl
__int64 v20;
/
/
r8
int
*
v21;
/
/
rax
int
v23;
/
/
[rsp
+
4h
] [rbp
-
3Ch
] BYREF
char v24;
/
/
[rsp
+
8h
] [rbp
-
38h
]
__int16 v25;
/
/
[rsp
+
9h
] [rbp
-
37h
]
char v26;
/
/
[rsp
+
Bh] [rbp
-
35h
]
unsigned
int
v27;
/
/
[rsp
+
Ch] [rbp
-
34h
]
char v28[
48
];
/
/
[rsp
+
10h
] [rbp
-
30h
] BYREF
v27
=
44
;
v4
=
0
;
*
(__m128i
*
)v28
=
_mm_load_si128((const __m128i
*
)&xmmword_14408);
*
(__m128i
*
)&v28[
32
]
=
_mm_load_si128((const __m128i
*
)&xmmword_143F8);
*
(__m128i
*
)&v28[
16
]
=
_mm_load_si128(xmmword_14418);
do
{
v5
=
v4
-
52
;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-12-2 02:39
被sunfishi编辑
,原因: