https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]jocker
32exe
https://blog.csdn.net/qq_32072825/article/details/121657090
两处 sp 分析错误,改回来在函数最后按一下 c 就可以正常反编译了
发现一个奇怪的函数,搜一下:
https://www.cnblogs.com/CCb0nd/p/17857745.html
对内存权限进行了修改 → SMC
int __cdecl main(int argc, const char **argv, const char **envp)
{
char input[50]; // [esp+12h] [ebp-96h] BYREF
char Destination[80]; // [esp+44h] [ebp-64h] BYREF
DWORD flOldProtect; // [esp+94h] [ebp-14h] BYREF
size_t v7; // [esp+98h] [ebp-10h]
int i; // [esp+9Ch] [ebp-Ch]
__main();
puts("please input you flag:");
if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
exit(1);
scanf("%40s", input);
v7 = strlen(input);
if ( v7 != 24 )
{
puts("Wrong!");
exit(0);
}
strcpy(Destination, input);
wrong(input);
omg(input);
for ( i = 0; i <= 186; ++i )
*((_BYTE *)encrypt + i) ^= 0x41u;
if ( encrypt(Destination) )
finally(Destination);
return 0;
}
复制出来输入,分成两个部分:
一个用 wrong
和 omg
检验 input,另一个用加密的函数 encrypt
对副本检验并处理
先看前面:
char *__cdecl wrong(char *a1)
{
char *result; // eax
int i; // [esp+Ch] [ebp-4h]
for ( i = 0; i <= 23; ++i )
{
result = &a1[i];
if ( (i & 1) != 0 )
a1[i] -= i;
else
a1[i] ^= i;
}
return result;
}
int __cdecl omg(char *a1)
{
int v2[24]; // [esp+18h] [ebp-80h] BYREF
int i; // [esp+78h] [ebp-20h]
int v4; // [esp+7Ch] [ebp-1Ch]
v4 = 1;
qmemcpy(v2, &unk_4030C0, sizeof(v2));
for ( i = 0; i <= 23; ++i )
{
if ( a1[i] != v2[i] )
v4 = 0;
}
if ( v4 == 1 )
return puts("hahahaha_do_you_find_me?");
else
return puts("wrong ~~ But seems a little program");
}
unsigned char ida_chars[] =
{
102, 0, 0, 0, 107, 0, 0, 0, 99, 0,
0, 0, 100, 0, 0, 0, 127, 0, 0, 0,
97, 0, 0, 0, 103, 0, 0, 0, 100, 0,
0, 0, 59, 0, 0, 0, 86, 0, 0, 0,
107, 0, 0, 0, 97, 0, 0, 0, 123, 0,
0, 0, 38, 0, 0, 0, 59, 0, 0, 0,
80, 0, 0, 0, 99, 0, 0, 0, 95, 0,
0, 0, 77, 0, 0, 0, 90, 0, 0, 0,
113, 0, 0, 0, 12, 0, 0, 0, 55, 0,
0, 0, 102, 0
};
解密脚本:
key = 0x66, 0x6B, 0x63, 0x64, 0x7F, 0x61, 0x67, 0x64, 0x3B, 0x56, 0x6B, 0x61, 0x7B, 0x26, 0x3B, 0x50, 0x63, 0x5F, 0x4D, 0x5A, 0x71, 0x0C, 0x37, 0x66
fake_flag = ''
for i in range(24):
if i % 2 == 1:
fake_flag += chr(key[i] + i)
else:
fake_flag += chr(key[i] ^ i)
print(fake_flag)
flag{fak3_alw35_sp_me!!}
果然不对,看下面加密函数
采用 dbg dump 的方法,输入 111111111111111111111111
运行到解密部分,进去函数
dump 出来重新用 IDA 打开,发现 start 点已经到 encrypt 函数里了(不过没有符号了)
int __cdecl start(int a1)
{
int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREF
int v3; // [esp+68h] [ebp-20h]
int i; // [esp+6Ch] [ebp-1Ch]
v3 = 1;
qmemcpy(v2, &unk_403040, sizeof(v2));
for ( i = 0; i <= 18; ++i )
{
if ( (char)(*(_BYTE *)(i + a1) ^ aHahahahaDoYouF[i]) != v2[i] )
{
puts("wrong ~");
v3 = 0;
exit(0);
}
}
puts("come here");
return v3;
}
就是对输入进行一个异或后的比较
st = "hahahaha_do_you_find_me?"
v2 = [0x0E, 0x0D, 0x09, 0x06, 0x13, 0x05, 0x58, 0x56, 0x3E, 0x06, 0x0C, 0x3C, 0x1F, 0x57, 0x14, 0x6B, 0x57, 0x59, 0x0D]
flag = [ chr(v2[i] ^ ord(st[i])) for i in range(len(v2)) ]
print("".join(flag))
flag{d07abccf8a410c
最后一个函数
int __cdecl sub_40159A(int a1)
{
unsigned int v1; // eax
char v3[9]; // [esp+13h] [ebp-15h] BYREF
int v4; // [esp+1Ch] [ebp-Ch]
strcpy(v3, "%tp&:");
v1 = time(0);
srand(v1);
v4 = rand() % 100;
v3[6] = 0;
*(_WORD *)&v3[7] = 0;
if ( (v3[(unsigned __int8)v3[5]] != *(_BYTE *)((unsigned __int8)v3[5] + a1)) == v4 )
return puts("Really??? Did you find it?OMG!!!");
else
return puts("I hide the last part, you will not succeed!!!");
}
有随机数了,看着好像是那种大概率是不可能事件的类型,这样我们需要根据上下文来猜测补全程序想要做的事情
由于前面采用的是对字符串进行异或解密,这里也根据最后一位是 }
来异或回去,解密的对象是 "%tp&:"
st = "hahahaha_do_you_find_me?"
v2 = [0x0E, 0x0D, 0x09, 0x06, 0x13, 0x05, 0x58, 0x56, 0x3E, 0x06, 0x0C, 0x3C, 0x1F, 0x57, 0x14, 0x6B, 0x57, 0x59, 0x0D]
flag = [chr(v2[i] ^ ord(st[i])) for i in range(len(v2))]
flag = "".join(flag)
v3 = "%tp&:"
v4 = ord(':') ^ ord('}')
v5 = [ord(v3[i]) ^ v4 for i in range(len(v3))]
flag += "".join([chr(i) for i in v5])
print(flag)
flag{d07abccf8a410cb37a}