记录一下buuctf的write up.
RE
Easyre
下载后的拖进ida64:
发现 flag{this_Is_a_EaSyRe}
helloword
打开下载的压缩包里面发现是个apk的文件
拖进APK改之理找到主函数发现flag
flag{7631a988259a00816deda84afb29430a}
Reverse1
打开压缩包拖进dbg,由于我们现在在内核模式空间(.dll),我们需要自己调整到用户层面(.exe),所以按一下alt+f9
大概主函数在exit的附近看见exit有两个我们在附近进去看看
我们看到了flag的值 但是我们需要判断进行了什么操作,然后我们去进行分析
经过分析来说
1 2 if ( Str2[j] == 'o' ) Str2[j] = '0' ;
可以看到进行的操作是o字符变成了0所以flag为:
flag{hell0_world}
Reverse2
打开压缩包放进ida
可以看到里面进行了判断如果字符串有i和r就变成1 看到了strcmp里面进行和flag地址进行了比较
1 2 3 .data:0000000000601080 flag db '{' ; DATA XREF: main+34↑r .data:0000000000601080 ; main+44↑r ... .data:0000000000601081 aHackingForFun db 'hacking_for_fun}' ,0
我们可以推出来flag{hacking_for_fun}进行变换:flag{hack1ng_fo1_fun}
新年快乐
我们把这个压缩包拖进PEiD的时候发现有壳是一个upx的壳
我们把这个包拖进dbg 找到popad
我们给jmp下断点
到call 00401000位置进去 发现已经脱壳成功
进行字符串探索 进入到403024:"please input the true flag:"位置进去看看
我们可以分析出来进行了字符串的strcmp的函数功能判断是否和HappyNewYear!相同
flag为flag{HappyNewYear!}
xor
打开压缩文件,拖进ida
看到strcmp函数进行了比较,我们进去看一下再跳转到100000F6Eh可以看到进行了字符串
1 2 for ( i = 1; i < '!' ; ++i ) v6[i] ^= v6[i - 1];
可以不难分析,进行了前一个和下一个字符串进行了异或,第一个字符串不变,而两次异或就是原来的值所以我们写一个python的脚本
1 2 3 4 5 6 7 8 9 10 11 12 str1 = ['f' , 0x0A, 'k' , 0x0C, 'w' , '&' , 'O' , '.' , '@' , 0x11, 'x' , 0x0D, 'Z' , ';' , 'U' , 0x11, 'p' , 0x19, 'F' , 0x1F, 'v' , '"' , 'M' , '#' , 'D' , 0x0E, 'g' , 6, 'h' , 0x0F, 'G' , '2' , 'O' ] x = 'f' for i in range(1, len(str1)): if (isinstance(str1[i], str)): if (isinstance(str1[i - 1], str)): x += chr(ord(str1[i]) ^ ord(str1[i - 1])) else : x += chr(ord(str1[i]) ^ str1[i - 1]) else : x += chr(str1[i] ^ ord(str1[i - 1])) print (x)
跑出来就是:
内涵的软件
打开压缩包中的文件拖进ida
进入pirntf的里面那个地址看看有什么重要信息
Y输入就是
N输入就是
如果输入非Y/N就是
我们看一下结果的函数我们发现了提示
flag为:flag{49d3c93df25caad81232130f3d2ebfad}
Reverse3
我们打开压缩包里的文件放进ida
看见了strcmp的函数里面进行了比较我们进去看一下
我们看到了关键的字符串:e3nifIH9b_C@n@dH
1 2 for ( j = 0; j < v10; ++j ) Dest[j] += j;
看到了这个函数我们就知道我们进行的操作是dest字符串第一个减去0第二个减去2 是原来的数组 写一个python的脚本
1 2 3 4 5 6 s = "e3nifIH9b_C@n@dH" x = " " for i in range(0,len(s)): x += chr(ord(s[i]) - i) print (x)
得到字符串 e2lfbDB2ZV95b3V9
strncpy是放进第一个数组里面我们看一下v1函数进行的操作
看到了的数是base64进行转换的数 去写python脚本
1 2 3 4 5 6 7 import base64 s = "e3nifIH9b_C@n@dH" x = " " for i in range(0,len(s)): x += chr(ord(s[i]) - i) print (base64.b64decode(x))
运行出现了flag:flag{i_l0ve_you}
不一样的flag
打开压缩包文件放进ida
1 2 3 4 5 6 7 if ( v8[5 * v4 - 41 + v5] == '1' ) exit (1); if ( v8[5 * v4 - 41 + v5] == '#' ){ puts("\nok, the order you enter is the flag!" ); exit (0); }
可以分析出来1是j结束运行到#就是flag
可以看到一个关键的字符串:*11110100001010000101111#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 if ( v6 == 2 ) { ++v4; } else if ( v6 > 2 ) { if ( v6 == 3 ) { --v5; } else { if ( v6 != 4 ) LABEL_13: exit (1); ++v5; } } else { if ( v6 != 1 ) goto LABEL_13; --v4; }
可以看到v6是输入的值,我们up和down是v4进行操作,left和right是v5进行操作 5 * v4 - 41 + v5 看出来是5*5方阵: *1111 01000 01010 00010 1111# 走迷宫flag为22244114422:flag{22244114422}
刮开有奖
把程序放入ida中,进行分析,找到了主函数
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 28 29 30 31 32 33 34 35 36 37 38 memset(&String, 0, 0xFFFFu); GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF); if ( strlen(&String) == 8 ) { v7 = 'Z' ; v8 = 'J' ; v9 = 'S' ; v10 = 'E' ; v11 = 'C' ; v12 = 'a' ; v13 = 'N' ; v14 = 'H' ; v15 = '3' ; v16 = 'n' ; v17 = 'g' ; sub_4010F0(&v7, 0, 10); memset(&v26, 0, 0xFFFFu); v26 = v23; v28 = v25; v27 = v24; v4 = (const char *)sub_401000(&v26, strlen(&v26)); memset(&v26, 0, 0xFFFFu); v27 = v21; v26 = v20; v28 = v22; v5 = (const char *)sub_401000(&v26, strlen(&v26)); if ( String == v7 + 34 && v19 == v11 && 4 * v20 - 141 == 3 * v9 && v21 / 4 == 2 * (v14 / 9) && !strcmp(v4, "ak1w" ) && !strcmp(v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0); } } return 0; }
GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF)知道是我们输入的位置,下面对string进行了判定,知道我们输入的字符应该是8位,然后对v9的开始的地址的数值中间有个函数的调用,我们进去看一下
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 int __cdecl sub_4010F0(int a1, int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for ( i = a2; i <= a3; a2 = i ) { v5 = 4 * i; v6 = *(_DWORD *)(4 * i + a1); if ( a2 < result && i < result ) { do { if ( v6 > *(_DWORD *)(a1 + 4 * result) ) { if ( i >= result ) break ; ++i; *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result); if ( i >= result ) break ; while ( *(_DWORD *)(a1 + 4 * i) <= v6 ) { if ( ++i >= result ) goto LABEL_13; } if ( i >= result ) break ; v5 = 4 * i; *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1); } --result; } while ( i < result ); } LABEL_13: *(_DWORD *)(a1 + 4 * result) = v6; sub_4010F0(a1, a2, i - 1); result = a3; ++i; } return result; }
转化成了c进行了运行,看一下进行了什么变化
进入到下面的一个加密方式
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 _BYTE *__cdecl sub_401000(int a1, int a2) { int v2; // eax int v3; // esi size_t v4; // ebx _BYTE *v5; // eax _BYTE *v6; // edi int v7; // eax _BYTE *v8; // ebx int v9; // edi signed int v10; // edx int v11; // edi signed int v12; // eax signed int v13; // esi _BYTE *result; // eax _BYTE *v15; // [esp+Ch] [ebp-10h] _BYTE *v16; // [esp+10h] [ebp-Ch] int v17; // [esp+14h] [ebp-8h] int v18; // [esp+18h] [ebp-4h] v2 = a2 / 3; v3 = 0; if ( a2 % 3 > 0 ) ++v2; v4 = 4 * v2 + 1; v5 = malloc(v4); v6 = v5; v15 = v5; if ( !v5 ) exit (0); memset(v5, 0, v4); v7 = a2; v8 = v6; v16 = v6; if ( a2 > 0 ) { while ( 1 ) { v9 = 0; v10 = 0; v18 = 0; do { if ( v3 >= v7 ) break ; ++v10; v9 = *(unsigned __int8 *)(v3++ + a1) | (v9 << 8); } while ( v10 < 3 ); v11 = v9 << 8 * (3 - v10); v12 = 0; v17 = v3; v13 = 18; do { if ( v10 >= v12 ) { *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F; v8 = v16; } else { *((_BYTE *)&v18 + v12) = 64; } *v8++ = byte_407830[*((char *)&v18 + v12)]; v13 -= 6; ++v12; v16 = v8; } while ( v13 > -6 ); v3 = v17; if ( v17 >= a2 ) break ; v7 = a2; } v6 = v15; } result = v6; *v8 = 0; return result; }
知道这是个base64:密码表为
flag的判别:
1 2 3 4 5 6 7 8 9 if ( String == v7 + 34 && v19 == v11 && 4 * v20 - 141 == 3 * v9 && v21 / 4 == 2 * (v14 / 9) && !strcmp(v4, "ak1w" ) && !strcmp(v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0); }
可以看出来后面的两个base64的加密等于V1Axak1w 前面的等于一个U一个J
1 2 3 4 5 6 7 8 9 10 11 import base64 base_now="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" base_init="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" clear="V1Axak1w" c="" for i in range(len(clear)): b=base_now.find(clear[i]) c+=base_init[b] c=base64.b64decode(c) print c
结果flag为:flag{UJWP1jMp}
SimpleRev
把程序放入ida中,找到主函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { int v3; // eax char v4; // [rsp+Fh] [rbp-1h] while ( 1 ) { while ( 1 ) { printf ("Welcome to CTF game!\nPlease input d/D to start or input q/Q to quit this program: " , argv, envp); v4 = getchar(); if ( v4 != 100 && v4 != 68 ) break ; Decry(); } if ( v4 == 113 || v4 == 81 ) Exit(); puts("Input fault format!" ); v3 = getchar(); putchar(v3); } }
可以看出来,重要的是Decry函数:
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;运算,最后与text比较
直接给程序跑了:
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 28 29 30 31 int main(void) { int i, j, n = 0, v5 = 10, v3 = 0, v2 = 0; char v1; char flag[11] = { 0 }; char str2[104] = { 0 }; char key[] = "ADSFKNDCLS" ; char text[] = "killshadow" ; for (i = 0; i < v5; ++i) { if (key[v3 % v5] > 64 && key[v3 % v5] <= 90) key[i] = key[v3 % v5] + 32; ++v3; } for (j = 0; j < 10; ++j) { for (v2 = 0; v2 < 10; ++v2) { v1 = text[v2] - 97 + 26 * j - 97 + key[v3++ % v5] + 39; if ((v1 >= 65 && v1 <= 90) || (v1 >= 97 && v1 <= 122)) { flag[v2] = v1; if (++n == 10) { printf ("%s\n" , flag); return 0; } } } } return 0; }
出来了flag:flag{KLDQCUDFZO}
Java逆向解密
[SWPU2019]EasiestRe
这道题主要运用了od的分析,打开放入了ida Shift+f12进行字符串检索看到了关键字
进入查看
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 do { v7 = (int *)&v24; if ( v26 >= 0x10 ) v7 = v24; *((_BYTE *)v7 + v5) ^= *((_BYTE *)&v33 + v5 % v6); ++v5; } while ( v5 < 32 ); v8 = (int *)&v24; v4 = (int)v24; if ( v26 >= 0x10 ) v8 = v24; v29 = 0; v27 = 0i64; v28 = 0i64; *(_QWORD *)&v30 = *(_QWORD *)v8; *((_QWORD *)&v30 + 1) = *((_QWORD *)v8 + 1); *(_QWORD *)&v31 = *((_QWORD *)v8 + 2); *((_QWORD *)&v31 + 1) = *((_QWORD *)v8 + 3); sub_4025C0(v22, v23, 256, (unsigned int)&v30, (unsigned int)&v27); v36 = -133220429; v37 = 1571732668; v9 = &v36; v38 = -2041750854; v10 = &v27; v39 = -748513468; v11 = 28; v40 = 371505743; v41 = 443719435; v42 = 644704357; v43 = 1741188026; while ( 1 ) { v12 = *v9; if ( *v9 != *(_DWORD *)v10 ) break ; ++v9; v10 = (__int128 *)((char *)v10 + 4); v14 = v11 < 4; v11 -= 4; if ( v14 ) { v13 = 0; goto LABEL_19; } }
这个就是主函数,防止od与ida不对应,我就看了pe结构进行了修改
可以看到dynamic_base 是动态链接库属性
找到了位置,由于偏移量,修改成00 81
进入od 发现第一次的异或的位置:具体的地方给了注释
我们进行了分析,他把我们输入的值和所对应的密钥进行了异或的关系
我们下内存断点然后F9,看后面是谁对这串字符进行了操作
找到了后,我们看到只是放到了堆栈里面,既没有cmp和je或者jne,所以需要继续下内存断点
发现,ecx里面存的是第二次异或的密钥,那么我们还要继续下内存断点
发现,有了cmp函数进行比较,这样我们的思路就完全分析明白了,自己改了ZF标志位分析后发现进行了两次异或操作然后跟最后的进行比较,看是否正确,所以写了c语言
出现了flag:flag{Y0uaretheB3st!#@_VirtualCC}
[SWPU2019]Android1
拿到后,直接把.so文件放进了ida,shift+f12发现flag字段后,发现不对,分了很奇怪的4个函数,c语言如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int main () { char v3[] = "MWa" ; char v2[3]; //后一次为4 for (int i = 0; i <= 2; ++i) v2[i] = v3[i] ^ 0x38; //uoY char v3[] = "AVE" ; for (int i = 0; i <= 2; ++i) v2[i] = v3[i] ^ 0x24; //era char v3[] = "R_C" ; for (int i = 0; i <= 2; ++i) v2[i] = v3[i] ^ 0x37; / /eht char v3[] = "#$D5 " ; for (int i = 0; i <= 3; ++i) v2[i] = v3[i] ^ 0x77; //TS3B for (int i = 0; i <= 3; ++i) printf ("%c" , v2[i]); return 0; }
flag为:flag{YouaretheB3ST}
[SWPU2019]Android3
找到check函数:
判断长度是否为11,根据data值操作来存放数组的下标,进行调用fun1
相当于链表,查看fun2
V1=原始值 v2= -1^((b下标+原来下标)%2)
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 28 29 30 31 32 33 34 35 36 37 38 int main (){ char a[] = "0123456789a" ; int data[] = { 6, 2, 5, 0, 7, 3, 10, 9, 1, 4, 8 }; int data2[] = { 0x3C, 0x6C, 0x33, 0x4F, 0x81, 0x38, 0x2C, 0x5E, 0x54, 0x45, 0x40 }; int v1[24] = { 0 }; int b; int* z1; int* z2; int* z3; for (int i = 0; i < 11; i++) { b = data[i]; v1[2 * b ] = i; v1[2 * b + 1] = a[i]; } z1 = (int*)malloc(16u); int i = 0; while (i != 11) { z2 = (int*)malloc(16u); *z2 = v1[2 * i + 2]; z2[1] = i; z3 = &v1[2 * i + 2]; z2[3] = 0; ++i; *(z2 + 2) = *(z3 + 1); z1[3] = *z2; z1 = z2; v1[1] = (int)z2; } z1[3] = 0; while (1) { *z3 = z3[3]; if ((z3[1] + z3[0]) % 2) { b = z3[2] + (z3[1] + z3[0]); printf ("%d\n" ,data2[z3[1]] - z3[1] - z3[0]); } else { b = z3[2] - (z3[1] + z3[0]); printf ("%d\n" ,data2[z3[1]] + z3[1] + z3[0]); }} int s[] = { 50,48,49,57,83,87,80,85,99,116,102 }; for (int i = 0;i<11 ;i++) { printf ("%c" , s[i]);}
flag:flag{2019SWPUctf}
RoarCTF2019 polyre
从大佬那里问出来是ollvm混淆问题
参考教程:https://security.tencent.com/index.php/blog/msg/112
使用default.py脚本:https://security.tencent.com/index.php/opensource/detail/18