BUUCTF Reverse WriteUp easyre 直接拖进IDA分析,拖进PEID发现不是有效的PE文件
找到main函数,送分题
1 2 3 4 5 6 7 8 9 10 11 12 13 int __cdecl main (int argc, const char **argv, const char **envp) { int b; int a; _main(); scanf ("%d%d" , &a, &b); if ( a == b ) printf ("flag{this_Is_a_EaSyRe}" ); else printf ("sorry,you can't get flag" ); return 0 ; }
flag{this_Is_a_EaSyRe}
reverse1 直接拖进IDA分析,是个64位exe可执行文件
shift+F12大法找到wrong flag
,然后查看引用找到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 28 29 30 31 32 33 34 35 36 __int64 sub_1400118C0 () { char *v0; signed __int64 i; size_t v2; size_t v3; char v5; int j; char Str1; unsigned __int64 v8; v0 = &v5; for ( i = 82 i64; i; --i ) { *(_DWORD *)v0 = -858993460 ; v0 += 4 ; } for ( j = 0 ; ; ++j ) { v8 = j; v2 = j_strlen(Str2); if ( v8 > v2 ) break ; if ( Str2[j] == 111 ) Str2[j] = 48 ; } sub_1400111D1("input the flag:" ); sub_14001128F("%20s" , &Str1); v3 = j_strlen(Str2); if ( !strncmp (&Str1, Str2, v3) ) sub_1400111D1("this is the right flag!\n" ); else sub_1400111D1("wrong flag\n" ); sub_14001113B(&v5, &unk_140019D00); return 0 i64; }
这个Str2
就是我们要找的flag了,虽然可以下断点直接跳出来,但是觉得太麻烦,直接逆
上面的for就是把Str2
里面的o
换成0
,跟一下发现是{hello_world}
提交flagflag{hell0_w0rld}
reverse2 惯例拖进IDA,发现这次是ELF的x86_64,直接找到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 28 29 30 31 32 int __cdecl main (int argc, const char **argv, const char **envp) { int result; int stat_loc; int i; __pid_t pid; char s2; unsigned __int64 v8; v8 = __readfsqword(0x28 u); pid = fork(); if ( pid ) { argv = (const char **)&stat_loc; waitpid(pid, &stat_loc, 0 ); } else { for ( i = 0 ; i <= strlen (&flag); ++i ) { if ( *(&flag + i) == 105 || *(&flag + i) == 114 ) *(&flag + i) = 49 ; } } printf ("input the flag:" , argv); __isoc99_scanf("%20s" , &s2); if ( !strcmp (&flag, &s2) ) result = puts ("this is the right flag!" ); else result = puts ("wrong flag!" ); return result; }
发现有个fork操作,多进程,不管这么多先直接看上面主线程的for
1 2 3 4 5 for ( i = 0 ; i <= strlen (flag); ++i ){ if ( flag[i] == 'i' || flag[i] == 'r' ) flag[i] = '1' ; }
把flag里面的i/r
换成1
再跟一下flag
是{hacking_for_fun}
得到变换后的flagflag{hack1ng_fo1_fun}
提交得分,居然没有在多进程里面设坑……
新年快乐 拖进PEID查看发现加了个UPX的壳,随便找个脱壳机给脱了,发现我的脱壳机还脱不下来,upx官方脱壳机,直接在官方下载一个最新的UPX,脱下来之后, 用PEID再看发现是yoda's Protector
什么的,直接拖进IDA看看,找到main 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int __cdecl main (int argc, const char **argv, const char **envp) { int result; char v4; __int16 v5; __int16 v6; __main(); strcpy (&v4, "HappyNewYear!" ); v5 = 0 ; memset (&v6, 0 , 0x1E u); printf ("please input the true flag:" ); scanf ("%s" , &v5); if ( !strncmp ((const char *)&v5, &v4, strlen (&v4)) ) result = puts ("this is true flag!" ); else result = puts ("wrong!" ); return result; }
直接拿到flag HappyNewYear!
内涵的软件 好家伙一来就是一个EXE,拖进IDA发现是个X86的exe,旁边函数列表一大堆,还是老规矩找字符串
手动运行一下程序,挺有趣的
1 2 3 4 5 6 7 8 9 10 11 12 13 PS .\70125468-0786-4705-bd91-87037f8f3e16.exe 距离出现答案还有5秒,请耐心等待! 距离出现答案还有4秒,请耐心等待! 距离出现答案还有3秒,请耐心等待! 距离出现答案还有2秒,请耐心等待! 距离出现答案还有1秒,请耐心等待! 距离出现答案还有0秒,请耐心等待! 这里本来应该是答案的,但是粗心的程序员忘记把变量写进来了,你要不逆向试试看:(Y/N) Y OD吾爱破解或者IDA这些逆向软件都挺好的!
于是在main里面找到字符串DBAPP{49d3c93df25caad81232130f3d2ebfad}
,交上去不对
然后看了下提示,把DBAPP ,换成flag,出了,艹
guessgame 拖进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 28 29 30 31 32 int __cdecl main (int argc, const char **argv, const char **envp) { unsigned int v3; int v4; _main(); v4 = 0 ; v3 = time(0 i64); srand(v3); while ( 1 ) { menu(); printf (QingXuanZe); scanf ("%d" , &v4); if ( v4 == 1 ) { game(); } else if ( v4 == 2 ) { puts ("想啥呢弟弟" ); } else if ( v4 ) { puts (XuanZeCuoWu); } else { puts ("退出游戏" ); } } }
优化一下变量名,还是比较清晰的,进入game里面看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int game () { int input; int randNum; input = 0 ; randNum = rand() % 100 + 1 ; while ( 1 ) { while ( 1 ) { printf (QingShuRuShuZi); scanf ("%d" , &input); if ( input <= randNum ) break ; puts (DaLe); } if ( input >= randNum ) break ; puts (XiaoLe); } return puts (aFlaga); }
本质上就是一个猜数游戏,猜对了也没奖励,于是打开字符串窗口,第一个就是flag,BJD{S1mple_ReV3r5e_W1th_0D_0r_IDA}
,提交成功
逆了一下,原来就是把这个字符串,藏在menu的一个变量里面,估计是用的内联汇编之类的,伪代码是看不出来的,但是看汇编一下子就出来了
helloworld 下载下来发现是一个安卓apk文件,啊这,俺从来没逆向过安卓文件啊
网上找了一堆教程,发现,首先用dex2jar
把apk里面的dex给反编译出jar来,然后用jar-decompiler
一瞬出flag
MainActivity.class
源码在这
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.example.helloword;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;public class MainActivity extends ActionBarActivity { protected void onCreate (Bundle paramBundle) { super .onCreate(paramBundle); setContentView(2130903064 ); "flag{7631a988259a00816deda84afb29430a}" .compareTo("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ); } public boolean onCreateOptionsMenu (Menu paramMenu) { getMenuInflater().inflate(2131492864 , paramMenu); return true ; } public boolean onOptionsItemSelected (MenuItem paramMenuItem) { return (paramMenuItem.getItemId() == 2131034172 ) ? true : super .onOptionsItemSelected(paramMenuItem); } }
一瞬拿到flag
xor 下载下来二话不说直接拖进IDA,发现还是个mac平台的软件,不过也能分析出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; int result; signed int i; char flag[264 ]; __int64 v7; memset (flag, 0 , 0x100 uLL); v3 = (char *)256 ; printf ("Input your flag:\n" , 0L L); get_line(flag, 256L L); if ( strlen (flag) != 33 ) goto failed; for ( i = 1 ; i < 33 ; ++i ) flag[i] ^= flag[i - 1 ]; v3 = global; if ( !strncmp (flag, global, 0x21 uLL) ) printf ("Success" , v3); else failed: printf ("Failed" , v3); result = __stack_chk_guard; if ( __stack_chk_guard == v7 ) result = 0 ; return result; }
输入的flag每一位都和前一位进行xor
,然后和内置的数据进行比较
然后就是写脚本出结果了
1 2 3 4 5 6 7 8 9 10 data = [ 0x66 , 0x0A , 0x6B , 0x0C , 0x77 , 0x26 , 0x4F , 0x2E , 0x40 , 0x11 , 0x78 , 0x0D , 0x5A , 0x3B , 0x55 , 0x11 , 0x70 , 0x19 , 0x46 , 0x1F , 0x76 , 0x22 , 0x4D , 0x23 , 0x44 , 0x0E , 0x67 , 0x06 , 0x68 , 0x0F , 0x47 , 0x32 , 0x4F , 0x00 ] for i in range(33 , 0 , -1 ): data[i] ^= data[i-1 ] print('' .join([chr(x) for x in data]))
得到结果flag{QianQiuWanDai_YiTongJiangHu}
reverse3 拖进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 28 29 30 31 32 33 34 35 36 37 __int64 main_0 () { int flagLength; const char *v1; size_t v2; int v3; __int64 v4; signed int j; signed int i; signed int v8; char Dest[108 ]; char flag; char v11; for ( i = 0 ; i < 100 ; ++i ) { if ( (unsigned int )i >= 0x64 ) j____report_rangecheckfailure(); Dest[i] = 0 ; } print("please enter the flag:" ); scanf ("%20s" , &flag); flagLength = j_strlen(&flag); v1 = (const char *)sub_4110BE((int )&flag, flagLength, (int )&v11); strncpy (Dest, v1, 40u ); v8 = j_strlen(Dest); for ( j = 0 ; j < v8; ++j ) Dest[j] += j; v2 = j_strlen(Dest); if ( !strncmp (Dest, Str2, v2) ) print("rigth flag!\n" ); else print("wrong flag!\n" ); HIDWORD(v4) = v3; LODWORD(v4) = 0 ; return v4; }
发现这次没有这么简单了,看了一下逻辑,大概是把输入的flag经过一个变换,然后再来一个每一位都加上当前的index这样的操作,最后和目的作比较
看一下这里面的变换函数
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 void *__cdecl sub_411AB0 (char *flag, unsigned int flagLength, int *a3) { int v4; int v5; int v6; int v7; signed int i; unsigned int v9; int v10; signed int v11; void *Dst; char *v13; if ( !flag || !flagLength ) return 0 ; v9 = flagLength / 3 ; if ( (flagLength / 3 ) % 3 ) ++v9; v10 = 4 * v9; *a3 = v10; Dst = malloc (v10 + 1 ); if ( !Dst ) return 0 ; j_memset(Dst, 0 , v10 + 1 ); v13 = flag; v11 = flagLength; v7 = 0 ; while ( v11 > 0 ) { byte_41A144[2 ] = 0 ; byte_41A144[1 ] = 0 ; byte_41A144[0 ] = 0 ; for ( i = 0 ; i < 3 && v11 >= 1 ; ++i ) { byte_41A144[i] = *v13; --v11; ++v13; } if ( !i ) break ; switch ( i ) { case 1 : *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ]; v4 = v7 + 1 ; *(Dst + v4++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16 * (byte_41A144[0 ] & 3 )]; *(Dst + v4++) = aAbcdefghijklmn[64 ]; *(Dst + v4) = aAbcdefghijklmn[64 ]; v7 = v4 + 1 ; break ; case 2 : *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ]; v5 = v7 + 1 ; *(Dst + v5++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16 * (byte_41A144[0 ] & 3 )]; *(Dst + v5++) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | 4 * (byte_41A144[1 ] & 0xF )]; *(Dst + v5) = aAbcdefghijklmn[64 ]; v7 = v5 + 1 ; break ; case 3 : *(Dst + v7) = aAbcdefghijklmn[byte_41A144[0 ] >> 2 ]; v6 = v7 + 1 ; *(Dst + v6++) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | 16 * (byte_41A144[0 ] & 3 )]; *(Dst + v6++) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | 4 * (byte_41A144[1 ] & 0xF )]; *(Dst + v6) = aAbcdefghijklmn[byte_41A144[2 ] & 0x3F ]; v7 = v6 + 1 ; break ; } } *(Dst + v7) = 0 ; return Dst; }
也有字母表,看上去真的很像base64,而且密码表也是base64的,就先猜是,然后写脚本
1 2 3 4 5 6 import base64s1 = 'e3nifIH9b_C@n@dH' s1 = list(s1) for i in range(len(s1)): s1[i] = chr(ord(s1[i]) - i) print(base64.b64decode('' .join(s1)))
然后就是得到flag{i_l0ve_you}
,果然是这个base64
不一样的flag 是个x86下windows程序,看样子像是一个迷宫题,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 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 int __cdecl main (int argc, const char **argv, const char **envp) { char v3; int x; int y; signed int input; int i; int map ; __main(); x = 0 ; y = 0 ; qmemcpy(&v3, _data_start__, 0x19 u); while ( 1 ) { puts ("you can choose one action to execute" ); puts ("1 up" ); puts ("2 down" ); puts ("3 left" ); printf ("4 right\n:" ); scanf ("%d" , &input); if ( input == 2 ) { ++x; } else if ( input > 2 ) { if ( input == 3 ) { --y; } else { if ( input != 4 ) LABEL_13: exit (1 ); ++y; } } else { if ( input != 1 ) goto LABEL_13; --x; } for ( i = 0 ; i <= 1 ; ++i ) { if ( *(&x + i) < 0 || *(&x + i) > 4 ) exit (1 ); } if ( *(&map + 5 * x + y - 41 ) == '1' ) exit (1 ); if ( *(&map + 5 * x + y - 41 ) == '#' ) { puts ("\nok, the order you enter is the flag!" ); exit (0 ); } } }
然后看汇编发现push了一串字符,应该就是地图了
*11110100001010000101111#
然后是五个一行
1 2 3 4 5 *1111 01000 01010 00010 1111#`
没病走两步,得到flag222441144222
SimpleRev x64的一个elf文件,拖进IDA,WSL下面直接跑不了,linux下也跑不了直接提示段错误,淦,main函数就是一个菜单,重点在decry()
函数里面,跟进去
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 unsigned __int64 Decry () { char v1; int v2; int v3; int i; int v5; char src[8 ]; __int64 v7; int v8; __int64 v9; __int64 v10; int v11; unsigned __int64 v12; v12 = __readfsqword(0x28 u); *(_QWORD *)src = 'SLCDN'; v7 = 0L L; v8 = 0 ; v9 = 'wodah'; v10 = 0L L; v11 = 0 ; text = (char *)join(key3, &v9); strcpy (key, key1); strcat (key, src); v2 = 0 ; v3 = 0 ; getchar(); v5 = strlen (key); for ( i = 0 ; i < v5; ++i ) { if ( key[v3 % v5] > '@' && key[v3 % v5] <= 90 ) key[i] = key[v3 % v5] + ' ' ; ++v3; } printf ("Please input your flag:" , src); while ( 1 ) { v1 = getchar(); if ( v1 == 10 ) break ; if ( v1 == 32 ) { ++v2; } else { if ( v1 <= 96 || v1 > 122 ) { if ( v1 > 64 && v1 <= 90 ) str2[v2] = (v1 - 39 - key[v3++ % v5] + 97 ) % 26 + 97 ; } else { str2[v2] = (v1 - 39 - key[v3++ % v5] + 97 ) % 26 + 97 ; } if ( !(v3 % v5) ) putchar (32 ); ++v2; } } if ( !strcmp (text, str2) ) puts ("Congratulation!\n" ); else puts ("Try again!\n" ); return __readfsqword(0x28 u) ^ v12; }
进去之后有几个阴间计算,跟一下
text = killshadow
key = adsfkndcls
大概就是输入的字符和这个key进行运算之后要等于text,注意这个式子
str2[idx] = (inputChar - '\'' - key[cnt++ % kenLength] + 'a') % 26 + 'a'
这个取模让人有点难受,但是想到了取模的一个运算法则 $$ (a + b) % c=(a % c + b % c)%c $$ 又因为key里面全部都是小写字符,不可能是超过26的,而inputChar - ‘\‘的值大概在25-100之间
写个脚本穷举一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 text = list('killshadow' ) text = [ord(x) for x in text] key = list('adsfkndcls' ) key = [ord(x) for x in key] flag = [0 ] * len(text) for i in range(len(text)): flag[i] = text[i] - ord('a' ) flag[i] += 26 * 2 flag[i] += key[i] - ord('a' ) flag[i] += ord('\'' ) print('' .join([chr(x) for x in flag]))
KL^Q]UDFZi
和efxkwo^t
什么阴间flag,交上去完全不对
得,看一下网上的wp,直接爆破,因为这个是按位加密的,爆破脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def change (x:int, index:int ): char = (x - ord('\'' ) - (key[index] - ord('a' ))) % 26 + ord('a' ) return char text = list('killshadow' ) text = [ord(x) for x in text] key = list('adsfkndcls' ) key = [ord(x) for x in key] flag = [0 ] * len(text) charset = list(range(ord('A' ), ord('Z' )+1 )) for cnt in range(len(text)): for i in charset: res = change(i, cnt) if res == text[cnt]: flag[cnt] = i print('' .join([chr(x) for x in flag]))
出了多解,一个是大写的KLDQCUDFZO
,一个是小写的efxkwoxzti
,按理来说中间随便混杂都满足条件,垃圾题实锤了
刮开有奖 IDA分析是个win32下的窗口化程序,然而俺只能看见一个刮开有奖,其余啥也看不见,不管,进入diagFunc 查看对话框逻辑
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 BOOL __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int key[11 ]; char input[8 ]; char chunk[3 ]; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( a3 == 1001 ) { memset (input, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , input, 0xFFFF ); if ( strlen (input) == 8 ) { key[0 ] = 'Z' ; key[1 ] = 'J' ; key[2 ] = 'S' ; key[3 ] = 'E' ; key[4 ] = 'C' ; key[5 ] = 'a' ; key[6 ] = 'N' ; key[7 ] = 'H' ; key[8 ] = '3' ; key[9 ] = 'n' ; key[10 ] = 'g' ; sub_4010F0(key, 0 , 10 ); memset (chunk, 0 , 0xFFFF u); chunk[0 ] = input[5 ]; chunk[2 ] = input[7 ]; chunk[1 ] = input[6 ]; v4 = sub_401000(chunk, strlen (chunk)); memset (chunk, 0 , 0xFFFF u); chunk[1 ] = input[3 ]; chunk[0 ] = input[2 ]; chunk[2 ] = input[4 ]; v5 = sub_401000(chunk, strlen (chunk)); if ( input[0 ] == key[0 ] + 34 && input[1 ] == key[4 ] && 4 * input[2 ] - 141 == 3 * key[2 ] && input[3 ] / 4 == 2 * (key[7 ] / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( a3 != 1 && a3 != 2 ) return 0 ; EndDialog(hDlg, a3); return 1 ; }
可以看到就是这两个函数,第一个sub_4010F0
是对key进行加密,进去跟了一下逻辑好像还有个递归,不管直接动态调试,在OD里面改几个跳转指令,跟一下发现key由ZJSECaNH3ng
变为了3CEHJNSZagn
就是个简单的位置变换,
然后就是对sub_401000
进行分析了,发现了一个密码表,看样子就是base64了,然后根据后面的判断条件推测一下就能知道input[0]
和input[1]
了,后面还有个input[3]
和input[4]
进行验证一下就知道猜想对不对,毕竟我也在字符串列表中找到了变表的base64
接出来是UJWP1jMp
,出了
Java 逆向解密 压缩包打开是个class文件,使用Java Decompiler一把梭,发现加密逻辑很简单
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 import java.util.ArrayList;import java.util.Scanner;public class Reverse { public static void main (String[] args) { Scanner s = new Scanner(System.in); System.out.println("Please input the flag ); String str = s.next(); System.out.println(" Your input is ); System.out.println(str); char [] stringArr = str.toCharArray(); Encrypt(stringArr); } public static void Encrypt (char [] arr) { ArrayList<Integer> Resultlist = new ArrayList<>(); for (int i = 0 ; i < arr.length; i++) { int result = arr[i] + 64 ^ 0x20 ; Resultlist.add(Integer.valueOf(result)); } int [] KEY = { 180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 }; ArrayList<Integer> KEYList = new ArrayList<>(); for (int j = 0 ; j < KEY.length; j++) KEYList.add(Integer.valueOf(KEY[j])); System.out.println("Result:" ); if (Resultlist.equals(KEYList)) { System.out.println("Congratulations); } else { System.err.println(" Error); } } }
直接白给,写脚本出结果
1 2 3 4 5 6 table = [180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 ] for i in range(len(table)): table[i] ^= 0x20 table[i] -= 64 print('' .join([chr(x) for x in table]))
flag{This_is_the_flag_!}
findit 是个apk,使用dex2jar
变成jar
之后再使用java decompiler
查看逻辑
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 package com.example.findit;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends ActionBarActivity { protected void onCreate (Bundle paramBundle) { super .onCreate(paramBundle); setContentView(2130903064 ); Button button = (Button)findViewById(2131034173 ); final EditText edit = (EditText)findViewById(2131034174 ); final TextView text = (TextView)findViewById(2131034175 ); button.setOnClickListener(new View.OnClickListener() { public void onClick (View param1View) { char [] arrayOfChar1 = new char [17 ]; char [] arrayOfChar2 = new char [38 ]; int i = 0 ; while (true ) { String str; if (i >= 17 ) { if (String.valueOf(arrayOfChar1).equals(edit.getText().toString())) { for (i = 0 ;; i++) { if (i >= 38 ) { str = String.valueOf(arrayOfChar2); text.setText(str); return ; } if ((b[i] >= 'A' && b[i] <= 'Z' ) || (b[i] >= 'a' && b[i] <= 'z' )) { arrayOfChar2[i] = (char )(b[i] + 16 ); if ((arrayOfChar2[i] > 'Z' && arrayOfChar2[i] < 'a' ) || arrayOfChar2[i] >= 'z' ) arrayOfChar2[i] = (char )(arrayOfChar2[i] - 26 ); } else { arrayOfChar2[i] = b[i]; } } break ; } } else { if ((a[i] < 'I' && a[i] >= 'A' ) || (a[i] < 'i' && a[i] >= 'a' )) { str[i] = (char )(a[i] + 18 ); } else if ((a[i] >= 'A' && a[i] <= 'Z' ) || (a[i] >= 'a' && a[i] <= 'z' )) { str[i] = (char )(a[i] - 8 ); } else { str[i] = a[i]; } i++; continue ; } text.setText("); return; } } }); } public boolean onOptionsItemSelected(MenuItem paramMenuItem) { return (paramMenuItem.getItemId() == 2131034176) ? true : super.onOptionsItemSelected(paramMenuItem); } }
用a/b两个字符串里面的字符变换之后赋值给两个数组,但是,我并不知道这两个数组的内容啊
那就用apktools
给解包看看有啥内容,发现MainActivity.smail
有俩文件,其中有一个就是数组,复制粘贴下来
1 2 3 4 table1 = [0x54 , 0x68 , 0x69 , 0x73 , 0x49 , 0x73 , 0x54 , 0x68 , 0x65 , 0x46 , 0x6c , 0x61 , 0x67 , 0x48 , 0x6f , 0x6d , 0x65 , ] table2 = [0x70 , 0x76 , 0x6b , 0x71 , 0x7b , 0x6d , 0x31 , 0x36 , 0x34 , 0x36 , 0x37 , 0x35 , 0x32 , 0x36 , 0x32 , 0x30 , 0x33 , 0x33 , 0x6c , 0x34 , 0x6d , 0x34 , 0x39 , 0x6c , 0x6e , 0x70 , 0x37 , 0x70 , 0x39 , 0x6d , 0x6e , 0x6b , 0x32 , 0x38 , 0x6b , 0x37 , 0x35 , 0x7d , ]
然后就是去看看两个数组到底是啥内容,直接复制粘贴进idea跑
发现str是LzakAkLzwXdsyZgew
直接交,不对,看来还得看看table2的,结果是flag{c164675262033b4c49bdf7f9cda28a75}
,出了
8086 IDA加载发现是个DOS文件,没有函数,看看汇编
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 seg001:0000 sub_10030 proc near ; CODE XREF: sub_10030↓j seg001:0000 ; start+5↓p seg001:0000 jmp short sub_10030 seg001:0000 sub_10030 endp seg001:0000 seg001:0002 ; --------------------------------------------------------------------------- seg001:0002 mov cx, 22h ; '"' seg001:0005 lea bx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;" seg001:0009 seg001:0009 loc_10039: ; CODE XREF: seg001:000F↓j seg001:0009 mov di, cx seg001:000B dec di seg001:000C xor byte ptr [bx+di], 1Fh seg001:000F loop loc_10039 seg001:0011 lea dx, aUDuTZWjQGjzZWz ; "]U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;" seg001:0015 mov ah, 9 seg001:0017 int 21h ; DOS - PRINT STRING seg001:0017 ; DS:DX -> string terminated by "$" seg001:0019 retn seg001:001A assume ss:dseg, ds:nothing seg001:001A seg001:001A ; =============== S U B R O U T I N E ======================================= seg001:001A seg001:001A ; Attributes: noreturn seg001:001A seg001:001A public start seg001:001A start proc near seg001:001A mov ax, seg dseg seg001:001D mov ds, ax seg001:001F assume ds:dseg seg001:001F call sub_10030 seg001:001F start endp seg001:001F seg001:0022 ; --------------------------------------------------------------------------- seg001:0022 mov ah, 4Ch seg001:0024 int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT) seg001:0024 seg001 ends ; AL = exit code seg001:0024 seg001:0024 seg001:0024 end start
非常简单,对列表里面没一个字符取xor 0x1F
就行
写个脚本
1 2 3 4 5 6 7 a = ']U[du~|t@{z@wj.}.~q@gjz{z@wzqW~/b;' a = list(a) a = [ord(x) for x in a] flag = [] for i in a: flag.append(i ^ 0x1f ) print('' .join([chr(x) for x in flag]))
出结果BJD{jack_de_hu1b1an_xuede_henHa0}
check_1n 打开一看还真是字符画版的笔记本电脑,有点东西,照样拖进IDA,发现里面一堆函数,main函数的逻辑并不明显,通过找字符找到打印笔记本电脑的函数,然后查看引用
里面的字符串太多了,静态分析感觉都不太好用了,只好上od
md上OD也跟不出个什么鬼,发现一个奇怪的字符串2i9Q8AtFJTfL3ahU2XGuemEqZJ2ensozjg1EjPJwCHy4RY1Nyvn1ZE1bZe
然后大概是有个解密函数,跟进去,发现加密函数异常难看,但是这个应该是解密出来的函数,要是能够跟一下就好了,使用OD在main函数直接跳转,发现在malloc这个函数被卡出来,而且中途还有一堆反调的东西,淦
最后还是通过Shift + F12
的方法找到了开机密码HelloWorld
然后有个flag文件,打开之后是虚假的flag, base64解密得Why don't you try the magic brick game
然后试试打砖块
然后输了之后flag自己就出来了,人才.jpg
flag{f5dfd0f5-0343-4642-8f28-9adbb74c4ede}