GFSJ0808-【Windows_Reverse2】
手脱壳 base64
能看到是ASProtect壳 然后程序入口还有pushad 我们直接使用esp定律来脱壳
脱壳完成后
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Buffer[1024]; // [esp+8h] [ebp-C04h] BYREF
char v5[1024]; // [esp+408h] [ebp-804h] BYREF
char v6[1024]; // [esp+808h] [ebp-404h] BYREF
memset(v5, 0, sizeof(v5));
memset(v6, 0, sizeof(v6));
printf("input code:");
scanf("%s", v5);
if ( !sub_7511F0(v5) )
{
printf("invalid input\n");
exit(0);
}
sub_751240(v6);
memset(Buffer, 0, sizeof(Buffer));
sprintf(Buffer, "DDCTF{%s}", v6);
if ( !strcmp(Buffer, aDdctfReverse) )
printf("You've got it !!! %s\n", Buffer);
else
printf("Something wrong. Try again...\n");
return 0;
}
很简单的操作 一个数字和大写字符判断
char __usercall sub_7511F0@<al>(const char *a1@<esi>)
{
int v1; // eax
int v2; // edx
int v3; // ecx
char v4; // al
v1 = strlen(a1);
v2 = v1;
if ( v1 && v1 % 2 != 1 )
{
v3 = 0;
if ( v1 <= 0 )
return 1;
while ( 1 )
{
v4 = a1[v3];
if ( (v4 < '0' || v4 > '9') && (v4 < 'A' || v4 > 'F') )
break;
if ( ++v3 >= v2 )
return 1;
}
}
return 0;
}
加密函数
int __usercall sub_751240@<eax>(const char *a1@<esi>, int a2)
{
int v2; // edi
int v3; // edx
char v4; // bl
char v5; // al
char v6; // al
unsigned int v7; // ecx
char v9; // [esp+Bh] [ebp-405h]
_BYTE v10[1024]; // [esp+Ch] [ebp-404h] BYREF
v2 = strlen(a1);
memset(v10, 0, sizeof(v10));
v3 = 0;
if ( v2 > 0 )
{
v4 = v9;
do
{
v5 = a1[v3];
if ( (unsigned __int8)(v5 - 48) > 9u )
{
if ( (unsigned __int8)(v5 - 65) <= 5u )
v9 = v5 - 55;
}
else
{
v9 = a1[v3] - 48;
}
v6 = a1[v3 + 1];
if ( (unsigned __int8)(v6 - 48) > 9u )
{
if ( (unsigned __int8)(v6 - 65) <= 5u )
v4 = v6 - 55;
}
else
{
v4 = a1[v3 + 1] - 48;
}
v7 = (unsigned int)v3 >> 1;
v3 += 2;
v10[v7] = v4 | (16 * v9);
}
while ( v3 < v2 );
}
return sub_751000(v2 / 2, a2);
}
再往下看 一个base64 xor 了0x76
int __cdecl sub_751000(int a1, void *a2)
{
char *v2; // ecx
int v3; // ebp
char *v4; // edi
int v5; // esi
unsigned __int8 v6; // bl
int i; // esi
int v8; // edi
int v9; // edi
size_t v10; // esi
void *v11; // edi
const void *p_Src; // eax
unsigned __int8 v14; // [esp+14h] [ebp-38h] BYREF
unsigned __int8 v15; // [esp+15h] [ebp-37h]
unsigned __int8 v16; // [esp+16h] [ebp-36h]
char v17; // [esp+18h] [ebp-34h]
char v18; // [esp+19h] [ebp-33h]
char v19; // [esp+1Ah] [ebp-32h]
char j; // [esp+1Bh] [ebp-31h]
void *v21; // [esp+1Ch] [ebp-30h]
char v22[4]; // [esp+20h] [ebp-2Ch] BYREF
void *Src; // [esp+24h] [ebp-28h] BYREF
size_t Size; // [esp+34h] [ebp-18h]
unsigned int v25; // [esp+38h] [ebp-14h]
int v26; // [esp+48h] [ebp-4h]
v3 = a1;
v4 = v2;
v21 = a2;
std::string::string(v22);
v5 = 0;
v26 = 0;
if ( a1 )
{
do
{
*(&v14 + v5) = *v4;
v6 = v15;
++v5;
--v3;
++v4;
if ( v5 == 3 )
{
v17 = v14 >> 2;
v18 = (v15 >> 4) + 16 * (v14 & 3);
v19 = (v16 >> 6) + 4 * (v15 & 0xF);
j = v16 & 0x3F;
for ( i = 0; i < 4; ++i )
std::string::operator+=(v22, (unsigned __int8)byte_753020[(unsigned __int8)*(&v17 + i)] ^ 0x76);
v5 = 0;
}
}
while ( v3 );
if ( v5 )
{
if ( v5 < 3 )
{
memset(&v14 + v5, 0, 3 - v5);
v6 = v15;
}
v18 = (v6 >> 4) + 16 * (v14 & 3);
v17 = v14 >> 2;
v19 = (v16 >> 6) + 4 * (v6 & 0xF);
v8 = 0;
for ( j = v16 & 0x3F; v8 < v5 + 1; ++v8 )
std::string::operator+=(v22, (unsigned __int8)byte_753020[(unsigned __int8)*(&v17 + v8)] ^ 0x76);
if ( v5 < 3 )
{
v9 = 3 - v5;
do
{
std::string::operator+=(v22, 61);
--v9;
}
while ( v9 );
}
}
}
v10 = Size;
v11 = v21;
memset(v21, 0, Size + 1);
p_Src = Src;
if ( v25 < 0x10 )
p_Src = &Src;
memcpy(v11, p_Src, v10);
v26 = -1;
return std::string::~string(v22);
}
我们直接xor回来发现是标准的base64表
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
那我们直接解码下面的reverse+ 那为什么没有进行sub_751240@<eax> 的操作呢 其实是
hex字符串 -> 原始字节 也就是hex解码 所以流程可以看成这样
输入 hex
↓
sub_751240:hex 转 bytes
↓
sub_751000:把 bytes 做 Base64 编码
↓
得到 reverse+
↓
比较DDCTF{reverse+}
exp
import base64
s = b"reverse+"
code = base64.b64decode(s)
print(code.hex().upper())
flag
flag{ADEBDEAEC7BE}
评论