魔法师的逆向之旅 1.revese2 一道简单的字符替换
2.内涵的软件 DBAPP{49d3c93df25caad81232130f3d2ebfad}
我还以为有什么加密,结果找半天没找着,直接将DBAPP改为flag就过了
3.新年快乐 打开一看内容很少,查壳,为upx壳
4.xor 1 2 3 4 5 6 7 8 9 10 11 12 13 #include<stdio.h> int main(void) { char arry[] = {0x66,0xA,0x6B,0xC,0x77,0x26,0x4F,0x2E,0x40,0x11,0x78,0xD,0x5A,0x3B,0x55,0x11,0x70,0x19,0x46,0x1F,0x76,0x22,0x4D,0x23,0x44,0xE,0x67,0x6,0x68,0xF,0x47,0x32,0x4F,0x0}; //char arry[] = "f\nk\x0cw&O.@\x11x\rZ;U\x11p\x19F\x1fv\"M#D\x0eg\x06h\x0fG2O\x00"; for(int i = 32; i>=1; i--) { arry[i]^= arry[i-1]; } printf("%s", arry); return 0; }
注意一下\x19F\x会匹配之后紧跟的16进制数直到第一个非16进制数,所以还是直接粘贴对应的16进制ascii码
5.reverse3 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=(base64)
1 2 3 4 5 6 7 8 9 10 11 #include<stdio.h> #include<string.h> int main(void) { char temp[] = "e3nifIH9b_C@n@dH"; for(int i = strlen(temp)-1; i>=0; i--) { temp[i] -=i; } printf("%s", temp); }
之后cyberchef
6.helloword 简单的android逆向,正好最近也在学anroid逆向
直接去androidmainfest找清单文件,然后进入主程序
7.不一样的flag 确实不太一样,这道题看了wp才明白
1 2 3 4 puts("1 up"); puts("2 down"); puts("3 left"); printf("4 right\n:");
这种上下作于一看就是迷宫,这就去找迷宫为何
*(DWORD *)&11110100001010000101111 [25]掌握上下
v4左右,一开始均置为0,掌左右为纵坐标
看这个判断的49这是’1’的ascii码,也就是1不可走,#结束
5 * *(DWORD *)&11110100001010000101111 [25] - 41 + v4
这是5*纵坐标,这说明宽度为5,也刚好5乘5
*1111
01000
01010
00010
1111#
所以为222441144222就得到结束
8.SimpleRev
v11 = __readfsqword(0x28u):读取线程局部存储(TLS)中的金丝雀值(canary),用于检测栈溢出攻击。(有栈溢出,canary会修改)
这道题的关键是大小端序
text = join((const char *)key3, (const char *)s_);// “kills” strcpy(key, key1); // “ADSFK” 进去看的data由于是字符串所以不存在端序问题,按d将其变为data后就会出现小端序
*(_QWORD *)src = ‘SLCDN’;
QWORD s [2]虽然输入的是字符串,但均转为8字节的数据,也均使用小端序存内存中是NDCL
text为密文(根据if ( !strcmp(text, str2) ) puts(“Congratulation!\n”);)
text是killshadow
密钥为ADSFKNDCL
1 2 3 4 5 6 for ( i = 0; i < v7; ++i ) { if ( key[v5 % v7] > 64 && key[v5 % v7] <= 90 ) key[i] = key[v5 % v7] + 32; ++v5; }
这一看就是就是大小写转换
1 2 3 4 5 6 7 8 9 10 11 12 13 if ( char <= 96 || char > 'z' ) { if ( char > '@' && char <= 'Z' ) { str2[v4] = (char - 39 - key[v5 % i_1] + 97) % 26 + 97; ++v5; } } else { str2[v4] = (char - 39 - key[v5 % i_1] + 97) % 26 + 97; ++v5; }
所以解密就是
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 #include<stdio.h> #include<string.h> #define base58_size 58 int main(void) { char arry[] = "killshadow"; char key[] = "adsfkndcls"; int temp; for(int i = 0; i<strlen(arry); i++) { temp = arry[i] - 97; printf("%d ", temp); } printf("\n"); for(int i = 0; i<strlen(key); i++) { temp = -key[i] + 97 - 39; printf("%d ", temp); } return 0; } #include<stdio.h> int main(void) { int arry[] = {10 ,8 ,11 ,11 ,18 ,7 ,0 ,3 ,14 ,22 }; int temp[] = {-39, -42, -57, -44, -49, -52, -42, -41, -50, -57}; for(int i = 0; i<10; i++) { for(char num = 'A'; num<='Z'; num++) { if(arry[i] == (num+temp[i])%26) { printf("%c", num); } } } }
stract函数仅是关心内存中存的值,其他的并不关心
查看小端序方法 (1)deteceasy中LE小端序,BE大端序
(2)将数值赋给字符串
(3
temp(void)
{int num = 1;
return (*(char*)&num == 1); // 1为小端序,0为大端序
}
(4)小端序:x86/AMD64 架构(Windows/Linux)、ARM 架构
大端序:网络协议、Java 字节码、部分嵌入式系统(如 PowerPC)PNG 为大端序
9.[GXYCTF2019]luck_guy1 程序有个伪随机数生成,所以有固定顺序
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 #include<string.h> #include<tsdio.h> int main(void) { char arry[] = {0x69, 0x63, 0x75, 0x67, 0x60, 0x6F, 0x66, 0x7F}; for(int i = 0; i<=7; i++) { if(i%2==1) arry[i] -= 2; else arry[i]--; } for(int i = 0; i<=7; i++) printf("%c", arry[i]); }
得到hate_me}
10.Java逆向解密 注意的是^优先级低于-
11. JustRE sprintf(char * buffer, const char * format, )
例如sprintf(buffer, “Age: %d, Height: %.2f”, age, height); 不想python中的格式字符串”%d”, 3
12.刮开有奖 一开始没有思路,这道题的加密挺复杂的,想打断点调试的发现直接运行程序后根本不经过断电所在的程序,看了网上的wp后豁然开朗
又是刮开无奖
1 2 3 4 5 6 7 8 9 10 11 v7[0 ] = 90 ; v7[1 ] = 74 ; n_S_ = 83 ; n_E_ = 69 ; n_C_ = 67 ; n_a_ = 97 ; n_N_ = 78 ; n_H_ = 72 ; n_3_ = 51 ; n_n_ = 110 ; n_g_ = 103 ;
这一看就是字符串
紧跟着 sub_9110F0(v7, 0, 10); 这里使用了直接将代码粘贴到
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 #include <stdio.h> #include <stdint.h> int sub_9110F0 (uint8_t *a1, int nuberis0, int n10) { int n10_1; int n10_2; int n10_3; int v6; n10_1 = n10; for ( n10_2 = nuberis0; n10_2 <= n10; nuberis0 = n10_2 ) { n10_3 = n10_2; v6 = a1[n10_2]; if ( nuberis0 < n10_1 && n10_2 < n10_1 ) { do { if ( v6 > a1[n10_1] ) { if ( n10_2 >= n10_1 ) break ; ++n10_2; a1[n10_3] = a1[n10_1]; if ( n10_2 >= n10_1 ) break ; while ( a1[n10_2] <= v6 ) { if ( ++n10_2 >= n10_1 ) goto LABEL_13; } if ( n10_2 >= n10_1 ) break ; n10_3 = n10_2; a1[n10_1] = a1[n10_2]; } --n10_1; } while ( n10_2 < n10_1 ); } LABEL_13: a1[n10_1] = v6; sub_9110F0(a1, nuberis0, n10_2 - 1 ); n10_1 = n10; ++n10_2; } return n10_1; } int main (void ) { char temp[12 ] = "ZJSECaNH3ng" ; sub_9110F0(temp, 0 , 10 ); printf ("%s\n" , temp); }
直接将解密解出,下面就是标准的base64加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 v18[0 ] = String[5 ]; v18[2 ] = String[7 ]; v18[1 ] = String[6 ]; v4 = sub_911000((int )v18, strlen (v18)); memset (v18, 0 , 0xFFFFu ); v18[1 ] = String[3 ]; v18[0 ] = String[2 ]; v18[2 ] = String[4 ]; if ( String[0 ] == v7[0 ] + 34 && String[1 ] == n_C_ && 4 * String[2 ] - 141 == 3 * n_S_ && String[3 ] / 4 == 2 * (n_H_ / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } }
这下知道v4与v5的原来是什么,当然注意v4与v5被赋值的字符串下标的顺序
13.maz 这道题是要找到迷宫怎么样
上线及看见upx壳
1 2 3 4 5 6 7 8 9 maze = '*******+********* ****** **** ******* **F****** **************' end = maze.index('F' ) end_x = 5 end_y = 4 width = (end-end_x)//end_y length = len (maze)//width for i in range (length): print (maze[(width*i):(width * (i+1 ))])