ReverseMe Lv1 无花无壳纯C语言编写
编译环境:C语言 ,Vs2022 msvc x86 Release特点:无花无壳,纯手写控制流平坦化+虚假控制流。因此可能会被杀毒软件特征。
注意是ReverseMe,请各位大佬找出正确的密码(flag),爆破无效。
软件的输入输出如图所示。
查毒链接:https://www.virustotal.com/gui/file/4529398e2e7905188b260d7f148208ef3d9b3b6cd4ff5a61674ed137ccd90624/detection
附件解压密码:123
本帖最后由 geesehoward 于 2025-3-28 16:12 编辑
控制台程序,直接拖入IDA,main函数如下
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // edx
int v4; // ecx
unsigned int v5; // esi
unsigned int v6; // edi
int v7; // ebx
unsigned __int64 v8; // kr30_8
unsigned __int64 v9; // rcx
unsigned int v10; // eax
__int64 v11; // rax
unsigned int v12; // eax
int v13; // edx
unsigned int v14; // esi
int v15; // ebx
unsigned int v16; // edi
unsigned int v17; // ecx
unsigned int v18; // eax
unsigned int v19; // edx
unsigned __int64 v20; // kr68_8
unsigned int v21; // kr20_4
int v22; // ecx
char v23; //
char v24; //
int v25; //
unsigned int v26; //
int v27; //
int v28; //
int v29; //
unsigned int v30; //
unsigned int v31; //
int v32; //
int v33; //
char Arglist; // BYREF
while ( 1 )
{
memset(Arglist, 0, 0x100u);
xmmword_4043C8 = xmmword_404060;
sub_401020(":Please input password(without spaces).\r\n[:] ", v23);
sub_401060("%s", (char)Arglist);
v3 = 0;
v30 = 0;
do
{
v4 = *((char *)&xmmword_4043C8 + v3);
v5 = 0xDEADC0DE;
v28 = v4;
v6 = 0xDEADC0DE;
v24 = -1;
LOBYTE(v7) = 0xDE;
while ( 1 )
{
while ( 1 )
{
while ( v6 > 0xC7B5A3F1 || v6 >= 0xC7B5A3F1 && v5 > 0x9D4E6F82 )
{
if ( v5 == -559038242 && v6 == -559038242 )
{
if ( (v7 & 1) != 0 )
{
v5 = -1655804030;
v6 = -944397327;
}
else
{
v5 = -944397327;
v6 = -1655804030;
}
v11 = 345069055i64 * (unsigned int)(v4 + 197);
v4 = v28;
v7 = HIBYTE(HIDWORD(v11));
}
}
if ( v5 != -1655804030 || v6 != -944397327 )
break;
v5 = -944397327;
v6 = -1655804030;
LOBYTE(v7) = 0;
}
if ( v5 == 0xA8C3D7E4 && !v6 )
break;
if ( v5 == -944397327 && v6 == -1655804030 )
{
v24 = v4 & 0x3A | ~(_BYTE)v4 & 0xC5;
v8 = 0x9D4E6F82C7B5A3F1ui64 * (int)(v4 & 0xFFFFFF3A | ~(_BYTE)v4 & 0xC5);
v5 = -1463560220;
v9 = 3781878765i64 * HIDWORD(v8)
+ ((3781878765u * (unsigned __int64)(-944397327 * (v4 & 0xFFFFFF3A | ~(_BYTE)v4 & 0xC5))) >> 32);
v10 = (((250939340i64 * (unsigned int)v8 + (unsigned __int64)(unsigned int)v9) >> 32) + HIDWORD(v9)) >> 32;
HIDWORD(v9) += (250939340i64 * (unsigned int)v8 + (unsigned __int64)(unsigned int)v9) >> 32;
v4 = v28;
v7 = (__PAIR64__(v10, HIDWORD(v9))
+ 250939340i64 * HIDWORD(v8)
+ ((v8 - (__PAIR64__(v10, HIDWORD(v9)) + 250939340i64 * HIDWORD(v8))) >> 1)) >> 31;
v6 = 0;
}
}
*((_BYTE *)&xmmword_4043C8 + v30) = v24 - v30 * (15 - v30);
v3 = v30 + 1;
v30 = v3;
}
while ( v3 < 0x10 );
v12 = 0;
v27 = 0;
v26 = 0;
do
{
v13 = *((char *)&xmmword_4043C8 + v12);
v14 = -559038242;
v15 = Arglist;
v16 = -559038242;
v25 = v13;
v33 = v15;
LOBYTE(v17) = -34;
v29 = -1;
while ( 1 )
{
while ( 1 )
{
while ( v16 > 0xC7B5A3F1 || v16 >= 0xC7B5A3F1 && v14 > 0x9D4E6F82 )
{
if ( v14 == -559038242 && v16 == -559038242 )
{
if ( (v17 & 1) != 0 )
{
v14 = -1655804030;
v16 = -944397327;
}
else
{
v14 = -944397327;
v16 = -1655804030;
}
v21 = v15 + v13;
v13 = v25;
v17 = v21 / 0xC725A3A;
}
}
if ( v14 != -1655804030 || v16 != -944397327 )
break;
v14 = -944397327;
v16 = -1655804030;
LOBYTE(v17) = 0;
}
if ( v14 == -1463560220 && !v16 )
break;
if ( v14 == -944397327 && v16 == -1655804030 )
{
v32 = v15 & ~v13;
v29 = (v32 | v13 & ~v15) == 0;
v31 = (0x9D4E6F82C7B5A3F1ui64 * ((v32 | v13 & ~v15) == 0)) >> 32;
v14 = -1463560220;
v18 = (((250939340i64 * (unsigned int)(-944397327 * v29)
+ ((0x4C2B8975A651791Di64 * (unsigned __int64)((v32 | v13 & ~v15) == 0)) >> 32)) >> 32)
+ ((3781878765i64 * v31 + ((3781878765u * (unsigned __int64)(unsigned int)(-944397327 * v29)) >> 32)) >> 32)) >> 32;
v19 = ((250939340i64 * (unsigned int)(-944397327 * v29)
+ ((0x4C2B8975A651791Di64 * (unsigned __int64)((v32 | v13 & ~v15) == 0)) >> 32)) >> 32)
+ ((3781878765i64 * v31 + ((3781878765u * (unsigned __int64)(unsigned int)(-944397327 * v29)) >> 32)) >> 32);
v15 = v33;
v20 = __PAIR64__(v18, v19)
+ 250939340i64 * v31
+ ((__PAIR64__(v31, -944397327 * v29) - (__PAIR64__(v18, v19) + 250939340i64 * v31)) >> 1);
v13 = v25;
v17 = v20 >> 31;
v16 = 0;
}
}
v22 = v27;
if ( !v29 )
v22 = -1;
v12 = v26 + 1;
v27 = v22;
v26 = v12;
}
while ( v12 < 0xF );
if ( v22 )
puts(":Failed.\r\n");
else
puts(":Success.\r\n");
}
}
其中几个while(1)循环都是干扰项,简化代码,得到如下有效代码
int result = 0;
char Arglist; // BYREF
while (1)
{
result = 0;
memset(Arglist, 0, 0x100u);
unsigned char Keybase[] = { 0xF0, 0xFA, 0xBE, 0x52, 0x5C, 0x54, 0x5C, 0x6F, 0xAE, 0xAA, 0x54, 0x99, 0x59, 0xB8, 0x86, 0x00 };
printf(":Please input password(without spaces).\r\n[:] ");
scanf_s("%s", Arglist, 260);
for(int i = 0;i < 0x10;i++)
{
char c = Keybase;
char v24 = c & 0x3A | ~(_BYTE)c & 0xC5;
Keybase = v24 - i * (15 - i);
}
for(int i = 0;i < 0xF;i++)
{
char v13 = Keybase;
char v15 = Arglist;
char v32 = v15 & ~v13;
int v29 = (v32 | v13 & ~v15) == 0;
if (!v29)
result = -1;
}
if (result)
puts(":Failed.\r\n");
else
puts(":Success.\r\n");
}
分析两段循环,第一段是转化Key,第二段是将输入的flag按位与转化的key做运算,运算结果为0,(key&~flag) |(~key & flag),等同于判断key=flag。
修改代码
Keybase = 0;
printf("Key:%s\n", Keybase);
打印得到flag
补充一个解出的代码,是在ai帮助下写的,我对py不太熟悉
本帖最后由 Cl0sueN1ght 于 2025-3-28 11:13 编辑
## 明码
main 函数反编译观察到疑似的加密字符串(s)和用户输入的(ms)
``` cpp
memset(ms, 0, 0x100u);
s = xmmword_404060; // 86B8599954AAAE6F5C545C52BEFAF0h
sub_401020("Please input password(without spaces).\r\n[:] ", v23);
sub_401060("%s", (char)ms);
```
追踪 s 的数据流,serial 的解密操作
``` cpp
do
{
sc = *((char *)&s + vc3_);
sc2 = sc & 0x3A | ~(_BYTE)sc & 0xC5;
*((_BYTE *)&s + vc3) = sc2 - vc3 * (15 - vc3);
vc3_ = vc3 + 1;
vc3 = vc3_;
}
while ( vc3_ < 0x10 );
```
将解密的 serial 与 m_serial 进行比较
``` cpp
do
{
sc_1 = *((char *)&s + vc);
msc = ms;
m = msc & ~sc_1;
nz = (m | sc_1 & ~msc) == 0;
if ( !nz )
f = -1;
vc = vc2_ + 1;
}
while ( vc < 0xF );
```
## 动态调试
由于程序允许多次验证,输入 "Cl0sueN1ght is coming",观察 base+0x000043C8 (17352d) 内存
``` cpp
004043C835 31 61 73 6D 5F 63 72 33 39 5F 30 78 63 35 C551asm_cr39_0xc5Å
004043D800 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00................
```
## 反混淆
混淆控制流呈现明显的模板的特征,提取完数据流后,经过编译优化,得到结果
下载>>拖入IDA>>F5>>伪代码扔到deepseek>>得到以下代码。。。
int main()
{
const unsigned char initial_data = {
0xF0,0xFA,0xBE,0x52,0x5C,0x54,0x5C,0x6F,
0xAE,0xAA,0x54,0x99,0x59,0xB8,0x86 };
unsigned char processed = { 0 };
// 处理初始数据生成密码
for (int i = 0; i < 15; ++i) {
processed = (unsigned char)((initial_data ^ 0xC5) - i * (15 - i));
}
std::cout << processed;
} 牛 学习了
牛 学习了 菜鸟学习了 第一段可以简化成这样,第二段只是比较
memset(Arglist, 0, 0x100u);
keys = xmmword_404060; // 86B8599954AAAE6F5C545C52BEFAF0
sub_401020("[*]:Please input password(without spaces).\r\n[:] ");
scanf("%s", Arglist);
idx = 0;
v29 = 0;
do
{
v4 = *((char *)keys);
v5 = -559038242;
v27 = v4;
v23 = v4 & 0x3A | ~(_BYTE)v4 & 0xC5;
*((_BYTE *)keys) = v23 - idx * (15 - idx);
}
while ( idx < 0x10 );
python写一个脚本解密
hex_str='86B8599954AAAE6F5C545C52BEFAF0'
key_bytes = bytes.fromhex(hex_str)[::-1]
for i in range(15):
b = key_bytes
val = (b ^ 0xc5) - i * (15 - i)
print(chr(val),end='')
# 51asm_cr39_0xc5
页:
[1]
2