2025蓝桥杯网络安全赛道逆向第一题ShadowPhases_
这是一道非常简单的题目我会先给展示比赛时如何快速拿到flag之后会讲解加密部分逻辑以及脚本的编写1.首先解压文件拖入ida反编译int __fastcall main(int argc, const char **argv, const char **envp) { char Str1[128]; // [rsp30h] [rbp-50h] BYREF char Str2[128]; // [rspB0h] [rbp30h] BYREF void *v6; // [rsp130h] [rbpB0h] void *v7; // [rsp138h] [rbpB8h] void *v8; // [rsp140h] [rbpC0h] void *v9; // [rsp150h] [rbpD0h] void *v10; // [rsp158h] [rbpD8h] void *v11; // [rsp160h] [rbpE0h] _BYTE v12[13]; // [rsp16Eh] [rbpEEh] BYREF _BYTE v13[15]; // [rsp17Bh] [rbpFBh] BYREF _BYTE Src[5]; // [rsp18Ah] [rbp10Ah] BYREF char _[9]; // [rsp18Fh] [rbp10Fh] BYREF void *v16; // [rsp198h] [rbp118h] void *v17; // [rsp1A0h] [rbp120h] void *Block; // [rsp1A8h] [rbp128h] char __Df[6]; // [rsp1B2h] [rbp132h] BYREF size_t n13; // [rsp1B8h] [rbp138h] size_t i; // [rsp1C0h] [rbp140h] size_t Size; // [rsp1C8h] [rbp148h] sub_401B10(argc, argv, envp); Src[0] 0; Src[1] 5; Src[2] -125; Src[3] 0x80; Src[4] -114; strcpy(_, ); _[2] -125; _[3] 47; _[4] -86; _[5] 43; _[6] -127; _[7] -88; _[8] -91; Size 14; v13[0] 19; v13[1] 57; v13[2] -66; v13[3] -66; v13[4] -76; v13[5] 56; v13[6] -72; v13[7] -70; v13[8] -69; v13[9] -76; v13[10] 62; v13[11] -112; v13[12] 58; v13[13] -70; v13[14] -76; i 15; v12[0] -117; v12[1] -119; v12[2] 34; v12[3] -120; v12[4] -117; v12[5] 32; v12[6] 9; v12[7] 34; v12[8] -120; v12[9] 8; v12[10] -115; v12[11] -120; v12[12] -81; n13 13; __Df[5] -103; __Df[4] -35; __Df[3] -1; qmemcpy(__Df, \Df, 3); Block malloc(0xFu); v17 malloc(i 1); v16 malloc(n13 1); if ( !Block || !v17 || !v16 ) { puts(Buffer); exit(1); } memcpy(Block, Src, Size); memcpy(v17, v13, i); memcpy(v16, v12, n13); sub_4015B6((__int64)Block, Size, __Df[2]); sub_4015B6((__int64)v17, i, __Df[1]); sub_4015B6((__int64)v16, n13, __Df[0]); *((_BYTE *)Block Size) 0; *((_BYTE *)v17 i) 0; *((_BYTE *)v16 n13) 0; v9 v17; v10 v16; v11 Block; v6 Block; v7 v17; v8 v16; sub_401550(Str2, 128, %s%s%s, (const char *)Block, (const char *)v17, (const char *)v16); printf(Format); scanf(%127s, Str1); if ( !strcmp(Str1, Str2) ) puts(Buffer_); else puts(Buffer__0); free(Block); free(v17); free(v16); return 0; }解法1其实通过这部分就可以看出其实就是将我们输入的内容与str2进行对比相同则是正确的flag那么我们只需要在判断的时候添加一个断点通过动态调试找到str2的数据就可以了这样我们就找到了正确的flag解法2通过第一张图部分我们很容易分析出这段代码的主要加密应该就放在sub_4015B6中我们跟进去看一下这里我已经将注释写好了我们可以看到这里是将a1的数据进行一个sub_40159A操作后通过循环和a3进行异或来得到正确的flag片段之后将这三段flag拼到一起就是正确的flag我们进去查看一下sub_40159A这里面其实就是一个简单的移位ok,整个加密逻辑我们其实已经分析完了接下来就是理清思路编写脚本我们只需要将给出的数据按照它的加密逻辑编写就行了不过这里我们需要注意的是这里我们需要注意C 语言字符串处理函数的一个“隐藏特性在 C 语言中字符串是以 \0ASCII 码为 0结尾的。当你调用 strcpy(dest, ) 时它不仅仅拷贝了那个加号 它实际上拷贝了两个字节第一个字节是 (ASCII 码 43)。第二个字节是 \0 (ASCII 码 0)用来表示字符串的结束。所以说这里的_[0] 的值是 。_[1] 的值被自动设为了 0def rotl8(val):#实现循环左移 return ((val 1) | (val 7)) 0xFF def solve(data, key): flag_part for i in data: byte_unsigned i 0xFF decrypted_byte ord(key) ^ rotl8(byte_unsigned) flag_part chr(decrypted_byte) return flag_part block1_data [0,5,-125,0x80,-114,ord(),0,-125,47,-86,43,-127,-88,-91] key1 f #__Df[2] block2_data [19, 57, -66, -66, -76, 56, -72, -70, -69, -76, 62, -112, 58, -70, -76] key2 D # __Df[1] block3_data [-117, -119, 34, -120, -117, 32, 9, 34, -120, 8, -115, -120, -81] key3 # __Df[0] res1 solve(block1_data,key1) res2 solve(block2_data,key2) res3 solve(block3_data, key3) print(fFlag 片段 1: {res1}) print(fFlag 片段 2: {res2}) print(fFlag 片段 3: {res3}) print(f完整 Flag: {res1 res2 res3})