解题过程:
直接放入IDA分析,跳入main函数,得到如下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 int __cdecl main(int argc, const char **argv, const char **envp) { char *v3; // rax char v5; // [rsp+Fh] [rbp-41h] char v6[56]; // [rsp+10h] [rbp-40h] BYREF unsigned __int64 v7; // [rsp+48h] [rbp-8h] v7 = __readfsqword(0x28u); printf("Try my base64 program?.....\n>"); __isoc99_scanf("%20s", v6); v5 = time(0LL); srand(v5); if ( (rand() & 1) != 0 ) { v3 = base64_encode(v6); puts(v3); puts("Is there something wrong?"); } else { puts("Sorry I think it's not prepared yet...."); puts("And I get a strange string from my program which is different from the standard base64:"); puts("d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="); puts("What's wrong??"); } return 0; }
显然,最底下有一串形似base64编码的字符串
1 d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==
解码发现无法正确得到内容,猜测是映射表被更改过
观察发现一个明显怪异的函数:“O_OLookAtYou”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __int64 O_OLookAtYou() { __int64 result; // rax char v1; // [rsp+1h] [rbp-5h] int i; // [rsp+2h] [rbp-4h] for ( i = 0; i <= 9; ++i ) { v1 = base64_table[i]; base64_table[i] = base64_table[19 - i]; result = 19 - i; base64_table[result] = v1; } return result; }
直接放入VS得到置换后结果:
1 2 3 4 5 6 7 8 9 10 11 12 int main() { char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (int i = 0; i <= 9; ++i) { char v1 = base64_table[i]; base64_table[i] = base64_table[19 - i]; char result = 19 - i; base64_table[result] = v1; } cout << base64_table;//TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ }
得到新表,直接对密文进行解密即可得到flag
-——————————————————————————————-
明确一点,当main函数找不到期望的内容的时候,应该从start函数开始看
main函数为用户代码的入口,但在此之前应有许多函数库需要初始化,这些初始化工作则从start函数开始
1 2 3 4 5 6 7 8 9 10 11 12 13 // positive sp value has been detected, the output may be wrong! void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void)) { __int64 v3; // rax int v4; // esi __int64 v5; // [rsp-8h] [rbp-8h] BYREF char *retaddr; // [rsp+0h] [rbp+0h] BYREF v4 = v5; v5 = v3; __libc_start_main(main, v4, &retaddr, _libc_csu_init, _libc_csu_fini, a3, &v5); __halt(); }
本题中,__libc_start_main()函数调用了包括main在内的三个函数(但第三个函数进入后会发现里面什么都没有)
1 2 3 4 5 6 7 8 9 10 11 12 13 void __fastcall _libc_csu_init(unsigned int a1, __int64 a2, __int64 a3) { signed __int64 v4; // rbp __int64 i; // rbx v4 = &_do_global_dtors_aux_fini_array_entry - _frame_dummy_init_array_entry; init_proc(); if ( v4 ) { for ( i = 0LL; i != v4; ++i ) (_frame_dummy_init_array_entry[i])(a1, a2, a3); } }
v4变量使用了两个标签,不妨进入去看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .init_array:0000000000601E08 __frame_dummy_init_array_entry dq offset frame_dummy .init_array:0000000000601E08 ; DATA XREF: LOAD:00000000004000F8↑o .init_array:0000000000601E08 ; LOAD:0000000000400210↑o ... .init_array:0000000000601E08 ; Alternative name is '__init_array_start' .init_array:0000000000601E10 dq offset O_OLookAtYou .init_array:0000000000601E10 _init_array ends .init_array:0000000000601E10 .fini_array:0000000000601E18 ; ELF Termination Function Table .fini_array:0000000000601E18 ; =========================================================================== .fini_array:0000000000601E18 .fini_array:0000000000601E18 ; Segment type: Pure data .fini_array:0000000000601E18 ; Segment permissions: Read/Write .fini_array:0000000000601E18 _fini_array segment qword public 'DATA' use64 .fini_array:0000000000601E18 assume cs:_fini_array .fini_array:0000000000601E18 ;org 601E18h .fini_array:0000000000601E18 __do_global_dtors_aux_fini_array_entry dq offset __do_global_dtors_aux
0000000000601E10地址处引用了O_OLookAtYou函数的地址
这一系列函数通过_libc_csu_init函数中的for循环去使用
当然,实际上看看表有没有被更改只需要对base64_table查看其交叉引用即可
所以最后还是自己瞎忙活一通,算是吃个瘪长个教训吧……
插画ID:89345225