学习逆向之后,在github找题目进行复现的。
Easy_Encryption
提示很多,直接找到main函数,简单分析一下,对输入flag进行2个加密函数后,最后与一个已知密文比较。其中第二个明显的base64加密。
来到一个加密函数,由于ida栈顶分析失败导致,直接alt+k修改一下就可以了。
愉快的看伪代码,一个注意的地方:
直接简单的爆破。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <stdio.h> #include <math.h>
int main(void) { char s[] = "artqkoehqpkbihv", i = 0, j = 0; char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for(i = 0; base[i]; i++) base[i] = abs(base[i]-97); for(i = 0; i <= s[i]; i++) for(j = 97; j <= 122; j++) if((j+base[i]-97)%26+97 == s[i]) putchar(j); return 0; }
|
game
ida载入后,发现伪代码十分难看。。。看了一会儿,实在不想分析了,所有函数都是一种形式,感觉是什么混淆代码的技术。
百度后,发现是ollvm,控制流平坦化技术。
控制流平坦化(control flow flattening)的基本思想主要是通过一个主分发器来控制程序基本块的执行流程,这个主分发器就是函数中的switch语句。
且目前可以利用符号执行来去除控制流平坦化。利用符号执行去除控制流平坦化
而这也需要angr,网上说的都是建议安装在python虚拟环境中。
跟着教程安装完虚拟环境并创建后,但angr又安装失败。。。后面发现还可以直接用dokcer。
了解一波docker,docker,折腾一些时间(谷歌大法帮了大忙👍)后成功执行deflat.py脚本。
又是愉快的伪代码,简单就不分析了,使用gdb动调出2个对比的数独表,找出差异的数字,即0所在位置。
然后使用notepad++找不不同:
最后简单解密一下:
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
| #include <stdio.h> #include <string.h>
int main(void) { char s[] = "4693641762894685722843556137219876255986"; int i = 0, j = 0, k = 0, count = 0; for(i = 0; s[i]; i++) { for(j = 33; j <= 122; j++) { if(((j&0xf3 | ~j&0xc)-20) == s[i]) { s[i] = j; break; } } } for(i = 0; i < strlen(s); i += 2) { char temp = s[i]; s[i] = s[i+1]; s[i+1] = temp; } k = strlen(s)/2; for(i = 0; i < strlen(s)/2; i++) { char temp = s[k]; s[k] = s[i]; s[i] = temp; k++; } puts(s); return 0; }
|
crackme
打开程序,出现hooked,表示已经对程序中的的函数hook成功。
而之前我也在逆向工程核心原理一书中看到过该章节的一点内容,它的介绍:
代码逆向分析中,钩取(hooking)是一种截取信息,更改程序流程,添加新功能的技术。
ida中找到main函数后,会发现很奇怪,有一个异常,且没有操作输入flag的函数,猜测是hook改变了程序的程序流程。但可以通过数据交叉引用找到关键函数。
看了一下所有与计算输入数据与比较数据相关的函数,了解大致流程后,OD进行动调看看:
其中main函数中的MessageBox函数执行后并没有正常的执行,而是跳到了一个新的函数,也是ida中分析过的过数据加密的函数。结合ida继续动调:
OD中看到跳到的main函数触发异常的地方,但是程序无法处理的异常。。。
那上图中的TopLevelExceptionFilter关键加密函数不执行的嘛。。使用PEtools来dump出正常执行的程序看到数据改变了的,那是执行了的。。
百度一下SetUnhandledExceptionFilter(TopLevelExceptionFilter)函数:简单来说就是设置一个发生异常处理的函数,且它会将原来默认处理异常的函数hook掉。且我们的程序要不处于调试状态才会去执行它设置的异常处理函数。介绍
参数:lpTopLevelExceptionFilter 函数指针。当异常发生时,且程序不处于调试模式(在vs或者别的调试器里运行)则首先调用该函数。
程序流程清楚了,开始分析算法:
第二个加密函数变种的base64,但第一个看不出什么名堂,自己逆的话感觉工程量肯定大且很大几率搞不出来。。
就想着先把变种的base64先解密,但一直解密乱码。。不能啊,自己也写了2个函数来测试,能将变种加密的base64还原为正常base64加密的,但题中的密文不行,。。
模拟本题的变种base64加密(也是从模拟发现是base64的):
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
| #include <stdio.h> #include <stdlib.h> #include <string.h>
int main(void) { int k; int v3; signed int j; int v5; signed int i; char *v7; signed int v8; int v9; int temp = 0; char str[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"; char Str[] = "123456"; v5 = 0; v8 = strlen(Str); if ( v8 % 3 ) v9 = 4 * (v8 / 3) + 4; else v9 = 4 * (v8 / 3); v7 = (char *)malloc(sizeof(char)*(v9+1)); v7[v9] = 0; for ( i = 0; i < v8; i += 3 ) { v3 = 0; for ( j = 0; j < 3; ++j ) v3 |= (unsigned __int8)Str[j + i] << 8 * (2 - j); for ( k = 0; k < 4; ++k ) { if ( k >= 4 - (i + 3 - v8) && i + 3 > v8 ) v7[v5] = '!'; else temp = (((v3 >> 6 * (3 - k)) & 0x3F)+24)%64, v7[v5] = str[temp], printf("%d ", temp);; ++v5; } } puts(v7); }
|
还原成正常加密的base64密文:
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 <stdio.h>
int main(void) { int i = 0, j = 0, k = 0; char a[] = "KRGlLBSo"; char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char a1[] = {20, 53, 0, 19, 8, 14, 41, 36, 14, 50, 22, 18, 47, 6, 38, 63, 24, 14, 24, 5, 17, 56}; for(i = 0; a[i]; i++) for(j = 0; j < 64; j++) if(a[i] == s[j]) { int t = j; if(t <= 25) t += 26; else if(t <= 51) t -= 26; for(k = 0; k < 64; k++) if((k+24)%64 == t) { putchar(s[k]); break; } } return 0; }
|
正常base64解密:可以看到,解密出明文。
就这样卡住了。。。也无心看第一个加密了。
不行,去看了看writeup,原来这个解密出本来就是乱码,转化为16进制就好。。。又直接看了第一个加密是sm4。。
它在加密中其实有标志的:一是表,二是0xA3B1BAC6
最后python安装pysm4进行解密:
首先base64解密且转化为16进制:
1 2 3 4 5 6 7 8 9 10
| from base64 import b64decode
def str_to_hex(s): return ''.join([hex(c).replace('0x', '') for c in s])
s = "WdCVKQ3yQAYU9I0naQaHTg==" s1 = b64decode(s)
ans = str_to_hex(s1) print(ans)
|
sm4解密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from pysm4 import encrypt, decrypt
mk = 0x77686572655f6172655f755f6e6f773f
cipher_num = 0x59d095290df2400614f48d276906874e
clear_num = decrypt(cipher_num, mk) s = hex(clear_num)[2:] print(s)
def hex_to_str(s): return ''.join([chr(i) for i in [int(s[j]+s[j+1], 16) for j in range(0, len(s), 2)]]) print(hex_to_str(s))
|