壳的分类
刷题记录 新年快乐 首先用PEiD查看其大小 是32位 又发现加了壳UPX
在od中打开,脱壳要先找到oep,由于现在的脱壳水平十分菜鸡,于是就一个个f8先运行
把一些死循环跳过,经过漫长的努力后发现了popad
继续f8,跳过jnz死循环,最后进入程序(找到oep)
右键dump一下
dump过后再用ida32打开dump过后的程序
此时已经出现的原有函数,f5查看c伪代码,最终得到flag
flag{HappyNewYear!}
xor 首先判断一下,是64位的,然后丢到idapro64打开
按f5查看伪代码
hello world apk文件,Android逆向,用Androidkiller打开,找到flag
reserve 3 查壳后发现无壳,是32位的,用ida打开,shift+f12查看
发现right flag,双击进入
选中aRightFlag,按ctrl+x,再按f5查看伪代码
分析伪代码得知重点在Str2和Destination上,同时从sub_4110BE可以看出这里进行了函数加密,双击sub_4110BE
双击aAbcdefghijklmn,进入后发现’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=’
这肯定是base64加密了
再次分析伪代码,得知flag经过for循环,每次都加了j,查看Str2的值
那么要做的就很简单了。首先将字符串数组Str2每个减去i,再用得到的结果进行base64解密,由于本人是菜鸡,只能用在线解密,最后得到flag
不一样的flag 老规矩,查壳,查位
无壳,32位
本想常识一下动态分析,发现啥都不会,就会运行到那
发现了一个奇怪的字符串,但是不知道是干嘛的
用ida打开
在main函数中使用f5大法
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 __main(); v4 = 0 ; strcpy (v3, "*11110100001010000101111#" ); 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" , &v5); if ( v5 == 2 ) { ++*(_DWORD *)&v3[25 ]; } else if ( v5 > 2 ) { if ( v5 == 3 ) { --v4; } else { if ( v5 != 4 ) LABEL_13: exit (1 ); ++v4; } } else { if ( v5 != 1 ) goto LABEL_13; --*(_DWORD *)&v3[25 ]; } for ( i = 0 ; i <= 1 ; ++i ) { if ( *(int *)&v3[4 * i + 25 ] < 0 || *(int *)&v3[4 * i + 25 ] > 4 ) exit (1 ); } if ( v7[5 * *(_DWORD *)&v3[25 ] - 41 + v4] == 49 ) exit (1 ); if ( v7[5 * *(_DWORD *)&v3[25 ] - 41 + v4] == 35 ) { puts ("\nok, the order you enter is the flag!" ); exit (0 ); } } }
上下左右,考虑迷宫,那么就要寻找地图了
#是出口,所以之前发现的那个奇怪的字符串应该就是地图,地图不可能是一串,得是个形状,再考虑图中25的情况,那么应该是将那串字符变成5*5的形式
1 2 3 4 5 "*1111" "01000" "01010" "00010" "1111#
那就是下下下右右上上上右右下下下 2224411144222
测试flag是否正确,正确
[ACTF新生赛2020]easyre
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 { char v4[12 ]; int v5[3 ]; char v6[5 ]; int v7; int v8; int v9; char v10; int i; __main(); qmemcpy(v4, "*F'\"N,\"(I?+@" , sizeof (v4)); printf ("Please input:" ); scanf ("%s" , v6); if ( v6[0 ] != 65 || v6[1 ] != 67 || v6[2 ] != 84 || v6[3 ] != 70 || v6[4 ] != 123 || v10 != 125 ) return 0 ; v5[0 ] = v7; v5[1 ] = v8; v5[2 ] = v9; for ( i = 0 ; i <= 11 ; ++i ) { if ( v4[i] != _data_start__[*((char *)v5 + i) - 1 ] ) return 0 ; } printf ("You are correct!" ); return 0 ;
看懂了大概,应该是要用_data_Start_于v4比较,但是if那段看不懂要干嘛,先暂时放弃….
XCTF 新手区 game 打开文件,游戏意思大概是要我们把灯全部点亮后就可以得到flag
查壳后发现无壳
拖入od中进行调试,查找下有无flag的字符串
发现真有,跟进一下,发现他的位置在程序入口点的上方,这里我先下了个断点,但是禁用了
然后重载程序,在call指令且1程序有运行出结果画面的地方做好标记
试了很久之后发现,这个call最后总会跳转到一个地方使输入页面重新出现,那于是就想可以直接跳转到 done!flag那里,双击进行位置更改,成功得到flag!
调试过程:本来想到要用call直接跳转的时候就开始尝试了,在前几个call那里跳转总是会出来乱码
直到到这个call才成功
Hello ctf 拿到题目后查壳,无壳,32位
打开IDA,f5查看伪代码
分析代码:大致意思是先将字符串复制到x13中,然后输入字符串v9,v9长度不能大于17,然后仔细观察v13,正好34个长度,那么可以猜想v13应该是由17个16进制位组成的,继续分析,for循环中遍历v9,并将每一个下标所包含的数复制给v4,之后再sprintf中将v4数据格式化给Buffer,并且连接v10和Buffer,最后将v13和v10进行比较,相同则输出成功,在前面的memset函数中,已经将v10的值变为0,所以我们只要将v13进行16进制转换字符即可得到flag
BUU simplerev 拿到题目有点懵,无后缀,加exe后程序也不能运行,拖入ida32
提示要用64位打开,打开后查看伪代码
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 unsigned __int64 Decry () { char v1; int v2; int v3; int i; int v5; char src[8 ]; __int64 v7; int v8; __int64 v9[2 ]; int v10; unsigned __int64 v11; v11 = __readfsqword(0x28 u); *(_QWORD *)src = 'SLCDN' ; v7 = 0LL ; v8 = 0 ; v9[0 ] = 'wodah' ; v9[1 ] = '\0' ; v10 = 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] <= 'Z' ) key[i] = key[v3 % v5] + 32 ; ++v3; } printf ("Please input your flag:" ); while ( 1 ) { v1 = getchar(); if ( v1 == '\n' ) break ; if ( v1 == ' ' ) { ++v2; } else { if ( v1 <= 96 || v1 > 122 ) { if ( v1 > 64 && v1 <= 9 ) { str2[v2] = (v1 - 39 - key[v3 % v5] + 97 ) % 26 + 97 ; ++v3; }/ } else { str2[v2] = (v1 - 39 - key[v3 % v5] + 97 ) % 26 + 97 ; ++v3; } if ( !(v3 % v5) ) putchar (32 ); ++v2; } } if ( !strcmp (text, str2) ) puts ("Congratulation!\n" ); else puts ("Try again!\n" ); return __readfsqword(0x28 u) ^ v11; }
上脚本
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 #include <iostream> #include <iomanip> using namespace std;int main () { char key[] = "adsfkndcls" ; char text[] = "killshadow" ; int v3 = 10 , v5 = 10 ; for (int i = 0 ; i < 10 ; i++) { for (int j = 0 ; j < 128 ; j++) { if (j <= 'A' || j > 'z' || j > 'Z' && j <= 'a' ) { continue ; } if ((j - 39 - key[v3 % v5] + 97 ) % 26 + 97 == text[i]) { cout << char (j); ++v3; break ; } } } return 0 ; }
简单注册器
改用JEB打开
找到反编译代码
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 public void onClick (View arg13) { int v11 = 0x1F ; int v9 = 2 ; int v2 = 1 ; String v6 = this .val$editview.getText ().toString (); if (v6.length () != 0x20 || v6.charAt (v11) != 97 || v6.charAt (1 ) != 98 || v6.charAt (0 ) + v6.charAt (v9) - 0x30 != 56 ) { v2 = 0 ; } if (v2 == 1 ) { char [] v5 = "dd2940c04462b4dd7c450528835cca15" .toCharArray (); v5[v9] = ((char )(v5[v9] + v5[3 ] - 50 )); v5[4 ] = ((char )(v5[v9] + v5[5 ] - 0x30 )); v5[30 ] = ((char )(v5[v11] + v5[9 ] - 0x30 )); v5[14 ] = ((char )(v5[27 ] + v5[28 ] - 97 )); int v4; for (v4 = 0 ; v4 < 16 ; ++v4) { char v0 = v5[0x1F - v4]; v5[0x1F - v4] = v5[v4]; v5[v4] = v0; } this .val$textview.setText ("flag{" + String.valueOf (v5) + "}" ); } else { this .val$textview.setText ("输入注册码错误" ); } } }); }
稍微修改一下即可得到脚本
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 #include <iostream> #include <iomanip> #include <math.h> #include <cmath> using namespace std;int main () { int v11 = 0x1F ; int v9 = 2 ; int v2 = 1 ; if (v2 == 1 ) { char v5[] = "dd2940c04462b4dd7c450528835cca15" ; v5[v9] = ((char )(v5[v9] + v5[3 ] - 50 )); v5[4 ] = ((char )(v5[v9] + v5[5 ] - 0x30 )); v5[30 ] = ((char )(v5[v11] + v5[9 ] - 0x30 )); v5[14 ] = ((char )(v5[27 ] + v5[28 ] - 97 )); int v4; for (v4 = 0 ; v4 < 16 ; ++v4) { char v0 = v5[0x1F - v4]; v5[0x1F - v4] = v5[v4]; v5[v4] = v0; } for (int i = 0 ; i < 33 ; i++) { cout << v5[i]; } return 0 ; } }
flag{59acc538825054c7de4b26440c0999dd}
刮开有奖 查壳 无壳 32位
猜测应该是base64,跟进
ctrl+x,f5查看伪代码
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 INT_PTR __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7[2 ]; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; CHAR String[65536 ]; char v18[65536 ]; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( (_WORD)a3 == 1001 ) { memset (String, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , String, 0xFFFF ); if ( strlen (String) == 8 ) { v7[0 ] = 90 ; v7[1 ] = 74 ; v8 = 83 ; v9 = 69 ; v10 = 67 ; v11 = 97 ; v12 = 78 ; v13 = 72 ; v14 = 51 ; v15 = 110 ; v16 = 103 ; sub_4010F0(v7, 0 , 10 ); memset (v18, 0 , 0xFFFF u); v18[0 ] = String[5 ]; v18[2 ] = String[7 ]; v18[1 ] = String[6 ]; v4 = (const char *)sub_401000(v18, strlen (v18)); memset (v18, 0 , 0xFFFF u); v18[1 ] = String[3 ]; v18[0 ] = String[2 ]; v18[2 ] = String[4 ]; v5 = (const char *)sub_401000(v18, strlen (v18)); if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0 ; EndDialog(hDlg, (unsigned __int16)a3); return 1 ; }
跟进一下sub_4010F0
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; int i; int v5; int v6; 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; }
实在看不懂,试了一下用编译器运行,但是直接报错,所以在网上寻找答案时发现了一个非常适合新手的wp
(42条消息) BUUCTF 刮开有奖(特别详细了,尽自己全力理解所写)_别害怕我在的博客-CSDN博客_buuctf 刮开有奖
看到这里真的是恍然大悟
修改sub_4010F0函数后运行
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 #include <iostream> #include <cmath> using namespace std ;int __cdecl sub_4010F0 (char * a1, int a2, int a3) { int result; int i; int v5; int v6; result = a3; for (i = a2; i <= a3; a2 = i) { v5 = i; v6 = a1[i]; if (a2 < result && i < result) { do { if (v6 > a1[result]) { if (i >= result) break ; ++i; a1[v5] = a1[result]; if (i >= result) break ; while (a1[i] <= v6) { if (++i >= result) goto LABEL_13; } if (i >= result) break ; v5 = i; a1[result] = a1[i]; } --result; } while (i < result); } LABEL_13: a1[result] = v6; sub_4010F0(a1, a2, i - 1 ); result = a3; ++i; } return result; } int main () { char str[15 ] = { 90 ,74 ,83 ,69 ,67 ,97 ,78 ,72 ,51 ,110 ,103 }; sub_4010F0(str, 0 , 10 ); for (int i = 0 ; i < 11 ; i++) { cout << str[i]; } return 0 ; }
sub_4010F0函数是对v7-v16字符串的加密
跟进一下
发现数据byte_407830,继续跟进
估计就是base64加密,对v4,v5进行base64加密,在网上进行在线解密
v4 = jMp,v5 = WP1,分析最后的if语句
1 2 3 4 5 6 7 8 9 if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); }
最后组合前几个UJWP,再将v4v5跟其进行组合
得到flag flag{UJWP1jMp}
[ACTF新生赛2020]rome 查壳,无壳,32位
shift+f12查看字符串
进入到”You are correct!”中
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 int func () { int result; int v1[4 ]; unsigned __int8 v2; unsigned __int8 v3; unsigned __int8 v4; unsigned __int8 v5; unsigned __int8 v6; int v7; int v8; int v9; int v10; unsigned __int8 v11; char v12[29 ]; strcpy (v12, "Qsw3sj_lz4_Ujw@l" ); printf ("Please input:" ); scanf ("%s" , &v2); result = v2; if ( v2 == 65 ) { result = v3; if ( v3 == 67 ) { result = v4; if ( v4 == 84 ) { result = v5; if ( v5 == 70 ) { result = v6; if ( v6 == 123 ) { result = v11; if ( v11 == 125 ) { v1[0 ] = v7; v1[1 ] = v8; v1[2 ] = v9; v1[3 ] = v10; *(_DWORD *)&v12[17 ] = 0 ; while ( *(int *)&v12[17 ] <= 15 ) { if ( *((char *)v1 + *(_DWORD *)&v12[17 ]) > 64 && *((char *)v1 + *(_DWORD *)&v12[17 ]) <= 90 ) *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) = (*((char *)v1 + *(_DWORD *)&v12[17 ]) - 51 ) % 26 + 65 ; if ( *((char *)v1 + *(_DWORD *)&v12[17 ]) > 96 && *((char *)v1 + *(_DWORD *)&v12[17 ]) <= 122 ) *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) = (*((char *)v1 + *(_DWORD *)&v12[17 ]) - 79 ) % 26 + 97 ; ++*(_DWORD *)&v12[17 ]; } *(_DWORD *)&v12[17 ] = 0 ; while ( *(int *)&v12[17 ] <= 15 ) { result = (unsigned __int8)v12[*(_DWORD *)&v12[17 ]]; if ( *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) != (_BYTE)result ) return result; ++*(_DWORD *)&v12[17 ]; } result = printf ("You are correct!" ); } } } } } } return result; }
2022DASCTF Apr X FATE 防疫挑战赛 re 奇怪的交易 拿到题目,文件无后缀,拖入ida64,shift+f12查看字符串
猜测可能是upx的壳,用记事本打开,发现是ELF文件,
本来想用vs打开看看,发现不行
适合破解新手的160个CrackMe –001 查壳后发现无壳,拖入od调试
查找字符串
发现有ASCII “Sorry , The serial is incorect !”和ASCII “God Job dude !! =)”
双击进入0042FA63
在0042FA5A处有跳转,由于应该要跳过Try Again和Sorry….,所以把这里修改为jmp
再进入0042FB0C
这里应该要运行到此处,所以将0042FB03 nop掉,最后运行程序,成功!
接着破解serial
查找字符串Try Again,并在每一个Try Again下断点
接着发现有个数据的”Try Again!!”,同时发现疑似破解serial的关键 “Hello Dude!”
最后还有一个
下好断点后运行程序,向上查找
将0042F4D5处nop掉,因为这样就不会跳转到Failed,再次运行程序
rsa加密 参考blog(85条消息) 带你彻底理解RSA算法原理_小宝一号的博客-CSDN博客_rsa算法