-
-
[分享]2021 MAR DASCTF RE题解
-
2021-4-7 08:58 4166
-
这次比赛, 没有向以前一样爆零了,就很舒服
赛后官方提供了复盘,就用 复盘一下,写一下wp
drinkSomeTea
主函数逻辑
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 __cdecl main( int argc, const char * * argv, const char * * envp) { HANDLE v3; / / eax void * v4; / / esi int result; / / eax DWORD v6; / / edi char * v7; / / esi DWORD v8; / / ebx HANDLE v9; / / eax void * v10; / / esi DWORD NumberOfBytesRead; / / [esp + Ch] [ebp - 8h ] BYREF DWORD NumberOfBytesWritten; / / [esp + 10h ] [ebp - 4h ] BYREF sub_401000(); puts(aWelcomeToMyTea); v3 = CreateFileA(FileName, 0xC0000000 , 0 , 0 , 3u , 0x80u , 0 ); v4 = v3; if ( v3 = = (HANDLE) - 1 ) { puts(aIThinkYouDoNot); result = 0 ; } else { v6 = GetFileSize(v3, 0 ); if ( v6 < 0xEA60 ) { SetFilePointer(v4, 0 , 0 , 0 ); NumberOfBytesRead = 0 ; ReadFile(v4, &unk_409988, v6, &NumberOfBytesRead, 0 ); CloseHandle(v4); if ( v6 >> 3 ) { v7 = (char * )&unk_409988; v8 = v6 >> 3 ; do { / / 关键函数,但是被 嵌入了花指令, 负责了关键部分数据处理 ((void (__cdecl * )(char * , void * ))loc_4010A0)(v7, &unk_407030); v7 + = 8 ; - - v8; } while ( v8 ); } v9 = CreateFileA(aTeaPngOut, 0xC0000000 , 0 , 0 , 2u , 0x80u , 0 ); v10 = v9; if ( v9 = = (HANDLE) - 1 ) { puts(aIThinkYouDoNot); } else { NumberOfBytesWritten = 0 ; WriteFile(v9, &unk_409988, v6, &NumberOfBytesWritten, 0 ); CloseHandle(v10); puts(aNowThisCupOfTe); } result = 0 ; } else { puts(aYourTeaIsTooHo); result = 0 ; } } return result; } |
去花指令
明显的一个 tea 加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | int * __cdecl sub_4010A0( int * a1, _DWORD * a2) { int * result; / / eax int v3; / / [esp + Ch] [ebp - 14h ] int i; / / [esp + 14h ] [ebp - Ch] int v5; / / [esp + 18h ] [ebp - 8h ] int v6; / / [esp + 1Ch ] [ebp - 4h ] v5 = 0 ; v6 = a1[ 1 ]; v3 = * a1; for ( i = 0 ; i < 32 ; + + i ) { v5 - = 0x61C88647 ; v3 + = (a2[ 1 ] + (v6 >> 5 )) ^ (v5 + v6) ^ ( * a2 + 16 * v6); v6 + = (a2[ 3 ] + (v3 >> 5 )) ^ (v5 + v3) ^ (a2[ 2 ] + 16 * v3); } a1[ 1 ] = v6; result = a1; * a1 = v3; return result; } |
密钥在main 函数里面
flag{fake_flag!}get out!
解密代码
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 | / / tea加解密.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 / / #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <stdio.h> void decrypt(unsigned int * v, unsigned int * key) { int l; / / [esp + Ch] [ebp - 14h ] int sum ; / / [esp + 18h ] [ebp - 8h ] int r; / / [esp + 1Ch ] [ebp - 4h ] r = v[ 1 ]; l = v[ 0 ]; sum = 0xC6EF3720 ; for (size_t i = 0 ; i < 32 ; i + + ) { / / sum - = 0x61C88647 ; r - = (key[ 3 ] + (l >> 5 )) ^ ( sum + l) ^ (key[ 2 ] + ( 16 * l)); l - = (key[ 1 ] + (r >> 5 )) ^ ( sum + r) ^ (key[ 0 ] + ( 16 * r)); sum + = 0x61C88647 ; / / r - = ((l * 16 ) + key[ 2 ]) ^ (l + sum ) ^ ((l >> 5 ) + key[ 3 ]); / / l - = ((r * 16 ) + key[ 0 ]) ^ (r + sum ) ^ ((r >> 5 ) + key[ 1 ]); } v[ 0 ] = l; v[ 1 ] = r; } void de_file() { char file_path[] = { "C:\\Users\\Dell\\Desktop\\Test\\tea.png.out" }; FILE * file_point = fopen(file_path, "rb" ); fseek(file_point, 0 , SEEK_END); int len = ftell(file_point); fseek(file_point, 0 , SEEK_SET); char * file_content = (char * )malloc( len ); memset(file_content, 0 , len ); fread(file_content, 1 , len , file_point); fclose(file_point); char new_file_path[] = { "C:\\Users\\Dell\\Desktop\\Test\\tea.png" }; FILE * new_file_point = fopen(new_file_path, "wb" ); char secry_key[] = { 0x66 , 0x6C , 0x61 , 0x67 , 0x7B , 0x66 , 0x61 , 0x6B , 0x65 , 0x5F , 0x66 , 0x6C , 0x61 , 0x67 , 0x21 , 0x7D , 0x67 , 0x65 , 0x74 , 0x20 , 0x6F , 0x75 , 0x74 , 0x21 , 0x20 , 0x0A , 0x00 }; for ( int i = 0 ; i < len ; i + = 8 ) { decrypt((unsigned int * )(file_content + i), (unsigned int * )secry_key); } fwrite(file_content, 1 , len , new_file_point); fclose(new_file_point); } void main() { de_file(); } |
有点坑, 当使用魔数 0x61C88647 时, 解密的初始化数值必须是 0xC6EF3720
Enjoyit-1
de4dot 反混淆后,base64 变表解密,得到key, 再修改代码,输入key 即可得到flag
将所有等待时间删掉
getflag
replace
是一个 hook ,将 IsDebugParent 执行流程替换, 再里面将 最后的比较进行了替换, 有一层很复杂的东西, 手撕不动(指我自己) , 哭了,我怎么这么菜
main 函数
代码简洁,易懂
最后替换的函数,也是解题的关键
参考这位师傅 replace 解法: https://www.cnblogs.com/c10udlnk/p/14606861.html
师傅们tql
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 | from binascii import * from hashlib import md5 ans = unhexlify( "416f6b116549435c2c0f1143174339023d4d4c0f183e7828" ) tmps = [ 0 , 6 , 12 , 18 ] seq = [] for i in range ( 6 ): tmpl = [x + i for x in tmps] seq = seq + tmpl print (seq) arr1 = [ 0 for i in range ( 24 )] for i in range ( 24 ): arr1[seq[i]] = ans[i] box = [ 0x00000080 , 0x00000065 , 0x0000002F , 0x00000034 , 0x00000012 , 0x00000037 , 0x0000007D , 0x00000040 , 0x00000026 , 0x00000016 , 0x0000004B , 0x0000004D , 0x00000055 , 0x00000043 , 0x0000005C , 0x00000017 , 0x0000003F , 0x00000069 , 0x00000079 , 0x00000053 , 0x00000018 , 0x00000002 , 0x00000006 , 0x00000061 , 0x00000027 , 0x00000008 , 0x00000049 , 0x0000004A , 0x00000064 , 0x00000023 , 0x00000056 , 0x0000005B , 0x0000006F , 0x00000011 , 0x0000004F , 0x00000014 , 0x00000004 , 0x0000001E , 0x0000005E , 0x0000002D , 0x0000002A , 0x00000032 , 0x0000002B , 0x0000006C , 0x00000074 , 0x00000009 , 0x0000006E , 0x00000042 , 0x00000070 , 0x0000005A , 0x00000071 , 0x0000001C , 0x0000007B , 0x0000002C , 0x00000075 , 0x00000054 , 0x00000030 , 0x0000007E , 0x0000005F , 0x0000000E , 0x00000001 , 0x00000046 , 0x0000001D , 0x00000020 , 0x0000003C , 0x00000066 , 0x0000006B , 0x00000076 , 0x00000063 , 0x00000047 , 0x0000006A , 0x00000029 , 0x00000025 , 0x0000004E , 0x00000031 , 0x00000013 , 0x00000050 , 0x00000051 , 0x00000033 , 0x00000059 , 0x0000001A , 0x0000005D , 0x00000044 , 0x0000003E , 0x00000028 , 0x0000000F , 0x00000019 , 0x0000002E , 0x00000005 , 0x00000062 , 0x0000004C , 0x0000003A , 0x00000021 , 0x00000045 , 0x0000001F , 0x00000038 , 0x0000007F , 0x00000057 , 0x0000003D , 0x0000001B , 0x0000003B , 0x00000024 , 0x00000041 , 0x00000077 , 0x0000006D , 0x0000007A , 0x00000052 , 0x00000073 , 0x00000007 , 0x00000010 , 0x00000035 , 0x0000000A , 0x0000000D , 0x00000003 , 0x0000000B , 0x00000048 , 0x00000067 , 0x00000015 , 0x00000078 , 0x0000000C , 0x00000060 , 0x00000039 , 0x00000036 , 0x00000022 , 0x0000007C , 0x00000058 , 0x00000072 , 0x00000068 ] arr2 = [ 0 for i in range ( 24 )] for i in range ( 5 ): for j in range ( 24 ): arr2[j] = box.index(arr1[j]) arr1 = arr2 myInput = ''.join( map ( chr ,arr1)) print (myInput) flag = myInput.encode() print (md5(flag).hexdigest()) # 别忘了最后提交md5 |
变形栅栏 + 盒子变换
最后 md5 提交
这题,比赛的时候,上面的盒子变换都给我看傻了, 下面的栅栏直接给我干死,然后直接放弃这一题, 看师傅们随随便便解出来,我真的感觉自己是个废物
奇怪的扫雷
这题预期解是 开发扫雷外挂,并在几秒钟内解出来。 然后我也看不懂里面的代码,连异常咋触发的都看不懂, 哭了。靠着师傅们的wp, 勉强维持生活。
最后在出题人师傅不留余力的帮助下,完成了 扫雷外挂的开发, 太难了
使用工具:
- vs2019
- spy++
- ce
这里面出题人师傅关闭了 aslr , 所以基地址是直接固定的, 格子的大小是 16 * 16 ,sendmessage 点击是呈比例的, 和缩放与布局有关, 其他的也没啥, 具体参考:
https://www.xuenixiang.com/thread-2989-1-1.html
完整代码
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | / / q师傅扫雷外挂开发.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 / / #include <iostream> #include<Windows.h> #include "assert.h" #define MAPHEAD 0x0019627C #define MAPHEIGHT 0x19623C #define MAPWIDTH 0x196240 struct SigData { DWORD sate; DWORD flag; }Pro; int GetScaling() { / / 获取窗口当前显示的监视器 / / 使用桌面的句柄. HWND hWnd = GetDesktopWindow(); HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); / / 获取监视器逻辑宽度与高度 MONITORINFOEX miex; miex.cbSize = sizeof(miex); GetMonitorInfo(hMonitor, &miex); int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left); int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top); / / 获取监视器物理宽度与高度 DEVMODE dm; dm.dmSize = sizeof(dm); dm.dmDriverExtra = 0 ; EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm); int cxPhysical = dm.dmPelsWidth; int cyPhysical = dm.dmPelsHeight; / / 缩放比例计算 实际上使用任何一个即可 double horzScale = ((double)cxPhysical / (double)cxLogical); double vertScale = ((double)cyPhysical / (double)cyLogical); assert (horzScale = = vertScale); / / 宽或高这个缩放值应该是相等的 return ( int ) round ( 16.0 / horzScale); } int main() { int height = 0 ; int width = 0 ; DWORD MainPid = 0 ; HWND MainHwnd = FindWindow(NULL, TEXT( "奇怪的扫雷" )); GetWindowThreadProcessId(MainHwnd, &MainPid); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, MainPid); SIZE_T size = 4 ; ReadProcessMemory(hProcess, (LPCVOID)MAPWIDTH, &width, 4 , &size); ReadProcessMemory(hProcess, (LPCVOID)MAPHEIGHT, &height, 4 , &size); int LeiCount = 0 ; LPCVOID tmp = NULL; SIZE_T ProSize = 8 ; int Scalie = GetScaling(); for ( int x = 1 ; x < height + 1 ; x + + ) { for ( int y = 0 ; y < width; y + + ) { ReadProcessMemory(hProcess, (LPCVOID)(MAPHEAD + ((x - 1 ) * width + y) * 4 ), &tmp, 4 , &size); ReadProcessMemory(hProcess, (LPCVOID)tmp, &Pro, 8 , &ProSize); int xPos, yPos; xPos = (y * Scalie) + 26 ; yPos = (x * Scalie) + 46 ; if (Pro.flag = = 0xffffffff ) { SendMessage(MainHwnd, WM_RBUTTONDOWN, 0 , MAKELPARAM(xPos, yPos)); SendMessage(MainHwnd, WM_RBUTTONUP, 0 , MAKELPARAM(xPos, yPos)); printf( "雷 " ); LeiCount + + ; } else { SendMessage(MainHwnd, WM_LBUTTONDOWN, 0 , MAKELPARAM(xPos, yPos)); SendMessage(MainHwnd, WM_LBUTTONUP, 0 , MAKELPARAM(xPos, yPos)); printf( "无 " ); } } printf( "\n" ); } printf( "\n有雷: %d 个, 高:%d, 宽: %d" , LeiCount, height, width); return 1 ; } |
getflag