这次是我做过的最最最水的Re…奈何我一个只会re的只能干看着
PaperPlease
hint: 简单的字符串解密
ELF64文件
不管三七二十一直接复制(假的)flag提交一波,果然是假的
老老实实分析
__int64 __fastcall subfhsadkhjbfleiowiuoyfgshjdvbsmnakl(__int64 a1, __int64 fakeFlag) { int i; // [rsp+1Ch] [rbp-24h] char *dest; // [rsp+20h] [rbp-20h] char *s; // [rsp+28h] [rbp-18h] dest = (char *)malloc(0x80uLL); strcpy(dest, (const char *)(a1 + 7)); //掐头 dest[strlen(dest) - 1] = 0; // 去尾 s = (char *)malloc(0x80uLL); strcpy(s, (const char *)(fakeFlag + 7)); // 掐头 s[strlen(s) - 1] = 0; // 去尾 for ( i = 0; i < strlen(dest); ++i ) dest[i] ^= *((_BYTE *)unk_6984657 + i); // 简单异或 return unk_sa7ydu3jb432(dest, s); // 在.init 动态注册strcmp }
虽然注释写出来了,但是下面还是分析下unk_sa7ydu3jb432
,查看交叉引用可以看到这个函数
unsigned __int64 init() { const char *v0; // rax char v2[15]; // [rsp+1h] [rbp-Fh] BYREF *(_QWORD *)&v2[7] = __readfsqword(0x28u); strcpy(v2, "a ?WcV"); v0 = hafsddsfasfsdaevxcvdsfdfdscxvxcv(v2, (__int64)&unk_202A); // 简单字符串加密 unk_sa7ydu3jb432 = (__int64 (__fastcall *)(_QWORD, _QWORD))dlsym((void *)0xFFFFFFFFFFFFFFFFLL, v0); // 注册函数strcmp return __readfsqword(0x28u) ^ *(_QWORD *)&v2[7]; }
const char *__fastcall hafsddsfasfsdaevxcvdsfdfdscxvxcv(const char *a1, __int64 a2) { int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; i < strlen(a1); ++i ) a1[i] += *(_BYTE *)(i + a2); return a1; }
c++跑一波就知道v0
是strcmp
最终subfhsadkhjbfleiowiuoyfgshjdvbsmnakl
函数
__int64 __fastcall subfhsadkhjbfleiowiuoyfgshjdvbsmnakl(__int64 a1, __int64 fakeFlag) { int i; // [rsp+1Ch] [rbp-24h] char *dest; // [rsp+20h] [rbp-20h] char *s; // [rsp+28h] [rbp-18h] dest = (char *)malloc(0x80uLL); strcpy(dest, (const char *)(a1 + 7)); //掐头 dest[strlen(dest) - 1] = 0; // 去尾 s = (char *)malloc(0x80uLL); strcpy(s, (const char *)(fakeFlag + 7)); // 掐头 s[strlen(s) - 1] = 0; // 去尾 for ( i = 0; i < strlen(dest); ++i ) dest[i] ^= *((_BYTE *)unk_6984657 + i); // 简单异或 return strcmp(dest, s); // 在.init 动态注册strcmp }
放c++里跑一遍完事
#include <iostream> std::string hafsddsfasfsdaevxcvdsfdfdscxvxcv(std::string a1, std::string a2) { int i; // [rsp+1Ch] [rbp-14h] for ( i = 0; i < a1.length(); ++i ) a1[i] += (int)a2[i]; return a1; } int main() { using namespace std; // string str = hafsddsfasfsdaevxcvdsfdfdscxvxcv("a ?WcV", "\x12\x54\x33\x0C\x0A\x1A"); // cout << str << endl; unsigned char unk_2008[32] = { 0x56, 0x05, 0x53, 0x52, 0x04, 0x03, 0x53, 0x54, 0x04, 0x0B, 0x53, 0x51, 0x06, 0x06, 0x0F, 0x55, 0x05, 0x5B, 0x03, 0x56, 0x0E, 0x07, 0x57, 0x0E, 0x01, 0x0D, 0x56, 0x00, 0x04, 0x06, 0x0A, 0x5D }; string fakeflag = "5c715207e3abed7dfb7c8ea9c82d0e29"; for (int i = 0; i < fakeflag.length(); ++i) { fakeflag[i] ^= unk_2008[i]; } cout << fakeflag; return 0; }
end
upx壳,脱壳之后放IDA,定位到主函数sub_40238F
int sub_40238F() { int v0; // eax int v1; // eax int v2; // eax int v4[22]; // [esp+18h] [ebp-47Ch] BYREF char Buffer[19]; // [esp+71h] [ebp-423h] BYREF char v6[16]; // [esp+84h] [ebp-410h] BYREF int v7; // [esp+94h] [ebp-400h] BYREF int v8[250]; // [esp+98h] [ebp-3FCh] BYREF int v9; // [esp+480h] [ebp-14h] int v10; // [esp+484h] [ebp-10h] int v11; // [esp+488h] [ebp-Ch] int i; // [esp+48Ch] [ebp-8h] sub_402B50(); i = 0; v11 = 0; memset(v8, 0, sizeof(v8)); v9 = 0; do { while ( 1 ) { printf("Please input:"); scanf("%d", &v7); v0 = i++; v8[v0] = v7; switch ( v7 ) { case 2: // == 's' v11 += 7; break; case 8: // == 'w' v11 -= 7; break; case 6: // == 'd' ++v11; break; case 4: // == 'a' --v11; break; default: exit(1); } if ( !dword_406060[v11] ) exit(1); if ( dword_406060[v11] != 1 ) break; printf("continue"); } } while ( dword_406060[v11] != 35 ); // 出口 while ( v8[v9] ) { v1 = v9++; v10 += v8[v1]; } sprintf(Buffer, "%d", v10); // int2str printf("%s", Buffer); // "80" // md5 sub_401410(v4); // md5 init v2 = strlen(Buffer); sub_401451((int)v4, Buffer, v2); // md5 update sub_401582(v4, (int)v6); // md5 digest printf("congratulation"); printf("the flag is {"); for ( i = 0; i <= 15; ++i ) printf("%02x", (unsigned __int8)v6[i]); putchar(125); // '}' return 0; }
一看就是7*8迷宫… 方向控制为2,8,6,4,要求是到达0x00000023
即35处
把dword_406060
dump出来
走一遍
即2622668662224422666
然后其实不需要分析后面的函数就能出flag,不过还是看了下,就是标准的md5,即 md5(80)
,这点在最后输出flag时也得到的证实
发表回复