[极客大挑战]2022 复现
这次的极客大挑战学到了不少东西,包括之前没有深入了解的
android方面的逆向
RC4加密与解密
Base变表的爆破
pwn方面
主要还是在做题得到角度能到拓展
(做出来的题就不复现了哈)….(@A@)
RE
CrezyThursday.exe
根据官方wp可以知道,这题主要考点就是SMC也就是Self Modifying Code(动态代码加密技术)奇安信攻防社区-初探smc动态代码保护 (butian.net)
==这里我就简单说一下,详细的我另起一篇博客==
这里留给位置贴
主要的流程如下:
1 2 3 4 5 6
| IF .运行条件满足 CALL DecryptProc (Address of MyProc);对某个函数代码解密 ........ CALL MyProc ;调用这个函数 ........ CALL EncryptProc (Address of MyProc);再对代码进行加密,防止程序被Dump
|
可以看到这里对一个巨大的数组进行了操作
动调查看操作完以后的函数
发现这里的数据变成PE文件格式
dump下来以后发现这个可能dll文件
和官方wp描述相同,
1
| (当时还不知道这题是SMC就动调一直跟进到qword_7FF6D5DDC660...嘿嘿)
|
继续动调,发现了SMC的第二步,也就是调用解密后的代码,不过这里调用的dll就是了
通过动调拿到调用的dll函数是0x180001000h
回到dll
找到函数
进一步分析
(QAQ我Findcrypt插件分析不出来,不知道是RC4..然后就放弃这题了)
这现在知道了是RC4
这里就贴一个RC4的博客叭(待改)画饼+1
密钥是StartReverse,密文在后面的比对那里
1
| E75FC6E9D9E5D6115A85F34934E327DAC8D9BCE153A5F0D5
|
然后就可以拿到风神那里直接梭哈
拿到flag---SYC{wwww@RC_RC_RC_RC@wwww:)H}
maze
这题我做出来了,迷宫嘛
这里我根据网上的算法写了一个dfs算法找路,但是遍历范围太大了,没遍出来
但是减少他的方向选择就能出来
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 sys sys.setrecursionlimit(100000)
crack = '##########################0#0000000#0#0#000000000##0#######0#0#0#0#0#0###0##00000#000#00000#0#000#0######0###0#0##############0#0#0#0#0#000#0#000#000##0#0#S#0#0#0###0#0###0####000#00000#0#000#000#0#0####0#####0#0#0###0###0#0##0#00000#000#0#0#0#000#0##0#####0#0###0#0#0#0###0##0#000#000#0#0#0#0000000##0###0###0#0#0#0#0#0######0#000000000000000#00000##0#0#######0#####0###0####000#00000000000#000#000######0#####0#########0#0##00000#0000000000000#0#0##0###0#0#0###0###0#####0##000#0#0#0#00000#0#000#0##0#0#0#####0#0#####0######0#0#0#00000#00000000000##0#0#####0#0#0#0#0#####0##0#0#00000#0#0#0#00000#E##########################' maze = list(crack) method =['$','&'] path = [] def mark(maze,pos): maze[pos] = '1' def find_path(crack,pos,end): if(crack[pos] == 'E'): print("right!") return True for i in method: if( i == '$'): npos =pos+ 1 elif(i=='*'): npos = pos - 1 elif(i=="&"): npos = pos + 25 if(crack[npos]=='0' or crack[npos]=='E'): print(i,end='') if(find_path(crack,npos,end)): path.append(i) return True return False
if __name__ == "__main__": find_path(maze,155,598) for i in range(len(path)-1,-1,-1): print(path[i],end="")
|
flag–SYC{&$$$$&&&&&&$$&&&&$$&&&&$$$$$$$$$$&&}
EX
C++的异常报错题,比的时候没做好像,最后两天才进的比赛嘛…还要看pwn,孩子看不完哇QAQ。。。
这题看了一天。。真就一天复现一题 ___ 菜Orz(碎碎念)
这题其实是也不是第一次接触C++的异常报错了,不过前几次动调的话还能跑到catch块
但是这题就跑不到….恼…
看了wp学了正常做法
也就是通过patch掉throw,将抛出异常的地方patch成对应的catch块
这里有两种方法…
一种是官方wp的通过动调,trace模块找到对应的throw…catch
另一种就是直接找了
学了一天,发现,catch块都存在相同的函数调用,还挺规范呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| call ___cxa_begin_catch .text:000056073D3A1796 mov [rbp+var_88], rax .text:000056073D3A179D mov eax, cs:dword_56073D3A4010 .text:000056073D3A17A3 mov [rbp+var_A8], eax .text:000056073D3A17A9 mov eax, cs:dword_56073D3A4014 .text:000056073D3A17AF mov [rbp+var_A4], eax .text:000056073D3A17B5 mov eax, cs:dword_56073D3A4018 .text:000056073D3A17BB mov [rbp+var_A0], eax .text:000056073D3A17C1 mov eax, cs:dword_56073D3A401C .text:000056073D3A17C7 mov [rbp+var_9C], eax .text:000056073D3A17CD mov eax, cs:dword_56073D3A41D4 .text:000056073D3A17D3 add eax, 1 .text:000056073D3A17D6 mov cs:dword_56073D3A41D4, eax .text:000056073D3A17DC call ___cxa_end_catch
|
也就是通过**___cxa_begin_catch和___cxa_end_catch**包括catch块
并且IDA也会通过注释的方式,展示catch那里的throw
owned by 地址 就是抛出异常的地方
改它
然后F5出来
(好像没改太对。。。。)
这就是改出来的东西,起码能看了。。。是叭
相关的逻辑就是
v24,25分别从后往前进行保存4字节的s(s是输入的字符串)
(这里进行了两次赋值,所以最后v24=s[8]且v25=s[8+4])
然后有一个key表
在嵌套里面的代码是:
1 2 3 4
| for(int k=0;k<=31;k++){ v24 += (v0 + k2) ^ (v0 - k3) ^ roundKey ^ j; v25 += (v1 + k0) ^ (v1 - k1) ^ roundKey ^ j; }
|
官方解题脚本如下图:
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 <iostream> #include <cstdint> #include <cstdio> using namespace std; union solver { char flag[17]; uint32_t cipher[4]; }; int main() { solver s; s.cipher[0] = 0xa2216203; s.cipher[1] = 0xaa9f6a27; s.cipher[2] = 0x5d411ed3; s.cipher[3] = 0x503b3f1c; s.flag[16] = 0; uint32_t key[4] = {0x11223344, 0x22334455, 0x33445566, 0x44556677}; uint32_t roundKey = 0x99887766; for(int i = 0; i < 2; i++) { uint32_t v0 = s.cipher[i*2], v1 = s.cipher[i*2+1]; uint32_t k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3]; for(int j = 31; j >=0; j--) { v1 -= (v0 + k2) ^ (v0 - k3) ^ roundKey ^ j; v0 -= (v1 + k0) ^ (v1 - k1) ^ roundKey ^ j; } s.cipher[i*2] = v0; s.cipher[i*2+1] = v1; } cout << hex << s.cipher[3] << endl; string flag = s.flag; cout << flag << endl; }
//结果 //3376306c //syc-w3n-ch4-l0v3
|
这里使用了unint32_t数据类型,需要配置编译器使用c++11的编译规则
下一题
mvze
虚拟机题目(ezvm)